2012-05-01 9 views
5

Ich versuche, auf die Scanlinie einer Bitmap gemäß einer article on Embarcadero zuzugreifen. Mit Scanlinien wieWie kann der Scanline-Zugriff von TBitmap korrekt implementiert werden?

for y := 0 to n do 
begin 
    line := bitmap.scanline [y]; 
    for x := 0 to n do line [x] := value; 

habe ich zuvor implementiert. Ich bemerkte, dass der Zugriff auf eine Scanline relativ viel Zeit in Anspruch nimmt und der oben genannte Artikel bietet eine Lösung dafür. Ich kann es nicht richtig implementieren. Mein Code ist:

unit SCTester; 

interface 

uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
    ExtCtrls; 

type 
    TRGBQuad = packed record 
     b: uInt8; 
     g: uInt8; 
     r: uInt8; 
     alpha: uInt8; 
    end; // Record: TQuad // 

// Override the definitions in Graphics.pas 
    TRGBQuadArray = packed array [0..MaxInt div SizeOf (TRGBQuad) - 1] of TRGBQuad; 
    PRGBQuadArray = ^TRGBQuadArray; 

    TForm1 = class(TForm) 
    Image: TImage; 
    procedure ImageDblClick(Sender: TObject); 
    end; 

var Form1: TForm1; 

implementation 

{$R *.dfm} 

procedure TForm1.ImageDblClick(Sender: TObject); 
var Bitmap: TBitmap; 
    q: TRGBQuad; 
    x, y: NativeInt; 
    FirstLine: PRGBQuadArray; 
    idx: NativeInt; 
    LineLength: NativeInt; 
begin 
    q.r := 0; q.g := 0; 
    Bitmap := TBitmap.Create; 
    Bitmap.Height := Image.Height; 
    Bitmap.Width := Image.Width; 
    Bitmap.PixelFormat := pf32Bit; 
    FirstLine := Bitmap.ScanLine [0]; 
    LineLength := (NativeInt (Bitmap.Scanline [1]) - NativeInt (FirstLine)) div SizeOf (TRGBQuad); 
    try 
     for y := Bitmap.Height - 1 downto 0 do 
     begin 
     for x := 0 to Bitmap.Width - 1 do 
     begin 
      q.b := (x xor y) mod 255; 
      idx := y * LineLength + x; 
      FirstLine [idx] := q; 
     end; // for 
     end; // for 
     Image.Picture.Assign (Bitmap); 
    finally 
     Bitmap.Free; 
    end; // try..finally 
end; 

end. 

Und ich bekomme immer einen illegalen Zugang, wenn y = 1 und x = 0. LineLength ist negativ (die Breite der Bitmap), aber das könnte erwartet werden. Was mache ich falsch?

BEARBEITEN Sie: Der obige Code wird geändert, um die bis jetzt bearbeiteten Anmerkungen wiederzugeben.

+2

'tun idx' als' NativeInt' erklärt werden sollte, so könnte Ihr Code als auch in x64 verwendet werden. 'LineLength' darf nicht negativ sein (daher der illegale Zugriff). Meine Schlussfolgerung ist, dass Sie diesen Code im 64-Bit-Modus ausführen. –

+0

@LURD, Meine Gedanken genau - und jede LongInt (...) sollte durch NativeUInt ersetzt werden (...) – kobik

+0

@LURD LineLength kann negativ sein (und ist normalerweise negativ), das ist kein Problem, das AV verursacht. – kludg

Antwort

5

Um keinen negativen Index zuzugreifen, würde ich

procedure TForm1.Button1Click(Sender: TObject); 
var Bitmap: TBitmap; 
    q: TRGBQuad; 
    x, y: LongInt; 
    line{, FirstLine}: PRGBQuadArray; 
    idx: NativeInt; 
    LastLine: PRGBQuadArray; 
    LineLength: NativeInt; 
begin 
    q.r := 0; q.g := 0; 
    Bitmap := TBitmap.Create; 
    Bitmap.Height := Image.Height; 
    Bitmap.Width := Image.Width; 
    Bitmap.PixelFormat := pf32Bit; 

    LastLine := Bitmap.ScanLine[Bitmap.Height - 1]; 
    LineLength := (NativeInt(Bitmap.Scanline[Bitmap.Height - 2]) - NativeInt(Lastline)) div SizeOf(TRGBQuad); 
    try 
     for y := 0 to Bitmap.Height - 1 do 
     begin 
     for x := 0 to Bitmap.Width - 1 do 
     begin 
      q.b := (x xor y) mod 255; 
      idx := y * LineLength + x; 
      LastLine [idx] := q; 
     end; // for 
     end; // for 
     Image.Picture.Assign (Bitmap); 
    finally 
     Bitmap.Free; 
    end; // try..finally 
end; 
+0

Es funktioniert! Ich danke dir sehr! Dies ist in der Tat eine gute Möglichkeit, die negativen Zahlen zu vermeiden. Dies wird mir helfen, meine Bitmaps noch schneller zu machen. – Arnold

+0

@Arnold - Gern geschehen! .. Vergessen Sie nicht zu überprüfen, ob Sie eine Bitmap von unten nach oben haben. –

+1

Genau! Was ich in den Artikeln über Scanlinien gelesen habe, ist, dass Scanlinien "normalerweise" von oben nach unten geordnet sind und somit die negativen Zeilenlängen erzeugen. Man sollte sich bewusst sein, dass man, um diesen Code in allen Fällen korrekt laufen zu lassen, explizit die positive und negative Zeilenlänge codieren muss. Edit: Ich sollte auf Bottom-Up- und Top-Down-Bitmaps verweisen, um die verwirrende Terminologie negativer oder positiver Zeilenlängen zu vermeiden. – Arnold

1

LineLength ist negativ für viele Bitmaps, da sie häufig die Bottom-up-Methode zum Speichern von Zeilen verwenden. MSDN: BITMAPINFOHEADER. Also sollte diese Lösung für diesen Fall modifiziert werden.

+0

Was würden Sie vorschlagen? – Arnold

+0

Ich verstehe, was Sie meinen, aber ich finde 'LineLength ist negativ' ein bisschen verwirrend. Ich würde sagen, in einer Bottom-Up-Bitmap ist die erste Scanzeile die letzte im Speicherlayout. –

Verwandte Themen