Советы по Delphi

         

Bitmap.Scanline для PixelFormat=pf1bit, pf8bit, pf24bit


(Техника программирования в Delphi 3)

Кто-то из Италии попросил меня пример использования pf1bit в изображениях (Bitmaps), я послал часто ответа из имеющихся заготовок, подумал, и добавил здесь другие детали для pf8bit и pf24bit.

Общее

Новое в Delphi 3 свойство scanline допускает быстрый доступ к отдельным пикселям, но необходимо указать с каким Bitmap.PixelFormat вы работаете, прежде чем сможете иметь доступ к пикселям.

Возможные PixelFormats включают:

  1. pfDevice
  2. pf1bit
  3. pf4bit
  4. pf8bit
  5. pf15bit
  6. pf16bit
  7. pf24bit
  8. pf32bit
pf24bit-изображения

Для pf24bit-изображений необходимо определить:

    CONST PixelCountMax = 32768;
TYPE

pRGBArray = ^TRGBArray; TRGBArray = ARRAY[0..PixelCountMax-1] OF TRGBTriple;

Примечание: TRGBTriple определен в модуле Windows.PAS.

Для того, чтобы к существующему 24-битному изображению иметь доступ как к изображению, созданному с разрешением 3 байта на пиксел, сделайте следующее:

    ... VAR i           :  INTEGER; j           :  INTEGER; RowOriginal :  pRGBArray; RowProcessed:  pRGBArray; BEGIN IF   OriginalBitmap.PixelFormat <> pf24bit THEN RAISE EImageProcessingError.Create('GetImageSpace:  ' + 'Изображение должно быть 24-х битным.');
{Шаг через каждую строчку изображения.} FOR j := OriginalBitmap.Height-1 DOWNTO 0 DO BEGIN RowOriginal  := pRGBArray(OriginalBitmap.Scanline[j]); RowProcessed := pRGBArray(ProcessedBitmap.Scanline[j]);
FOR i := OriginalBitmap.Width-1 DOWNTO 0 DO BEGIN
//       Доступ к RGB-цветам отдельных пикселей должен осуществляться следующим образом: //           RowProcessed[i].rgbtRed     := RowOriginal[i].rgbtRed;
//           RowProcessed[i].rgbtGreen   := RowOriginal[i].rgbtGreen;
//           RowProcessed[i].rgbtBlue    := RowOriginal[i].rgbtBlue;

END
END ...

pf8bit-изображения

Доступ к такому формату изображения легко получить, используя TByteArray (определен в SysUtils.PAS):

    PByteArray = ^TByteArray; TByteArray = array[0..32767] of Byte;

(Я думаю (но сам этого не пробовал), что вы сможете получить доступ к pf16bit-изображениям, используя следующие определения в SysUtils.PAS:

    PWordArray = ^TWordArray; TWordArray = array[0..16383] of Word;

)

Для того, чтобы обработать 8-битное (pf8bit) изображение, используйте конструктор подобный этому, который создает гистограмму изображения:

    TYPE THistogram  = ARRAY[0..255] OF INTEGER; ...
VAR
Histogram:  THistogram; i      :  INTEGER; j      :  INTEGER; Row    :  pByteArray;
... FOR i := Low(THistogram) TO High(THistogram) DO Histogram[i] := 0;
IF  Bitmap.PixelFormat = pf8bit THEN BEGIN
FOR
j := Bitmap.Height-1 DOWNTO 0 DO BEGIN Row  := pByteArray(Bitmap.Scanline[j]); FOR i := Bitmap.Width-1 DOWNTO 0 DO BEGIN INC (Histogram[Row[i]]) END END
END ...

pf1bit-изображения

Доступ к pf8bit-изображениям осуществляется достаточно легко, с тех пор, как они стали использовать один байт на пиксель. Но вы можете сохранить много памяти, если вам необходим единственный бит на пиксель (как, например, с различными масками) в случае pf1bit-изображения.

Как и в случае с pf8bit-изображениями, используйте TByteArray для доступа к pf1bit-ным линиям чередования (Scanlines). Но для доступа к отдельным пикселям вам понадобиться работать с битами отдельного байта. Так, ширина линии чередования равна Bitmap.Width DIV 8 байт.

Нижеприведенный код показывает как можно создать шаблон 1-битного изображения: черный, белый, полоски, "g", "стрелка" и случайный -- опция "инвертировано" также доступна. (Надеюсь, технологию вы освоете без труда.)

Создайте форму с Image1: для TImage я использую одно изображение Image1 размером 256x256 и свойством Stretch := TRUE, чтобы отдельные пиксели было легко разглядеть. Кнопки Black, White и Stripes имеют свойство tags, c соответствующими значениями 0, 255, и 85 ($55 = 01010101 в двоичной системе исчисления), вызывающие при нажатии обработчик события ButtonStripesClick.

Кнопки "g" и "arrow" имеют собственные обработчики событий, позволяющие корректно распечатать тестовые изображения на принтере HP Laserjet.

"Random" случайным образом устанавливает биты в 1-битном изображении.

"Invert" меняет нули на единички и наоборот.

    // Пример того, как использовать Bitmap.Scanline для PixelFormat=pf1Bit.
// По просьбе Mino Ballone из Италии.
//
// Авторское право (C) 1997, Earl F. Glynn, Overland Park, KS. Все права
защищены.
// Может свободно использоваться для некоммерческих целей.

unit ScreenSingleBit;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm) Image1: TImage; ButtonBlack: TButton; ButtonWhite: TButton; ButtonStripes: TButton; ButtonG: TButton; ButtonArrow: TButton; ButtonRandom: TButton; ButtonInvert: TButton; procedure ButtonStripesClick(Sender: TObject); procedure ButtonGClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure ButtonRandomClick(Sender: TObject); procedure ButtonInvertClick(Sender: TObject); procedure ButtonArrowClick(Sender: TObject); private Bitmap:  TBitmap; { Private declarations } public { Public declarations } end;
var
Form1: TForm1;
implementation

{$R *.DFM}

CONST
BitsPerPixel = 8;
procedure TForm1.ButtonStripesClick(Sender: TObject);
VAR i     :  INTEGER; j     :  INTEGER; Row   :  pByteArray; Value :  BYTE; begin
Value := (Sender AS TButton).Tag; // Value = $00 = 00000000 в двоичном исчислении для черного
// Value = $FF = 11111111 в двоичном исчислении для белого
// Value = $55 = 01010101 в двоичном исчислении для черных и белых полос

FOR j := 0 TO Bitmap.Height-1 DO BEGIN Row := pByteArray(Bitmap.Scanline[j]); FOR i := 0 TO (Bitmap.Width DIV BitsPerPixel)-1 DO BEGIN Row[i] := Value END END;
Image1.Picture.Graphic := Bitmap end;

procedure TForm1.ButtonGClick(Sender: TObject);
CONST {Изображение "g" было адаптировано для печати на принтере LaserJet IIP в соответствии с техническим руководством}
G:  ARRAY[0..31, 0..3] OF BYTE = { 0}    ( ($00, $FC, $0F, $C0),   {00000000 11111100 00001111 11000000}
{ 1}      ($07, $FF, $1F, $E0),   {00000111 11111111 00011111 11100000}
{ 2}      ($0F, $FF, $9F, $C0),   {00001111 11111111 10011111 11000000}
{ 3}      ($3F, $D7, $DE, $00),   {00111111 11010111 11011110 00000000}
{ 4}      ($3E, $01, $FE, $00),   {00111110 00000001 11111110 00000000}
{ 5}      ($7C, $00, $7E, $00),   {01111100 00000000 01111110 00000000}
{ 6}      ($78, $00, $7E, $00),   {01111000 00000000 01111110 00000000}
{ 7}      ($F0, $00, $3E, $00),   {11110000 00000000 00111110 00000000}
{ 8}      ($F0, $00, $3E, $00),   {11110000 00000000 00111110 00000000}
{ 9}      ($F0, $00, $1E, $00),   {11110000 00000000 00011110 00000000}
{10}      ($F0, $00, $1E, $00),   {11110000 00000000 00011110 00000000}
{11}      ($F0, $00, $1E, $00),   {11110000 00000000 00011110 00000000}
{12}      ($F0, $00, $1E, $00),   {11110000 00000000 00011110 00000000}
{13}      ($F0, $00, $3E, $00),   {11110000 00000000 00111110 00000000}
{14}      ($78, $00, $3E, $00),   {01111000 00000000 00111110 00000000}
{15}      ($78, $00, $3E, $00),   {01111000 00000000 00111110 00000000}
{16}      ($78, $00, $7E, $00),   {01111000 00000000 01111110 00000000}
{17}      ($3C, $00, $FE, $00),   {00111100 00000000 11111110 00000000}
{18}      ($1F, $D7, $DE, $00),   {00011111 11010111 11011110 00000000}
{19}      ($0F, $FF, $5E, $00),   {00001111 11111111 10011110 00000000}
{20}      ($07, $FF, $1E, $00),   {00000111 11111111 00011110 00000000}
{21}      ($00, $A8, $1E, $00),   {00000000 10101000 00011110 00000000}
{22}      ($00, $00, $1E, $00),   {00000000 00000000 00011110 00000000}
{23}      ($00, $00, $1E, $00),   {00000000 00000000 00011110 00000000}
{24}      ($00, $00, $1E, $00),   {00000000 00000000 00011110 00000000}
{25}      ($00, $00, $3E, $00),   {00000000 00000000 00111110 00000000}
{26}      ($00, $00, $3C, $00),   {00000000 00000000 00111100 00000000}
{27}      ($00, $00, $7C, $00),   {00000000 00000000 01111100 00000000}
{28}      ($00, $01, $F8, $00),   {00000000 00000001 11111000 00000000}
{29}      ($01, $FF, $F0, $00),   {00000001 11111111 11110000 00000000}
{30}      ($03, $FF, $E0, $00),   {00000011 11111111 11100000 00000000}
{31}      ($01, $FF, $80, $00));  {00000001 11111111 10000000 00000000}

VAR i  :  INTEGER; j  :  INTEGER; Row:  pByteArray; begin
FOR j := 0 TO Bitmap.Height-1 DO BEGIN Row := pByteArray(Bitmap.Scanline[j]); FOR i := 0 TO (Bitmap.Width DIV BitsPerPixel)-1  DO BEGIN Row[i] := G[j,i] END END;
Image1.Picture.Graphic := Bitmap end;

procedure TForm1.ButtonArrowClick(Sender: TObject);
CONST {Изображение "стрелка" было адаптировано для печати на принтере LaserJet IIP в соответствии с техническим руководством}
ArrowARRAY[0..31, 0..3] OF BYTE = { 0}    ( ($00, $00, $80, $00),   {00000000 00000000 10000000 00000000}
{ 1}      ($00, $00, $C0, $00),   {00000000 00000000 11000000 00000000}
{ 2}      ($00, $00, $E0, $00),   {00000000 00000000 11100000 00000000}
{ 3}      ($00, $00, $F0, $00),   {00000000 00000000 11110000 00000000}
{ 4}      ($00, $00, $F8, $00),   {00000000 00000000 11111000 00000000}
{ 5}      ($00, $00, $FC, $00),   {00000000 00000000 11111100 00000000}
{ 6}      ($00, $00, $FE, $00),   {00000000 00000000 11111110 00000000}
{ 7}      ($00, $00, $FF, $00),   {00000000 00000000 11111111 00000000}
{ 8}      ($00, $00, $FF, $80),   {00000000 00000000 11111111 10000000}
{ 9}      ($FF, $FF, $FF, $C0),   {11111111 11111111 11111111 11000000}
{10}      ($FF, $FF, $FF, $E0),   {11111111 11111111 11111111 11100000}
{11}      ($FF, $FF, $FF, $F0),   {11111111 11111111 11111111 11110000}
{12}      ($FF, $FF, $FF, $F8),   {11111111 11111111 11111111 11111000}
{13}      ($FF, $FF, $FF, $FC),   {11111111 11111111 11111111 11111100}
{14}      ($FF, $FF, $FF, $FE),   {11111111 11111111 11111111 11111110}
{15}      ($FF, $FF, $FF, $FF),   {11111111 11111111 11111111 11111111}
{16}      ($FF, $FF, $FF, $FF),   {11111111 11111111 11111111 11111111}
{17}      ($FF, $FF, $FF, $FE),   {11111111 11111111 11111111 11111110}
{18}      ($FF, $FF, $FF, $FC),   {11111111 11111111 11111111 11111100}
{19}      ($FF, $FF, $FF, $F8),   {11111111 11111111 11111111 11111000}
{20}      ($FF, $FF, $FF, $F0),   {11111111 11111111 11111111 11110000}
{21}      ($FF, $FF, $FF, $E0),   {11111111 11111111 11111111 11100000}
{22}      ($FF, $FF, $FF, $C0),   {11111111 11111111 11111111 11000000}
{23}      ($00, $00, $FF, $80),   {00000000 00000000 11111111 10000000}
{24}      ($00, $00, $FF, $00),   {00000000 00000000 11111111 00000000}
{25}      ($00, $00, $FE, $00),   {00000000 00000000 11111110 00000000}
{26}      ($00, $00, $FC, $00),   {00000000 00000000 11111100 00000000}
{27}      ($00, $00, $F8, $00),   {00000000 00000000 11111000 00000000}
{28}      ($00, $00, $F0, $00),   {00000000 00000000 11110000 00000000}
{29}      ($00, $00, $E0, $00),   {00000000 00000000 11100000 00000000}
{30}      ($00, $00, $C0, $00),   {00000000 00000000 11000000 00000000}
{31}      ($00, $00, $80, $00));  {00000000 00000000 10000000 00000000}

VAR i  :  INTEGER; j  :  INTEGER; Row:  pByteArray; begin
FOR
j := 0 TO Bitmap.Height-1 DO BEGIN Row := pByteArray(Bitmap.Scanline[j]); FOR i := 0 TO (Bitmap.Width DIV BitsPerPixel)-1  DO BEGIN Row[i] := arrow[j,i] END END;
Image1.Picture.Graphic := Bitmap end;

procedure TForm1.FormCreate(Sender: TObject);
begin
Bitmap := TBitmap.Create; WITH Bitmap DO BEGIN Width  := 32; Height := 32; PixelFormat := pf1bit END; Image1.Picture.Graphic := Bitmap end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
Bitmap.Free end;

procedure TForm1.ButtonRandomClick(Sender: TObject);
VAR i  :  INTEGER; j  :  INTEGER; Row:  pByteArray; begin
FOR
j := 0 TO Bitmap.Height-1 DO BEGIN Row := pByteArray(Bitmap.Scanline[j]); FOR i := 0 TO (Bitmap.Width DIV BitsPerPixel)-1  DO BEGIN Row[i] := Random(256) END END;
Image1.Picture.Graphic := Bitmap end;

procedure TForm1.ButtonInvertClick(Sender: TObject);
VAR i  :  INTEGER; j  :  INTEGER; Row: pByteArray; begin
FOR
j := 0 TO Bitmap.Height-1 DO BEGIN Row := pByteArray(Bitmap.Scanline[j]); FOR i := 0 TO (Bitmap.Width DIV BitsPerPixel)-1  DO BEGIN Row[i] := NOT Row[i] END END;
Image1.Picture.Graphic := Bitmap end;

end.
[000123]



Содержание раздела