Оригинальный DVD-ROM: eXeL@B DVD !
eXeL@B ВИДЕОКУРС !

ВИДЕОКУРС 2017
выпущен 15 марта!


УЗНАТЬ БОЛЬШЕ >>
Домой | Статьи | RAR-cтатьи | FAQ | Форум | Скачать | Видеокурс
Новичку | Ссылки | Программирование | Интервью | Архив | Связь

БОЛЬШОЙ FAQ ПО DELPHI



Bitmap.Scanline для PixelFormat

Кто-то из Италии попросил меня пример использования 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 в соответствии с техническим руководством}
 
   Arrow: array[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.
 




<< ВЕРНУТЬСЯ В ОГЛАВЛЕНИЕ



Материалы находятся на сайте https://exelab.ru/pro/



Оригинальный DVD-ROM: eXeL@B DVD !


Вы находитесь на EXELAB.rU
Проект ReactOS