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

标签 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 channel 的副本(第二张图片)。整个图像是纯色的,并且 Alpha mask 图像的一部分以创建一个圆圈。

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

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

The alpha channel can be regarded either as a mask that temporarily hides transparent parts of the image, or as a means for constructing a non-rectangular image. In the first case, the colour values of fully transparent pixels should be preserved for future use. In the second case, the transparent pixels carry no useful data and are simply there to fill out the rectangular image area required by PNG. In this case, fully transparent pixels should all be assigned the same colour value for best compression.

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

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

请告诉我是否有其他人遇到过这种情况以及您是如何处理的。另外,如果有人知道任何实现 C# PNG 编码器的库(不那么严格),我们将不胜感激。

谢谢!

最佳答案

虽然我意识到这对某些人来说可能还不够,但就我而言,答案是改用 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 内置了对调整大小操作的支持,这也极大地简化了我的代码。

关于c# - 调整 PNG 图像大小,而不丢失完全透明像素的颜色数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28467645/

相关文章:

c# - Entity Framework 4 中的简单条件 LINQ 查询

java - 如何将图像保存和读取为文本,嵌入到代码中

Android Studio 1.3 SVG 到 png 的转换

c# - 无法计算所有者绘制文本中的位置

winapi - 比 GDI+ 更快的下一个最简单的图形渲染?

c++ - 来自位图的 GDI+ C++ 纹理画笔图案

c# - 将所有单元格从 datagridview 更新到数据库

c# - 阻止玩家发送垃圾邮件导致故障的移动键

c# - 普通 MVC 项目登录需要哪些表?

python - 使用 PIL 将 PNG32 转换为 PNG8,同时保留透明度