You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何更高效检测32bpp DDB位图是否包含有效Alpha通道?

区分32bpp HBITMAP是0RGB还是ARGB格式的优化方法探讨

Windows GDI的HBITMAP对象没有专门标记是否包含有效Alpha通道的标志。我们可以通过GetObject()函数获取BITMAP结构,利用其中的bmBitsPixel字段先排除掉低于32bpp的位图格式——这类格式本身无法包含Alpha通道。

当bmBitsPixel == 32时,位图存在两种可能的格式:0RGB(所有像素的Alpha通道值为0)或ARGB(至少有一个像素的Alpha值非零)。目前我知道的唯一区分方法是检查像素中是否存在非零Alpha值(若有错误请指正):只要有一个像素的Alpha值不为0,Windows就会将该位图视为ARGB格式。

这个判定结果对ICON处理以及DrawIcon()、DrawIconEx()等函数的行为影响很大。这些函数会根据特定标志,结合图标颜色位图的格式(0RGB或ARGB),决定是否忽略或是使用包含整个图标透明数据的单色掩码ICONINFO.hbmMask。

下面的代码通过将DDB位图缩至1x1px并检测该像素是否存在非零Alpha值,来判断位图属于0RGB还是ARGB格式:

BOOL HasAlpha(HBITMAP hBmp)
{
    BOOL res = FALSE;
    BITMAP bmp = {0};
    GetObject(hBmp, sizeof(BITMAP), &bmp);

    if (bmp.bmBitsPixel == 32)
    {
        HDC hDCsrc = CreateCompatibleDC(0);
        HBITMAP hBmpOldSrc = (HBITMAP)SelectObject(hDCsrc, hBmp);
        HDC hDCdst = CreateCompatibleDC(hDCsrc);
        HBITMAP hBmpDst = CreateCompatibleBitmap(hDCsrc, 1, 1);
        HBITMAP hBmpOldDst = (HBITMAP)SelectObject(hDCdst, hBmpDst);
        PDWORD pPixel;

        SetStretchBltMode(hDCdst, STRETCH_ORSCANS); //STRETCH_ANDSCANS
        StretchBlt(hDCdst, 0, 0, 1, 1, hDCsrc, 0, 0, bmp.bmWidth, bmp.bmHeight, SRCCOPY);
           
        if (pPixel = (PDWORD)GetBMBits(hDCdst, DIB_RGB_COLORS))
        {
            if (*pPixel & 0xFF000000)
                res = TRUE;

            _aligned_free(pPixel);
        }

        SelectObject(hDCsrc, hBmpOldSrc);
        DeleteObject(SelectObject(hDCdst, hBmpOldDst));
        DeleteDC(hDCsrc);
        DeleteDC(hDCdst);
    }

    return res;
}

LPVOID GetBMBits(HDC hDC, UINT usage)    //使用完毕后必须用_aligned_free()释放结果,usage参数为DIB_RGB_COLORS或DIB_PAL_COLORS
{
    LPVOID pMem = NULL;
    BITMAPINFO BmpInf[2]; BmpInf[0].bmiHeader.biBitCount = 0; BmpInf[0].bmiHeader.biSize = sizeof(BITMAPINFOHEADER);

    HBITMAP hBmp = HBITMAP(SelectObject(hDC, CreateCompatibleBitmap(hDC, 0, 0)));  //取出DC中当前的位图

    if (GetDIBits(hDC, hBmp, 0, 1, NULL, &BmpInf[0], usage))
    {
        if (pMem = _aligned_malloc(BmpInf[0].bmiHeader.biSizeImage, sizeof(DWORD)))
        {
            if (!GetDIBits(hDC, hBmp, 0, BmpInf[0].bmiHeader.biHeight, pMem, &BmpInf[0], usage))
            {
                _aligned_free(pMem);
                pMem = NULL;
            }
        }
    }

    DeleteObject(SelectObject(hDC, hBmp));
    return pMem;
}

已知将DDB的像素数据读取到用户态的成本较高,请问是否存在更优的分类方法?


内容的提问来源于stack exchange,提问作者George Robinson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 12:17:08