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

Winapi 如何使用MFC或GDI或GDI+为位图中的所有像素设置alpha值;,winapi,mfc,gdi+,gdi,cmfctoolbar,Winapi,Mfc,Gdi+,Gdi,Cmfctoolbar,我正在使用MFC应用程序。我用一个内存DC创建了一个位图,我想把它保存到DIB文件中 我发现这段代码是迄今为止最优雅的: void Save(CBitmap * bitmap) { CImage image; image.Attach((HBITMAP)pcBitmap->GetSafeHandle()); image.Save("bla.bmp", Gdiplus::ImageFormatBMP); } 生成的文件是32 BPP的颜色空间,所有alpha值都设置为“0” 现

我正在使用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值


到目前为止,我拒绝迭代每个像素并修改位图的内存。我要求一个优雅的解决方案。可能是一行。

使用
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;
}

或者使用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;
}
bool保存(CBitmap*位图)
{
如果(!位图)
返回false;
位图bm;
位图->获取位图(&bm);
if(bm.bmBitsPixel<16)
返回false;//需要调色板
Gdiplus::GDIPlusStartupInputTMP;
ULONG_PTR令牌;
Gdiplus::Gdiplus启动(&token,&tmp,NULL);
Gdiplus::Bitmap*src=Gdiplus::Bitmap::FromHBITMAP(*位图,NULL);
Gdiplus::Bitmap*dst=src->Clone(0,0,src->GetWidth(),src->GetHeight(),0,0,
像素格式(32bppargb);
LPCOLESTR clsid_bmp=L“{557cf400-1a04-11d3-9a73-0000f81ef32e}”;
CLSID-CLSID;
CLSIDFromString(clsid\u bmp,&clsid);
bool result=dst->Save(L“file.bmp”、&clsid)==0;
删除src;
删除dst;
Gdiplus::GdiplusShutdown(令牌);
返回结果;
}

您希望alpha为0xff,而不是0-不是吗?尝试使用GDI+进行保存,它可以很好地处理alpha通道
CImage
只是
HBITMAP
的包装,它没有任何alpha通道的概念。CImage.Save()在内部调用GDI+。我用调试器进行了验证。我的内存DC与我的窗口DC兼容,因此图像为32 BPP。GDI+将所有像素的alpha值设置为0。但是我希望所有像素的alpha值都是0xFF,因为这样图像就可以加载到CMFCToolbar对象中。查看
CImage::Save()
源代码,它检查
m_bHasAlphaChannel
(由
SetHasAlphaChannel()
调用设置)并使用
PixelFormat32bppARGB
创建GDI+位图。因此,这应该保留所有alpha通道数据。在调用
Save()
函数之前,您只需设置alpha通道值。
SetHasAlphaChannel
设置一个标志并在末尾创建一个32位图像,或者它用于透明绘图,但它不会影响可能保持为零的alpha。这就做到了。有趣的方法。非常感谢你。但我最终还是手工创建位图和手工编写文件。如果可能的话,我想避免这种情况。然后按照前面的建议使用GDI+。手动旋转几个像素没什么错,这可能是最快的方法。小小的挑剔:为什么要预填充
vec
?GDI+I在这里结束:
void Save(CBitmap*bitmap){Gdiplus::bitmap bm((HBITMAP)pcBitmap->GetSafeHandle(),NULL);bm.Save(pwszFileName,&clsidEncoder,NULL);}
仍然所有像素的alpha值都是0。在
bm.Save(…)
之前,必须进行一些转换来改变alpha值。@ChristophThien请参阅更新。确保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;
}