Einzelnen Beitrag anzeigen

cocsy

Registriert seit: 12. Jul 2011
30 Beiträge
 
Delphi 11 Alexandria
 
#24

AW: Direct2D.Canvas in einer Bitmap speichern

  Alt 3. Apr 2023, 18:40
Hier noch einmal die Lösung zusammengefasst

Delphi-Quellcode:
interface

uses
  Winapi.Windows, Winapi.D2D1, Winapi.DXGI, Winapi.DxgiFormat,
  System.SysUtils, System.Classes,
  Vcl.Graphics, Vcl.Direct2D;

type
  // This describes how the individual mapping operation should be performed.
  PD2D1_MAP_OPTIONS = ^D2D1_MAP_OPTIONS;
  D2D1_MAP_OPTIONS = DWord;
{$EXTERNALSYM D2D1_MAP_OPTIONS}


const
  // The mapped pointer has undefined behavior.
  D2D1_MAP_OPTIONS_NONE = D2D1_MAP_OPTIONS(0); {$EXTERNALSYM D2D1_MAP_OPTIONS_NONE} // The mapped pointer can be read from.
  D2D1_MAP_OPTIONS_READ = D2D1_MAP_OPTIONS(1); {$EXTERNALSYM D2D1_MAP_OPTIONS_READ} // The mapped pointer can be written to.
  D2D1_MAP_OPTIONS_WRITE = D2D1_MAP_OPTIONS(2); {$EXTERNALSYM D2D1_MAP_OPTIONS_WRITE} // The previous contents of the bitmap are discarded when it is mapped.
  D2D1_MAP_OPTIONS_DISCARD = D2D1_MAP_OPTIONS(4); {$EXTERNALSYM D2D1_MAP_OPTIONS_DISCARD} // D2D1_MAP_OPTIONS_FORCE_DWORD = FORCEDWORD;

type
  // Specifies how the bitmap can be used.
  PD2D1_BITMAP_OPTIONS = ^D2D1_BITMAP_OPTIONS;
  D2D1_BITMAP_OPTIONS = DWord; {$EXTERNALSYM D2D1_BITMAP_OPTIONS}


const
  // The bitmap is created with default properties.
  D2D1_BITMAP_OPTIONS_NONE = D2D1_BITMAP_OPTIONS($00000000);
  // The bitmap can be specified as a target in ID2D1DeviceContext.SetTarget
  D2D1_BITMAP_OPTIONS_TARGET = D2D1_BITMAP_OPTIONS($00000001);
  // The bitmap cannot be used as an input to DrawBitmap, DrawImage, in a bitmap
  // brush or as an input to an effect.
  D2D1_BITMAP_OPTIONS_CANNOT_DRAW = D2D1_BITMAP_OPTIONS($00000002);
  // The bitmap can be read from the CPU.
  D2D1_BITMAP_OPTIONS_CPU_READ = D2D1_BITMAP_OPTIONS($00000004);
  // The bitmap works with the ID2D1GdiInteropRenderTarget.GetDC API.
  D2D1_BITMAP_OPTIONS_GDI_COMPATIBLE = D2D1_BITMAP_OPTIONS($00000008);
  // D2D1_BITMAP_OPTIONS_FORCE_DWORD = FORCEDWORD;

type
    // Describes mapped memory from the ID2D1Bitmap1.Map API.
  PD2D1_MAPPED_RECT = ^D2D1_MAPPED_RECT;

  D2D1_MAPPED_RECT = record
    pitch : UINT32;
    bits : PByte;
  end;

  ID2D1Bitmap1 = interface(ID2D1Bitmap)
    ['{a898a84c-3873-4588-b08b-ebbf978df041}']

    // Retrieves the color context information associated with the bitmap.
    procedure GetColorContext(out colorContext : IInterface); stdcall;

    // Retrieves the bitmap options used when creating the API.
    function GetOptions() : D2D1_BITMAP_OPTIONS; stdcall;

    // Retrieves the DXGI surface from the corresponding bitmap, if the bitmap was
    // created from a device derived from a D3D device.
    function GetSurface(out dxgiSurface : IDXGISurface) : HResult; stdcall;

    // Maps the given bitmap into memory. The bitmap must have been created with the
    // D2D1_BITMAP_OPTIONS_CPU_READ flag.
    function Map(options : D2D1_MAP_OPTIONS; out mappedRect : D2D1_MAPPED_RECT) : HResult; stdcall;

    // Unmaps the given bitmap from memory.
    function Unmap() : HResult; stdcall;

  end;

  IID_ID2D1Bitmap1 = ID2D1Bitmap1;

  // Extended bitmap properties.
  PD2D1_BITMAP_PROPERTIES1 = ^D2D1_BITMAP_PROPERTIES1;

  D2D1_BITMAP_PROPERTIES1 = record
    _pixelFormat : D2D1_PIXEL_FORMAT;
    dpiX : Single;
    dpiY : Single;

    // Specifies how the bitmap can be used.
    bitmapOptions : D2D1_BITMAP_OPTIONS;
    colorContext : IInterface;
  end;
{$EXTERNALSYM D2D1_BITMAP_PROPERTIES1}

  // Interface ID2D1DeviceContext
  // ============================
  // The device context represents a set of state and a command buffer that is used
  // to render to a target bitmap.
  //
{$HPPEMIT 'DECLARE_DINTERFACE_TYPE(ID2D1DeviceContext);'}
{$EXTERNALSYM ID2D1DeviceContext}

  ID2D1DeviceContext = interface(ID2D1RenderTarget)
    ['{e8f7fe7a-191c-466d-ad95-975678bda998}']

    // Creates a bitmap with extended bitmap properties, potentially from a block of
    // memory.
    function CreateBitmap(size : D2D1_SIZE_U; sourceData : Pointer; pitch : UINT32;
      bitmapProperties : PD2D1_BITMAP_PROPERTIES1;
      out bitmap : ID2D1Bitmap1) : HResult; stdcall;
  end;

function DoSaveAsBitmap(const ARenderTarget : ID2D1RenderTarget; out ResBmp : TBitmap) : Boolean;

implementation



function DoSaveAsBitmap(const ARenderTarget : ID2D1RenderTarget; out ResBmp : TBitmap) : Boolean;
var
  HR : HResult;
  DeviceContext : ID2D1DeviceContext;
  CopyBmp : ID2D1Bitmap1;
  mappedRect : D2D1_MAPPED_RECT;
  SizeU : D2D1_SIZE_U;
  destPoint : D2D1_POINT_2U;
  srcRect : D2D1_RECT_U;
  BmpProps : D2D1_BITMAP_PROPERTIES1;
  BmpInfo : TBitmapInfo;
begin
  Result := false;
  ResBmp := TBitmap.Create; // create vcl.bitmap

  if Supports(ARenderTarget, ID2D1DeviceContext, DeviceContext) then
  begin
    DeviceContext.GetPixelFormat(BmpProps._pixelFormat);
    DeviceContext.GetDpi(BmpProps.dpiX, BmpProps.dpiY);
    DeviceContext.GetPixelSize(SizeU);
    BmpProps.bitmapOptions := D2D1_BITMAP_OPTIONS_CPU_READ or D2D1_BITMAP_OPTIONS_CANNOT_DRAW;

    HR := DeviceContext.CreateBitmap(SizeU, nil, 0, @BmpProps, CopyBmp); // create CopyBmp : ID2D1Bitmap1
    if Succeeded(HR) then
    begin
      srcRect.left := 0;
      srcRect.top := 0;
      srcRect.right := SizeU.Width;
      srcRect.bottom := SizeU.Height;

      destPoint.X := 0;
      destPoint.Y := 0;
      HR := CopyBmp.CopyFromRenderTarget(destPoint, DeviceContext, srcRect); // copy pixel to CopyBmp
      if Succeeded(HR) then
      begin
        HR := CopyBmp.Map(D2D1_MAP_OPTIONS_READ, mappedRect);
        if Succeeded(HR) then
        begin
          FillChar(BmpInfo, SizeOf(BmpInfo), 0);
          SizeU.Width := mappedRect.pitch div 4;
          BmpInfo.bmiHeader.biSize := SizeOf(BmpInfo.bmiHeader);
          BmpInfo.bmiHeader.biHeight := -SizeU.Height;
          BmpInfo.bmiHeader.biWidth := SizeU.Width;
          BmpInfo.bmiHeader.biPlanes := 1;
          BmpInfo.bmiHeader.biBitCount := 32;

          ResBmp.SetSize(SizeU.Width, SizeU.Height);
          ResBmp.PixelFormat := TPixelFormat.pf32bit;

          const _DC = CreateCompatibleDC(0);
          Result := SetDIBits(_DC, ResBmp.Handle, 0, ResBmp.Height, mappedRect.bits, BmpInfo, DIB_RGB_COLORS) > 0;

          CopyBmp.Unmap;
        end;
      end;
    end;
  end;

  if not Result then
    FreeAndNil(ResBmp);
end;

end.
einen Großen Dank an TiGü, er hat das gelöst, was die VCL nicht mitgebracht hat
Jan
  Mit Zitat antworten Zitat