我一直试图找到一种方法来调整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值为零的任何地方,像素都变成黑色 .
我的声誉太低,不能遗忘地内嵌这些图像 .
First Image是我用来测试的图像 . 为了快速参考,我保存了一个没有alpha通道的副本(第二张图像) . 整个图像是纯色,alpha遮罩部分图像以创建圆形 .
第三张图像是上面代码的结果图像 . 我再次保存了两份副本 . 在第四张图像中,很明显在转换过程中数据丢失了 . 我期望看到的是填充整个图像的相同单一颜色 .
做一些阅读我在PNG文件规范中发现了这个:
alpha通道可以被视为暂时隐藏图像的透明部分的掩模,或者被视为构造非矩形图像的手段 . 在第一种情况下,应保留完全透明像素的颜色值以供将来使用 . 在第二种情况下,透明像素不携带有用的数据,只是填充PNG所需的矩形图像区域 . 在这种情况下,应为全透明像素分配相同的颜色值以获得最佳压缩效果 .
所以看起来由PNG编码器决定如何处理alpha为零的颜色值 . 有没有办法告诉GDI的编码器不要将颜色数据归零?
我需要保留颜色数据的原因是为了进一步动态调整图像大小 . 如果图像的可见部分的边缘没有均匀的颜色,则它们非常容易产生振铃伪影 . 关于这个问题,Unity forums上也有一篇文章 .
请让我知道是否有其他人遇到过此以及您是如何处理的 . 此外,如果有人知道任何实现C#PNG编码器的库不那么粗糙,我们将不胜感激 .
谢谢!
2 回答
虽然我意识到这对某些人来说可能还不够,但就我而言,答案是切换到使用ImageMagick's .NET wrapper . 我也能够在他们的论坛上找到一个thread,其中包含我遇到的确切问题 .
在调整图像大小时,这似乎是一个常见的错误,ImageMagick已在其库中修复了此问题 .
正如您所看到的,由于ImageMagick内置支持调整大小操作,这也极大地简化了我的代码 .
没有ImageMagick,您可以简单地使用以下代码并且它可以工作,不要更改CompositingQuality或任何其他Graphics属性: