Looking for fast "PutPixel" procedure

I am looking for an efficient way to set pixels in a bitmap or on a canvas (Delphi 2.) Executing Bitmap.Canvas.Pixels[x,y]:=clBlack" is very slow - it does about 60,000 pixels/second on my 166Mhz Pentium. In my application, I do about 22 extended arithmetic operations per pixel (including sqrt/sin/cos), and even then the Pixels property takes 8 times longer to execute than my code. In the past under DOS, the time to "PutPixel" was a tiny fraction of the calculation time. I cannot construct the image I am building using any other method such as lines, etc.

I thought that creating a bitmap in memory would be faster than plotting directly to the canvas, but it isn't. An outline of my code is:

    Bitmap := TBitMap.Create;
    Bitmap.Height := Image1.Height;
    Bitmap.Width := Image1.Width;
    { Do calculations and call this approx 40,000 times: }
        Bitmap.Canvas.Pixels[x,y] := clBlack;
    Image1.Picture.Graphic := Bitmap;

I have tried various options such as "IgnorePalette := True", but it makes no difference.

Does anybody know of a way of getting to the bitmap in memory? I am sure I could write code to "twiddle bits" there much faster than the Pixels property. Or is there any other way?
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Most of the newsgroups say that on screen images are the fastest and that by doing it off screen, your procedures will be about 3 times slower than an onscreen edit.  They also recommend using a function called CreateDIBSection to create your bitmap and to edit it by pointer to each bit.  I've never done it, but that is what they recommend.  If you want to see the discussion, goto Alta Vista and search the UseNet for: fast delphi bitmap

Good Luck,
I reckon you've got no chance. I've done a lot of personal
research into this - I tried all dos ways of putting pixels
(Int 10h, Mem) Etc, and using the ASM command,
eving setting up an array directly in segA000. Your only hope
is with a bitmap of some description.

You can use Memory Image of Bitmap and then use SetDIBits function to apply changes.
This is example of this.

unit Unit1;


  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  Forms, Dialogs, StdCtrls, Buttons, ExtCtrls;

 XSize = 4*63; { must be devided by 4 !!!}
 YSize = 250;

  TForm1 = class(TForm)
    BitBtn1: TBitBtn;
    PaintBox1: TPaintBox;
    Label1: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure BitBtn1Click(Sender: TObject);
    ByteInfo : PBitmapInfo;
    ByteBits : array[0..YSize-1,0..XSize-1] of byte;
  public {}

  Form1: TForm1;


{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
 i,j : longint;
 for j:=0 to YSize-1 do
   for i:=0 to XSize-1 do
     ByteBits[j,i]:=Random(255); { here is filling byte array }

 { Create BitmapInfoHeader for 256 color bitmap }
 GetMem( ByteInfo, SizeOf(TBitmapInfoHeader) + 256*SizeOf(TRGBQuad) );
 ByteInfo^.BmiHeader.biSize := SizeOf(TBitmapInfoHeader);
 ByteInfo^.BmiHeader.biWidth := XSize;
 ByteInfo^.BmiHeader.biHeight := YSize;
 ByteInfo^.BmiHeader.biPlanes := 1;
 ByteInfo^.BmiHeader.biBitCount := 8; { 256 color }
 ByteInfo^.BmiHeader.biCompression := BI_RGB;
 ByteInfo^.BmiHeader.biSizeImage := 0;
 ByteInfo^.BmiHeader.biXPelsPerMeter:= 1000;
 ByteInfo^.BmiHeader.biYPelsPerMeter:= 1000;
 ByteInfo^.BmiHeader.biClrUsed:= 0;
 ByteInfo^.BmiHeader.biClrImportant:= 0;
 for i:=0   to 255 do
   ByteInfo^.BmiColors[i].rgbRed := Random(255);
   ByteInfo^.BmiColors[i].rgbGreen := Random(255);
   ByteInfo^.BmiColors[i].rgbBlue := Random(255);
   ByteInfo^.BmiColors[i].rgbReserved := 0;

procedure TForm1.FormDestroy(Sender: TObject);
  FreeMem( ByteInfo, SizeOf(TBitmapInfoHeader) + 256*SizeOf(TRGBQuad) );

procedure TForm1.BitBtn1Click(Sender: TObject);
 Bmp : HBitmap;
 NewDC : HDC;
 T1 : TDateTime;
 i,j,k : integer;
 Count : integer;
 NewDC := CreateCompatibleDC( PaintBox1.Canvas.Handle );
 Bmp := CreateCompatibleBitmap( PaintBox1.Canvas.Handle, XSize, YSize );
 SelectObject( NewDC, Bmp );
 Count := 50;
 for i:=1 to Count do
   SetDIBits( NewDC, Bmp, 0, YSize, @ByteBits, ByteInfo^, DIB_RGB_Colors );
   BitBlt( PaintBox1.Canvas.Handle, 0, 0, XSize, YSize, NewDC, 0, 0, SrcCopy );
   for j:=0 to YSize-1 do
   for k:=0 to XSize-1 do
     ByteBits[j,k] := ByteBits[j,k+1];
 DeleteObject( Bmp );
 DeleteDC( NewDC );
 Label1.Caption := 'Time=' + FormatFloat('#.000',(Now-t1)*100000*1000/(Count*YSize*XSize))+
                   'ms for one pixel''s read+write';


If You need modify existing  bitmap then of course you can use GetDIBits and then this example.


Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
numbercrunchAuthor Commented:
Thank you Mirek!! I have not yet tried this code, but at last I
have a working example to build from! I will let you know what
success I have.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today

From novice to tech pro — start learning today.

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.