Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Wie schwarz-weiß Canvas effizient befüllen? (https://www.delphipraxis.net/216438-wie-schwarz-weiss-canvas-effizient-befuellen.html)

iphi 29. Dez 2024 09:31

Delphi-Version: 7

Wie schwarz-weiß Canvas effizient befüllen?
 
Hallo,

ich habe schwarzweiß Pixeldaten in einem Array of Byte, immer 8 Pixel pro Byte.
Momentan fülle ich meinen Canvas mit
Delphi-Quellcode:
Canvas.Pixels[i,j]:=PixelColor;
was sehr langsam ist. Gibt es eine Möglichkeit, die 8 Pixels in einem Byte auf einmal zu setzen oder gar eine ganze Zeile?

Tom

dummzeuch 29. Dez 2024 10:00

AW: Wie schwarz-weiß Canvas effizient befüllen?
 
Du meinst Graustufen, nicht schwarz-weiß, oder?

Schneller als Pixel[] ist der Zugriff über Scanline, und das um Größenordnungen.
Und selbst das kann man noch verbessern, indem man die Zahl der Scanline-Aufrufe reduziert, denn auch die sind relativ aufwändig.

Ich habe darüber mal vor Urzeiten geblogt:

https://blog.dummzeuch.de/2019/12/12...lls-in-delphi/

Wobei es im Blog Post allerdings um 24 Bit Farbbitmaps geht, nicht um 8 Bit Graustufen.

iphi 29. Dez 2024 10:15

AW: Wie schwarz-weiß Canvas effizient befüllen?
 
Zitat:

Du meinst Graustufen, nicht schwarz-weiß, oder?
Nein, ich meine tatsächlich schwarzweiß, nur zwei Farben, 1 Bit pro Pixel, 1 Byte = 8 Pixels.
Hilft da ScanLine? Die Funktion war mir bislang nicht geläufig.

dummzeuch 29. Dez 2024 10:51

AW: Wie schwarz-weiß Canvas effizient befüllen?
 
Zitat:

Zitat von iphi (Beitrag 1544628)
Zitat:

Du meinst Graustufen, nicht schwarz-weiß, oder?
Nein, ich meine tatsächlich schwarzweiß, nur zwei Farben, 1 Bit pro Pixel, 1 Byte = 8 Pixels.
Hilft da ScanLine? Die Funktion war mir bislang nicht geläufig.

Hm, ja, auch dann müsste es mit Scanline funktionieren. Dann setzt man je Byte gleich 8 Pixel auf einmal. Das habe ich allerdings noch nie ausprobiert.

iphi 29. Dez 2024 11:03

AW: Wie schwarz-weiß Canvas effizient befüllen?
 
Hab gerade Dein Tutorial gelesen, ist prima! :-)
Ich glaube, jetzt hab ich verstanden wie das mit ScanLine geht.
Per ScanLine bekomme ich die Startadresse der Pixeldaten.
Dann muss ich nur noch meine Daten rein kopieren.
Probiere ich gleich mal aus.

Danke für den Tipp!

Olli73 29. Dez 2024 11:21

AW: Wie schwarz-weiß Canvas effizient befüllen?
 
Nachdem ich Copilot etwas in die Richtung CreateDIBSection und CopyMemory geschubst habe, kam das hier raus:

Delphi-Quellcode:
uses
  Windows, Graphics, SysUtils;

type
  TByteArray = array of Byte;

procedure CreateMonochromeBitmapWithCopyMemory(const ByteArray: TByteArray; Width, Height: Integer);
var
  Bitmap: HBITMAP;
  DC: HDC;
  Bits: Pointer;
  BitmapInfo: TBitmapInfo;
  RowBytes: Integer;
begin
  // Bitmap-Info initialisieren
  ZeroMemory(@BitmapInfo, SizeOf(BitmapInfo));
  with BitmapInfo.bmiHeader do
  begin
    biSize := SizeOf(TBitmapInfoHeader);
    biWidth := Width;
    biHeight := -Height; // Top-Down
    biPlanes := 1;
    biBitCount := 1; // 1-Bit Farbtiefe (monochrom)
    biCompression := BI_RGB;
  end;

  // Device Context erstellen
  DC := GetDC(0);
  try
    // DIB-Section erstellen
    Bitmap := CreateDIBSection(DC, BitmapInfo, DIB_RGB_COLORS, Bits, 0, 0);
    if Bitmap = 0 then
      raise Exception.Create('CreateDIBSection fehlgeschlagen');

    // Breite der Bitmap-Zeile in Bytes (jedes Bit repräsentiert einen Pixel)
    RowBytes := ((Width + 31) div 32) * 4;

    // Pixelarray kopieren
    CopyMemory(Bits, @ByteArray[0], Min(Length(ByteArray), RowBytes * Height));

    // Das Bitmap weiterverarbeiten (z.B. in eine TBitmap laden)
    with TBitmap.Create do
    try
      Handle := Bitmap;
      SaveToFile('MonochromeBitmapWithCopyMemory.bmp'); // Speichern des Bitmaps als Datei
    finally
      Free;
    end;

  finally
    ReleaseDC(0, DC);
  end;
end;
Das Format des Arrays muss natürlich passen.

iphi 29. Dez 2024 15:55

AW: Wie schwarz-weiß Canvas effizient befüllen?
 
Bei mir geht es jetzt so:
Delphi-Quellcode:
procedure TForm1.DrawLinesFast(l: TLines);
var
  bm: TBitmap;
  i: Integer;
  w,h: integer;
  p: pointer;
begin
  h:=length(l);
  if h=0 then exit;
  w:=length(l[0].b);
  if w=0 then exit;
  bm := TBitmap.Create;
  Try
    bm.PixelFormat := pf1bit;
    bm.Width:=w*8;
    bm.Height:=h;
    bm.Canvas.Refresh;
    for i:=0 to h-1 do
      begin
        p:=bm.ScanLine[i];
        move(l[i].b[0],p^,w);
      end;
    Im.Picture.Assign(bm);
  Finally
    bm.Free;
  End;
end;
Eine Sache wundert mich: Die Zeilen sind im Speicher umgekehrt angeordnet, d.h. die unterste Zeile mit der höchsten Zeilennummer steht an der niedrigsten Speicheradresse.

dummzeuch 29. Dez 2024 16:54

AW: Wie schwarz-weiß Canvas effizient befüllen?
 
Das ist bei TBitmap normal. Ich meine mich dunkel zu erinnern, dass man das auch ändern kann, aber ich finde es nicht mehr.

Redeemer 29. Dez 2024 17:17

AW: Wie schwarz-weiß Canvas effizient befüllen?
 
Negative Höhe. Geht dich aber auch nichts an.


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:40 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz