我想使用尽可能少的RAM打开一些相对较大的文件(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对象。
有没有办法从磁盘加载图像,同时保持mem足迹小?
-
(测试文件:1.JPG 2.74MB 3264x1840 pix)
答案 0 :(得分:1)
信封背面计算得出6百万像素。假设32位颜色,则需要24MB。
你不会做比当前代码更好的事情。
答案 1 :(得分:1)
内存使用量不是来自JPEG库,而是来自您使用它的方式。
如果将JPEG转换为TBitmap,它将创建位图资源,然后将JPEG解压缩到位图内存缓冲区中。
您可以直接从JPEG内容绘制到屏幕中。根据JPEG实现,它将使用(或不使用)临时TBitmap
。
您不依赖于Borland提供的JPEG单元。
例如,您可以尝试直接从未压缩的内存缓冲区调用StretchDIBits()
Windows API(此代码从我们的SSE JPEG decoder中提取):
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;
创建一个巨大的位图有时是不可能的(至少在Windows XP下),因为它使用共享的GDI资源,而使用普通RAM和StretchDIBits
将始终有效,即使对于大量内容也是如此。您可以创建一个内存映射文件来处理二进制内容,但只需一次分配内存就足够了(Windows只有在内存不足时才会使用硬盘)。使用今天的PC,即使是大图片,也应该有足够的RAM。 (即使你的3264x1840像素,17 MB也不是什么大问题。)
然后,从包含原始像素三元组的全局未压缩内存缓冲区中,您可以使用
一个较小的位图对应于图片的一个区域,然后使用StretchDIBits(aBitmap.Handle,...
在该区域上工作。它将使用更少的GDI资源。
你也可以依赖GDI +绘图,它将绘制它而不需要任何临时位图。参见例如这OpenSource unit。从我们的测试来看,它非常快,可以在没有任何TBitmap
的情况下使用。你也可以只询问整个图片的一个区域,并在你的位图画布上使用GDI +绘制它:这将使用更少的RAM。并且你的exe将比默认的JPEG单元小一点。而且您将能够显示并保存不仅是JPEG,还有GIF和TIFF格式。
如果您想进一步减少内存使用量,则必须直接调用最低级别的JPEG库。它只能解压缩JPEG的区域。所以你可以最小化使用的RAM。你可能会{4}用Delphi,有点旧,但仍在工作。