c++ - WIC 的 JPEG 解码问题
问题描述
我目前正在尝试使用 WIC 将图像从磁盘加载到内存中。我在这里使用 MSDN 文档来编写我的代码。
一切都适用于加载 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)
推荐阅读
- clojure - Clojure 和 ClojureScript 之间的 core.async 区别
- c# - 如何比较两个datagridViewRows并将其传递给第三个datagridView c#
- node.js - 无法导入导出的函数
- excel - 寻找一个循环解决方案,从主 ws 复制到工作簿中的每个空工作表
- java - Java 多米诺骨牌与递归:第二个如果块被调用已更新的值
- r - 从格式化为图片的PDF中提取表格数据
- php - PHP - 根据数组的 ID 号显示名称
- android - 以编程方式填充 ProgressBar 背景
- electron - 打包后电子托盘图标不显示
- python-3.x - 使用循环构建时间序列数据库