Board index » delphi » Access an array of trgbtriple like bitmap by scanline

Access an array of trgbtriple like bitmap by scanline

Hi all ,
My question is : Can i access with a pointer the rows of a N x M array in a
similar way like i do using scanline with bitmaps :
For example when handling bitmaps i write something like :

procedure modifybitmap(var bitmap:tbitmap);
type
Trgbrow = array[0..30000] of trgbtriple ;
Prgbrow = ^Trgbrow ;
var
pp:Prgbrow;
i,j:integer;
begin
bitmap.pixelformat:=pf24bit;
for j:=0 to bitmap.height-1 do
begin
pp:=bitmap.scanline[j];
for i:=0 to bitmap.width-1 do
begin
pp[i].rgbtred:=200;
pp[i].rgbtgreen:=200;
pp[i].rgbtblue:=200;
end;
end;

how can i do the same for an array of integer or any other type (trgbtriple
included)

 

Re:Access an array of trgbtriple like bitmap by scanline


Hi, Francescosava:

Sorry for first sending this by private E-mail.  I hit "Reply" instead of
"Reply Group" --sorry.

Quote
> My question is : Can i access with a pointer the rows of a N x M array in a
> similar way like i do using scanline with bitmaps :

I'm not sure I understand your question.   Are you trying to use
a TBitmap as a 2D array and store objects other than pixels in
each array element?

Using pf24bit will not work well, since you have an array of
3-byte fields.  If you use pf32bit instead, a TBitmap can be
used to be a 2D matrix of any type of 4-byte quantity, including
a 4-byte "single" floating-point value, or a 4-byte integer.

The "Raw Image" in this Lab Report shows how to use a pf32bit
TBitmap (and even display it) that is really a 2D array of IEEE
single floating-point values:
http://www.efg2.com/Lab/FractalsAndChaos/Lyapunov.htm

The "Raw Image" in this Lab Report shows how to use a pf32bit
TBitmap to store a 2D array of 4-byte integer values:
http://www.efg2.com/Lab/FractalsAndChaos/FractalsShow2.htm

A pf32bit TBitmap can be used like a 2D Matrix of 4-byte values,
but it's not particularly fast because of overhead in accessing
the values.  You can even display this data (like in the Lab
Reports above) as an image, or save it to disk and later
reload it.

If this didn't answer your question, feel free to clarify
what you're asking about.

Find other details of working with Scanline here:
http://www.efg2.com/Lab/ImageProcessing/Scanline.htm

Happy New Year,

--
efg

Earl F. Glynn     E-mail:  e...@efg2.com
Overland Park, KS  USA

efg's Computer Lab:  http://www.efg2.com/Lab
Mirror:  http://homepages.borland.com/efg2lab/Default.htm

Re:Access an array of trgbtriple like bitmap by scanline


Hi Francesco?,

?  schrieb in <92lec6$6...@bornews.inprise.com>:

Quote
> My question is : Can i access with a pointer the rows of a N x M array in a
> similar way like i do using scanline with bitmaps :

This is only possible, if you have a fixed value for bitmap width.

Note, that the compiler generate code for calculation the adress of a
array element. You can also use this way and write a own function to
calculate the correct adress:

Preparing (for 24 bit):

var
  LineSize : LongInt;
  FirstLine : Pointer;
begin
  FirstLine := Bitmap.ScanLine[0];
  LineSize := 0;
  if Bitmap.Height > 1 then
    LineSize := LongInt(Bitmap.ScanLine[1]) - LongInt(FirstLine);
end;

function GetPixelAdress(X, Y : Integer): PRGBTriple;
begin
  Result := Pointer(LongInt(FirstLine) + Y * LineSize +
                                         X * SizeOf(TRGBTriple));
end;

Please note, LineSize is negativ in the most cases (Bottom-Top-Bitmaps).

This is a rational method for a random access of the pixels, similar to
your sample the adress are calculate for each pixel by multiplication
and addition.

In your example you use a sequential access. You can optimize the
access, if you reduce the calculation of a simple and faster addition.

procedure ModifyBitmap(var Bitmap: TBitmap);
var
  LineSize : LongInt;
  FirstLine : Pointer;
  LineStart : PByte;  // must by a PByte for Inc() with LineSize in Byte
  PixelPtr : PRGBTriple;
  w, h : Integer;
  x, y : Integer;
begin
  w := Bitmap.Width;
  h := Bitmap.Height;
  FirstLine := bitmap.ScanLine[0];
  LineSize := 0;
  if bitmap.Height > 1 then
    LineSize := LongInt(bitmap.ScanLine[1]) - LongInt(FirstLine);

  LineStart := PByte(FirstLine);
  for y := 0 to h-1 do begin
    PixelPtr := PRGBTriple(LineStart);
    for x := 0 to w-1 do begin
      PixelPtr^.rgbtRed   := 200;
      PixelPtr^.rgbtGreen := 200;
      PixelPtr^.rgbtBlue  := 200;
      Inc(PixelPtr);  // next pixel
    end;
    Inc(LineStart, LineSize);
  end;
end;

By Peter.

I wish all a happy new millenium.

Re:Access an array of trgbtriple like bitmap by scanline


Quote
> I'm not sure I understand your question.   Are you trying to use
> a TBitmap as a 2D array and store objects other than pixels in
> each array element?

sorry for my Bad english : what i meant to say it 's the opposite :
I want to use a 2D array in which i want to store trgbtriple or bytes values
(taking them from a bitmap of course ) , but i want fast access to this
array like i have with bitmap.scanline . The problem is this : i want to put
in a 2d array a copy of a bitmap because i want to use it as a "brush" to
paint in my photoretouch program . I have already done this but i 'm
convinced that accessing each element of the array ( ex. brusharray[i,j] )
is slower than if i could have a pointer to each row of the array (like
scanline) and then accessing each element of the row ( example Prow[i] ) .
In other words what i'm questioning is if there is a way to access 2D array
values using pointers ( note that i'm able to do it with a 1D array ) .
Please do not hesitate to tell me if neither now my question is clear enough
.
Thx , Francesco ,
Happy Millennium .

Re:Access an array of trgbtriple like bitmap by scanline


I don't think accessing an array is slower, at least if you use powers
of 2 (2,4,8,16...) as "width" of your array. Of course you can store a
pointer to each row of the array, too:

Var
  MyArray: Array[0..99,0..99] of WhatEver;
  MyScanline: Array[0..99] of Pointer; // perhaps better ^WhatEverRow;
Begin
  For i := 0 To 99 Do MyScanline[i] := @Array[i,0];

But I do not quite understand why you use an 2dim array instead of a
bitmap for your brush? If you want, you can access the bitmap very
similar to an array via scanline...

Type
  TByte3: Array[0..2] of Byte;
  PByte3: ^TByte3;
  TRow3: Array[0..65535] of TByte3;
  PRow3: ^PRow3;
  TRows3: Array[0..65535] of PRow3;
  PRows3: ^PRows3;
Var
  MyArray: PRows3;
Begin
  GetMem (MyArray,SizeOf(PRow3)*MyBitmap.Height);
  For i := 0 To MyBitmap.Height-1 Do MyArray[i] := MyBitmap.Scanline[i];
  MyArray^[15]^[12][0] := SomeRed; // access the 12th pixel of the 15th
scanline
  MyArray^[15]^[12][1] := SomeGreen; // same pixel, other color channel
  MyArray^[15]^[12][2] := SomeBlue;
  // or is 0 blue and 2 red? I am not quite sure (and a bit tired)
  FreeMem (MyArray,SizeOf(PRow)*MyBitmap.Height);
End;

The disadvantage of this: you need some extra space to store some
pointers (the start position of each scanline). If you access each line
very often this might be worth it. If not I prefer this one (not a real
array any more):

Var
  MyRow: PRow3;
Begin
  MyRow := MyBitmap.Scanline[15];
  MyRow^[12][0] := SomeRed; // access the 12th pixel of the 15th
scanline
  MyRow^[12][1] := SomeGreen;
  MyRow^[12][2] := SomeBlue;
End;

Okay, you are right, that one's very similar to the code you posted.
Maybe I don't know what you want to do with you brush, but I really
don't think there is a problem accessing it that way.

Oh... one more thing: I have not tested the code. If you have problems
with it (maybe I have done something completely wrong), let me know...

Jens

Re:Access an array of trgbtriple like bitmap by scanline


Quote
Jens Gruschel <j...@pegtop.de> wrote in message

3A4E8D9A.C03FC...@pegtop.de...

Quote
> I don't think accessing an array is slower, at least if you use powers
> of 2 (2,4,8,16...) as "width" of your array. Of course you can store a
> pointer to each row of the array, too:

> Var
>   MyArray: Array[0..99,0..99] of WhatEver;
>   MyScanline: Array[0..99] of Pointer; // perhaps better ^WhatEverRow;
> Begin
>   For i := 0 To 99 Do MyScanline[i] := @Array[i,0];

Thanx very much : i tried this and worked well for me !

Quote
> But I do not quite understand why you use an 2dim array instead of a
> bitmap for your brush? If you want, you can access the bitmap very
> similar to an array via scanline...

I don't need to modify the brush bitmap but only to read its values once :
So i think it's better to save the values to a 2d array the first time i
load the bitmap and then read the array (faster) instead of the bitmap
(slower ? !) . I need any speed that is possible to read the brush gray
values because i'm painting (and showing in real time ) with the brush on an
other bitmap !
From other side i thought that reading the elements of the brush array in
the standard way ( grayvalue:=brusharray[i , j] ) was slower than having
many pointers that point to each j row of the array and access the elements
of that row by prow[ i ] .

Francesco

Re:Access an array of trgbtriple like bitmap by scanline


Quote
> I don't need to modify the brush bitmap but only to read its values once :
> So i think it's better to save the values to a 2d array the first time i
> load the bitmap and then read the array (faster) instead of the bitmap
> (slower ? !) . I need any speed that is possible to read the brush gray
> values because i'm painting (and showing in real time ) with the brush on an
> other bitmap !
> From other side i thought that reading the elements of the brush array in
> the standard way ( grayvalue:=brusharray[i , j] ) was slower than having
> many pointers that point to each j row of the array and access the elements
> of that row by prow[ i ] .

Sorry, I did not see this entry until now. Of course
grayvalue:=brusharray[x,y] is slower, because to access the element,
Delphi has to calculate y * ElelmentsPerRow + x. If you use a pointer to
each row, Delphi just has to calculate RowPointer[y] + x. Using powers
of 2 should also be a solution, because y SHL 8 + x is much faster than
y * 256 + x and does the same. Delphi optimizes * to SHL automatically
if you multiply by a power of 2 (only constants of course). But I really
think if you use a bitmap and scanline, it should be about as fast as
the array technique, especially if you store the scanlines in an array
first.

Jens

Re:Access an array of trgbtriple like bitmap by scanline


Quote
Jens Gruschel <j...@pegtop.de> wrote in message

3A5BADF3.19068...@pegtop.de...

Quote
> > I don't need to modify the brush bitmap but only to read its values once
:
> > So i think it's better to save the values to a 2d array the first time i
> > load the bitmap and then read the array (faster) instead of the bitmap
> > (slower ? !) . I need any speed that is possible to read the brush gray
> > values because i'm painting (and showing in real time ) with the brush
on an
> > other bitmap !
> > From other side i thought that reading the elements of the brush array
in
> > the standard way ( grayvalue:=brusharray[i , j] ) was slower than having
> > many pointers that point to each j row of the array and access the
elements
> > of that row by prow[ i ] .

> Sorry, I did not see this entry until now. Of course
> grayvalue:=brusharray[x,y] is slower, because to access the element,
> Delphi has to calculate y * ElelmentsPerRow + x. If you use a pointer to
> each row, Delphi just has to calculate RowPointer[y] + x. Using powers
> of 2 should also be a solution, because y SHL 8 + x is much faster than
> y * 256 + x and does the same. Delphi optimizes * to SHL automatically
> if you multiply by a power of 2 (only constants of course). But I really
> think if you use a bitmap and scanline, it should be about as fast as
> the array technique, especially if you store the scanlines in an array
> first.

> Jens

Thanx Jens : Now my routine is enough fast and i think well optimized .

Other Threads