PaZword
PaZword copied to clipboard
Non-accurate color when using local file icon
Describe the bug Using the following image as an icon will transform the blue of the sky to orange.
Additional context
It's probably due to some sort of encodage.
The problem appears to be in the FromStream extension, I suspect FromStream passes non-palette pngs' pixels unswizzled. The serialisation provider's WritableBitmapToBase64Async is looking for RgBa8, FromStream is clearly BgR8 for the blue and red to swap.
Replace the following in the IconService.cs to fix this bug
public async Task<string> PickUpIconFromLocalFileAsync(CancellationToken cancellationToken)
{
return await TaskHelper.RunOnUIThreadAsync(async () =>
{
try
{
var fileOpenPicker = new Windows.Storage.Pickers.FileOpenPicker
{
ViewMode = Windows.Storage.Pickers.PickerViewMode.List,
SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.PicturesLibrary
};
fileOpenPicker.FileTypeFilter.Add(".jpg");
fileOpenPicker.FileTypeFilter.Add(".jpeg");
fileOpenPicker.FileTypeFilter.Add(".png");
fileOpenPicker.FileTypeFilter.Add(".bmp");
StorageFile storageFile = await fileOpenPicker.PickSingleFileAsync();
if (storageFile != null)
{
// Read the retrieved image's bytes and write them into an IRandomAccessStream
IRandomAccessStream stream = await storageFile.OpenAsync(FileAccessMode.Read);
IBuffer buffer = new Windows.Storage.Streams.Buffer((uint)stream.Size);
await stream.ReadAsync(buffer, (uint)stream.Size, InputStreamOptions.None);
InMemoryRandomAccessStream randomAccessStream = new InMemoryRandomAccessStream();
await randomAccessStream.WriteAsync(buffer);
// Decode the image (with premultiplied alpha) as Rgba8 not the streams Bgra8
// GetPixelDataAsync lets us pass in the desired format and it'll do the magic to translate as it decodes
BitmapDecoder decoder = await BitmapDecoder.CreateAsync(randomAccessStream);
var pixelData = await decoder.GetPixelDataAsync(BitmapPixelFormat.Rgba8, BitmapAlphaMode.Premultiplied, new BitmapTransform(), ExifOrientationMode.IgnoreExifOrientation, ColorManagementMode.DoNotColorManage);
// Get the decoded bytes
byte[] imageData = pixelData.DetachPixelData();
// And stick them in a WriteableBitmap
WriteableBitmap image = new WriteableBitmap((int)decoder.PixelWidth, (int)decoder.PixelHeight);
Stream pixelStream = image.PixelBuffer.AsStream();
pixelStream.Seek(0, SeekOrigin.Begin);
pixelStream.Write(imageData, 0, imageData.Length);
if (image.PixelWidth > Constants.AccountIconSize + 50)
{
// If we judge the image is too big, we resize it. This improves the image quality because the resize is bilinear,
// and it reduce the size of the user data bundle file.
double propotion = image.PixelWidth / (double)image.PixelHeight;
image = image.Resize(
(int)Constants.AccountIconSize,
(int)(Constants.AccountIconSize / propotion),
WriteableBitmapExtensions.Interpolation.Bilinear);
}
return await _serializationProvider.WritableBitmapToBase64Async(image, cancellationToken).ConfigureAwait(true);
}
}
catch (OperationCanceledException) { }
catch (Exception ex)
{
_logger.LogFault(PickUpIconFromLocalFileAsyncFaultEvent, $"Unable to open an image file.", ex);
}
return string.Empty;
}).ConfigureAwait(false);
}
Hi,
Thank you so much for this! Feel free to open a Pull Request if you want to contribute to it, or I can make one this weekend probably :)
Hi,
Your welcome on the fix, as I am in the middle of a few things can I get you to apply the fix if you are happy with it.