Question

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

Was it helpful?

Solution

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

OTHER TIPS

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

This error occurs if you set the size of the bitmap to something larger than te size of you desktop. To avoid this error you can create a Device Independent bitmap in the following way:

bmp := TBitmap.Create;
bmp.HandleType := bmDIB;
bmp.Width := Printer.PageWidth;
bmp.Height := Printer.PageHeight; 

Whether you need this solution depends on the capabilities of your video card. We had this error a lot in terminal server situations where not much video RAM was allocated to one session. Using this solution you force Delphi to use normal RAM for your bitmap instead of memory on your video card.

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

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;

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

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.

It's not the JPEG format: the spec allows bitmaps as large as 32767x32767 pixels.

The problem is the huge mem consumption of big bitmaps, and the TCanvas limits that ultimately can be traced down to the Windows platform.

My NativeJpg library decodes the JPEG processing separate from visualisation, and you can e.g. save such a JPEG using "strip by strip", with more manageable bitmap tiles as a result.

NativeJpg is open-source and you can download this lib here: http://www.simdesign.nl/forum/viewforum.php?f=16

Look at the tiledemo to see how to create and save huge artificial JPEG images.

Kind regards, Nils

To consume less memory, you can always try create smaller bitmaps. lets say you divide the printer height by 10, or set a max height to 1000. Just a suggestion, not sure if it is applicable in your case. It does result more than one image per page.

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;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top