WICConvertBitmapSource + CopyPixels会生成蓝色图像

时间:2017-07-01 15:33:56

标签: c++ image image-processing wic

我正在尝试使用WIC将图像加载到内存缓冲区中以进行进一步处理,然后在完成后将其写回文件。具体做法是:

  1. 将图像加载到IWICBitmapFrameDecode中。
  2. 加载的IWICBitmapFrameDecode报告其像素格式为GUID_WICPixelFormat24bppBGR。我想使用32bpp RGBA,所以我打电话给WICConvertBitmapSource
  3. 在转换后的帧上调用CopyPixels以获取内存缓冲区。
  4. 使用WritePixels将内存缓冲区写回IWICBitmapFrameEncode。
  5. 这会产生可识别的图像,但生成的图像大多呈蓝色,就像红色通道被解释为蓝色一样。

    如果我调用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;
    }
    

1 个答案:

答案 0 :(得分:2)

PNG编码器仅支持GUID_WICPixelFormat32bppBGRA(BGR)32bpp,如PNG Native Codec官方文档中所述。当您使用GUID_WICPixelFormat32bppRGBA进行呼叫时,进行频道切换。变态只会使用你的像素,因为它们是BGR,而不是RGB,并且不会告诉你有问题。

我不知道您要做什么,但在您的示例中,您可以在调用WICConvertBitmapSource时将GUID_WICPixelFormat32bppRGBA替换为GUID_WICPixelFormat32bppBGRA(并且还替换最后一个的定义) pixelFormat变量以确保您的源代码正确,但它不会改变任何内容。

PS:您可以使用Wic保存文件,不需要使用其他API创建流,请参阅我的答案:Capture screen using DirectX