Delphi 使用尽可能少的内存打开图像

Delphi 使用尽可能少的内存打开图像,delphi,graphics,Delphi,Graphics,我想用尽可能少的内存打开一些相对较大的文件(jpg、gif、bmp)。 在我的程序中,我需要将所有打开的文件转换为BMP,以便我可以处理它们。但是,如果使用经典转换代码,从JPG到BMP的转换需要27.1MB的RAM: function ConvertJPG2BMP(FullFileName: string; BMP: TBitmap); VAR JPG: TJpegImage; begin JPG:= TJpegImage.Create; TRY TRY JPG.Load

我想用尽可能少的内存打开一些相对较大的文件(jpg、gif、bmp)。 在我的程序中,我需要将所有打开的文件转换为BMP,以便我可以处理它们。但是,如果使用经典转换代码,从JPG到BMP的转换需要27.1MB的RAM:

function ConvertJPG2BMP(FullFileName: string; BMP: TBitmap);
VAR JPG:  TJpegImage;
begin
 JPG:= TJpegImage.Create;
 TRY
   TRY
     JPG.LoadFromFile(FullFileName);
     BMP.Assign(JPG);
   EXCEPT
   END;
 FINALLY
   FreeAndNil(JPG);
 end;
end;
因为它使用两个图像(一个jpeg,然后传输到位图)

--

但是,如果我使用TPicture加载文件,我只使用7.1MB的RAM。但是在本例中,TPicture.Bitmap是空的,我需要一个有效的TBitmap对象

有没有办法在保持内存占用空间小的同时从磁盘加载映像

--


(测试文件:1.JPG 2.74MB 3264x1840 pix)

信封背面的计算给出了600万像素。假设是32位的颜色,这将使您的容量达到24MB


您不会比当前代码做得更好。

内存使用不是来自JPEG库,而是来自您使用它的方式

如果将JPEG转换为TBitmap,它将创建位图资源,然后将JPEG解压缩到位图内存缓冲区中


您可以直接从JPEG内容绘制到屏幕中。根据JPEG实现,它将使用(或不使用)临时
TBitmap

您没有绑定到Borland提供的JPEG单元

例如,您可以尝试从未压缩的内存缓冲区直接调用
stretchibits()
windows API,因此(此代码是从我们的:

创建一个巨大的位图有时是不可能的(至少在Windows XP下是不可能的),因为它使用共享的GDI资源,而使用普通RAM和
stretchibits
将始终有效,即使对于巨大的内容也是如此。您可以创建一个内存映射文件来处理二进制内容,但只需立即分配内存就足够了(而且Windows只有在内存不足时才会使用硬盘)。对于今天的个人电脑,你应该有足够的内存,即使是大图片。(即使对于3264x1840像素,17MB也不是什么大问题)

然后,从这个包含原始像素三元组的全局未压缩内存缓冲区中,可以使用 与图片区域相对应的较小位图,然后使用
stretchibits(aBitmap.Handle,
)处理该区域。它将使用较少的GDI资源

例如,您也可以依赖GDI+绘图,它将在不使用任何临时位图的情况下进行绘制。请参见此示例。根据我们的测试,它非常快,可以在不使用任何
TBitmap
的情况下使用。您也可以只要求整个图片的一个区域,并在位图画布上使用GDI+进行绘制:这将使用更少的RAM。您的exe将e比默认的JPEG单位小一点。您不仅可以显示和保存JPEG格式,还可以显示和保存GIF和TIFF格式


如果您想进一步减少内存使用,您必须直接调用最低级别的JPEG库。它只能解压缩JPEG的一个区域。因此,您可以最小化使用的RAM。您可以使用Delphi,有点旧,但仍在工作。

嗨,David。我几乎同意您的演算:我认为位图像素是多余的3字节为红色(无透明度)。这将导致17.1MB。出于对齐的原因,即使是24位颜色,每个像素也会消耗32位。此外,TPicture如何以7.1 MB的速度加载jpeg文件?我对jpeg一无所知。为了便于加载和保存,我猜磁盘上也会有4个字节。Windows位图优化了速度而不是大小。为什么需要保持内存使用率较低?现代PC通常有如此多的内存,以至于30 MB几乎不明显。如果你真的想保持低内存使用率,你可能需要“逐块”解构JPEG文件。同意Harriv的解码意见,微小的内存占用需要a)单独解码JPEG 8×8px块,b)将光栅数据写入内存映射的DIB部分。TJPEG图像和TBitmap无法分别符合a)和b)的要求。GPL?关于“只需购买更多内存”的讨论,为了便于比较,请将JPEG文件转换为BMP并直接加载BMP文件。当你跳过JPEG时,你的程序会消耗多少内存?@Harriv,我想这是程序员自然希望最小化不必要的内存使用。OP的任务不需要在内存中存储整个光栅。此外,OP的测试光栅非常小,天真的方法会吃得更多@祭坛,有一个比较的想法-TJPEGImage。比例会影响解码内存占用,请确保竞争方法不会以这种方式优化解压缩。那么问题中OP说我需要将所有打开的文件转换为BMP以便我可以处理它们的那部分呢。@David 1。您可以在不使用全局TBitmap的情况下处理二进制内容,但在较小的
TBitmap上使用
StretchDIBits
。Handle
,只映射整个图片的一个区域。2.若你们能够直接处理JPEG的区域(我的最后一段),你们将使用更少的内存和更小的位图。我相信你们可以这样做,若你们愿意的话。我不会因为你的答案没有解决OP提出的问题而否决你的答案。嗨,Bouchez。我以前尝试过SSE Jpeg解码器,但它不能处理所有Jpeg文件。“您可以直接从Jpeg内容绘制到屏幕上”-图像从未在屏幕上绘制。我对它进行了一些处理,然后将其保存为BMP。我认为,如果我将处理应用于小块,其中一些将无法很好地工作,因为它们使用相邻像素来计算内容。在大图像被切成小块的地方,可能会出现一些奇怪的线条。
procedure TJpegDecode.DrawTo(Canvas: TCanvas; X, Y: integer);
var BMI: TBitmapInfo;
begin
  if @self=nil then
    exit;
  ToBMI(BMI);
  StretchDIBits(Canvas.Handle,X,Y,width,height,0,0,width,height,pRGB,
   BMI,DIB_RGB_COLORS,SrcCopy);
end;