AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Multimedia Delphi Direct2D.Canvas in einer Bitmap speichern
Thema durchsuchen
Ansicht
Themen-Optionen

Direct2D.Canvas in einer Bitmap speichern

Ein Thema von cocsy · begonnen am 15. Mär 2023 · letzter Beitrag vom 19. Apr 2023
Antwort Antwort
Seite 1 von 3  1 23      
cocsy

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

Direct2D.Canvas in einer Bitmap speichern

  Alt 15. Mär 2023, 12:39
Hallo Leute,

ich möchte eine mittels Direct2D gezeichneten Fläche in einer Bitmap (oder anderen Graphik) speichern.

Meine Bemühungen sind bisher ins leere gelaufen und bin daher für Ideen offen.

TDirect2DCanvas.CreateBitmap // liefert zwar ein Interface "ID2D1Bitmap" ich kann damit aber nicht viel anfangen

vielen Dank für eure Hilfe
Jan
  Mit Zitat antworten Zitat
Benutzerbild von Union
Union

Registriert seit: 18. Mär 2004
Ort: Luxembourg
3.487 Beiträge
 
Delphi 7 Enterprise
 
#2

AW: Direct2D.Canvas in einer Bitmap speichern

  Alt 16. Mär 2023, 12:09
Die von Dir angegebene Methode ist auch für das Schreiben einer Bitmap in den 2d Canvas.
Ibi fas ubi proxima merces
sudo /Developer/Library/uninstall-devtools --mode=all
  Mit Zitat antworten Zitat
Benutzerbild von Olli73
Olli73

Registriert seit: 25. Apr 2008
Ort: Neunkirchen
662 Beiträge
 
#3

AW: Direct2D.Canvas in einer Bitmap speichern

  Alt 16. Mär 2023, 19:15
Das neue Bing sagt u.a. das hier:

Delphi-Quellcode:
procedure SaveDirect2DCanvasAsPNG(const FileName: string; const Canvas: TDirect2DCanvas);
var
  png: TPngImage;
begin
  png := TPngImage.CreateBlank(COLOR_RGBALPHA, 8,
    Canvas.RenderTarget.Size.Width,.
    Canvas.RenderTarget.Size.Height);
  try
    Canvas.RenderTarget.GetPixelData(PixelFormat32bppPBGRA,
      png.Scanline[0], png.Height * png.BytesPerScanline);
    png.SaveToFile(FileName);
  finally
    png.Free;
  end;
end;
  Mit Zitat antworten Zitat
cocsy

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

AW: Direct2D.Canvas in einer Bitmap speichern

  Alt 17. Mär 2023, 16:01
Das neue Bing sagt u.a. das hier:

Delphi-Quellcode:
procedure SaveDirect2DCanvasAsPNG(const FileName: string; const Canvas: TDirect2DCanvas);
var
  png: TPngImage;
begin
  png := TPngImage.CreateBlank(COLOR_RGBALPHA, 8,
    Canvas.RenderTarget.Size.Width,.
    Canvas.RenderTarget.Size.Height);
  try
    Canvas.RenderTarget.GetPixelData(PixelFormat32bppPBGRA,
      png.Scanline[0], png.Height * png.BytesPerScanline);
    png.SaveToFile(FileName);
  finally
    png.Free;
  end;
end;
das Funktioniert leider nicht

ich verwende die Vcl.Direct2D; , welche beim RenderTarget nur ein Interface zurückgibt property RenderTarget: ID2D1RenderTarget read GetRenderTarget; dadurch fehlen mir einige Funktionen wie GetPixelData
Grundsätzlich geht der Ansatz in die richtige Richtung, daher danke für die Hilfe
Jan
  Mit Zitat antworten Zitat
Benutzerbild von Olli73
Olli73

Registriert seit: 25. Apr 2008
Ort: Neunkirchen
662 Beiträge
 
#5

AW: Direct2D.Canvas in einer Bitmap speichern

  Alt 17. Mär 2023, 17:15
Auf Nachfrage hat Bing gemeint es müsste Canvas.GetPixelData heißen, aber auch der d2dcanvas scheint die Funktion nicht zu haben. Bing war aber auf Nachfrage fest der Meinung, es hat das in der Delphi unit gefunden...
  Mit Zitat antworten Zitat
cocsy

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

AW: Direct2D.Canvas in einer Bitmap speichern

  Alt 20. Mär 2023, 06:35
Auf Nachfrage hat Bing gemeint es müsste Canvas.GetPixelData heißen, aber auch der d2dcanvas scheint die Funktion nicht zu haben. Bing war aber auf Nachfrage fest der Meinung, es hat das in der Delphi unit gefunden...
korrekt, kann ich auch nicht in der Vcl.Direct2D; finden, vielleicht verwendet Bing eine zukünftige Version

mir ist leider noch nicht geholfen
Jan
  Mit Zitat antworten Zitat
Benutzerbild von Olli73
Olli73

Registriert seit: 25. Apr 2008
Ort: Neunkirchen
662 Beiträge
 
#7

AW: Direct2D.Canvas in einer Bitmap speichern

  Alt 20. Mär 2023, 06:56
Vielleicht hilft dir das hier weiter?

https://stackoverflow.com/questions/...s-to-clipboard
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.060 Beiträge
 
Delphi 10.4 Sydney
 
#8

AW: Direct2D.Canvas in einer Bitmap speichern

  Alt 24. Mär 2023, 10:41
Da der interne Übersetzungsstand in Delphi von Direct2D auf der Version 1.0 festgefroren ist, muss man sich ein bisschen behelfen, um per Direct2D 1.1 "einfach" an die rohen Bitmapdaten zu kommen.
Der Quelltext unten baut auf diesem DowWiki-Beispiel auf: https://docwiki.embarcadero.com/RADS...as_exclusively
Nach dem Zeichen in der Paint-Routine kann man per Strg + Rechtsklick das aktuelle Bitmap abspeichern. Default-Dateipfad ist 'C:\Temp\BeispielBitmapFuerDelphiPraxis.bmp'.
Die im folgenden Quelltext verwendeten Definitionen stammen vom MfPack (https://github.com/FactoryXCode/MfPa...ctX.D2d1_1.pas).

Delphi-Quellcode:
unit SaveD2DBitmap;

interface

uses
    Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, Vcl.Graphics,
    Vcl.Controls, Vcl.Forms, Vcl.Direct2D, Winapi.D2D1, Winapi.DXGI;

type
    TForm2 = class(TForm)
        procedure FormPaint(Sender: TObject);
        procedure FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
    private
        FCanvas: TDirect2DCanvas;
    protected
        procedure CreateWnd; override;

        procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
        procedure WMSize(var Message: TWMSize); message WM_SIZE;
    public
        property Canvas: TDirect2DCanvas read FCanvas;
    end;

var
    Form2: TForm2;

implementation

{$R *.dfm}
{ TForm2 }

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;

procedure DoSaveAsBitmap(const ARenderTarget: ID2D1RenderTarget; ABitmapFileName: string = '');
var
    HR: HResult;
    DeviceContext: ID2D1DeviceContext;
    CopyBitmap: ID2D1Bitmap1;
    MapOptions: D2D1_MAP_OPTIONS;
    MappedRect: D2D1_MAPPED_RECT;
    SizeU: D2D1_SIZE_U;
    destPoint: D2D1_POINT_2U;
    srcRect: D2D1_RECT_U;
    BitmapProps: D2D1_BITMAP_PROPERTIES1;
    BitmapInfo: TBitmapInfo;
    VCLBitmap: TBitmap;
    NumberOfScanLinesCopied: UINT32;
begin
    if Supports(ARenderTarget, ID2D1DeviceContext, DeviceContext) then
    begin
        DeviceContext.GetPixelFormat(BitmapProps._pixelFormat);
        DeviceContext.GetDpi(BitmapProps.dpiX, BitmapProps.dpiY);
        DeviceContext.GetPixelSize(SizeU);
        BitmapProps.bitmapOptions := D2D1_BITMAP_OPTIONS_CPU_READ or D2D1_BITMAP_OPTIONS_CANNOT_DRAW;

        HR := DeviceContext.CreateBitmap(SizeU, nil, 0, @BitmapProps, CopyBitmap);
        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 := CopyBitmap.CopyFromRenderTarget(destPoint, DeviceContext, srcRect);
            if Succeeded(HR) then
            begin
                MapOptions := D2D1_MAP_OPTIONS_READ;
                HR := CopyBitmap.Map(MapOptions, MappedRect);
                if Succeeded(HR) then
                begin
                    FillChar(BitmapInfo, SizeOf(BitmapInfo), 0);

                    SizeU.Width := MappedRect.pitch div 4;

                    BitmapInfo.bmiHeader.biSize := SizeOf(BitmapInfo.bmiHeader);
                    BitmapInfo.bmiHeader.biHeight := -SizeU.Height;
                    BitmapInfo.bmiHeader.biWidth := SizeU.Width;
                    BitmapInfo.bmiHeader.biPlanes := 1;
                    BitmapInfo.bmiHeader.biBitCount := 32;

                    VCLBitmap := TBitmap.Create(SizeU.Width, SizeU.Height);
                    try
                        VCLBitmap.PixelFormat := TPixelFormat.pf32bit;
                        NumberOfScanLinesCopied := SetDIBits(VCLBitmap.Canvas.Handle, VCLBitmap.Handle, 0, VCLBitmap.Height, MappedRect.bits,
                          BitmapInfo, DIB_RGB_COLORS);

                        if NumberOfScanLinesCopied > 0 then
                        begin
                            if ABitmapFileName = 'then
                            begin
                                ABitmapFilename := IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0))) + 'Test.bmp';
                            end;
                            VCLBitmap.SaveToFile(ABitmapFilename);
                        end
                        else
                            RaiseLastOSError;
                    finally
                        VCLBitmap.Free;
                    end;
                    CopyBitmap.Unmap;
                end;
            end;
        end;
    end;
end;

procedure TForm2.CreateWnd;
begin
    inherited;
    FCanvas := TDirect2DCanvas.Create(Handle);
end;

procedure TForm2.FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
    if (ssCtrl in Shift) and (Button = TMouseButton.mbRight) then
    begin
        DoSaveAsBitmap(FCanvas.RenderTarget, 'C:\Temp\BeispielBitmapFuerDelphiPraxis.bmp');
    end;
end;

procedure TForm2.FormPaint(Sender: TObject);
var
    LRect: TRect;
begin
    LRect := Self.ClientRect;
    { Drawing goes here }
    Canvas.Brush.Color := clRed;
    Canvas.Pen.Color := clBlue;
    Canvas.Rectangle(10, 10, LRect.Width div 2, LRect.Height div 2);

    Canvas.Pen.Color := clYellow;
    Canvas.DrawLine(D2D1PointF(0, 0), D2D1PointF(LRect.Width, LRect.Height));
end;

procedure TForm2.WMPaint(var Message: TWMPaint);
var
    PaintStruct: TPaintStruct;
begin
    BeginPaint(Handle, PaintStruct);
    try
        FCanvas.BeginDraw;
        try
            Paint;
        finally
            FCanvas.EndDraw;
        end;
    finally
        EndPaint(Handle, PaintStruct);
    end;
end;

procedure TForm2.WMSize(var Message: TWMSize);
var
    ClientSize: TD2D1SizeU;
begin
    if Assigned(FCanvas) then
    begin
        ClientSize := D2D1SizeU(ClientWidth, ClientHeight);
        ID2D1HwndRenderTarget(FCanvas.RenderTarget).Resize(ClientSize);
    end;

    inherited;
end;

end.
  Mit Zitat antworten Zitat
cocsy

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

AW: Direct2D.Canvas in einer Bitmap speichern

  Alt 29. Mär 2023, 15:43
der Ansatz von TiGü ist richtig gut,
leider liefert NumberOfScanLinesCopied := SetDIBits(VCLBitmap.Canvas.Handle, VCLBitmap.Handle, 0, VCLBitmap.Height, MappedRect.bits; BitmapInfo, DIB_RGB_COLORS); 0 zurück...
Jan
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.060 Beiträge
 
Delphi 10.4 Sydney
 
#10

AW: Direct2D.Canvas in einer Bitmap speichern

  Alt 30. Mär 2023, 09:15
Ja nun, dann muss ja irgendwas im Argen sein.
Was ist denn die Exception, die im Else-Zweig bei RaiseLastOSError geworfen wird?
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 3  1 23      

 

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 21:44 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz