【问题标题】:CreateIconIndirect - interpretation of pixel dataCreateIconIndirect - 像素数据的解释
【发布时间】:2021-12-02 08:11:51
【问题描述】:

我想使用 CreateIconIndirect 手动创建一个图标,如下所示:

HDC hDC = ::CreateCompatibleDC( nullptr );

BITMAPINFO bmiMask = {};
bmiMask.bmiHeader.biSize = sizeof( bmiMask.bmiHeader );
bmiMask.bmiHeader.biWidth = 16;
bmiMask.bmiHeader.biHeight = -16; // starts with top row
bmiMask.bmiHeader.biPlanes = 1;
bmiMask.bmiHeader.biBitCount = 32;
BYTE *byMask = nullptr;
HBITMAP hbmMask = ::CreateDIBSection( hDC, &bmiMask, DIB_RGB_COLORS,
                                      reinterpret_cast< void** >( &byMask ),
                                      nullptr, 0 );
BYTE bgraMask[] = { 0x00, 0x00, 0x00, 0x00 };
for( int i = 0; i < 16 * 16; i++ )
    for( int j = 0; j < 4; j++ )
        byMask[ i * 4 + j ] = bgraMask[ j ];
byMask[ 0 ] = 0x00; byMask[ 1 ] = 0x00; byMask[ 2 ] = 0x00; byMask[ 3 ] = 0x00;

BITMAPINFO bmiColor = {};
bmiColor.bmiHeader.biSize = sizeof( bmiColor.bmiHeader );
bmiColor.bmiHeader.biWidth = 16;
bmiColor.bmiHeader.biHeight = -16; // starts with top row
bmiColor.bmiHeader.biPlanes = 1;
bmiColor.bmiHeader.biBitCount = 32;
BYTE *byColor = nullptr;
HBITMAP hbmColor = ::CreateDIBSection( hDC, &bmiColor, DIB_RGB_COLORS,
                                       reinterpret_cast< void** >( &byColor ),
                                       nullptr, 0 );
BYTE bgraColor[] = { 0xff, 0xff, 0xff, 0xff };
for( int i = 0; i < 16 * 16; i++ )
    for( int j = 0; j < 4; j++ )
        byColor[ i * 4 + j ] = bgraColor[ j ];
byColor[ 0 ] = 0x00; byColor[ 1 ] = 0x00; byColor[ 2 ] = 0x00; byColor[ 3 ] = 0x00;

ICONINFO ii = {};
ii.fIcon = TRUE;
ii.xHotspot = ii.yHotspot = 0;
ii.hbmMask = hbmMask;
ii.hbmColor = hbmColor;
HICON hIcon = ::CreateIconIndirect( &ii );
::SendMessage( hwndDialog, WM_SETICON, ICON_SMALL,
               reinterpret_cast< LPARAM >( hIcon ) );

根据 MSDN (https://docs.microsoft.com/en-us/previous-versions/dd183376(v=vs.85)),每个像素的数据由 4 个字节组成:蓝色、绿色、红色和一个未使用的字节。

我通过更改 byMask 和 byColor 的值对数据进行了一些实验,然后进行屏幕截图并在 MS Paint 中读取准确的 RGB 值。 (每次我将记事本直接放在应用程序的窗口后面,以获得最终的透明度/Alpha 通道效果的恒定背景。)

首先我只更改了左上角,而其余数据为掩码为 0x00,颜色为 0xff。结果:大部分图标是白色的(如预期的那样),左上角的像素有以下颜色:

MR MA CR CA OR OG OB

00 00 00 ff 00 00 00
00 00 00 00 d3 e9 fe
00 00 ff 00 d3 e9 fe (a)
ff 00 00 00 d3 e9 fe
ff ff 00 00 d3 e9 fe
00 ff 00 00 d3 e9 fe
00 00 ff ff ff 00 00 (b)
ff 00 ff ff ff 00 00
ff ff ff ff ff 00 00
00 ff ff ff ff 00 00

之后,我将两个位图中的每个像素都更改为相同的值。 (并使用 MS Paint 的填充工具检查图片只有一种颜色。)

MR MA CR CA OR OG OB

00 00 00 ff 00 00 00
00 00 00 00 00 00 00
00 00 ff 00 ff 00 00 (c)
ff 00 00 00 00 00 00
ff ff 00 00 00 00 00
00 ff 00 00 00 00 00
00 00 ff ff ff 00 00 (d)
ff 00 ff ff ff 00 00 (d)
ff ff ff ff ff 00 00 (d)
00 ff ff ff ff 00 00 (d)

缩写:M=mask C=Color O=Observation R=red G=green B=blue A=alpha/4.byte

我不明白以下内容(字母指上表中的行):

  • 如果忽略 4. 字节,而不是 alpha 通道,为什么像素 (a) 不像 (b) 那样 ff0000?
  • 如果我只更改其他像素,为什么第一个像素会更改:(c) vs (a)?
  • 为什么所有标有(d)的行的结果都一样,为什么这里的掩码不起作用?

我的代码有错误吗?我看错了 MSDN 页面吗?

【问题讨论】:

  • 如果你想使用掩码位图,那么我认为它必须是 1bpp。否则,您可以使用带有 alpha 通道的 32bpp 图像位图,方法是使用带有适当位域掩码的BITMAPV5HEADER 创建位图(在这种情况下,掩码位图只是一个虚拟位图,未使用)。
  • 这个 alpha 通道对我来说很可疑,因为 d3e9fe 看起来像应用了一些透明度。这种行为是否记录在某处?我在这里没有找到它:docs.microsoft.com/en-us/windows/win32/api/winuser/… 和这里:docs.microsoft.com/en-us/windows/win32/api/winuser/…
  • 我将 biSize 字段设置为 BITMAPHEADER 结构的大小,并在调试器中检查它是 40。是否有可能我的输入被视为 BITMAPV5HEADER,其大小为 120 ?
  • 没有。这里的版本控制完全基于您提供的大小。如果传递的值为 40,系统会将数据解释为 BITMAPHEADER
  • 抱歉,应该读作 " 会将数据解释为 BITMAPINFOHEADER"

标签: winapi


【解决方案1】:

好的,我想通了。由于历史原因,有两种类型的 32 位/像素位图:一种使用 3 字节表示 3 种颜色,最后一种未使用(通常设置为 0),另一种使用第四字节表示 alpha 通道.

关键是该类型没有由任何字段指示,但如果所有第 4 个字节都为零,Windows 将其视为旧格式位图(不带 alpha),如果有第四个字节,则将其视为新格式(带 alpha)字节不为零。所以这将导致一个全黑的图标:

for( int i = 0; i < 16 * 16; i++ )
    for( int j = 0; j < 4; j++ )
        byColor[ i * 4 + j ] = 0x00;

但是如果我在上面加上这一行,整个图标就会变成透明的*:

byColor[ 7 * 16 + 7 + 0 ] = 0x01;

* 除了第 7 行第 7 列中的像素,它将只有 255/256 透明。

【讨论】:

  • 实际上只有一种 32bpp 位图。古怪之处在于您用来操作它们的 API 调用。很少有 GDI 调用(例如AlphaBlend)准备好处理 alpha 透明度。他们中的大多数会完全忽略 alpha 通道,有些人会猜测,以区分有和没有 alpha 通道的 DIB。 The evolution of the ICO file format, part 3: Alpha-blended images 有更多关于该主题的信息。
猜你喜欢
  • 2014-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-04-16
  • 2020-07-15
  • 1970-01-01
  • 1970-01-01
  • 2011-11-10
相关资源
最近更新 更多