最近运用 windows 下 WIC IWICBitmapFrameEncode 将 RGB32转Jpeg,遇到一个问题,转出来的Jpeg,显示不对:1、画面灰色,有白条纹;2、画面是倒的(从opengl纹理读到的),如下:
而RGB24直接转jpeg是正常的,通过MSDN相关资料发现,jpeg编解码器只支持RGB24格式
本机像素格式概述 - Win32 apps | Microsoft Docs
两步解决以上问题:
1、需要采用IWICFormatConverter,将RGB32转为RGB24
hr = piFactory->CreateBitmapFromMemory(
width, height, GUID_WICPixelFormat32bppRGBA, width * 4,
height * width * 4, buffer, &piBitmapSrc);
// Create the flip / rotator.
if (SUCCEEDED(hr)) {
hr = piFactory->CreateFormatConverter(&piFormatConverter);
}
// Initialize the format converter.
if (SUCCEEDED(hr)) {
hr = piFormatConverter->Initialize(
piBitmapSrc, // Input source to convert
GUID_WICPixelFormat24bppBGR, // Destination pixel format
WICBitmapDitherTypeNone, // Specified dither pattern
NULL, // Specify a particular palette
0.f, // Alpha threshold
WICBitmapPaletteTypeCustom // Palette translation type
);
}
2、运用Jpeg编码器的选项 BitmapTransform,将画面旋转180度,该选项还支持其他变换,详见以下链接
JPEG 格式概述 - Win32 apps | Microsoft Docs
if (SUCCEEDED(hr)) {
PROPBAG2 option = {0};
option.pstrName = L"BitmapTransform";
VARIANT varValue;
VariantInit(&varValue);
varValue.vt = VT_UI1;
varValue.bVal = WICBitmapTransformRotate180;
hr = pPropertybag->Write(1, &option, &varValue);
if (SUCCEEDED(hr)) {
hr = piBitmapFrame->Initialize(pPropertybag);
}
}
具体实现代码如下:
int RGB32BufferToJpeg(uint8_t* buffer, int width, int height, const std::wstring& filePath)
{
IWICImagingFactory* piFactory = NULL;
IWICBitmapEncoder* piEncoder = NULL;
IWICBitmapFrameEncode* piBitmapFrame = NULL;
IWICStream* piStream = NULL;
IWICBitmap* piBitmapSrc = NULL;
IWICFormatConverter* piFormatConverter = NULL;
IWICBitmapSource* piBitmapTmp = NULL;
IPropertyBag2* pPropertybag = NULL;
CoInitialize(NULL);
HRESULT hr =
CoCreateInstance(CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory, (LPVOID*)&piFactory);
if (SUCCEEDED(hr)) {
hr = piFactory->CreateStream(&piStream);
}
if (SUCCEEDED(hr)) {
LPCWSTR tmp = reinterpret_cast<LPCWSTR>(filePath.c_str());
hr = piStream->InitializeFromFilename(tmp, GENERIC_WRITE);
}
if (SUCCEEDED(hr)) {
hr = piFactory->CreateEncoder(GUID_ContainerFormatJpeg, NULL, &piEncoder);
}
if (SUCCEEDED(hr)) {
hr = piEncoder->Initialize(piStream, WICBitmapEncoderNoCache);
}
if (SUCCEEDED(hr)) {
hr = piEncoder->CreateNewFrame(&piBitmapFrame, &pPropertybag);
}
if (SUCCEEDED(hr)) {
PROPBAG2 option = {0};
option.pstrName = L"BitmapTransform";
VARIANT varValue;
VariantInit(&varValue);
varValue.vt = VT_UI1;
varValue.bVal = WICBitmapTransformRotate180;
hr = pPropertybag->Write(1, &option, &varValue);
if (SUCCEEDED(hr)) {
hr = piBitmapFrame->Initialize(pPropertybag);
}
}
if (SUCCEEDED(hr)) {
hr = piBitmapFrame->SetSize(width, height);
}
hr = piFactory->CreateBitmapFromMemory(
width, height, GUID_WICPixelFormat32bppRGBA, width * 4,
height * width * 4, buffer, &piBitmapSrc);
// Create the flip / rotator.
if (SUCCEEDED(hr)) {
hr = piFactory->CreateFormatConverter(&piFormatConverter);
}
// Initialize the format converter.
if (SUCCEEDED(hr)) {
hr = piFormatConverter->Initialize(
piBitmapSrc, // Input source to convert
GUID_WICPixelFormat24bppBGR, // Destination pixel format
WICBitmapDitherTypeNone, // Specified dither pattern
NULL, // Specify a particular palette
0.f, // Alpha threshold
WICBitmapPaletteTypeCustom // Palette translation type
);
}
if (SUCCEEDED(hr))
piFormatConverter->QueryInterface(IID_IWICBitmapSource,
reinterpret_cast<void**>(&piBitmapTmp));
if (SUCCEEDED(hr)) {
hr = piBitmapFrame->WriteSource(piBitmapTmp, NULL);
}
if (SUCCEEDED(hr)) {
hr = piBitmapFrame->Commit();
}
if (SUCCEEDED(hr)) {
hr = piEncoder->Commit();
}
if (piBitmapTmp) {
piBitmapTmp->Release();
}
if (piFormatConverter) {
piFormatConverter->Release();
}
if (piBitmapSrc) {
piBitmapSrc->Release();
}
if (piEncoder) {
piEncoder->Release();
}
if (piBitmapFrame) {
piBitmapFrame->Release();
}
if (pPropertybag) {
pPropertybag->Release();
}
if (piStream) {
piStream->Release();
}
if (piFactory) {
piFactory->Release();
}
return SUCCEEDED(hr) ? 0 : -1;
}