如何用CryptStringToBinary解码Base64图片及Bitmap透明度问题
问题解答
1. 如何用CryptStringToBinary API返回的值重建图片?
你的代码里memcpy(pImage, ???? , imageSize);这一步是错误的,正确做法是第二次调用CryptStringToBinary,把Base64字符串解码成二进制图片数据到你分配好的内存缓冲区里。完整流程如下:
- 第一次调用
CryptStringToBinary,传入NULL作为输出缓冲区,获取解码后二进制数据的长度dwDataLen; - 用
GlobalAlloc分配对应大小的内存,并用GlobalLock锁定得到指针pImage; - 第二次调用
CryptStringToBinary,把Base64字符串解码到pImage指向的缓冲区; - 用
CreateStreamOnHGlobal把内存转换成IStream,再用GDI+的Image类加载这个流,就能得到图片对象。
修正后的关键代码片段:
// 第一次调用获取数据长度(已有代码) CryptStringToBinary( base64, _tcslen(base64), CRYPT_STRING_BASE64, NULL, &dwDataLen, &dwSkip, &dwFlags); DWORD imageSize = dwDataLen; HGLOBAL hMem = ::GlobalAlloc(GMEM_MOVEABLE, imageSize); LPVOID pImage = ::GlobalLock(hMem); // 第二次调用,真正解码Base64到内存缓冲区 CryptStringToBinary( base64, _tcslen(base64), CRYPT_STRING_BASE64, (BYTE*)pImage, &dwDataLen, &dwSkip, &dwFlags); // 后续创建流、加载图片的代码不变 IStream* pStream = NULL; ::CreateStreamOnHGlobal(hMem, FALSE, &pStream); Gdiplus::Image image(pStream);
2. 当前创建Bitmap的方式是否能保留图片的透明度?
当前代码的方式大概率会丢失透明度,需要调整几个关键点:
- 确保PixelFormat支持Alpha通道:你用
image.GetPixelFormat()获取格式是对的,但要确认原图片的格式是带Alpha通道的(比如PixelFormat32bppARGB)。如果原图片不带Alpha通道,Clear(Color::Transparent)不会有效果; - 设置Graphics的合成模式:默认合成模式可能会覆盖透明区域,需要显式设置
CompositingMode为CompositingModeSourceOver,这样绘制时会保留Alpha通道; - HICON转换的注意事项:
Bitmap::GetHICON()可以保留透明度,但要求Bitmap是32位ARGB格式,且系统支持透明图标(Windows XP及以上均支持)。
修正后的Bitmap创建代码:
int wd = image.GetWidth(); int hgt = image.GetHeight(); auto format = image.GetPixelFormat(); Bitmap* bmp = new Bitmap(wd, hgt, format); auto gg = std::unique_ptr<Graphics>(Graphics::FromImage(bmp)); // 关键:设置合成模式以支持透明 gg->SetCompositingMode(CompositingModeSourceOver); gg->Clear(Color::Transparent); gg->DrawImage(&image, 0, 0, wd, hgt); HICON hIcon; // 检查转换是否成功 if(bmp->GetHICON(&hIcon) != Ok) { // 处理转换失败的逻辑 }
另外,用完HICON后要调用DestroyIcon(hIcon)释放资源,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Cesar
相关产品推荐
相关产品推荐

