WIC 的 JPEG 解码问题

JPEG Decoding problems with WIC

我目前正在尝试使用 WIC 将图像从磁盘加载到内存中。我使用 MSDN 文档 here 编写我的代码。

加载 PNG 图像一切正常。加载 JPEG 图像没有任何错误,但不会产生正确的结果!有趣的是,当我将图像从 JPEG 转换为 PNG(使用 irfan 视图)时,错误仍然存​​在。

考虑以下测试图像:

如您所见,图像在 x 方向上缩小了,所有颜色信息都消失了。然而,当你放大时,你可以看到仍然有一些颜色存在,但它看起来不像预期的那样:

(将图像作为纹理上传到 GPU 时问题仍然存在)

为了便于阅读,我删除了我的 WIC 加载代码,省略了错误处理和资源释放:

// CoInitialize(NULL) called in main

// WIC Factory
IWICImagingFactory* ptrFactory = NULL;
CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&ptrFactory));

// Open decoder
IWICBitmapDecoder* ptrDecoder = NULL;
ptrFactory->CreateDecoderFromFilename(fileName, NULL, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &ptrDecoder)

// Get first frame
IWICBitmapFrameDecode* ptrFrameDecoder = NULL;
ptrDecoder->GetFrame(0, &ptrFrameDecoder));

// Read formate
WICPixelFormatGUID frameNativeFormat;
ptrFrameDecoder->GetPixelFormat(&frameNativeFormat);

// Computing target format selectConverterWic(...) and selectConverterDx(...) are just some very basic functions for selecting the right convert to formate by iterating over an std::array witch contains the mappings suggested by the MSDC article mentioned above
WICPixelFormatGUID targetFormat;
DXGI_FORMAT targetFormatDx;
if (!selectConverterDx(frameNativeFormat, &targetFormatDx)) {
    // Try to find WIC to WIC converter
    selectConverterWic(frameNativeFormat, &targetFormat)
    selectConverterDx(targetFormat, &targetFormatDx)
}else {
    memcpy(&targetFormat, &frameNativeFormat, sizeof(GUID));
}

// Get format info
IWICComponentInfo* ptrCmpInfo = NULL;
ptrFactory->CreateComponentInfo(targetFormat, &ptrCmpInfo);

// Get type
WICComponentType ptrCmpType;
ptrCmpInfo->GetComponentType(&ptrCmpType);


// Get info from type
IWICPixelFormatInfo* ptrFormatInfo = NULL;
ptrCmpInfo->QueryInterface(IID_PPV_ARGS(&ptrFormatInfo));

// Get BBP
UINT uiBitsPerPixel;
ptrFormatInfo->GetBitsPerPixel(&uiBitsPerPixel);

// ID3D12Device->CheckFeatureSupport(...) and fallback omitted

// Image size
UINT width, height;
ptrFrameDecoder->GetSize(&width, &height);

// Tempory memory allocation
UINT rowPitch = (width * uiBitsPerPixel + 7) / 8;
SIZE_T imageSize = (SIZE_T)rowPitch * (SIZE_T)height;
void* workMemory = malloc(imageSize);

// Check if direct copy is possible
if (memcmp(&frameNativeFormat, &targetFormat, sizeof(GUID)) == 0){
    ptrFrameDecoder->CopyPixels(NULL, rowPitch, (UINT)imageSize, (BYTE*)workMemory);
}else{
    // Format conversion (Got never hit by a jpeg file; I tried to force it but results weren't right asswell)
    IWICFormatConverter* ptrFormatConverter = NULL;
    ptrFactory->CreateFormatConverter(&ptrFormatConverter);
    ptrFormatConverter->Initialize(ptrFrameDecoder, targetFormat, WICBitmapDitherTypeErrorDiffusion, NULL, 0, WICBitmapPaletteTypeCustom);
    ptrFormatConverter->CopyPixels(NULL, rowPitch, (UINT)imageSize, (BYTE*)workMemory);
    
}

// I inspected workMemory and got the result you saw above
// Some more code for copying data to user supplied parameters

在此先感谢您的帮助!

上面的代码完全可以正常工作!问题出在省略的 DirectX 12 功能支持检查中:

ID3D12Device->CheckFeatureSupport(...)

我忘记了一个反转导致执行了以下代码片段

memcpy(&frameNativeFormat, &GUID_WICPixelFormat32bppRGBA, sizeof(GUID));
targetFormatDx = DXGI_FORMAT_R8G8B8A8_UNORM;
uiBitsPerPixel = 32;

第二个错误是我覆盖了“frameNativeFormat”而不是“targetFormat”,这导致没有执行任何转换(至少对于 JPEG)。

解决这两个问题给了我一个不错的纹理加载算法(至少 Windows)