views:

793

answers:

7

In Delphi 7, I have a library that uses the TCanvas component to output some information. The resulting image is about 4800*6000 pixels and I would like to print it and save it as .jpeg.

To achieve this, I created a TBitmap and gave its Canvas as parameter to the library and then I assigned the bitmap to the jpeg. Apparently, this is taking too much memory, because I am getting an exception when trying to set the bitmap's width and height, saying "Not enough storage is available to process this command."

// output to printer
Printer.BeginDoc();
doPrint(Printer.Canvas);
Printer.EndDoc();

// output in bmp.Canvas
bmp := TBitmap.Create;
bmp.Width := Printer.PageWidth;
bmp.Height := Printer.PageHeight; // <- BAM! Exception!
doPrint(bmp.Canvas);

// save as jpeg
jpg := TJPEGImage.Create;
jpg.Assign(bmp);
jpg.SaveToFile('...');

// free
bmp.Free();
jpg.Free();

What am I doing wrong? Could I save Printer.Canvas directly as a .jpeg file?

Edit: Updated image size approximation from 2000*2000 to 4800*6000

A: 

Delphi's TBitmap class has problems handling such large bitmaps. And no, you cannot save a TCanvas directly to a .jpg file.

Remy Lebeau - TeamB
If nobody comes up with any ideas/workarounds any time soon, I will accept your answer.
Tom
The `TBitmap` class itself has no problems at all, it is merely a wrapper around Windows API functions. Depending on Windows version and graphics card (driver) there may be problems or not, simple as that, but Delphi doesn't really enter into it. I can create a 10000 by 10000 pixel bitmap without problems on my system. It just takes a while to fill it with colour or save it to a file (380 MB size).
mghie
Half of the answer is still right...
Tom
A: 

I tried the following code on my machine (Windows XP, Delphi 2006), and did not receive any exceptions. What OS are you using?

  procedure TForm3.Button3Click(Sender: TObject);
  var
     bmp : TBitmap;
  begin
     bmp := TBitmap.Create;
     bmp.PixelFormat := pf32bit;
     bmp.Width := 6000;
     bmp.Height := 4800;
     bmp.Free;
  end;
Ben Ziegler
Windows XP SP1 with 1GB of RAM. The application is used on Windows 7 with 2 GB of RAM without any hassle, but I would like to make sure that it runs fine on my system (at least for debugging's sake)
Tom
+1  A: 

you should be able to process large bitmaps using TBitmap32 from Graphic32 (http://www.graphics32.org/wiki/)

glob
Works fine, thank you!
Tom
A: 

As mghie said: It depends a lot on your system see EFGs computer lab on large bitmaps

Jan Oosting
+1  A: 

You should set the pixelformat for the bmp to something before sizing up the bmp, as Ben Ziegler suggests. This makes all the difference.

Niels Thomsen
I'll try this as well, it's a black and white image anyway.
Tom
A: 

Try to set PixelFormat to pf32bit or pf24bit (as in example by Ben Ziegler), in most cases this PixelFormat does the trick (as I remember, it was mainly on XP). You can find more info here.

kibab
A: 

Not sure if this will work or help. But we created a function which will save a component to a jpeg:

    function SaveComponentToJPeg(mControl: TWinControl): TJpegImage;
    var
      bmp: TPicture;
      jpg : TJpegImage;
      dc: HDC;
      wnd: HWND;
      Params: array[0..255] of Char;

    begin
      bmp:=TPicture.Create;
      jpg := TJpegImage.create;
      try
        bmp.Bitmap.Width  := mControl.Width  - 05;  // Deduct for border.
        bmp.Bitmap.Height := mControl.Height -05;  // Deduct for border.
        wnd               := mControl.Handle;  //ctiveWindow;
        dc                := GetDc(wnd);
        BitBlt(bmp.Bitmap.Canvas.Handle,0,0,bmp.Width,bmp.Height,dc,0,0,SrcCopy);
        ReleaseDc(wnd, dc);
        jpg.assign(bmp.bitmap);
        result := jpg
      finally
        bmp.Free;
      end;
    end;
M Schenkel
I'm already doing this. The code is posted in the question.
Tom