0
votes

Does anyone have an idea on how to "clone" a bitmap (ID2D1Bitmap).

I would like to clone a portion of the bitmap and have it have all the same attributes of the original (DPI, resolution, etc) and the only different would be the size. Gdiplus has a Clone function that I would like to simulate.

Thanks

I initially started with this

CComPtr<ID2D1Bitmap> imageD;
      // if region is entire original image no need to create a cropped image
      if (left != 0 || top != 0 || right != imageSize.width || bottom != imageSize.height)
      {
         // get format of original image
         D2D1_PIXEL_FORMAT fmt = imageData.image->GetPixelFormat();

         D2D1_SIZE_U bitmapPixelSize = D2D1::SizeU((UINT)(right - left), (UINT)(bottom - top));

         // create destination image of "clipped" source image
         HRESULT hr = m_pRenderTarget->CreateBitmap(bitmapPixelSize, D2D1::BitmapProperties(
            D2D1::PixelFormat(fmt.format, fmt.alphaMode),
            (float)imageData.resX, (float)imageData.resY), &imageD);

         if (hr != S_OK)
         {
            return;
         }

         D2D1_POINT_2U topleft = D2D1::Point2U(0, 0);
         D2D1_RECT_U srcRect = D2D1::RectU((UINT)left, (UINT)top, (UINT)right, (UINT)bottom);
         // get the "clipped" source
         hr = imageD->CopyFromBitmap(&topleft, imageData.image, &srcRect);

         if (hr != S_OK)
         {
            return;
         }

         imageSize = imageD->GetPixelSize();
      }
      else
         imageD = imageData.image;

      // create a textured brush w/ wrapping capabilities
      CComPtr <ID2D1BitmapBrush> pFabricBitmapBrush;
      HRESULT hr = m_pRenderTarget->CreateBitmapBrush(imageD, &pFabricBitmapBrush);
      pFabricBitmapBrush->SetExtendModeX(D2D1_EXTEND_MODE_WRAP);
      pFabricBitmapBrush->SetExtendModeY(D2D1_EXTEND_MODE_WRAP);

As you can see I'm applying the new (cropped) bitmap as a brush. When I do this the brush itself draws a smaller image, using the "clone" API with Gdiplus the logic draws correct. This is what led me to the idea that the Direct2d "copy" is not giving me the same attributes as the original image.

This seem to work. Resolution, DPI, dimensions, etc - must read very carefully.

float dpiXs, dpiYs;
         imageData.image->GetDpi(&dpiXs, &dpiYs);

         D2D1_SIZE_U bitmapPixelSize = D2D1::SizeU((UINT)(right - left), (UINT)(bottom - top));

         // create destination image of "clipped" source image
         HRESULT hr = m_pRenderTarget->CreateBitmap(bitmapPixelSize, D2D1::BitmapProperties(
            D2D1::PixelFormat(fmt.format, fmt.alphaMode), dpiXs, dpiYs), &imageD);
1

1 Answers

0
votes

There is no such a function, but you can write your own.

function CloneBitmap(src: ID2D1Bitmap; x, y, width, height: Integer; dst: ID2D1Bitmap): HResult;
begin
  Result :=
    // I assume that you have an access to the DeviceContext (or an ID2D1RenderTarget),
    // so you can create a new bitmap
    yourDeviceContext.CreateBitmap(
      D2D_SIZE_U(width, height),
      nil,
      0,
      src.GetPixelFormat,
      dst);

  if Succeeded(Result) then
    Result :=
      dst.CopyFromBitmap(
        D2D_POINT_2F(0, 0),
        src,
        D2D_RECT_U(
          x,
          y,
          x + width,
          y + height));
end;

I recommend to read about ID2D1RenderTarget::CreateBitmap and ID2D1Bitmap::CopyFromBitmap, so you will understand when these methods will fail (ie - when the above function result will differ from S_OK).

By the way, have you considered to crop and draw "on the fly" with the ID2D1RenderTarget::DrawBitmap method (directly in your render loop) ?