# Pixel-by-Pixel drawing

Is there any fast and efficient way to draw pixel by pixel images ??
I need to make a program which extracts some image data from a binary file and draw them on a window. The image data format is several bits per pixel, so I'm thinking on grouping bits and draw pixel by pixel according to its meaning.

###### Who is Participating?

x

Commented:
button click to do Bit by Bit test of 16 byte memory block and a scanline of an 8x8 bitmap =

procedure TForm1.sbut_Scan8BmpClick(Sender: TObject);
type
PAryCard = ^TAryCard;
TAryCard = Array[Word] of Cardinal;

var
p2BitMem: Pointer;
Bmp8x8: TBitmap;
y, x, PosX, PosY, index: Integer;
{aryColor is where I place the 4 color values of 2 bit color used
for the output in Bmp8x8}
aryColor: Array[0..3] of Cardinal;
pScan: PAryCard;
begin
p2BitMem := AllocMem(16);
{I use a 16 byte memory block for my 2 bit color depth pixel definitions}

PDWORD(p2BitMem)^ := 1987654321;
{I just add values to my mem block for 2 bit values}
PInt(Cardinal(p2BitMem)+4)^ := 0;
PInt(Cardinal(p2BitMem)+8)^ := MAXDWORD;
PInt(Cardinal(p2BitMem)+12)^ := 123456789;

{for these "Color" values you will need to reverse the normal TColor
Red and Blue bytes, so the "Normal" Red \$FF need to be changed to \$FF0000
but green is still \$FF00}
aryColor[0] := \$FF0000; // red color placed if bit value 00
aryColor[1] := \$FF00; // green bit value 01
aryColor[2] := \$FF; // blue bit value 10
aryColor[3] := \$FFFF00; // yellow bit value 11

Bmp8x8 := TBitmap.Create;
try
Bmp8x8.Height := 8;
Bmp8x8.Width := 8;
Bmp8x8.PixelFormat := pf32Bit; // MUST BE 32 BIT for this Scanline op

PosY := 0;
PosX := 0;
for y := 0 to Bmp8x8.Height - 1 do
begin
pScan := Bmp8x8.ScanLine[y];

for x := 0 To Bmp8x8.Width-1 do
begin
{I use  1 shl PosX   to test for individual BITS}
if PByte(PosY + Cardinal(p2BitMem))^ and (1 shl PosX) <> 0 then index := 2
else index := 0;
Inc(PosX);
if PByte(PosY + Cardinal(p2BitMem))^ and (1 shl PosX) <> 0 then Inc(Index);
Inc(PosX);
if (x = 3) or (x=7) then
begin
Inc(PosY);
PosX := 0;
end;
{the tests above get two BIT values from each tested Byte in an X run}
PScan[x] := aryColor[index];
{index will be 0, 1, 2 or 3}
end;
end;

Canvas.Draw(820, 260, Bmp8x8);
finally
FreeAndNil(Bmp8x8);
FreeMem(p2BitMem);
end;
end;
0

Commented:
The faster way to achieve this is to use TBitmap.ScanLine();
You pass the row as parameter and you have a pointer to the row, so each X bits you have a new pixel of the row, where X is the image color depth (16 bits, 24 bits, etc...).
Setting TBitmap.PixelFormat = pf24bits; will help a lot since red for the pixel will be 1 byte, blue and red to.

0

Commented:
hello patroclus02 , , you ask - -
Is there any fast and efficient way to draw pixel by pixel images ??

I guess that would depend on what you are drawing on, if you are drawing on a windows Control DC (canvas in Delphi) then the answer may be NO, as with a window DC, I would think that  the   SetPixel( )  function would have to be used, a SLOW method if you need to change alot of pixels. . . but with a system Bitmap you can get the pixel definition memory and change it, that is usually called a  ScanLine operation, which is Very Much faster than the DC  SetPixel( )  function . . .

you do not really say what kind of image data you get your pixel data from, using a scanline operation is faster but can get complicated, with input pixel data that does not match the scanline pixel data. . . . ., do not know what you mean by -
"thinking on grouping bits and draw pixel by pixel according to its meaning"

maybe more info about what kind of image data you have to get would help?
0

Commented:
Everything is relative. You can draw a boatload of pixels in one second on a modern PC. Problem is, images require boatloads of pixels. However, it may be "good enough" for your purposes.

Using nothing fancy at all in terms of hardware (2 GHz Celeron, and whatever video card came with the Dell) , I just ran the code below (using a timer interval of 5000 msec and a form defined ClientWidth & ClientHeight of 500 each).

With full form displayed on screen (without clipping) its takes me about 1.9 seconds to draw a million pixels. With another form overlaying the entire client region of the form, it takes about 0.8 second to draw a million pixels. Replacing the call to Pixel with a simple noop drops to the to under 0.01 seconds. Interestingly, I if replace the pixel call with sleep(0), I get the same execution times.

Since modern video cards are 24/32 bits, you probably won't be able to optimize based on bits per pixel (without putting user into a low-color graphics mode)

procedure TForm1.Timer1Timer(Sender: TObject);
var
StartTime: TDateTime;
EndTime: TDateTime;
ii: integer;
jj: integer;
ColorLoop: integer;
mycolor: TColor;
can: TCanvas;
begin
StartTime := now;
with Canvas do
begin
for ColorLoop := 0 to 3 do
begin
// making drawing obvious by changing color
if (ColorLoop mod 2  = 0) then MyColor := clBlack else MyColor := clWhite;
for ii := 0 to 499 do
begin
// Application.ProcessMessages;
for jj := 0 to 499 do
begin
Pixels [ii, jj] := MyColor;
end;
end;
end;
end;
EndTime := now;
Caption := format('pixels in %.3f seconds', [(EndTime - StartTime) * SecsPerDay]);
end;

Drawing to a TCanvas using the Pixel[x,y] = Color

0

Author Commented:
What I want to do is extract tile images from a binary file. Tile images are small images (8x8 pixels) which you use to make bigger images. I need to display a tile image set, and then, several objects made from different tiles.

"thinking on grouping bits and draw pixel by pixel according to its meaning"
This means that I take 2 bits at a time (image information is 2 bits color depth. Later on, you can add other 2 bits to get up to 16 diferent colours, but inside the binary file, only 2 bits are stored). So each 2 bits, I draw a pixel depending on if they are 00, 01, 10 or 11.
So far I'm using a DirectX libraries for drawing routines, and a method called "Point", which just takes a sparameters X, Y and colour of pixel to draw. So far, it works fine it seems... Usually I don't need to draw more than 300.000-400.000 pixels at a time.
0

Commented:
you really should have mentioned that you are using  DirectX methods, that makes an extream difference in the code methods. . .

I do NOT know the relative performance values for the  "Point" method, since ALL performance values are relative (compare the speed of one method to another method), you would need anouther method to compare it to to make a faster or slower judgement. . . .

if the "Point" method is working for you (you do not have some timing errors, or fram rate drop), you may want to continue to use it. . .
if it is not working for you,  you may look at another method (I have not used any directX in a number of years) for faster results, , I can remember a function that would draw a bitmap to the directX DC, perhaps a you can get the 8x8 pixel 2 bit info and place it on a 8x8 bitmap (of the needed color depth) with a scanline and then draw the 8x8 bitmap on the DirectX output DC. . .
as I said, I do not have the knowledge to give much for  DirectX,

if you do not get any helpful comments here, you may want to ask this question AGAIN, and be sure to specificly ask about DirectX methods
0

Author Commented:
Well, I'm not using DirectX directly. I'm using some libraries that interface with it.
The "point" method IS working for me so far.
But, would any non-DirectX method be faster? more adecuate maybe?
0

Commented:
?????
As I have tried to say before, IF you want to use a bitmap then the ScanLine method is fast compared to SetPixel( ) or Canvas.Pixel(x,y), but I DO NOT KNOW any performace values for the  "point" method, so I can not compare,

if you like I can do a 8x8 pixel TBitmap scanLine using 4 colors input (as in a 2 bit color depth you describe) and then you will need a method to "Paint" this bitmap onto whatever you are drawing on. . .
you may can test the relative performance of the two methods?
0

Author Commented:
That would be fine, so I can compare both my solution and that one you talk about.
0

Author Commented:
Thank you
0

Commented:
I think this code will go in the correct direction for the bit tests

PosY := 0;
PosX := 7;
for y := 0 to Bmp8x8.Height - 1 do
begin
pScan := Bmp8x8.ScanLine[y];

for x := 0 To Bmp8x8.Width-1 do
begin
{I use  1 shl PosX   to test for individual BITS}
if PByte(PosY + Cardinal(p2BitMem))^ and (1 shl PosX) <> 0 then index := 2
else index := 0;
Dec(PosX);
if PByte(PosY + Cardinal(p2BitMem))^ and (1 shl PosX) <> 0 then Inc(index);
Dec(PosX);
if (x = 3) or (x=7) then
begin
Inc(PosY);
PosX := 7;
end;
{the tests above get two BIT values from each tested Byte in an X run}
PScan[x] := aryColor[index];
{index will be 0, 1, 2 or 3}
end;
end;

I think that I needed to start with the High bit (7) and decrease the bit position, I do not have much time to test this, so you may test both versions to see which matches the bits. . . .
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.