最近使用Dirtect2D进行绘图操作,查阅了一些资料,也遇到了一些问题,其中部分问题网上也没有明确的正解(至少本人未找到),为止,本人记录一下,以供遇到同样问题的朋友们参考。
一,生成IWICImagingFactory
IWICImagingFactory* m_pIWICImagingFactory = NULL;
if (NULL == m_pIWICImagingFactory)
{
CoInitialize(NULL);
CoCreateInstance(
CLSID_WICImagingFactory,
NULL,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&m_pIWICImagingFactory)
);
}
IWICImagingFactory这个是组件,所以需要调用CoInitialize(NULL);如果没有调用是生成不了IWICImagingFactory的。
剩下的也就不多说了,直接调用测试函数(这个函数里面的buffer未释放)
GetID2D1BitmapFromImageData(
ID2D1RenderTarget *pRenderTarget,
IWICImagingFactory *pIWICFactory,
void* pImageData,//RGB图像的buffer
int imageW,//RGB图像的宽
int ImageH,//RGB图像的高
UINT destinationWidth,//目标图像的宽,因为这个函数进行了缩放操作,所以提供这个参数
UINT destinationHeight,//目标图像的高,因为这个函数进行了缩放操作,所以提供这个参数
ID2D1Bitmap **ppBitmap
HRESULT GetID2D1BitmapFromImageData(
ID2D1RenderTarget *pRenderTarget,
IWICImagingFactory *pIWICFactory,
void* pImageData,
int imageW,
int ImageH,
UINT destinationWidth,
UINT destinationHeight,
ID2D1Bitmap **ppBitmap
)
{
HRESULT hr = S_OK;
IWICBitmapDecoder *pDecoder = NULL;
IWICBitmapFrameDecode *pSource = NULL;
IWICStream *pStream = NULL;
IWICFormatConverter *pConverter = NULL;
IWICBitmapScaler *pScaler = NULL;
static BYTE* buffer = NULL; //这里写静态的,只是为了测试,正式写的时候根据实际情况修改
hr = pIWICFactory->CreateStream(&pStream);
if (SUCCEEDED(hr))
{
if (!buffer)
{
BITMAPINFOHEADER bmiHdr; //定义信息头
bmiHdr.biSize = sizeof(BITMAPINFOHEADER);
bmiHdr.biWidth = imageW;
bmiHdr.biHeight = -ImageH;
bmiHdr.biPlanes = 1;
bmiHdr.biBitCount = 24;
bmiHdr.biCompression = BI_RGB;
bmiHdr.biSizeImage = imageW * ImageH * 3;
bmiHdr.biXPelsPerMeter = 0;
bmiHdr.biYPelsPerMeter = 0;
bmiHdr.biClrUsed = 0;
bmiHdr.biClrImportant = 0;
BITMAPFILEHEADER fheader = { 0 };
fheader.bfType = 'M' << 8 | 'B';
fheader.bfSize = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER) + bmiHdr.biSizeImage;
fheader.bfOffBits = sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER);
buffer = new BYTE[fheader.bfSize];
memcpy(buffer, &fheader, sizeof(fheader));
memcpy(buffer + sizeof(fheader), &bmiHdr, sizeof(bmiHdr));
}
memcpy(buffer + sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER), reinterpret_cast<BYTE*>(pImageData), imageW * ImageH * 3);
/*
//测试BITMAPINFO数据是否正确,如果正确则可以正确的保存out.bmp
FILE* file;
fopen_s(&file, "out.bmp", "wb");
fwrite((const char*)(buffer), 1, fheader.bfSize, file);
fclose(file);*/
// Initialize the stream with the memory pointer and size.
hr = pStream->InitializeFromMemory(
reinterpret_cast<BYTE*>(buffer),
imageW * ImageH * 3 + sizeof(BITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER)
);
}
//网上很多说CreateDecoderFromStream创建失败(0x88982f50 未找到组件),实际是没有正确的生成pStream
//参考https://stackoverflow.com/questions/9979848/iwicimagingfactorycreatedecoderfromstream-fails-error-message-message-is-no
hr = pIWICFactory->CreateDecoderFromStream(
pStream,
NULL,
WICDecodeMetadataCacheOnLoad,
&pDecoder
);
/*
//该方法用于测试CreateDecoderFromFilename, 如果使用该方法,可以注释上面Stream的部分
if (!pDecoder)
{
hr = pIWICFactory->CreateDecoderFromFilename(
_T("D:\\CheckImage3.bmp"),
NULL,
GENERIC_READ,
WICDecodeMetadataCacheOnLoad,
&pDecoder
);
}
*/
if (SUCCEEDED(hr))
{
// Create the initial frame.
hr = pDecoder->GetFrame(0, &pSource);
}
if (SUCCEEDED(hr))
{
hr = pIWICFactory->CreateFormatConverter(&pConverter);
}
// If a new width or height was specified, create an
// IWICBitmapScaler and use it to resize the image.
if (destinationWidth != 0 || destinationHeight != 0)
{
if (SUCCEEDED(hr))
{
if (destinationWidth == 0)
{
UINT originalWidth, originalHeight;
hr = pSource->GetSize(&originalWidth, &originalHeight);
FLOAT scalar = static_cast<FLOAT>(destinationHeight) / static_cast<FLOAT>(originalHeight);
destinationWidth = static_cast<UINT>(scalar * static_cast<FLOAT>(originalWidth));
}
else if (destinationHeight == 0)
{
UINT originalWidth, originalHeight;
hr = pSource->GetSize(&originalWidth, &originalHeight);
FLOAT scalar = static_cast<FLOAT>(destinationWidth) / static_cast<FLOAT>(originalWidth);
destinationHeight = static_cast<UINT>(scalar * static_cast<FLOAT>(originalHeight));
}
hr = pIWICFactory->CreateBitmapScaler(&pScaler);
if (SUCCEEDED(hr))
{
hr = pScaler->Initialize(
pSource,
destinationWidth,
destinationHeight,
WICBitmapInterpolationModeNearestNeighbor//WICBitmapInterpolationModeCubic
);
}
if (SUCCEEDED(hr))
{
hr = pConverter->Initialize(
pScaler,
GUID_WICPixelFormat32bppPBGRA,
WICBitmapDitherTypeNone,
NULL,
0.f,
WICBitmapPaletteTypeMedianCut
);
}
if (SUCCEEDED(hr))
{
//create a Direct2D bitmap from the WIC bitmap.
hr = pRenderTarget->CreateBitmapFromWicBitmap(
pConverter,
NULL,
ppBitmap
);
/*
//从pConverter的内存中拷贝数据,效果同上面方法
pConverter->GetSize(&destinationWidth, &destinationHeight);
const UINT cbStride = destinationWidth * 4;
const UINT cbImage = cbStride * destinationHeight;
static BYTE * pvImageBits = new BYTE[cbImage];
hr = pConverter->CopyPixels(NULL, cbStride, cbImage, pvImageBits);
{
(*ppBitmap)->CopyFromMemory(&D2D1::RectU(0, 0, destinationWidth, destinationHeight), pvImageBits, cbStride);
}
*/
}
}
}
SafeRelease(&pDecoder);
SafeRelease(&pSource);
SafeRelease(&pStream);
SafeRelease(&pConverter);
SafeRelease(&pScaler);
return hr;
}
最后,DrawBitmap后,要记得释放掉生成的ppBitmap哦。