开发者

Open an image using as little RAM as possible

I want to open some relative big files (jpg, gif, bmp) using as little RAM as possible. Inside my program I need all open files converted to BMP so I can process them. However the conversion from JPG to BMP takes 27.1MB of RAM if I use the classic conversion code:

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;

because it uses two images (a jpeg that is transferred to a bitmap then).

--

However, if I use a TPicture to load the file, I use onl开发者_运维知识库y 7.1MB of RAM. But in this case the TPicture.Bitmap is empty and I need a valid TBitmap object.

Is there any way to load images from disk while keeping the mem footprint small?

--

(Test file: 1.JPG 2.74MB 3264x1840 pix)


Back of the envelope calculation gives 6 mega pixels. Assuming 32 bit colour this takes you to 24MB.

You aren't going to do any better than your current code.


The memory usage does not come from the JPEG library, but in the way you use it.

If you convert a JPEG into a TBitmap, it will create a bitmap resource, then uncompress the JPEG into the bitmap memory buffer.

You can paint directly from the JPEG content into the screen. Depending on the JPEG implementation, it will use (or not) a temporary TBitmap.

You are not tied to the JPEG unit supplied by Borland.

For instance, you may try calling directly the StretchDIBits() windows API from the uncompressed memory buffer, as such (this code is extracted from our 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;

Creating a huge bitmap is sometimes not possible (at least under Windows XP), because it uses shared GDI resources, whereas using plain RAM and StretchDIBits will always work, even for huge content. You can create a memory mapped file to handle the binary content, but just allocating the memory at once would suffice (and Windows will use hard drive only if short of RAM). With today's PCs, you should have enough RAM available even for big pictures. (17 MB is not a big deal, even for your 3264x1840 pix).

Then, from this global uncompressed memory buffer containing raw pixel triplets, you can use a smaller bitmap corresponding to a region of the picture, then work on the region using StretchDIBits(aBitmap.Handle,.... It will use less GDI resource.

You could also rely for instance on GDI+ drawing, which will draw it without any temporary bitmap. See e.g. this OpenSource unit. From our testing, it's very fast and can be used without any TBitmap. You could also ask only for a region of the whole picture, and draw it using GDI+ on your bitmap canvas: this will use less RAM. And your exe will be a bit smaller than the default JPEG unit. And you'll be able to display and save not only JPEG, but GIF and TIFF formats.

If you want to minimize even further the memory usage, you'll have to call directly the JPEG library, at lowest-level. It's able to uncompress only a region of the JPEG. So you would be able to minimize used RAM. You may try using the IJL library with Delphi, a bit old, but still working.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜