如何使用 MFC 或 GDI 或 GDI+ 为位图中的所有像素设置 alpha 值
How to set alpha value for all pixels in a bitmap using MFC or GDI or GDI+
我在 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;
}
作为替代方案(但我不确定这是否可靠)用 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;
}
我在 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;
}
作为替代方案(但我不确定这是否可靠)用
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;
}