Solved

Pixel-by-Pixel drawing

Posted on 2004-09-21
11
1,411 Views
Last Modified: 2012-08-13
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.

Any advice?? thanks
0
Comment
Question by:patroclus02
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
11 Comments
 
LVL 4

Expert Comment

by:MrJul
ID: 12113662
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
 
LVL 34

Expert Comment

by:Slick812
ID: 12113796
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
 
LVL 6

Expert Comment

by:gwalkeriq
ID: 12118563
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
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:patroclus02
ID: 12120567
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
 
LVL 34

Expert Comment

by:Slick812
ID: 12126237
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 Comment

by:patroclus02
ID: 12158947
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
 
LVL 34

Expert Comment

by:Slick812
ID: 12162882
?????
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 Comment

by:patroclus02
ID: 12206662
That would be fine, so I can compare both my solution and that one you talk about.
0
 
LVL 34

Accepted Solution

by:
Slick812 earned 60 total points
ID: 12208715
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
 

Author Comment

by:patroclus02
ID: 12215286
Thank you
0
 
LVL 34

Expert Comment

by:Slick812
ID: 12219783
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

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
In this video we outline the Physical Segments view of NetCrunch network monitor. By following this brief how-to video, you will be able to learn how NetCrunch visualizes your network, how granular is the information collected, as well as where to f…
This tutorial will teach you the special effect of super speed similar to the fictional character Wally West aka "The Flash" After Shake : http://www.videocopilot.net/presets/after_shake/ All lightning effects with instructions : http://www.mediaf…

691 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question