2012-05-01 2 views
5

Я пытаюсь получить доступ к строке сканирования растрового изображения в соответствии с article on Embarcadero. Использование линий сканирования, таких какКак правильно реализовать доступ к каналу сканирования для TBitmap?

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

Я реализовал ранее. Я заметил, что доступ к сканирующей линии занимает относительно много времени, и упомянутая выше статья предлагает решение этого. Я не могу реализовать его правильно. Мой код:

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. 

И я всегда получаю незаконный доступ, когда y = 1 и x = 0. LineLength отрицательна (ширина растрового изображения), но это можно было бы ожидать. Что я делаю не так?

EDIT: Код, указанный выше, изменен, чтобы отражать сделанные замечания до сих пор.

+2

'idx' должен быть объявлен как' NativeInt', так что ваш код может быть использован в x64, а также. 'LineLength' не должен быть отрицательным (отсюда и незаконный доступ). Я пришел к выводу, что вы запускаете этот код в режиме 64 бит. –

+0

@LURD, мои мысли точно - и каждый LongInt (...) должен быть заменен на NativeUInt (...) – kobik

+0

@LURD LineLength может быть отрицательным (и обычно отрицательным), это не проблема, вызывающая AV. – kludg

ответ

5

Чтобы не получить доступ к любому отрицательному показателю, я бы

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

Это работает! Спасибо огромное! Это действительно хороший способ избежать отрицательных чисел. Это поможет мне ускорить мои растровые изображения еще больше. – Arnold

+0

@ Арнольд - Добро пожаловать! .. Не забудьте проверить, что у вас есть растровое изображение снизу вверх. –

+1

Точно! То, что я читал в статьях о сканированных линиях, заключается в том, что строки сканирования обычно «упорядочиваются сверху вниз», следовательно, генерируют отрицательные длины строк. Следует помнить, что для корректного выполнения этого кода во всех случаях необходимо явно указывать длину положительной и отрицательной строк. Изменить: я должен ссылаться на упорядоченные растровые изображения снизу вверх и сверху вниз, чтобы избежать запутанной терминологии отрицательной или положительной длины линий. – Arnold

1

LineLength отрицательный для множества растровых изображений, потому что они часто используют метод снизу вверх для хранения строк. MSDN: BITMAPINFOHEADER. Поэтому это решение должно быть изменено для такого случая.

+0

Что бы вы предложили? – Arnold

+0

Я понимаю, что вы имеете в виду, но я считаю, что «LineLength отрицательный» немного запутан. Я бы сказал, что в восходящем растровом изображении первая строка сканирования является последней в макете памяти. –

Смежные вопросы