Add image source from StorageFile UWP - c#

I'm trying to add image source from Storage Folder. First I capture photo and save it to the Storage Folder
Windows.Storage.StorageFolder storageFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
private async void btnPhoto_Click(object sender, RoutedEventArgs e)
{
// Create the file that we're going to save the photo to.
var file = await storageFolder.CreateFileAsync("sample.jpg", CreationCollisionOption.GenerateUniqueName);
// Update the file with the contents of the photograph.
await _mediaCapture.CapturePhotoToStorageFileAsync(ImageEncodingProperties.CreateJpeg(), file);
}
At the next Page I should get the photo from cache, but I have an exception, when I'm creating sampleFile
public async void GetImage()
{
string filename = "sample.jpg";
Windows.Storage.StorageFile sampleFile =
await Windows.Storage.KnownFolders.DocumentsLibrary.GetFileAsync(filename); // Here I have exception {"Access is denied.\r\n"} System.UnauthoriziedAccessException
BitmapImage img = new BitmapImage();
img = await LoadImage(sampleFile);
image1.Source = img;
}
private static async Task<BitmapImage> LoadImage(StorageFile file)
{
BitmapImage bitmapImage = new BitmapImage();
FileRandomAccessStream stream = (FileRandomAccessStream)await file.OpenAsync(FileAccessMode.Read);
bitmapImage.SetSource(stream);
return bitmapImage;
}
What I'm doing wrong? And how can I get access to Storage Folder?

You can't access the document library unless the user allows you to do that. You can specify document library access in the manifest, but only for certain files, and such app will probably never be published in the Windows Store unless it REALLY requires that access as stated by Microsoft. As you are using .jpg files you have Pictures library for that, and you can specify it in the manifest and everything will work just fine.
Otherwise you get access by file picker, storing the token to recall it later.

Related

How do I use the CanvasBitmap.SaveAsync method?

In the Win2D API documentation they say
Saves the entire bitmap to a file with the specified file name, using
a default quality level of 0.9 and CanvasBitmapFileFormat.Auto.
It doesn't say where the file is saved or how to choose where the file is saved.
I tried playing with the method in order to figure it out but everytime I call it I get an "Access denied" exception error.
string filename = "Test pic test.png";
StorageFile TestFile = await PictureFolder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting);
using (IRandomAccessStream strem = await TestFile.OpenAsync(FileAccessMode.ReadWrite))
{
await CanvasImage.SaveAsync(filename);
}
Firstly, this above description is for CanvasBitmap.SaveAsync method. Since Win2D also contains CanvasImage class, I suggest to avoid naming the instance to CanvasImage.
According to this similar issue:
In general you can't pass around paths in the user's filesystem (as opposed to special folders like the app package directory) because of the UWP security model:
https://learn.microsoft.com/en-us/windows/uwp/files/file-access-permissions
So that you need to pass the stream directly into SaveAsync, not just the path as a string. In your code snippet you open the file stream but didn't save the stream to the file. Just save the stream to the file it will work. For example:
CanvasDevice device = CanvasDevice.GetSharedDevice();
CanvasRenderTarget renderTarget = new CanvasRenderTarget(device, 300, 300, 96);
using (var ds = renderTarget.CreateDrawingSession())
{
ds.Clear(Colors.White);
ds.DrawRectangle(155, 115, 80, 30, Colors.Black);
}
CanvasBitmap bit = renderTarget;
string filename = "Test pic test.png";
StorageFolder pictureFolder = KnownFolders.SavedPictures;
var file = await pictureFolder.CreateFileAsync(filename, CreationCollisionOption.ReplaceExisting);
using (var fileStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
await bit.SaveAsync(fileStream, CanvasBitmapFileFormat.Png, 1f);
}
More details you can reference this blog.

How to get ImageStream from MediaCapture?

In WP 8 I used PhotoCamera to make a camera app and to save the image in camera roll I used this method:
private void cam_CaptureImageAvailable(object sender, ContentReadyEventArgs e)
{
string fileName = "photo.jpg";
MediaLibrary library = new MediaLibrary();
library.SavePictureToCameraRoll(fileName, e.ImageStream);
}
In WPSL 8.1 I use MediaCapture and I use the same style to save image in camera roll but I don't know how to retrieve ImageStream from MediaCapture like in e.ImageStream. I am open to suggestions even with other programming style for saving to camera roll.
var file = await Windows.Storage.KnownFolders.PicturesLibrary.CreateFileAsync(IMAGECAPTURE_FILENAME, Windows.Storage.CreationCollisionOption.ReplaceExisting);
await _exceptionHandler.Run(async () =>
{
await _mediaCapture.CapturePhotoToStorageFileAsync(_imageEncodingProperties, file);
var photoStream = await file.OpenAsync(Windows.Storage.FileAccessMode.Read);
await bitmap.SetSourceAsync(photoStream);
});
The above is taken from a UWP app to save an image to storage, then read it from disk as a stream. I've never been able to capture the image directly as a stream.

Write byte array to storage file in windows phone

I'm using Visual studio 2012, c#, silverlight, windows phone 8 app.
We get our data from a webservice, and through the webservice we get a picture that is an base64 string.
I convert it to a byte array, and now I want to save it so the Storage of the windows phone, using a memory stream? I don't know if it is the right approach. I don't want to save it to isolated storage, just the local folder because I want to show the picture after a person tapped on the link.
this is what I have so far.
byte[] ImageArray;
var image = Attachmentlist.Attachment.ToString();
imagename = Attachmentlist.FileName.ToString();
ImageArray = Convert.FromBase64String(image.ToString());
StorageFolder myfolder = Windows.Storage.ApplicationData.Current.LocalFolder;
await myfolder.CreateFileAsync(imagename.ToString());
StorageFile myfile = await myfolder.GetFileAsync(imagename.ToString());
MemoryStream ms = new MemoryStream();
so after I have initialized the memory stream how do I take the byte array and write it to the storage file, and after that retrieve it again?
To write file to disc try this code:
StorageFile sampleFile = await myfolder.CreateFileAsync(imagename.ToString(),
CreateCollisionOption.ReplaceExisting);
await FileIO.WriteBytesAsync(sampleFile, ImageArray);
Memory stream creates stream that writes in memory so it is not applicable to this problem.
StorageFolder folder = ApplicationData.Current.LocalFolder;
StorageFile imageFile = await folder.CreateFileAsync("Sample.png", CreationCollisionOption.ReplaceExisting);
using (IRandomAccessStream fileStream = await imageFile.OpenAsync(FileAccessMode.ReadWrite))
{
using (IOutputStream outputStream = fileStream.GetOutputStreamAt(0))
{
using (DataWriter dataWriter = new DataWriter(outputStream))
{
dataWriter.WriteBytes(imageBuffer);
await dataWriter.StoreAsync();
dataWriter.DetachStream();
}
//await outputStream.FlushAsync();
}
//await fileStream.FlushAsync();
}

Download and Save image in Pictures Library through Windows 8 Metro XAML App

I am trying to develop a simple Windows 8 Metro app which simply downloads an image file from a given URL (say http://sample.com/foo.jpg) and then save it to Pictures Library.
I have an image control in the UI to display the downloaded image.
I'm also facing difficulty in setting the image source for the image control to the newly downloaded image (actually I'm not even able to download it).
Also, is it possible to store the image file in a particular folder in the Pictures library (if it doesn't exist, then the app should create it)?
I'm really stuck here.
Please help me.
Here's some rough code that I believe accomplishes what you want. It assumes you have two image controls (Image1 and Image2) and that you have the Pictures Library capability checked in the manifest. Take a look at the XAML images sample as well
Uri uri = new Uri("http://www.picsimages.net/photo/lebron-james/lebron-james_1312647633.jpg");
var fileName = Guid.NewGuid().ToString() + ".jpg";
// download pic
var bitmapImage = new BitmapImage();
var httpClient = new HttpClient();
var httpResponse = await httpClient.GetAsync(uri);
byte[] b = await httpResponse.Content.ReadAsByteArrayAsync();
// create a new in memory stream and datawriter
using (var stream = new InMemoryRandomAccessStream())
{
using (DataWriter dw = new DataWriter(stream))
{
// write the raw bytes and store
dw.WriteBytes(b);
await dw.StoreAsync();
// set the image source
stream.Seek(0);
bitmapImage.SetSource(stream);
// set image in first control
Image1.Source = bitmapImage;
// write to pictures library
var storageFile = await KnownFolders.PicturesLibrary.CreateFileAsync(
fileName,
CreationCollisionOption.ReplaceExisting);
using (var storageStream = await storageFile.OpenAsync(FileAccessMode.ReadWrite))
{
await RandomAccessStream.CopyAndCloseAsync(stream.GetInputStreamAt(0), storageStream.GetOutputStreamAt(0));
}
}
}
// read from pictures library
var pictureFile = await KnownFolders.PicturesLibrary.GetFileAsync(fileName);
using ( var pictureStream = await pictureFile.OpenAsync(FileAccessMode.Read) )
{
bitmapImage.SetSource(pictureStream);
}
Image2.Source = bitmapImage;
}

The best way load files from Isolated Storage

In my Windows Store App I save/use files (almost images) in Isolated Storage. When I need to present image i use following:
var file = await folder.GetFileAsync(fileName);
using (var stream = await file.OpenAsync(FileAccessMode.Read))
{
obj.Image = new BitmapImage();
await obj.Image.SetSourceAsync(stream);
}
But when I use 3+ images in same page I have lags. I'm looking for faster solution to access Isolated Storage files.
You can try to start with this article Optimize media resources (Windows Store apps using C#/VB/C++ and XAML), and couple more things:
Make sure that if you show them in the ListView / GridView - you have enabled virtualization (you use right ItemsPanel which supports virtualization).
If you just need to load images from local storage - set the binding from Image.Source to to the right URI (ms-appx:/// or ms-appdata:///local/), and Image control will do everything for you.
I don't know how you're opening multiple images, but since all the methods are asynchronous you shouldn't iterate through your files sequentially, but open all of them in parallel.
So instead of doing this (where you're waiting for the previous image to load before starting to load the next one):
foreach (var fileName in fileNames)
{
var file = await folder.GetFileAsync(fileName);
using (var stream = await file.OpenAsync(FileAccessMode.Read))
{
obj.Image = new BitmapImage();
await obj.Image.SetSourceAsync(stream);
}
}
You should approach it like this:
// not sure about the type of obj
public async Task<Image> LoadImage(string fileName, dynamic obj)
{
var file = await folder.GetFileAsync(fileName);
using (var stream = await file.OpenAsync(FileAccessMode.Read))
{
obj.Image = new BitmapImage();
await obj.Image.SetSourceAsync(stream);
}
}
var tasks = fileNames.Select(f => LoadImage(f, obj)).ToArray();
await Task.WhenAll(tasks);
This will initialize an array of awaitable tasks loading the images and then await all of them at the same time so that they will execute in parallel.

Categories

Resources