Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>So here is my solution I came with after lot of googling and trial/error coding:</p> <p>The goal here was to find out, how to manipulate images in WinRT, specifically in <a href="http://www.microsoft.com/en-us/download/details.aspx?displaylang=en&amp;id=27411" rel="nofollow noreferrer">Background Tasks</a>. Background Tasks are even more limited than just regular WinRT projects, because they must be of type <a href="http://msdn.microsoft.com/en-us/library/windows/apps/hh441572.aspx" rel="nofollow noreferrer">Windows Runtime Component</a>. 99% of available libraries on NuGet targeting WinRT are targeting only the default WinRT projects, therefore they cannot be used in Windows Runtime Component projects. </p> <p>At first I tried to use the <a href="http://writeablebitmapex.codeplex.com/" rel="nofollow noreferrer">well-known WriteableBitmapEx library</a> - porting the necessary code to my winmd project. There is even <a href="http://writeablebitmapex.codeplex.com/SourceControl/changeset/view/94114" rel="nofollow noreferrer">branch of the WBE project targeting winmd</a>, but it is unfinished. I made it compile after adding [ReadOnlyArray], [WriteOnlyArray] attributes to method parameters of type array and also after changing the project namespace to something not starting with "Windows" - winmd project limitation.</p> <p>Even though I was able to use this library in my Background Task project it wasn't working, because, as I discovered, WriteableBitmap must be instantiated in UI thread and this is not possible as far as I know in Background Task.</p> <p>In the meantime I have also found this <a href="http://msdn.microsoft.com/fr-fr/library/windows/apps/windows.graphics.imaging.aspx" rel="nofollow noreferrer">MSDN article about Image manipulation in WinRT</a>. Most of samples there are only in the JavaScript section, so I had to convert it to C# first. I've also found this helpful <a href="https://stackoverflow.com/questions/10013799/winrt-image-handling">article on StackOverflow about image manipulation in WinRT</a>.</p> <pre class="lang-cs prettyprint-override"><code>internal static async Task LoadTileImageInternalAsync(string imagePath) { string tileName = imagePath.GetHashedTileName(); StorageFile origFile = await ApplicationData.Current.LocalFolder.GetFileAsync(imagePath); // open file for the new tile image file StorageFile tileFile = await ApplicationData.Current.LocalFolder.CreateFileAsync(tileName, CreationCollisionOption.ReplaceExisting); using (IRandomAccessStream tileStream = await tileFile.OpenAsync(FileAccessMode.ReadWrite)) { // get width and height from the original image IRandomAccessStreamWithContentType stream = await origFile.OpenReadAsync(); ImageProperties properties = await origFile.Properties.GetImagePropertiesAsync(); uint width = properties.Width; uint height = properties.Height; // get proper decoder for the input file - jpg/png/gif BitmapDecoder decoder = await GetProperDecoder(stream, imagePath); if (decoder == null) return; // should not happen // get byte array of actual decoded image PixelDataProvider data = await decoder.GetPixelDataAsync(); byte[] bytes = data.DetachPixelData(); // create encoder for saving the tile image BitmapPropertySet propertySet = new BitmapPropertySet(); // create class representing target jpeg quality - a bit obscure, but it works BitmapTypedValue qualityValue = new BitmapTypedValue(TargetJpegQuality, PropertyType.Single); propertySet.Add("ImageQuality", qualityValue); // create the target jpeg decoder BitmapEncoder be = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, tileStream, propertySet); be.SetPixelData(BitmapPixelFormat.Rgba8, BitmapAlphaMode.Straight, width, height, 96.0, 96.0, bytes); // crop the image, if it's too big if (width &gt; MaxImageWidth || height &gt; MaxImageHeight) { BitmapBounds bounds = new BitmapBounds(); if (width &gt; MaxImageWidth) { bounds.Width = MaxImageWidth; bounds.X = (width - MaxImageWidth) / 2; } else bounds.Width = width; if (height &gt; MaxImageHeight) { bounds.Height = MaxImageHeight; bounds.Y = (height - MaxImageHeight) / 2; } else bounds.Height = height; be.BitmapTransform.Bounds = bounds; } // save the target jpg to the file await be.FlushAsync(); } } private static async Task&lt;BitmapDecoder&gt; GetProperDecoder(IRandomAccessStreamWithContentType stream, string imagePath) { string ext = Path.GetExtension(imagePath); switch (ext) { case ".jpg": case ".jpeg": return await BitmapDecoder.CreateAsync(BitmapDecoder.JpegDecoderId, stream); case ".png": return await BitmapDecoder.CreateAsync(BitmapDecoder.PngDecoderId, stream); case ".gif": return await BitmapDecoder.CreateAsync(BitmapDecoder.GifDecoderId, stream); } return null; } </code></pre> <p>In this sample we open one file, decode it into byte array, and encode it back into new file with different size/format/quality.</p> <p>The result is fully working image manipulation even in Windows Runtime Component Class and without WriteableBitmapEx library.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload