在 OS X 上加载表面时,SDL2 预乘 alpha 通道?

jdo*_*lan 3 c sdl image sdl-2

我正在通过 OS X Sierra 上的 SDL2 2.0.7 和 SDL2_image 2.0.2 加载 32 位 RGBA 法线贴图纹理,并在 Alpha 通道中编码高度图。

这些纹理中的每个像素都有一个非零 RGB 值,编码方向法向量。方向向量 (0, 0, 0)(即black)无效。

然而,当我通过 SDL2_image 加载这样的纹理时,alpha 值为 0 的纹理区域也会产生 RGB 值 0。我认为 SDL 可能会预乘这些像素的 alpha 值?

附件是这些法线贴图纹理之一。您可以通过在 GIMP 等中打开纹理并在透明区域之一使用颜色选择器来确认它是否有效。事实上,您会看到透明区域仍然具有偏蓝色的 RGB 颜色(编码的法线向量)。

32 位 RGBA 法线贴图,带有用于视差贴图的 alpha 编码高度图

下面是一个最小的测试用例,说明了所附 PNG 文件的问题:

#include <SDL_image.h>
#include <assert.h>

int main(int argc, char **argv) {

    SDL_Surface *s = IMG_Load("green3_2_nm.png");
    assert(s);

    for (int i = 0; i < s->w * s->h; i++) {
        const Uint32 *in = (Uint32 *) (s->pixels + i * s->format->BytesPerPixel);

        SDL_Color color;
        SDL_GetRGBA(*in, s->format, &color.r, &color.g, &color.b, &color.a);

        assert(color.r || color.g || color.b);
    }

    SDL_FreeSurface(s);

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我正在编译这个测试用例gcc $(pkg-config --cflags --libs sdl2_image) test.c

第 15 行的断言将导致图像中的几行失败——即 alpha 值降至 0 的位置。

我尝试过 TGA 和 PNG 图像格式,但 SDL 对这两种图像格式做了同样的事情。

这是 SDL 中的错误,还是我遗漏了什么?我很好奇人们是否也在其他平台上看到同样的问题。

===

答案:Core Graphics(Apple OS X 上 SDL2_image 的默认图像加载后端)确实会预乘 alpha -总是如此。解决方案是在没有 Core Graphics 支持的情况下重新编译 SDL2_image,并启用 libpng、libjpeg 和您需要的任何其他图像编解码器:

./configure \
--disable-imageio \
--disable-png-shared \
--disable-tif-shared \
--disable-jpg-shared \
--disable-webp-shared
Run Code Online (Sandbox Code Playgroud)

在我的系统上,我必须禁用 Core Graphics ( imageio)以及其他编解码器的共享库加载,如您所见。这产生了一个SDL2_image.so与 libpng、libjpg 等静态链接的 fat,但按预期工作。

Die*_*Epp 5

SDL_image 是特定于平台的图像加载代码的包装器,而不是在所有平台上使用相同的图像加载器。

  • Linux:LibPNG、LibJPEG
  • macOS、iOS:核心显卡
  • Windows:WinCodec

这样做的优点是可以减小 SDL_image 的大小,因为它不必附带任何图像解码代码,并且可以动态链接到可能已安装在系统上的某些内容。但是,在 macOS 和 iOS 上,Core Graphics 不支持非预乘 alpha,因此 SDL_image 必须将其反转。

请参阅:mac-opengl - 回复:kCGImageAlphaFirst 未实现(原为:(无主题)),从 2007 年 5 月开始(来自 Wayback 机器):

老实说,我不希望CGBitmapContextCreate()很快支持非预乘 alpha。

...

我不确定使用 ImageIO + CoreGraphics 是否真的旨在用于 OpenGL 应用程序的图像加载方案。

此行为是在LibSDL bug #838 中发现的 - OSX SDL 使颜色与 alpha 的增加成比例变暗,并且在 SDL_image变更集 240中引入了解决方法。

您可以看到,解决方法只是取消预乘 alpha,这是一个非常有损失的过程。

为了解决这个问题,您可以在 macOS 上使用 LibPNG 构建自己的 SDL_image 版本。这应该可以通过配置实现,您不必对 SDL_image 代码本身进行任何更改。为此,请使用该--disable-imageio选项。SDL_image 附带了自己的 LibPNG 代码副本,因此您不需要安装 LibPNG 即可使其正常工作。