我正在尝试使用 WIC 将图像加载到内存缓冲区中以进行进一步处理,然后在完成后将其写回到文件中。具体来说:
- 将图像加载到 IWICBitmapFrameDecode 中。
- 加载的 IWICBitmapFrameDecode 报告其像素格式为 GUID_WICPixelFormat24bppBGR。我想在 32bpp RGBA 下工作,所以我打电话 WICConvertBitmapSource .
- 调用 CopyPixels在转换后的帧上获取内存缓冲区。
- 使用 WritePixels 将内存缓冲区写回 IWICBitmapFrameEncode .
这会产生可识别的图像,但生成的图像大部分呈蓝色,就好像红色 channel 被解释为蓝色一样。
如果我打电话WriteSource直接写入转换后的帧,而不是写入内存缓冲区,它可以工作。如果我从原始未转换的帧中调用 CopyPixels(并相应地更新我的步幅和像素格式),它就会起作用。只是 WICConvertBitmapSource 的组合加上内存缓冲区 (CopyPixels + WritePixels) 的使用导致了问题,但我无法弄清楚我做错了什么。
这是我的代码。
int main() {
IWICImagingFactory *pFactory;
IWICBitmapDecoder *pDecoder = NULL;
CoInitializeEx(NULL, COINIT_MULTITHREADED);
CoCreateInstance(
CLSID_WICImagingFactory,
NULL,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
(LPVOID*)&pFactory
);
// Load the image.
pFactory->CreateDecoderFromFilename(L"input.png", NULL, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &pDecoder);
IWICBitmapFrameDecode *pFrame = NULL;
pDecoder->GetFrame(0, &pFrame);
// pFrame->GetPixelFormat shows that the image is 24bpp BGR.
// Convert to 32bpp RGBA for easier processing.
IWICBitmapSource *pConvertedFrame = NULL;
WICConvertBitmapSource(GUID_WICPixelFormat32bppRGBA, pFrame, &pConvertedFrame);
// Copy the 32bpp RGBA image to a buffer for further processing.
UINT width, height;
pConvertedFrame->GetSize(&width, &height);
const unsigned bytesPerPixel = 4;
const unsigned stride = width * bytesPerPixel;
const unsigned bitmapSize = width * height * bytesPerPixel;
BYTE *buffer = new BYTE[bitmapSize];
pConvertedFrame->CopyPixels(nullptr, stride, bitmapSize, buffer);
// Insert image buffer processing here. (Not currently implemented.)
// Create an encoder to turn the buffer back into an image file.
IWICBitmapEncoder *pEncoder = NULL;
pFactory->CreateEncoder(GUID_ContainerFormatPng, nullptr, &pEncoder);
IStream *pStream = NULL;
SHCreateStreamOnFileEx(L"output.png", STGM_WRITE | STGM_CREATE, FILE_ATTRIBUTE_NORMAL, true, NULL, &pStream);
pEncoder->Initialize(pStream, WICBitmapEncoderNoCache);
IWICBitmapFrameEncode *pFrameEncode = NULL;
pEncoder->CreateNewFrame(&pFrameEncode, NULL);
pFrameEncode->Initialize(NULL);
WICPixelFormatGUID pixelFormat = GUID_WICPixelFormat32bppRGBA;
pFrameEncode->SetPixelFormat(&pixelFormat);
pFrameEncode->SetSize(width, height);
pFrameEncode->WritePixels(height, stride, bitmapSize, buffer);
pFrameEncode->Commit();
pEncoder->Commit();
pStream->Commit(STGC_DEFAULT);
return 0;
}
最佳答案
PNG 编码器仅支持 PNG Native Codec 中指定的 32bpp 的 GUID_WICPixelFormat32bppBGRA
(BGR)。官方文档。当您使用 GUID_WICPixelFormat32bppRGBA 调用它时,它不会进行 channel 切换。变态者只会使用你的像素,因为它们是 BGR,而不是 RGB,并且不会告诉你有问题。
我不知道您要做什么,但在您的示例中,您可以在对 WICConvertBitmapSource 的调用中将 GUID_WICPixelFormat32bppRGBA
替换为 GUID_WICPixelFormat32bppBGRA
(以及替换最后一个 pixelFormat
变量的定义以确保您的源代码正确,但它不会改变任何内容)。
PS:您可以使用Wic来保存文件,不需要使用其他API创建流,请参见我的答案:Capture screen using DirectX
关于c++ - WICConvertBitmapSource + CopyPixels 结果为蓝色图像,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44862631/