Einzelnen Beitrag anzeigen

Amateurprofi

Registriert seit: 17. Nov 2005
Ort: Hamburg
1.041 Beiträge
 
Delphi XE2 Professional
 
#6

AW: 24-Bit Bitmap um 90 grad drehen - Resourcen-Optimierung

  Alt 18. Okt 2020, 16:18
Das Thema hatten wir hier zwar schon öfter, aber nicht unter dem Gesichtspunkt, den ich hier ansprechen möchte:

Ich nutze zum drehen von 24 bzw. 32 Bitmaps bislang immer die folgende Routine (aus dem Doberenz-Buch):

Delphi-Quellcode:
procedure Drehe90Rechts (bm: TBitmap);
type
  TMyHelp = array [0..0] of TRGBQuad;
var
  P, Pend : PRGBQuad; x, y, b, h: Integer; RowOut: ^TMyHelp; help: TBitmap;
begin
  Bm.pixelformat := pf32bit;

  help := TBitmap.create;
  help.pixelformat := pf32bit;

  b := bm.height;
  h := bm.width;

  help.SetSize (b, h);
  PEnd := Bm.scanline[bm.height-1];

  for y := 0 to h-1 do begin

    rowout := help.scanline [y];
    p := PEnd;
    inc (p, y);

    for x := 0 to (b-1) do begin
      rowout [x] := p^;
      inc (p, h);
    end;

  end;

  bm.Assign (help);
  help.free;
end;
Ich dachte, OK die nehmen auch für eine 24-Bit-Bitmap eine 32-Bitmap, weil der Compiler die 32-Bits in einem Register direkt kopieren kann. Wenn man sich das in der CPU ansieht, dann stimmt das wohl auch, bei 24 muss er wohl erst 16-Bit und dann noch mal 8 kopieren, dadurch 2 Befehle mehr (siehe anliegenden Screenshot).

Nur: Bei sehr großen Bilder (teste gerade eins im Format 21600 x 10800) braucht er, aber um die 32-Bit-Hilfsbit anzulegen, statt 660 MB bei einer 24 Bit, bei der 32-Bit Bitmap ca. 1 GB zusätzlichen Arbeitsspeicher.

Daher meine Überlegung, statt die Routine mit 32-Bit zu verwenden, bei einer 24-Bit es mit einer 24-Bit routine zu machen.

Delphi-Quellcode:
procedure Drehe90Rechts24 (bm: TBitmap);
type
  TMyHelp = array [0..0] of TRGBTriple;
var
  P, Pend : PRGBTriple; x, y, b, h: Integer; RowOut: ^TMyHelp; help: TBitmap;
begin
  help := TBitmap.create;
  help.pixelformat := pf24bit;

  b := bm.height;
  h := bm.width;

  help.SetSize (b, h);
  PEnd := Bm.scanline[bm.height-1];

  for y := 0 to h-1 do begin

    rowout := help.scanline [y];
    p := PEnd;
    inc (p, y);

    for x := 0 to b-1 do begin
      rowout [x] := p^;
      inc (p, h);
    end;

  end;

  bm.Assign (help);
  help.free;
end;

Leider funktioniert die nicht. Komme leider nicht dahinter warum (es fehlen 1-2 Pixel) und bei Bildgrößen mit ungeraden werten geht es nach dem 2. Drehen ganz schief.

Hat einer eine Idee, wie man es richtig machen könnte?
Zu Drehe90Rechts24 (bm: TBitmap);


Vor der ersten Schleife wird PEnd auf das erste Pixel der letzten Zeile in BM gestellt
In der Y Schleife wird
1) P = PEnd gesetzt, also auf Pixel[0,letzte Zeile]
2) P um Y erhöht, also auf Pixel[Y,letzte Zeile gestellt]
In der X Schleife wird
1) Pixel P^ nach Help kopiert
2) P um H Pixel erhöht.
Das soll P auf die jeweils nächste Zeile in BM stellen.
Das funktioniert bei 32 Bit-Bitmaps, aber nicht bei 24 Bit, weil hier
der Offset zur nächsten Zeile (in Bytes) nicht Breite*3 ist, sondern immer ein
vielfaches von 4 ist. (Breite*3+3) div 4*4 sollte die Anzahl Bytes je Zeile ergeben.
Workaround:
var Offs:NativeInt;
1) Vor der Y Schleife
PEnd := Bm.scanline[bm.height-1];
Offs := NativeInt(Bm.scanline[bm.height-2])-NativeInt(PEnd);
2) In der X Schleife
Inc (NativeInt(p), Offs); // statt inc (p, h);
Gruß, Klaus
Die Titanic wurde von Profis gebaut,
die Arche Noah von einem Amateur.
... Und dieser Beitrag vom Amateurprofi....
  Mit Zitat antworten Zitat