WriteableBitmap错误地呈现PNG

时间:2014-10-23 09:26:42

标签: c# visual-studio-2013 windows-phone-8.1 writeablebitmap writeablebitmapex

我无法渲染使用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运行该代码,图像将显示错误的颜色。如果我使用使用RGB作为“颜色类型”的PNG进行相同的测试,那么一切正常。

我查看了Codeplex论坛,但没有看到任何与此相关的帖子。我已经将它报告为一个问题,尽管它可能与我渲染它的方式有关。我使用WriteableBitmap的方式是否有任何错误可能导致错误的渲染?


更新

根据这个讨论 https://writeablebitmapex.codeplex.com/discussions/274445 该问题与字节的意外顺序有关。这些评论来自一年半以前,所以我认为应该在某个地方进行适当的修复......

错误渲染的图像位于上面的代码中。

使用相同的代码,这个正确呈现。 http://www.queness.com/resources/images/png/apple_ex.png

这两个图像之间的唯一区别是“颜色类型”属性。失败的那个被设​​置为“Palette”,正确渲染的那个被设​​置为“RGB Alpha”。

谢谢! 卡洛斯。

1 个答案:

答案 0 :(得分:1)

问题似乎出现在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;