2012-05-01 5 views
5

Sto tentando di accedere alla scanline di una bitmap in base a article on Embarcadero. Utilizzo di scanlines comeCome implementare correttamente l'accesso scanline di TBitmap?

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

Ho implementato prima. Ho notato che l'accesso a una scanline richiede relativamente tempo e l'articolo menzionato sopra offre una soluzione a questo. Non sono in grado di implementarlo correttamente. Il mio codice è:

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. 

E ottengo sempre un accesso illegale quando y = 1 e x = 0. LineLength è negativo (la larghezza della bitmap), ma ciò potrebbe essere previsto. Che cosa sto facendo di sbagliato?

MODIFICA: Il codice sopra riportato è stato modificato per riflettere le osservazioni elaborate fino a quel momento.

+2

'idx' dovrebbero essere dichiarati come' NativeInt', così il vostro codice potrebbe essere utilizzato in 64 pure. 'LineLength' non deve essere negativo (quindi l'accesso illegale). La mia conclusione è che si sta eseguendo questo codice in modalità 64 bit. –

+0

@LURD, I miei pensieri esattamente - e ogni LongInt (...) dovrebbe essere sostituito con NativeUInt (...) – kobik

+0

@LURD LineLength può essere negativo (e di solito è negativo), che non è un problema che causa AV. – kludg

risposta

5

di non di accedere a qualsiasi indice negativo, vorrei fare

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

Funziona! Grazie mille! Questo è davvero un buon modo per evitare i numeri negativi. Questo mi aiuterà a velocizzare ancora di più i miei bitmap. – Arnold

+0

@Arnold - Prego! .. Non dimenticare di verificare di avere una bitmap bottom-up. –

+1

Esattamente! Quello che ho letto negli articoli sulle linee di scansione è che le linee di scansione sono ordinate di solito dall'alto verso il basso, generando quindi le lunghezze delle linee negative. Si dovrebbe essere consapevoli del fatto che per fare in modo che questo codice funzioni correttamente in tutti i casi è necessario codificare esplicitamente le lunghezze delle linee positive e negative. Modifica: dovrei fare riferimento alle bitmap ordinate dal basso verso l'alto e dall'alto in modo da evitare la terminologia confusa delle lunghezze di riga negative o positive. – Arnold

1

LineLength è negativo per un sacco di bitmap, poiché utilizzano frequentemente il metodo dal basso verso l'alto per memorizzare le righe. MSDN: BITMAPINFOHEADER. Quindi questa soluzione dovrebbe essere modificata per questo caso.

+0

Cosa suggeriresti? – Arnold

+0

Capisco cosa intendi, ma trovo che "LineLength è negativo" un po 'confuso. Direi che in una bitmap bottom-up la prima scanline è l'ultima nel layout di memoria. –