【问题标题】:Saving indexed BMP as a PNG doesn't save transparency on Mac将索引 BMP 保存为 PNG 不会在 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 吗?还是单声道?还是什么?

标签: c# image bitmap png


【解决方案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 位调色板,除非您有特殊要求。另请参阅我的回答的第一句话。
猜你喜欢
  • 1970-01-01
  • 2011-01-13
  • 2011-06-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-08
  • 2015-06-17
相关资源
最近更新 更多