Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   [FMX] Array of Byte (ARGB) schnell in ein TBitmap umwandeln? (https://www.delphipraxis.net/194159-%5Bfmx%5D-array-byte-argb-schnell-ein-tbitmap-umwandeln.html)

JayZ 23. Okt 2017 23:13

[FMX] Array of Byte (ARGB) schnell in ein TBitmap umwandeln?
 
hi liebe community

ich würde gerne wissen ob es möglich ist ein array of byte in ein bitmap umzuwandeln.

das array ist ein dimensional und so aufgebaut dass pro pixel vier mal ein byte elemente gesetzt werden müssen.

man stelle sich vor, dass das bitmap welches ich schlussendlich haben will eine grösse von 3x2 hat, also 3 breit und 2 hoch und mein array sieht folgendermassen aus:
Delphi-Quellcode:
var
  LPixelArray : array of byte;
begin
  LPixelArray = [
   { A , R , G , B }
    255, 0 , 0 , 0, // Element für pixel 1,1
    255, 0 , 0 , 0, // Element für pixel 2,1
    255, 0 , 0 , 0, // Element für pixel 3,1
    255, 0 , 0 , 0, // Element für pixel 1,2
    255, 0 , 0 , 0, // Element für pixel 2,2
    255, 0 , 0 , 0  // Element für pixel 3,2
  ]
end;
Zzr vereinfachung sind hier alle alpha werte 255 und die r g und b werte auf 0 dargestellt. Nun würde ich gerne dieses array so schnell wie es geht in ein TBitmap umwandeln, wenn möglich ohne den weg über Delphi-Referenz durchsuchenTBitmap.Map zu gehen.

ich habe bereits versucht ein TMemoryStream zu erstellen den ich dann mit Delphi-Referenz durchsuchenTMemoryStream.WriteData mit dem array gefüllt habe und anschliessend versucht das stream mit TBitmap.LoadFromStream zu laden was leider gescheitert ist. Der exakte code ist hier: (versuch mit einer grösse von 3 x 1)

Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
  LBitmap : TBitmap;
  LPixelArray : array of byte;
  LStream : TMemoryStream;
begin
  LPixelArray := [
    255,0,0,0,
    255,255,0,0,
    255,0,0,255
  ];

  LStream := TMemoryStream.Create;
  try
    LStream.WriteData(LPixelArray[0], Length(LPixelArray));
    LBitmap := TBitmap.Create(3, 1);
    try
      LBitmap.LoadFromStream(LStream);
      Image1.Bitmap.Assign(LBitmap);
    finally
      LBitmap.Free;
    end;
  finally
    LStream.Free;
  end;
end;
Und bevor ich was sau doofes mache...................
wäre das überhaupt eine möglichkeit die performanter ist als die pixel später über TBitmap.Map zu verändern?

vielen dank für ihre zeit :)

liebe grüsse

Namenloser 23. Okt 2017 23:33

AW: [FMX] Array of Byte (ARGB) schnell in ein TBitmap umwandeln?
 
Es wird sich wohl nicht vermeiden lassen, die Daten zu kopieren. Ich denke, das schnellste wäre, einfach das Bitmap mit der entsprechenden Größe und dem entsprechenden Pixelformat zu erzeugen, und dann mittels Scanline die Daten aus dem Array Zeile für Zeile rüberzukopieren.

Dein Ansatz mit dem MemoryStream kann so nicht funktionieren, weil der Bitmap-Header fehlt. Aber auch wenn du den Bitmap-Header hinzufügen würdest, wäre es eher kontraproduktiv, da so erst die Daten vom Array in den MemoryStream kopiert werden müssten und anschließend noch mal vom MemoryStream in das Bitmap. Also eine Kopie umsonst.

Delphi-Quellcode:
procedure PixelArrayToBitmap(const PixelArray: array of Byte; const Width: Integer; const Height: Integer; Bitmap: TBitmap)
var
  y: integer;
begin
  Bitmap.PixelFormat := pf32bit;
  Bitmap.SetSize(Width, Height);

  for y := 0 to Height - 1 do
    Move(PixelArray[Width*y], Bitmap.Scanline[y]^, 4*Width);
end;
Versuch es mal damit. Das sind aber gerade die ersten Zeilen Delphi, die ich seit Ewigkeiten schreibe, deshalb ohne Gewähr.

JayZ 24. Okt 2017 00:06

AW: [FMX] Array of Byte (ARGB) schnell in ein TBitmap umwandeln?
 
Hallo Namenloser! :)

erstmal vielen vielen dank für die schnelle antwort und ich kann dich beruhigen, dein delphi scheinst du immer noch einwandfrei zu beherrschen! :) naja, jedenfalls fast wenn man das vergessene semikolon ganz am schluss der ersten zeile ausschliesst. :D

Der code scheint echt sehr schnell zu sein, genau das was ich gesucht habe jedoch ist diese lösung leider primär wohl für VCL und nicht FMX da das TBitmap von FMX kein ScanLine besitzt/unterstützt. Ich habe die funktion trotzdem mal ein wenig umgeschrieben, dass sie intern ein vcl bitmap benutzt aber doch ein fmx bitmap zurück gibt, halt wieder durch das speichern und laden des streams. ausserdem schien der alpha channel nicht zu funktionieren und habe ihn das PixelFormat auf pf24bit geändert, Alpha brauche ich nicht unbedingt. :)

Hier die umgebaute funktion:
Delphi-Quellcode:
procedure PixelArrayToBitmap(const PixelArray: array of Byte; const Width: Integer; const Height: Integer; Bitmap: TBitmap);
var
  y: integer;
  LBitmap : VCL.Graphics.TBitmap;
  LMemStream : TMemoryStream;
begin
  LBitmap := VCL.Graphics.TBitmap.Create;
  try
    LBitmap.PixelFormat := pf24bit;
    LBitmap.SetSize(Width, Height);

    for y := 0 to Height - 1 do
      Move(PixelArray[Width*y], LBitmap.Scanline[y]^, 3*Width);
    try
      LMemStream := TMemoryStream.Create;
      LBitmap.SaveToStream(LMemStream);
      Bitmap.LoadFromStream(LMemStream);
    finally
      LMemStream.Free;
    end;
  finally
    LBitmap.Free;
  end;
end;
Diese erzeugt mir mein FullHD Bitmap innerhalb von kürzester Zeit, danke dafür! :thumb:

Ich werde nun ein paar tests durchführen und mal sehen ob die FMX variante von setpixel brauchbar ist im gegensatz zu der sehr langsamen VCL methode, was ich aber bezweifle >_<

Sollte sich noch eine Lösung finden die man direkt unter FMX benutzen könnte um den performance verlust des umwandeln von einem vcl in ein fmx bitmap zu umgehen wäre ich natürlich auch sehr sehr froh darüber. :)

Freundliche Grüsse

Rollo62 24. Okt 2017 06:20

AW: [FMX] Array of Byte (ARGB) schnell in ein TBitmap umwandeln?
 
Der offizielle Weg wäre über MapAccess.
http://docwiki.embarcadero.com/CodeE...Pixel_(Delphi)
http://docwiki.embarcadero.com/Libra...cs.TBitmap.Map

Das wird bei FMX auch nötig sein um die Unterschiede auf verschiedenen Plattformen abzufangen.
Tricks mit direktem Copy könnten möglich sein, da wäre ich aber sehr vorsichtig, und würde auf jeden Fall
zumindest alle Richtungen Testen (Threadverhalten).

Das MapAccess funktioniert eigentlich ganz gut und schnell, zumindest für mich.

Rollo


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:47 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