Board index » delphi » How to access the RGB value's from Bitmap.Scanline[y]

How to access the RGB value's from Bitmap.Scanline[y]

Does somebody know how to get the individual RGB value's of one pixel
from BitMap.ScanLine[y]  ?

 

Re:How to access the RGB value's from Bitmap.Scanline[y]


Quote
Chris Wood wrote:

> Does somebody know how to get the individual RGB value's of one pixel
> from BitMap.ScanLine[y]  ?

        Scanline[y] is a pointer to row y of the image data. What
format the data's in depends on the value of PixelFormat. For example
IF PixelFormat = pf24Bit you can do something like this:

type
        PRGBs = ^TRGBs;
        TRGBs = array[0..1000000] of TRGBTriple;
var P: PRGBs;
begin
  for y:=0 to ABitmap.Height - 1 do
  begin
    P:= PRGBs(ABitmap.Scanline[y]);
    for x:= 0 to ABitmap.Width - 1 do
      with P^[x] do
      begin
        DoSomething(rgbtRed);
        DoSomething(rgbtGreen);
        DoSomething(rgbtBlue);
      end;
  end;
end;

--
David Ullrich

sig.txt not found

Re:How to access the RGB value's from Bitmap.Scanline[y]


Is it faster (and if so, why) to use Scanline[y] and an array to access a
given pixel, rather than just simply using Pixel[x,y]?

Thank you.

Quote
David Ullrich wrote:
>         Scanline[y] is a pointer to row y of the image data.

--
Wayne Herbert
Manager, Computer Products
Key Maps, Inc.
1411 West Alabama
Houston, TX  77006

Vox:  713.522.7949
Fax:  713.521.3202
Email:  wherb...@rice.edu

"Why is it only drug dealers and software developers call their clients
'users'?"

Re:How to access the RGB value's from Bitmap.Scanline[y]


Quote
Wayne Herbert wrote in message <34982B28.528EA...@keymaps.com>...
>Is it faster (and if so, why) to use Scanline[y] and an array to access a
>given pixel, rather than just simply using Pixel[x,y]?

Scanline is MUCH faster than using Pixel.  The main negative about
Scanline is that you need to know the number of bits per pixel to
access the pixels.  If you don't have a 16- or 24-bit bitmap, the
values in the scanline property are indices into a palette map.
The palette table gives the actual RGB values for display of
256 colors or less.

Here's a Technical Note about Scanline that I wrote a few months ago:

Subject:      Bitmap.Scanline for PixelFormat=pf1bit, pf8bit, pf24bit
(Delphi 3 Technical Note)
From:         "Earl F. Glynn" <EarlGl...@worldnet.att.net>
Date:         1997/09/27
Message-ID:   <60jsso$olf@bgtnsc03.worldnet.att.net>
Newsgroups:   comp.lang.pascal.delphi.misc

Since someone from Italy asked me for an example of using pf1bit
Bitmaps, I thought I would post part of my response and add
other details for pf8bit and pf24bit here in case others were wondering.

Background
-----------------
The new Delphi 3 scanline property allows quick access to
individual pixels, but you must know what Bitmap.PixelFormat
you're working with before you can access the pixels.

Possible PixelFormats include:
      pfDevice
      pf1bit
      pf4bit
      pf8bit
      pf15bit
      pf16bit
      pf24bit
      pf32bit

pf24bit Bitmaps
----------------------
For pf24bit bitmaps, I define (I wish Borland would)

  CONST
    PixelCountMax = 32768;

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

Note:  TRGBTriple is defined in the Windows.PAS unit.

To step through a 24-bit bitmap and while creating a new one and access
the 3-bytes-per-pixel data, use a construct like the following:

  ...
  VAR
    i           :  INTEGER;
    j           :  INTEGER;
    RowOriginal :  pRGBArray;
    RowProcessed:  pRGBArray;
  BEGIN
    IF   OriginalBitmap.PixelFormat <> pf24bit
    THEN RAISE EImageProcessingError.Create('GetImageSpace:  ' +
               'Bitmap must be 24-bit color.');

    {Step through each row of image.}
    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

//       Access individual color RGB color planes with references like:
//           RowProcessed[i].rgbtRed     := RowOriginal[i].rgbtRed;
//           RowProcessed[i].rgbtGreen  := RowOriginal[i].rgbtGreen;
//           RowProcessed[i].rgbtBlue    := RowOriginal[i].rgbtBlue;

      END

    END
    ...

pf8bit Bitmaps
---------------------
Access to these byte-per-pixel bitmaps is easy using the
TByteArray (defined in SysUtils.PAS):

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

(I suppose, but I've never tried it, you could access pf16bit Bitmaps using
the following defined in SysUtils.PAS:

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

To process an 8-bit (pf8bit) bitmap, use a construct like the following
that
constructs a histogram of such a bitmap:

  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 Bitmaps
--------------------
Accessing pf8bit bitmaps is easy since they are one byte per pixel.
But you can save a lot of memory if you only need a single bit per pixel
(such as with various masks), if you use pf1bit Bitmaps.

As with pf8bit bitmaps, use a TByteArray to access pf1bit Scanlines.
But you will need to perform bit operations on the bytes to access the
various pixels.  Also, the width of the Scanline is Bitmap.Width DIV 8
bytes.

The following code shows how to create the following kinds of 1-bit
bitmaps:  black, white, stripes, "g", "arrow" and random -- an "invert"
option is also available.

Create a form with an Image1:  TImage on it -- I used 1 256x256 Image1
with Stretch := TRUE to see the individual pixels more easily.  The buttons
Black, White and stripes have tags of 0, 255, and 85 ($55 = 01010101
binary) that call ButtonstripesClick when selected.

Buttons "g" and "arrow" call separate event handlers to draw these bitmaps
taken form HP Laserjet examples.

"Random" just randomly sets bits on in the 1-bit bitmaps.

"Invert" changes all the 0s to 1's and vice versa.

// Example of how to use Bitmap.Scanline for PixelFormat=pf1Bit.
// Requested by Mino Ballone from Italy.
//
// Copyright (C) 1997, Earl F. Glynn, Overland Park, KS.  All rights
reserved.
// May be freely used for non-commerical purposes.

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 binary for black
// Value = $FF = 11111111 binary for white
// Value = $55 = 01010101 binary for black & white stripes

  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
    {The "g" bitmap was adapted from the LaserJet IIP Printer Tech Ref
Manual}
    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
    {The "arrow" bitmap was adapted from the LaserJet IIP Printer Tech Ref
Manual}
    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}
{ ...

read more »

Other Threads