Delphi World - Bitmap.Scanline для PixelFormat
Delphi World - это проект, являющийся сборником статей и малодокументированных возможностей  по программированию в среде Delphi. Здесь вы найдёте работы по следующим категориям: delphi, delfi, borland, bds, дельфи, делфи, дэльфи, дэлфи, programming, example, программирование, исходные коды, code, исходники, source, sources, сорцы, сорсы, soft, programs, программы, and, how, delphiworld, базы данных, графика, игры, интернет, сети, компоненты, классы, мультимедиа, ос, железо, программа, интерфейс, рабочий стол, синтаксис, технологии, файловая система...
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.

Проект Delphi World © Выпуск 2002 - 2017
Автор проекта: Эксклюзивные курсы программирования