调整PNG图像大小而不会丢失完全透明像素的颜色数据

时间:2015-02-12 01:18:09

标签: c# png gdi+ alpha

我一直试图找到一种方法来调整PNG图像的大小而不会丢失完全透明像素的颜色数据。以下是我用来实现此目的的代码:

//sourceImage is also a bitmap read in earlier
using (var scaledBitmap = new Bitmap(desiredWidth, desiredHeight, PixelFormat.Format32bppArgb)){
    using (var g = Graphics.FromImage(scaledBitmap)){

        var attr = new ImageAttributes();
        attr.SetWrapMode(WrapMode.TileFlipXY);
        g.CompositingQuality = CompositingQuality.HighQuality;
        g.CompositingMode    = CompositingMode.SourceCopy;
        g.InterpolationMode  = InterpolationMode.HighQualityBicubic;
        g.SmoothingMode      = SmoothingMode.AntiAlias;
        g.PixelOffsetMode    = PixelOffsetMode.HighQuality;

        g.DrawImage(sourceImage, new Rectangle(0, 0, desiredWidth, desiredHeight), 0, 0, sourceImage.Width, sourceImage.Height, GraphicsUnit.Pixel, attr);
    }
    scaledBitmap.Save(memoryStream, ImageFormat.Png);
   //use new bitmap here
}

但是这个例子的问题是,如果像素的alpha值为零,则像素变为黑色。

我的名声太低,无法将这些图片内联地发布。

Images

第一张图片是我用来测试的图片。为了快速参考,我保存了没有Alpha通道的副本(第二张图像)。整个图像是纯色,alpha遮罩部分图像以创建圆圈。

第三张图像是上面代码生成的图像。我再次保存了两份副本。在第四张图像中,很明显在转换过程中数据丢失了。我期望看到的是填充整个图像的相同颜色。

做一些阅读我在PNG文件规范中发现了这一点:

  

alpha通道可以被视为暂时隐藏图像的透明部分的掩模,或者被视为用于构造非矩形图像的装置。在第一种情况下,应保留完全透明像素的颜色值以供将来使用。在第二种情况下,透明像素不携带有用的数据,只是填充PNG所需的矩形图像区域。在这种情况下,应为全透明像素分配相同的颜色值以获得最佳压缩效果。

因此看起来像是由PNG编码器决定如何处理alpha为零的颜色值。有没有办法告诉GDI +的编码器不要将颜色数据归零?

我需要保留颜色数据的原因是为了进一步动态调整图像大小。如果图像的可见部分的边缘没有均匀的颜色,则它们非常容易产生振铃伪影。关于此问题,Unity forums上还有一篇帖子。

如果有其他人遇到此问题以及您如何处理,请告诉我。此外,如果有人知道任何实现C#PNG编码器的库不那么粗糙,我们将不胜感激。

谢谢!

1 个答案:

答案 0 :(得分:2)

虽然我意识到这对某些人来说可能还不够,但就我而言,答案是转而使用ImageMagick's .NET wrapper。我也能在他们的论坛上找到thread我遇到的确切问题。

在调整图像大小时,这似乎是一个常见错误,ImageMagick已在其库中修复了此问题。

using ImageMagick;

using (var sourceImage = new MagickImage(texture)){ //texture is of type Stream
    sourceImage.Resize(desiredWidth, desiredHeight);
    sourceImage.Write(memoryStream, MagickFormat.Png);
}
// use memoryStream here

正如您所看到的,由于ImageMagick内置支持调整大小操作,这也极大地简化了我的代码。