Created
May 23, 2016 02:03
-
-
Save alexsorokoletov/71431e403c0fa55f1b4c942845a3c850 to your computer and use it in GitHub Desktop.
How to convert image to JPEG and specify quality (q) parameter in UWP C# XAML
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// <summary> | |
/// Converts source image file to jpeg of defined quality (0.85) | |
/// </summary> | |
/// <param name="sourceFile">Source StorageFile</param> | |
/// <param name="outputFile">Target StorageFile</param> | |
/// <returns></returns> | |
private async Task<StorageFile> ConvertImageToJpegAsync(StorageFile sourceFile, StorageFile outputFile) | |
{ | |
//you can use WinRTXamlToolkit StorageItemExtensions.GetSizeAsync to get file size (if you already plugged this nuget in) | |
var sourceFileProperties = await sourceFile.GetBasicPropertiesAsync(); | |
var fileSize = sourceFileProperties.Size; | |
var imageStream = await sourceFile.OpenReadAsync(); | |
Stopwatch stopwatch = new Stopwatch(); | |
stopwatch.Start(); | |
using (imageStream) | |
{ | |
var decoder = await BitmapDecoder.CreateAsync(imageStream); | |
var pixelData = await decoder.GetPixelDataAsync(); | |
var detachedPixelData = pixelData.DetachPixelData(); | |
pixelData = null; | |
//0.85d | |
double jpegImageQuality = Constants.ImageAttachStartingImageQuality; | |
//since we're using MvvmCross, we're outputing diagnostic info to MvxTrace, you can use System.Diagnostics.Debug.WriteLine instead | |
Mvx.TaggedTrace(MvxTraceLevel.Diagnostic, "ImageService", $"Source image size: {fileSize}, trying Q={jpegImageQuality}"); | |
var imageWriteableStream = await outputFile.OpenAsync(FileAccessMode.ReadWrite); | |
ulong jpegImageSize = 0; | |
using (imageWriteableStream) | |
{ | |
var propertySet = new BitmapPropertySet(); | |
var qualityValue = new BitmapTypedValue(jpegImageQuality, Windows.Foundation.PropertyType.Single); | |
propertySet.Add("ImageQuality", qualityValue); | |
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, imageWriteableStream, propertySet); | |
//key thing here is to use decoder.OrientedPixelWidth and decoder.OrientedPixelHeight otherwise you will get garbled image on devices on some photos with orientation in metadata | |
encoder.SetPixelData(decoder.BitmapPixelFormat, decoder.BitmapAlphaMode, decoder.OrientedPixelWidth, decoder.OrientedPixelHeight, decoder.DpiX, decoder.DpiY, detachedPixelData); | |
await encoder.FlushAsync(); | |
await imageWriteableStream.FlushAsync(); | |
jpegImageSize = imageWriteableStream.Size; | |
} | |
Mvx.TaggedTrace(MvxTraceLevel.Diagnostic, "ImageService", $"Final image size now: {jpegImageSize}"); | |
} | |
stopwatch.Stop(); | |
Mvx.TaggedTrace(MvxTraceLevel.Diagnostic, "ImageService", $"Time spent optimizing image: {stopwatch.Elapsed}"); | |
return outputFile; | |
} |
@JohnnyWestlake - interesting. If I understand what you're saying is that if outputFile
already exists and has content - it will not work correctly?
Thank you - you're a lifesaver! I couldn't find a working example anywhere else.
Cheers for this solution. Made small changes to adopt into c#/uwp.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Problem here is imageWriteableStream needs to set it's size to Zero before creating the encoder using it, as BitmapEncoder doesn't clear any existing data in the stream - so if the file already has content you have some issues.