以下是我的代码(感谢其他人)读取图像文件并返回Gdiplus :: Bitmap。我的问题是代码(在底部)正确创建Bitmap(它似乎工作)和调用代码,当我完成Bitmap时,我可以只调用delete pBitmap;
提前致谢
HRESULT ImageUtilities::LoadImageFromFile(
std::string path,
UINT destinationWidth,
UINT destinationHeight,
UINT frame,
Gdiplus::Bitmap **ppBitmap,
double *resX,
double *resY)
{
CComPtr<IWICBitmapFrameDecode> pSource;
CComPtr<IWICBitmapDecoder> pDecoder;
CComPtr<IWICFormatConverter> pConverter;
CComPtr<IWICBitmapScaler> pScaler;
// get image factory
IWICImagingFactory *pImageFactory = WICImagingFactory::GetInstance().GetFactory();
// get / determine image decoder
HRESULT hr = pImageFactory->CreateDecoderFromFilename( MultiByteToUnicode(path).c_str(), NULL, GENERIC_READ, WICDecodeMetadataCacheOnLoad, &pDecoder );
// get the specified frame from the image
if (SUCCEEDED(hr))
{
// Validate the given frame index nFrame
UINT nCount = 0;
// Get the number of frames in this image
if (SUCCEEDED(pDecoder->GetFrameCount(&nCount)))
{
if (frame >= nCount)
frame = nCount - 1; // If the requested frame number is too big, default to the last frame
}
// get the frame
if (SUCCEEDED(hr))
{
hr = pDecoder->GetFrame(0, &pSource);
}
}
// get the image converter
if (SUCCEEDED(hr))
{
// Convert the image format to 32bppPBGRA (DXGI_FORMAT_B8G8R8A8_UNORM + D2D1_ALPHA_MODE_PREMULTIPLIED)
hr = pImageFactory->CreateFormatConverter(&pConverter);
}
if (SUCCEEDED(hr))
{
pSource->GetResolution(resX, resY);
// if a new width or height was specified, create an IWICBitmapScaler and use it to resize the image
if (destinationWidth != 0 || destinationHeight != 0)
{
UINT originalWidth, originalHeight;
hr = pSource->GetSize(&originalWidth, &originalHeight);
if (SUCCEEDED(hr))
{
if (destinationWidth == 0)
{
FLOAT scalar = static_cast<FLOAT>(destinationHeight) / static_cast<FLOAT>(originalHeight);
destinationWidth = static_cast<UINT>(scalar * static_cast<FLOAT>(originalWidth));
}
else if (destinationHeight == 0)
{
FLOAT scalar = static_cast<FLOAT>(destinationWidth) / static_cast<FLOAT>(originalWidth);
destinationHeight = static_cast<UINT>(scalar * static_cast<FLOAT>(originalHeight));
}
hr = pImageFactory->CreateBitmapScaler(&pScaler);
if (SUCCEEDED(hr))
{
hr = pScaler->Initialize(pSource, destinationWidth, destinationHeight, WICBitmapInterpolationModeCubic);
}
if (SUCCEEDED(hr))
{
hr = pConverter->Initialize(pScaler, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone,
NULL,
0.f,
WICBitmapPaletteTypeMedianCut
);
}
}
}
else // Don't scale the image.
{
hr = pConverter->Initialize(pSource, GUID_WICPixelFormat32bppPBGRA, WICBitmapDitherTypeNone,
NULL,
0.f,
WICBitmapPaletteTypeMedianCut
);
}
}
// finally create a GDI+ Bitmap from the WIC bitmap.
if (SUCCEEDED(hr))
{
// calculate stride and necessary buffer size
UINT uWidth, uHeight;
hr = pConverter->GetSize(&uWidth, &uHeight);
const UINT cbStride = 4 * uWidth;
const UINT cbBufferSize = cbStride * uHeight;
// allocate buffer then copy pixels
// NOTE: we are responable to delete this buffer when we delete the Bitmap
BYTE *pBitmapBuffer = new BYTE[cbBufferSize];
WICRect rc;
rc.X = 0; rc.Y = 0; rc.Width = uWidth; rc.Height = uHeight;
hr = pConverter->CopyPixels(&rc, cbStride, cbBufferSize, (BYTE *)pBitmapBuffer);
// create a Gdiplus::Bitmap object
Gdiplus::Bitmap *pBitmap = new Gdiplus::Bitmap(uWidth, uHeight, cbStride,
PixelFormat32bppPARGB, pBitmapBuffer);
delete[] pBitmapBuffer;
if (Gdiplus::Ok != pBitmap->GetLastStatus())
{
return E_FAIL;
}
*ppBitmap = pBitmap;
}
return hr;
}
我将上面的内容改为以下内容,似乎运行得更好
Gdiplus::Bitmap *pBitmap = new Gdiplus::Bitmap(uWidth, uHeight, PixelFormat32bppPARGB);
Gdiplus::BitmapData bd;
Gdiplus::Rect rect(0, 0, pBitmap->GetWidth(), pBitmap->GetHeight());
Gdiplus::Status status = pBitmap->LockBits(&rect, Gdiplus::ImageLockModeWrite, PixelFormat32bppPARGB, &bd);
if (Gdiplus::Ok == status)
{
memcpy(bd.Scan0, pBitmapBuffer, cbStride*uHeight);
status = pBitmap->UnlockBits(&bd);
}
delete[] pBitmapBuffer;
答案 0 :(得分:0)
内存管理对我来说是正确的。如果没有将数据指针传递给Bitmap构造函数(或者传递NULL指针),则不负责释放图像数据。
假设新Bitmap对象的步幅符合您的预期并不是一个好主意。在这种情况下,我认为它会解决,但如果你将像素格式改为大小不超过4个字节,GDI +可能会为行添加一些填充。要干净利落地执行此操作,您应该从BitmapData中读取步幅并单独复制每一行。
您也可以在Bitmap锁定时执行CopyPixels调用,直接使用BitmapData中的Scan0,而不是分配中间缓冲区。