如何使用 MFC 或 GDI 或 GDI+ 设置位图中所有像素的 alpha 值

问题描述 投票:0回答:2

我正在使用 MFC 应用程序。我使用内存 DC 创建了一个位图,我想将其保存到 DIB 文件中。

我发现这段代码是迄今为止最优雅的:

void Save(CBitmap * bitmap) {
  CImage image;
  image.Attach((HBITMAP)pcBitmap->GetSafeHandle());
  image.Save("bla.bmp", Gdiplus::ImageFormatBMP);
}

生成的文件是 32 BPP 色彩空间,所有 alpha 值设置为“0”。

现在我想使用位图作为工具栏位图:

CMFCToolbar::GetImages()->Load("bla.bmp");

但是所有图标都消失了。

MFC在导入位图时内部调用PreMultiplyAlpha()。 那么所有像素的RGB分量都是“0”。实际上整个位图都被清零了。

如何在保存之前将每个像素的 alpha 值设置为“0xFF”?

我尝试过:

void Save(CBitmap * bitmap) {
  CImage image;
  image.Attach((HBITMAP)pcBitmap->GetSafeHandle());
  image.SetHasAlphaChannel(true);
  image.AlphaBlend(myBitmapDC, 0, 0);
  image.Save("bla.bmp", Gdiplus::ImageFormatBMP);
}

但这仅影响像素的 RGB 值。

到目前为止,我拒绝迭代每个像素并修改位图的内存。我正在寻求一个优雅的解决方案。也许是一句单行话。

winapi mfc gdi+ gdi cmfctoolbar
2个回答
3
投票

使用

GetDIBits
读取 32 位像素数据,并循环遍历各个位以将 alpha 设置为
0xFF

bool Save(CBitmap *bitmap)
{
    if(!bitmap)
        return false;

    BITMAP bm;
    bitmap->GetBitmap(&bm);
        if(bm.bmBitsPixel < 16)
            return false;

    DWORD size = bm.bmWidth * bm.bmHeight * 4;
    BITMAPINFOHEADER bih = { sizeof(bih), bm.bmWidth, bm.bmHeight, 1, 32, BI_RGB };
    BITMAPFILEHEADER bfh = { 'MB', 54 + size, 0, 0, 54 };

    CClientDC dc(0);
    std::vector<BYTE> vec(size, 0xFF);
    int test = GetDIBits(dc, *bitmap, 0, bm.bmHeight, &vec[0],
            (BITMAPINFO*)&bih, DIB_RGB_COLORS);
    for(DWORD i = 0; i < size; i += 4)
        vec[i + 3] = 0xFF;

    CFile fout;
    if(fout.Open(filename, CFile::modeCreate | CFile::modeWrite))
    {
        fout.Write(&bfh, sizeof(bfh));
        fout.Write(&bih, sizeof(bih));
        fout.Write(&vec[0], size);
        return true;
    }

    return false;
}


作为替代方案(但我不确定这是否可靠)用
0xFF
初始化内存。
GetDIBits
将设置 RGB 部分,但不会覆盖 alpha 值:

std::vector<BYTE> vec(size, 0xFF);
GetDIBits...


或者使用GDI+

bool Save(CBitmap *bitmap)
{
    if(!bitmap)
        return false;

    BITMAP bm;
    bitmap->GetBitmap(&bm);
    if(bm.bmBitsPixel < 16)
        return false; //needs palette

    Gdiplus::GdiplusStartupInput tmp;
    ULONG_PTR token;
    Gdiplus::GdiplusStartup(&token, &tmp, NULL);

    Gdiplus::Bitmap *src = Gdiplus::Bitmap::FromHBITMAP(*bitmap, NULL);
    Gdiplus::Bitmap *dst = src->Clone(0, 0, src->GetWidth(), src->GetHeight(), 
        PixelFormat32bppARGB);

    LPCOLESTR clsid_bmp = L"{557cf400-1a04-11d3-9a73-0000f81ef32e}";
    CLSID clsid;
    CLSIDFromString(clsid_bmp, &clsid);
    bool result = dst->Save(L"file.bmp", &clsid) == 0;
    delete src;
    delete dst;

    Gdiplus::GdiplusShutdown(token);

    return result;
}

0
投票

您可以使用以下代码将位图中的任意矩形设置为不透明(Alpha==0xFF):

void SetAlpharect(HBITMAP hBmp, int x, int y, int cx, int cy) { 位图 bmp = { 0 }; GetObject(hBmp, sizeof(BITMAP), &bmp);

if (bmp.bmBitsPixel == 32)
{
    HDC hDC = CreateCompatibleDC(0);
    HBITMAP hBmpOld = (HBITMAP)SelectObject(hDC, hBmp);
    BITMAPINFO bi = {};
    bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bi.bmiHeader.biWidth = 1;
    bi.bmiHeader.biHeight = 1;
    bi.bmiHeader.biPlanes = 1;
    bi.bmiHeader.biBitCount = 32;
    bi.bmiHeader.biCompression = BI_RGB; // BI_ALPHABITFIELDS;

    RGBQUAD rgba = { 0,0,0,0xFF };
    StretchDIBits(hDC, x, y, cx, cy, 0, 0, 1, 1, &rgba, &bi, DIB_RGB_COLORS, SRCPAINT);

    SelectObject(hDC, hBmpOld);
    DeleteDC(hDC);
}

}

© www.soinside.com 2019 - 2024. All rights reserved.