Processing large images with Delphi for saving as .jpeg
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
you should be able to process large bitmaps using TBitmap32 from Graphic32 (http://www.graphics32.org/wiki/)
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;
精彩评论