Winapi 给定HBITMAP,有没有办法确定它是否包含alpha通道?
为了改进,我正在寻找一种方法来确定通过Winapi 给定HBITMAP,有没有办法确定它是否包含alpha通道?,winapi,gdi,Winapi,Gdi,为了改进,我正在寻找一种方法来确定通过HBITMAP引用的位图是否包含alpha通道 我了解,我可以调用并检索结构: 位图bm={0}; ::GetObject(hbitmap、sizeof(bm)和bm); 但这只能得到存储像素颜色所需的位数。它没有告诉我实际使用了哪些位,或者它们与各个通道的关系。例如,16bpp位图可以对5-6-5 BGR图像或1-5-5-5 ABGR图像进行编码。同样,32bpp位图可以存储ABGR或xBGR数据 我可以更进一步,转而探索(如果有): 虽然这可以消除16
HBITMAP
引用的位图是否包含alpha通道
我了解,我可以调用并检索结构:
位图bm={0};
::GetObject(hbitmap、sizeof(bm)和bm);
但这只能得到存储像素颜色所需的位数。它没有告诉我实际使用了哪些位,或者它们与各个通道的关系。例如,16bpp位图可以对5-6-5 BGR图像或1-5-5-5 ABGR图像进行编码。同样,32bpp位图可以存储ABGR或xBGR数据
我可以更进一步,转而探索(如果有):
虽然这可以消除16bpp情况的歧义(使用dsBitfields
成员),但它仍然无法确定32bpp图像中是否存在alpha通道
是否有任何方法可以确定通过
HBITMAP
引用的位图是否包含alpha通道(以及使用了哪些位),或者该信息根本不可用?您无法确定,但如果您愿意迭代像素,您可以做出有根据的猜测
(不管怎样,现在还是忽略带有1位alpha通道的16位颜色。)
为了有一个alpha通道,位图必须是一个DIB部分,并且每个像素有32位。如问题中所述,您可以检查这些要求
我们还知道Windows只处理预乘的alpha。这意味着,对于每个像素A>=max(R,G,B)
。所以,如果你想扫描所有的像素,你可以排除一堆24位的图像。若该条件适用于所有像素,并且A中的任何一个非零,那个么几乎可以肯定您有一个alpha通道(或损坏的图像)
基本上,剩下的唯一不确定性是全透明图像与全黑图像,两者都由所有通道设置为零的像素组成。在这种情况下,也许只需进行有根据的猜测就足够了。我想是的,因为32位DIB段是一个非常强的信号。如果你有一个32位的设备相关位图,那么它没有alpha,如果你有一个没有alpha的设备无关位图,你可能会使用每像素24位来节省空间
一些更详细的位图信息标题可以告诉您是否为alpha通道保留了位。例如,请参阅,其中有一个掩码,指示哪些位是alpha通道(尽管文档中说了一些相互矛盾的事情)。对于BitMapv4标头也是如此。不幸的是,我认为没有办法从HBITMAP中获取此版本的标题。(我敢肯定,有些启用alpha的位图文件无法正确设置这些字段。)
众所周知,GDI不处理alpha通道(AlphaBlend除外,它不接受HBITMAP,而是访问选定的内存DC)。有一些用户API,比如UpdateLayeredWindow,可以处理带有alpha通道的图像,但是,像AlphaBlend一样,将位图数据从所选信息中提取到内存DC中。如果传递了正确的标志,则LoadImage将在加载HBITMAP访问的DIB时保留alpha通道。如果使用正确的标志创建图像列表,则ImageList_Add将保留HBITMAP和alpha通道。但是,在所有这些情况下,调用方必须知道位图数据包含正确的alpha数据,并为API设置正确的标志。这表明位图句柄中没有现成的信息
如果您可以访问从中加载图像的位图资源或文件,则可以查看原始标头是否使用BI_位字段并指定了alpha通道,但无法在所有情况下从HBITMAP访问该标头。(还有一个问题是页眉没有正确填写。)您可以使用函数间接获得它。文档中隐藏着一个注释: 如果hgdiobj是通过调用创建的位图的句柄,并且指定的缓冲区足够大,那么GetObject函数将返回一个结构。此外,DIBSECTION中包含的结构的bmBits成员将包含指向位图位值的指针 如果hgdiobj是通过任何其他方式创建的位图的句柄,GetObject只返回位图的宽度、高度和颜色格式信息。可以通过调用or函数获取位图的位值 (强调矿山) 换句话说:如果你试图解码它是一个DIBSECTION,但它只是一个位图,那么
dibSection.BitmapInfoHeader
不会被更新。(例如,保留为零)
记住位图和DIBSECTION的区别是很有帮助的:
| BITMAP | DIBSECTION |
|------------------------|--------------------------|
| bmType: Longint | bmType: Longint |
| bmWidth: Longint | bmWidth: Longint |
| bmHeight: Longint | bmHeight: Longint |
| bmWidthBytes: Longint | bmWidthBytes: Longint |
| bmPlanes: Word | bmPlanes: Word |
| bmBitsPixel: Word | bmBitsPixel: Word |
| bmBits: Pointer | bmBits: Pointer |
| | |
| |BITMAPINFOHEADER | <-- will remain unchanged for BITMAPs
| | biSize: DWORD |
| | biWidth: Longint |
| | biHeight: Longint |
| | biPlanes: Word |
| | biBitCount: Word |
| | biCompression: DWORD |
| | biSizeImage: DWORD |
| | biXPelsPerMeter: Longint |
| | biYPelsPerMeter: Longint |
| | biClrUsed: DWORD |
| | biClrImportant: DWORD |
| | |
| | dsBitfields: DWORD[3] |
| | dshSection: HANDLE |
| | dsOffset: DWORD |
我们是否有任何API函数支持带有
HBITMAP
s的alpha通道?没有API,位布局就没有多大意义。现有的定义位布局的方法是,但它与stretchibits
等函数一起使用,这些函数接受位图数据参数,而不是位图句柄。也就是说,当您处理老式位图句柄时,它非常简单,假设没有alpha通道,并且位布局是固定的。@RomanR.-我们是否有任何API函数支持带有HBITMAP的alpha通道-AlphaBlend
。假设唯一支持的alpha格式是ARGB,则可以使用试探法确定是否存在alpha通道。迭代所有像素,如果我们找到一个A字节大于0的像素,我们可以假设它是一个实际的alpha通道。当然,这对于所有透明/全黑图像都是失败的。“我们有任何支持HBITMAPs的alpha通道的API函数吗?”是的,除了AlphaBlend,还有ImageList t的API
| BITMAP | DIBSECTION |
|------------------------|--------------------------|
| bmType: Longint | bmType: Longint |
| bmWidth: Longint | bmWidth: Longint |
| bmHeight: Longint | bmHeight: Longint |
| bmWidthBytes: Longint | bmWidthBytes: Longint |
| bmPlanes: Word | bmPlanes: Word |
| bmBitsPixel: Word | bmBitsPixel: Word |
| bmBits: Pointer | bmBits: Pointer |
| | |
| |BITMAPINFOHEADER | <-- will remain unchanged for BITMAPs
| | biSize: DWORD |
| | biWidth: Longint |
| | biHeight: Longint |
| | biPlanes: Word |
| | biBitCount: Word |
| | biCompression: DWORD |
| | biSizeImage: DWORD |
| | biXPelsPerMeter: Longint |
| | biYPelsPerMeter: Longint |
| | biClrUsed: DWORD |
| | biClrImportant: DWORD |
| | |
| | dsBitfields: DWORD[3] |
| | dshSection: HANDLE |
| | dsOffset: DWORD |
function IsDibSection(bmp: HBITMAP): Boolean
{
Result := True; //assume that it is a DIBSECTION.
var ds: DIBSECTION = Default(DIBSECTION); //initialize everything to zeros
var res: Integer;
//Try to decode hbitmap as a DIBSECTION
res := GetObject(bmp, sizeof(ds), ref ds);
if (res = 0)
ThrowLastWin32Error();
//If the bitmap actually was a BITMAP (and not a DIBSECTION),
//then BitmapInfoHeader values will remain zeros
if ((ds.Bmih.biSize = 0)
and (ds.Bmih.biWidth = 0)
and (ds.Bmih.biHeight= 0)
and (ds.Bmih.biPlanes= 0)
and (ds.Bmih.biBitCount= 0)
and (ds.Bmih.biCompression= 0)
and (ds.Bmih.biSizeImage= 0)
and (ds.Bmih.biXPelsPerMeter= 0)
and (ds.Bmih.biYPelsPerMeter= 0)
and (ds.Bmih.biClrUsed= 0)
and (ds.Bmih.biClrImportant= 0))
Result := False; //it's not a dibsection
}