我一直试图找到一种方法来调整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值为零,则像素变为黑色。
我的名声太低,无法将这些图片内联地发布。
第一张图片是我用来测试的图片。为了快速参考,我保存了没有Alpha通道的副本(第二张图像)。整个图像是纯色,alpha遮罩部分图像以创建圆圈。
第三张图像是上面代码生成的图像。我再次保存了两份副本。在第四张图像中,很明显在转换过程中数据丢失了。我期望看到的是填充整个图像的相同颜色。
做一些阅读我在PNG文件规范中发现了这一点:
alpha通道可以被视为暂时隐藏图像的透明部分的掩模,或者被视为用于构造非矩形图像的装置。在第一种情况下,应保留完全透明像素的颜色值以供将来使用。在第二种情况下,透明像素不携带有用的数据,只是填充PNG所需的矩形图像区域。在这种情况下,应为全透明像素分配相同的颜色值以获得最佳压缩效果。
因此看起来像是由PNG编码器决定如何处理alpha为零的颜色值。有没有办法告诉GDI +的编码器不要将颜色数据归零?
我需要保留颜色数据的原因是为了进一步动态调整图像大小。如果图像的可见部分的边缘没有均匀的颜色,则它们非常容易产生振铃伪影。关于此问题,Unity forums上还有一篇帖子。
如果有其他人遇到此问题以及您如何处理,请告诉我。此外,如果有人知道任何实现C#PNG编码器的库不那么粗糙,我们将不胜感激。
谢谢!
答案 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内置支持调整大小操作,这也极大地简化了我的代码。