将索引 BMP 保存为 PNG 不会在 Mac 上保存透明度

Posted

技术标签:

【中文标题】将索引 BMP 保存为 PNG 不会在 Mac 上保存透明度【英文标题】:Saving indexed BMP as a PNG doesn't save transparency on Mac 【发布时间】:2020-06-25 04:43:48 【问题描述】:

我正在使用一种旧的游戏格式,他们使用索引位图。对于某些具有透明度的材质,它们使用调色板中的第一个索引作为设置为不可见的值。在代码中,我克隆位图,将此调色板值设置为完全透明,然后将其导出为 PNG。它在 Windows 上完美运行。但在 Mac 上却没有。

这是我的工作:

Bitmap cloneBitmap;
cloneBitmap = image.Clone(new Rectangle(0, 0, image.Width, image.Height), PixelFormat.Format8bppIndexed);

var palette = cloneBitmap.Palette;
palette.Entries[0] = Color.FromArgb(0, 0, 0, 0);
cloneBitmap.Palette = palette;

cloneBitmap.Save(filePath + fileName, ImageFormat.Png);

这在 PC 上运行良好。图像以透明度输出。在 Mac 上,它没有透明度,具有此索引的像素只是黑色。

【问题讨论】:

你试过用 0,255,255,255 代替吗:docs.microsoft.com/en-us/dotnet/api/… @SimonMourier 这使得应该是透明的白色而不是黑色的像素。它对保存透明度没有影响。 是 .NET Core 吗?还是单声道?还是什么? 【参考方案1】:

我假设您在应用程序中使用标准 System.Drawing 库进行图像处理。这个库中有很多功能是围绕Windows GDI+ API 的薄包装器。所以macOS可能没有一些处理图片的功能。

所以你有这些选项来处理这个问题:

在你的 Mac 上安装 GDI+ 库

如果您使用单声道,您可以尝试安装 GDI+ 库为System.Drawing (source) 提供 GDI+ api。

brew install mono-libgdiplus

使用 Windows 兼容包

Windows Compatibility Pack 提供 API,仅供 Windows 中的 .NET Framework 使用,用于跨平台应用程序,使用 .NET Core/Standard 编写。

详情请见docs。

但是,Microsoft.Windows.Compatibility 包包含许多您可能根本不需要的与 Windows 相关的 API。如果是这样,您只能安装 System.Drawing.Common 包。此包是System.Drawing 函数的兼容性包的一部分。

请参阅有用的 article,了解如何在 .NET Core 中使用 System.Drawing.Common

使用其他第三方库

如果以前的解决方案对您的问题没有帮助,请尝试使用第三方开源库来完成您的任务。它们肯定会在 macOS 上正常工作。

请参阅来自 Microsoft 博客的有用文章 this,以查找适合您的图像处理库。

【讨论】:

感谢您的帮助。【参考方案2】:

要求

输入:256 色调色板 (8bpp) BMP 输出:具有透明度的 PNG,输入图像中使用相关调色板第一个条目的区域必须透明显示 操作系统:macOS 和 Windows

验证

为了有一个测试用例,我创建了一个具有不同颜色的 256 色调色板 (8bpp) BMP 在 BMP 中间有一个矩形区域,使用索引为 0 的颜色 为确保中间区域是透明的,我在图像编辑软件中打开了生成的 .png,该软件以棋盘格图案显示透明区域

原始代码

当使用有问题的原始代码进行测试时,它会给出以下结果:

Windows .NET Framework:中间区域是透明的 Windows .NET Core:中间区域是透明的 macOS .NET Core:中间区域为黑色 macOS Mono:中间区域为黑色

这是意料之中的,因为 OP 在问题中也指出了这一点。

解决方法

一种适用于所有 4 种环境(Windows .NET Framework、.NET Core Windows/Mac 和 Mono)的方法是使用第一个条目的颜色调用 MakeTransparent 方法。

文档说:

public void MakeTransparent(System.Drawing.Color transparentColor);

使该位图的指定颜色透明。

见 https://docs.microsoft.com/en-us/dotnet/api/system.drawing.bitmap.maketransparent?view=netcore-3.1#System_Drawing_Bitmap_MakeTransparent_System_Drawing_Color_

在代码中它看起来像这样:

var firstColor = image.Palette.Entries[0];
image.MakeTransparent(Color.FromArgb(0, firstColor.R, firstColor.G, firstColor.B));
image.Save(filePath + fileName, ImageFormat.Png);

如果第一个颜色也可能出现在调色板的其他条目中,您可能需要确保源调色板的第一个条目中的颜色是唯一的,以防止其他区域也变得透明。

测试

如果在图像编辑程序中打开生成的 PNG,可以看到图像中间的透明区域:

【讨论】:

感谢完整的测试用例分解。帮助我意识到我并不疯狂。我最终使用了 MakeTransparent 方法,但通过调色板运行并确保第一个索引是唯一的,如果不是,则生成一个随机索引。 不过,这不会保留调色板。您可以在最终的屏幕截图中看到该图像被视为 RGBA 是的,它是一个 RGBA PNG。据我了解,要求是输出应该是具有透明度的 PNG,并且不一定具有 8 位调色板颜色空间。现在几乎没有理由使用 8 位调色板,除非您有特殊要求。另请参阅我的回答的第一句话。

以上是关于将索引 BMP 保存为 PNG 不会在 Mac 上保存透明度的主要内容,如果未能解决你的问题,请参考以下文章

将多个 png 转换为 bmp 从标准输入到标准输出

使用 libpng 将 OpenGL 屏幕像素保存为 PNG

python将RGBA图像保存为BMP文件

如何将我的图像保存为 BMP 格式?

bmp格式转换PNG格式 c语言或c++编程

bmp格式转换PNG格式 c语言或c++编程