WriteableBitmap无法正确呈现PNG
本文关键字:PNG WriteableBitmap | 更新日期: 2023-09-27 18:27:37
我在渲染使用Palette作为"颜色类型"的PNG时遇到问题。这里有一些简单的代码来重现这个问题:
private async System.Threading.Tasks.Task Fetch()
{
HttpClient httpClient = new HttpClient();
Uri uri = new Uri("http://static.splashnology.com/articles/How-to-Optimize-PNG-and-JPEG-without-Quality-Loss/PNG-Palette.png");
HttpResponseMessage response = await httpClient.GetAsync(uri);
if (response.StatusCode == HttpStatusCode.Ok)
{
try
{
var content = await response.Content.ReadAsBufferAsync();
WriteableBitmap image = await BitmapFactory.New(1, 1).FromStream(content.AsStream());
Rect destination = new Rect(0, 0, image.PixelWidth, image.PixelHeight);
Rect source = new Rect(0, 0, image.PixelWidth, image.PixelHeight);
WriteableBitmap canvas = new WriteableBitmap(image.PixelWidth, image.PixelHeight);
canvas.Blit(destination, image, source);
RadarImage.Source = canvas;
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine(e.Message);
System.Diagnostics.Debug.WriteLine(e.StackTrace);
}
}
}
如果我使用Windows Phone 8.1运行该代码,则图像将使用错误的颜色显示。如果我使用PNG做同样的测试,使用RGB作为"颜色类型",那么一切都很好。
我看了Codeplex论坛,还没有看到任何相关的帖子。我已经报告了这是一个问题,尽管这可能与我渲染它的方式有关。我使用WriteableBitmap的方式是否有任何错误,可能会导致错误的渲染?
更新
根据这一讨论https://writeablebitmapex.codeplex.com/discussions/274445该问题与意外的字节顺序有关。这些评论来自一年半前,所以我认为应该在某个地方进行适当的修复。。。
上面的代码中包含了渲染不正确的图像。
使用相同代码的这一个是正确呈现的。http://www.queness.com/resources/images/png/apple_ex.png
这两个图像之间的唯一区别是"颜色类型"属性。失败的设置为"Palette",而正确渲染的则设置为"RGB Alpha"。
谢谢!卡洛斯。
问题似乎出现在FromStream扩展中,它似乎将苍白的png转换为RGBA。正如您所注意到的,WriteableBitmap需要BGRA。我怀疑FromStream在未缩放的情况下通过非调色板pngs的像素。这让苹果以BGRA开始和结束,而猴子则以RGBA结束,并以红色和蓝色反向绘制。
你可以跳过FromStream并使用BitmapDecoder来绕过这个问题,这样你就可以指定你希望它解码成的格式:
// Read the retrieved image's bytes and write them into an IRandomAccessStream
IBuffer buffer = await response.Content.ReadAsBufferAsync();
var randomAccessStream = new InMemoryRandomAccessStream();
await randomAccessStream.WriteAsync(buffer);
// Decode the downloaded image as Bgra8 with premultiplied alpha
// 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.Bgra8, 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);
// And stick it in an Image so we can see it.
RadarImage.Source = image;