Gdiplus :: Bitmap释放内存

时间:2015-02-09 14:40:53

标签: bitmap gdi+

以下是我的代码(感谢其他人)读取图像文件并返回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;

1 个答案:

答案 0 :(得分:0)

内存管理对我来说是正确的。如果没有将数据指针传递给Bitmap构造函数(或者传递NULL指针),则不负责释放图像数据。

假设新Bitmap对象的步幅符合您的预期并不是一个好主意。在这种情况下,我认为它会解决,但如果你将像素格式改为大小不超过4个字节,GDI +可能会为行添加一些填充。要干净利落地执行此操作,您应该从BitmapData中读取步幅并单独复制每一行。

您也可以在Bitmap锁定时执行CopyPixels调用,直接使用BitmapData中的Scan0,而不是分配中间缓冲区。