How do I use the CanvasBitmap.SaveAsync method? - c#

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.

Related

Add image source from StorageFile UWP

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.

Download Video File via video URL in windows phone 8.1 C#

I have tried to download video file from video URL. Video file created but downloading does not happen here. just 57KB file generate. My code is here.
public async void DownloadTrack(Uri SongUri, string fileName)
{
using (HttpClient httpClient = new HttpClient())
{
var data = await httpClient.GetByteArrayAsync(SongUri);
StorageFolder storageFolder = KnownFolders.VideosLibrary;
var file = await storageFolder.CreateFileAsync(fileName, CreationCollisionOption.GenerateUniqueName);
///////////////////
using (var targetStream = await file.OpenAsync(FileAccessMode.ReadWrite))
{
await targetStream.AsStreamForWrite().WriteAsync(data, 0, data.Length);
await targetStream.FlushAsync();
}
}
}
Here video file creates but does not file download. I want to download file. I searched much about this. here is accepted Stackoverflow answer link but this also does the same. Example
can you please provide any better solution.

Download and save a picture from a url Universal windows app

I am using the below code to downlaod the picture form a remote url and save to Local storage folder
try
{
var rootFolder = await ApplicationData.Current.LocalFolder.CreateFolderAsync( "MyAppName\\CoverPics", CreationCollisionOption.OpenIfExists);
var coverpic_file = await rootFolder.CreateFileAsync(filename, CreationCollisionOption.FailIfExists);
try
{
var httpWebRequest = HttpWebRequest.CreateHttp(coverUrl);
HttpWebResponse response = (HttpWebResponse)await httpWebRequest.GetResponseAsync();
Stream resStream = response.GetResponseStream();
using (var stream = await coverpic_file.OpenAsync(FileAccessMode.ReadWrite))
{
await resStream.CopyToAsync(stream.AsStreamForWrite());
}
response.Dispose();
}
catch //any exceptions happend while saving the picture
{
saved = false;
}
}
catch
{
//https://msdn.microsoft.com/en-us/library/windows/apps/br227250.aspx
//Raise an exception if file already present
saved = true;
}
This code is working for me in most of the cases , but i noticed that for few pictures the image is not downloading completely.
I am callling this function in an async block for more tahn 100 images in a single go inside the foreach loop and in the end few of them are failed downloads
[ Either i can see some invalid file is getting created
or part of image only in downloading and rest of the area i can see a black colour block [ looks like image is corrupted].
Size of all images is less than 1 MB only
Can some one help me to optimize this code or point out the mistake in code so i can able to download all the images completely
I am not seeing any error in my code. But after trying some different ways of downloading and saving a file my code looks like this and
try
{
HttpClient client = new HttpClient(); // Create HttpClient
byte[] buffer = await client.GetByteArrayAsync(coverUrl); // Download file
using (Stream stream = await coverpic_file.OpenStreamForWriteAsync())
stream.Write(buffer, 0, buffer.Length); // Save
}
catch
{
saved = false;
}
And this code is working fine without causing any issues All images are downloading completely and no more issues of black block on images.
If any one can points out the difference with my first code will be really helpful to understood the reason for error
Have you tried using new Windows.Web.Http.HttpClient instead of HttpWebRequest?
Also take a look this SO question :
How do I use the new HttpClient from Windows.Web.Http to download an image?
If you not familiar with HttpClient, I sugest to watch CH9 presentation :
https://channel9.msdn.com/Events/Build/2013/4-092
I tried your download and experienced the same issues.
var myFolder = await ApplicationData.Current.LocalFolder.CreateFolderAsync("MyFolderPath", CreationCollisionOption.OpenIfExists);
var myFile = await myFolder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting);
BackgroundDownloader downloader = new BackgroundDownloader();
DownloadOperation download = downloader.CreateDownload(new Uri(URL), myFile);
await download.StartAsync();

How to correctly resize/recompress image

I have spent the last 10-12 hours trying to figure out how to correctly make a downloaded web image smaller in size and pixels in C# in a Windows Store app under development.
Whatever I do, I keep getting artifacts on the final images such as a "half picture", gray/same-colored areas and likewise. Like if the stream has not been flushed correctly although I believe to have done so (not done so in the code below since it works without it...)
This is my approach for retrieving the image - this part works, but is included here to make sure all info is here (see code below):
Get URL of image
Use HttpWebRequest to get response
Create stream to get response stream
Create empty StorageFile and open for writing
Copy the response stream to the storage file.
Close everything
From there, I need to do the following:
Determine the size (e.g. using BitmapDecoder)
If the width of the image is above a certain amount (e.g. 700 px), it must be resized.
No matter what, the files are always too big and need to be compressed further
The image need to be saved as a jpg with image quality set to a medium/semi-high setting
I have tried many things including messing pretty much around with BitmapEncoder/BitmapDecoder, but no matter what I am still getting half-processed images.
Can somebody please help me find the correct way to compress and resize images?
My code in the current state:
using (var response = await HttpWebRequest.CreateHttp(internetUri).GetResponseAsync())
{
using (var stream = response.GetResponseStream())
{
var imageFolder = await localFolder.CreateFolderAsync(
CachedImagesFolderEndFolderPath, CreationCollisionOption.OpenIfExists);
string fileName = string.Format("{0}.jpg",
Path.GetFileNameWithoutExtension(Path.GetRandomFileName()));
var file = await imageFolder.CreateFileAsync(fileName,
CreationCollisionOption.ReplaceExisting);
using (var filestream = await file.OpenStreamForWriteAsync())
{
await stream.CopyToAsync(filestream);
}
}
}
The following solution was provided by StefanDK in this edit:
It seems that the problem with my former solution was that I did not properly close the streams and that I did not have the correct settings.
Basically the solution incorporates elements from these articles:
How to resize Image in C# WinRT/winmd?
https://stackoverflow.com/questions/15481126/windows-store-app-resize-bitmapimage-c-sharp
http://msdn.microsoft.com/en-us/library/windows/apps/jj709942.aspx
http://msdn.microsoft.com/en-us/library/windows/apps/hh465076.aspx
From the main part of the code I make these calls for each image that needs downloading, resizing and compressing:
Main code
Note that I am well aware of the "not best practice" in assigning a string value and then setting it again. This is prototype code that has not been fine-tuned yet.
var img = await ArticleStorage.GetLocalImageAsync(src);
img = await ArticleStorage.ResizeAndCompressLocalImage(img);
Source code of the methods in ArticleStorage
public const string CachedImagesFolderFullPath = "ms-appdata:///local/cache/";
public const string CachedImagesFolderEndFolderPath = "cache";
public const string OfflinePhotoImgPath = "ms-appx:///Assets/OfflinePhoto.png";
public const int MaximumColumnWidth = 700;
public static async Task<string> GetLocalImageAsync(string internetUri)
{
if (string.IsNullOrEmpty(internetUri))
{
return null;
}
// Show default image if local folder does not exist
var localFolder = ApplicationData.Current.LocalFolder;
if (localFolder == null)
{
return OfflinePhotoImgPath;
}
// Default to offline photo
string src = OfflinePhotoImgPath;
try
{
using (var response = await HttpWebRequest.CreateHttp(internetUri)
.GetResponseAsync())
{
using (var stream = response.GetResponseStream())
{
// New random filename (e.g. x53fjtje.jpg)
string fileName = string.Format("{0}.jpg",
Path.GetFileNameWithoutExtension(Path.GetRandomFileName()));
var imageFolder = await localFolder.CreateFolderAsync(
CachedImagesFolderEndFolderPath,
CreationCollisionOption.OpenIfExists);
var file = await imageFolder.CreateFileAsync(fileName,
CreationCollisionOption.ReplaceExisting);
// Copy bytes from stream to local file
// without changing any file information
using (var filestream = await file.OpenStreamForWriteAsync())
{
await stream.CopyToAsync(filestream);
// Send back the local path to the image
// (including 'ms-appdata:///local/cache/')
return string.Format(CachedImagesFolderFullPath + "{0}",
fileName);
}
}
}
}
catch (Exception)
{
// Is implicitly handled with the setting
// of the initilized value of src
}
// If not succesfull, return the default offline image
return src;
}
public static async Task<string> ResizeAndCompressLocalImage(string imgSrc)
{
// Remove 'ms-appdata:///local/cache/' from the path ...
string sourcepathShort = imgSrc.Replace(
CachedImagesFolderFullPath,
string.Empty);
// Get the cached images folder
var folder = await ApplicationData.Current
.LocalFolder
.GetFolderAsync(
CachedImagesFolderEndFolderPath);
// Get a new random name (e.g. '555jkdhr5.jpg')
var targetPath = string.Format("{0}.jpg",
Path.GetFileNameWithoutExtension(
Path.GetRandomFileName()));
// Retrieve source and create target file
var sourceFile = await folder.GetFileAsync(sourcepathShort);
var targetFile = await folder.CreateFileAsync(targetPath);
using (var sourceFileStream = await sourceFile.OpenAsync(
Windows.Storage.FileAccessMode.Read))
{
using (var destFileStream = await targetFile.OpenAsync(
FileAccessMode.ReadWrite))
{
// Prepare decoding of the source image
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(
sourceFileStream);
// Find out if image needs resizing
double proportionWidth = (double)decoder.PixelWidth /
LayoutDimensions.MaximumColumnWidth;
double proportionImage = decoder.PixelHeight /
(double)decoder.PixelWidth;
// Get the new sizes of the image whether it is the same or should be resized
var newWidth = proportionWidth > 1 ?
(uint)(MaximumColumnWidth) :
decoder.PixelWidth;
var newHeight = proportionWidth > 1 ?
(uint)(MaximumColumnWidth * proportionImage) :
decoder.PixelHeight;
// Prepare set of properties for the bitmap
BitmapPropertySet propertySet = new BitmapPropertySet();
// Set ImageQuality
BitmapTypedValue qualityValue = new BitmapTypedValue(0.75,
PropertyType.Single);
propertySet.Add("ImageQuality", qualityValue);
//BitmapEncoder enc = await BitmapEncoder.CreateForTranscodingAsync(
destFileStream, decoder);
BitmapEncoder enc = await BitmapEncoder.CreateAsync(
BitmapEncoder.JpegEncoderId,
destFileStream, propertySet);
// Set the new dimensions
enc.BitmapTransform.ScaledHeight = newHeight;
enc.BitmapTransform.ScaledWidth = newWidth;
// Get image data from the source image
PixelDataProvider pixelData = await decoder.GetPixelDataAsync();
// Copy in all pixel data from source to target
enc.SetPixelData(
decoder.BitmapPixelFormat,
decoder.BitmapAlphaMode,
decoder.PixelWidth,
decoder.PixelHeight,
decoder.DpiX,
decoder.DpiY,
pixelData.DetachPixelData()
);
// Make the encoder process the image
await enc.FlushAsync();
// Write everything to the filestream
await destFileStream.FlushAsync();
}
}
try
{
// Delete the source file
await sourceFile.DeleteAsync();
}
catch(Exception)
{
}
// Return the new path
// including "ms-appdata:///local/cache/"
return string.Format(CachedImagesFolderFullPath + "{0}",
targetPath);
}

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;
}

Categories

Resources