如何使用ATL::CImage类将带有alpha通道的32位 BMP图像转换为PNG格式
我们使用32位 RGB位图,信息编码在第四字节中,通常用作“Alpha”通道,但在我们的场景中用来编码其他元数据。多年来我们一直无障碍地保存/加载32位 BMP格式的图像,全部使用(旧的)ATL::CImage 类。
我们想切换到PNG格式以节省磁盘空间,但只能实现以下两种结果之一:
m_hasAlphaChannel = FALSE:PNG图像在所有位置的alpha通道都设为0xFF。m_hasAlphaChannel = TRUE:所有像素值在保存前会乘以alpha值,因此每当alpha值为零时,图像中的信息都会丢失(这是典型情况)。
我们可以使用哪种API调用组合来确保在保存元数据的同时,未修改的像素值也被保存到图像中?
解决方案
也许你应该考虑使用其他库来保存/加载图像。
以下代码演示了如何使用 Windows成像组件(WIC) 来将数组保存为PNG,或从PNG加载数组。
为简化起见,省略了资源释放和错误处理。你应使用你偏好的COM智能指针来管理资源。
你可以把它改写为一对辅助函数,用于保存/加载 CImage,并添加适当的错误处理。
#include<Windows.h>
#include<wincodec.h>
#include<combaseapi.h>
#include<cassert>
#include<vector>
int main() {
CoInitializeEx(NULL, COINIT_MULTITHREADED | COINIT_DISABLE_OLE1DDE);
const int width = 200;
const int height = 200;
// Fill some random data.
// You should replace this with the pixel data you obtained from your CImage.
std::vector<BYTE> data(width * height * 4);
for (int i = 0; i < data.size(); ++i) {
data[i] = static_cast<BYTE>(i);
}
IWICImagingFactory* factory = nullptr; // can be reused
HRESULT hr = CoCreateInstance(
CLSID_WICImagingFactory,
nullptr,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&factory)
);
if (1) {
IWICBitmapEncoder* encoder = nullptr;
factory->CreateEncoder(GUID_ContainerFormatPng, nullptr, &encoder);
IWICStream* stream = nullptr;
factory->CreateStream(&stream);
stream->InitializeFromFilename(L"output.png", GENERIC_WRITE);
encoder->Initialize(stream, WICBitmapEncoderNoCache);
IWICBitmapFrameEncode* frame = nullptr;
encoder->CreateNewFrame(&frame, nullptr);
frame->Initialize(nullptr);
frame->SetSize(width, height);
WICPixelFormatGUID format = GUID_WICPixelFormat32bppBGRA;
frame->SetPixelFormat(&format);
frame->WritePixels(
height,
width * 4,
width * height * 4,
data.data()
);
frame->Commit();
encoder->Commit();
}
else {
// Confirm data is stored correctly
IWICBitmapDecoder* decoder = nullptr;
factory->CreateDecoderFromFilename(
L"output.png",
nullptr,
GENERIC_READ,
WICDecodeMetadataCacheOnLoad,
&decoder
);
IWICBitmapFrameDecode* frame = nullptr;
decoder->GetFrame(0, &frame);
IWICFormatConverter* converter = nullptr;
factory->CreateFormatConverter(&converter);
converter->Initialize(
frame,
GUID_WICPixelFormat32bppBGRA,
WICBitmapDitherTypeNone,
nullptr,
0.0,
WICBitmapPaletteTypeCustom
);
UINT width2, height2;
converter->GetSize(&width2, &height2);
assert(width2 == width && height2 == height);
std::vector<BYTE> pixels(width2 * height2 * 4);
converter->CopyPixels(
nullptr,
width2 * 4,
pixels.size(),
pixels.data()
);
assert(data == pixels);
}
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。