使用Delphi处理大图像以保存为.jpeg

时间:2009-10-28 20:09:11

标签: delphi image-processing jpeg delphi-7

在Delphi 7中,我有一个使用TCanvas组件输出一些信息的库。生成的图像大约为4800 * 6000像素,我想将其打印并保存为.jpeg

为了实现这一点,我创建了一个TBitmap并将其Canvas作为参数提供给库,然后我将位图分配给jpeg。显然,这会占用太多内存,因为我在尝试设置位图的宽度和高度时遇到异常,说“没有足够的存储空间来处理此命令。”

// 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();

我做错了什么?我可以将Printer.Canvas直接保存为.jpeg文件吗?

编辑:更新的图像尺寸近似值从2000 * 2000到4800 * 6000

10 个答案:

答案 0 :(得分:3)

您应该能够使用Graphic32中的TBitmap32处理大型位图(http://www.graphics32.org/wiki/

答案 1 :(得分:2)

正如Ben Ziegler建议的那样,你应该在确定bmp的大小之前将bmp的pixelformat设置为某些东西。这一切都有所不同。

答案 2 :(得分:1)

如果将位图的大小设置为大于桌面的大小,则会发生此错误。要避免此错误,您可以按以下方式创建设备无关位图:

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

是否需要此解决方案取决于视频卡的功能。我们在终端服务器情况下遇到了这个错误,在这种情况下,一个会话没有分配太多的视频RAM。使用此解决方案,您可以强制Delphi为您的位图使用普通RAM而不是视频卡上的内存。

答案 3 :(得分:0)

Delphi的TBitmap类在处理如此大的位图时遇到问题。不,你不能将TCanvas直接保存到.jpg文件。

答案 4 :(得分:0)

我在我的机器上尝试了以下代码(Windows XP,Delphi 2006),并且没有收到任何异常。您使用的操作系统是什么?

  procedure TForm3.Button3Click(Sender: TObject);
  var
     bmp : TBitmap;
  begin
     bmp := TBitmap.Create;
     bmp.PixelFormat := pf32bit;
     bmp.Width := 6000;
     bmp.Height := 4800;
     bmp.Free;
  end;

答案 5 :(得分:0)

正如mghie所说: 这在很大程度上取决于您的系统 见EFGs computer lab on large bitmaps

答案 6 :(得分:0)

尝试将PixelFormat设置为pf32bit或pf24bit(如Ben Ziegler的例子),在大多数情况下,这个PixelFormat可以解决问题(我记得,它主要是在XP上)。 您可以找到更多信息here

答案 7 :(得分:0)

这不是JPEG格式:规范允许位图大到32767x32767像素。

问题在于大位图的大量内存消耗, TCanvas限制最终可以追溯到Windows平台。

我的NativeJpg库将JPEG处理与可视化分开解码,您可以例如使用“逐条带”保存这样的JPEG,结果是更易于管理的位图图块。

NativeJpg是开源的,你可以在这里下载这个lib: http://www.simdesign.nl/forum/viewforum.php?f=16

查看tiledemo,了解如何创建和保存巨大的人工JPEG图像。

亲切的问候,Nils

答案 8 :(得分:0)

要消耗更少的内存,您始终可以尝试创建更小的位图。假设您将打印机高度除以10,或将最大高度设置为1000.只是一个建议,不确定它是否适用于您的情况。它确实每页产生多个图像。

答案 9 :(得分:-1)

不确定这是否有效或有帮助。但是我们创建了一个将组件保存到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;