Solved

Pixel-by-Pixel drawing

Posted on 2004-09-21
11
1,369 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
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 33

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
 

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 33

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
Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 

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 33

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 33

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 33

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

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
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…
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

757 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

Need Help in Real-Time?

Connect with top rated Experts

25 Experts available now in Live!

Get 1:1 Help Now