Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
How to convert image to JPEG and specify quality (q) parameter in UWP C# XAML
/// <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;
}
@borisdv

This comment has been minimized.

Copy link

@borisdv borisdv commented Aug 8, 2017

Hi, I tried your code ... set the quality to 0.5d or even to 0.1d .. image was awful but the size remains the same. I was testing this on big jpeg pictures with size around 6+mb. Is this behavior ok or am i doing something wrong ? thanks for answer :)

@alexsorokoletov

This comment has been minimized.

Copy link
Owner Author

@alexsorokoletov alexsorokoletov commented Aug 9, 2017

Hi @borisdv!
Should be working just fine.
Can you share a sample app and pictures that you use for tests?

@JohnnyWestlake

This comment has been minimized.

Copy link

@JohnnyWestlake JohnnyWestlake commented Jan 20, 2018

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.

@alexsorokoletov

This comment has been minimized.

Copy link
Owner Author

@alexsorokoletov alexsorokoletov commented Jan 21, 2018

@JohnnyWestlake - interesting. If I understand what you're saying is that if outputFile already exists and has content - it will not work correctly?

@GailBowen

This comment has been minimized.

Copy link

@GailBowen GailBowen commented Jan 4, 2019

Thank you - you're a lifesaver! I couldn't find a working example anywhere else.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.