2
\$\begingroup\$

This Delphi (Seattle 10) routine resizes a JPG image if one of its sizes is larger than AMaxDimension pixels, and gives it a compression factor of ACompressionQuality. Images smaller than 128x128 pixels are left alone. As the name says, it ignores alpha channel.

I'm not an expert in image manipulation and wonder if this can be (substantially) optimized. We see that it takes a long time for larger pictures.

procedure ResizeJPGImageWithoutAlpha(var AJPGImage: TJPegImage; AMaxDimension, ACompressionQuality: Integer);
var
   lBitmap   : TBitmap;
   lFactor   : Real;
   lNewWidth,
   lNewHeight: Integer;
begin
   if (AJPGImage.Width <= 128) and (AJPGImage.Height <= 128) then Exit;

   if AJPGImage.Width > AJPGImage.Height then
      if AJPGImage.Width > AMaxDimension then
         lFactor := AJPGImage.Width
      else
         lFactor := 0
   else
      if AJPGImage.Height > AMaxDimension then
         lFactor := AJPGImage.Height
      else
         lFactor := 0;
   if lFactor <> 0 then
   begin
      lFactor    := lFactor / AMaxDimension;
      lNewWidth  := Trunc(AJPGImage.Width  / lFactor);
      lNewHeight := Trunc(AJPGImage.Height / lFactor);
      lBitmap    := TBitmap.Create;
      try
         lBitmap.Width := lNewWidth;
         lBitmap.Height:= lNewHeight;
         lBitmap.Canvas.StretchDraw(lBitmap.Canvas.Cliprect, AJPGImage);
         // Convert back to JPEG
         AJPGImage.Assign(lBitmap);
      finally
         lBitmap.free;
      end;
   end
   else
      AJPGImage.DIBNeeded;
      // Decompress the jpeg image into a bitmap.
      // DIBNeeded is used when the jpeg image needs a bitmap representation of its image.
      // Compress will not work without that (width/height become 0). The resize code already caused a bitmap.
   AJPGImage.CompressionQuality := ACompressionQuality;
   AJPGImage.Compress;
end;

Notes:

  • Input JPG or PNG types can be anything.
  • We resize to images that have as their largest dimension 128, 1024, 2048 or 4096.
  • On my local machine, if I have large images with dimensions like 7000 or 10000 pixels, it takes 10-11 seconds on the stretchdraw, 0,3 sec for the assignment to the JPG, 0.1 sec on the compression. This code has to run in a web service, so speed is important.
  • I notice that newly created TJPEGImages have these defaults. Maybe there's something to be done with that?

    var   // Default settings for all new TJPEGImage instances
      JPEGDefaults: TJPEGDefaults = (
        CompressionQuality: 90;
        Grayscale: False;
        Performance: jpBestQuality;
        PixelFormat: jf24Bit;         // initialized to match video mode
        ProgressiveDisplay: False;
        ProgressiveEncoding: False;
        Scale: jsFullSize;
        Smoothing: True;
      );
    
\$\endgroup\$
0
1
\$\begingroup\$

I have no particular expertise with this, but here are some random thoughts:

First, you could try resizing the the images in some other application just to get some benchmarks so you can get an idea how slow your code is. I'm thinking of things like Windows Paint, Irfan View, Paint.Net.

Do you have enough ram? I imagine that the images would be expanded out in raw form into a buffer at some stage. If the buffer used 32 bits or 4 bytes per pixel, then a 10,000 * 10,000 image would require 10000 * 10000 * 4 / 1024 / 1024 = 381 MB.

I don't know if StretchDraw will use the graphics hardware on your video card to do the jpeg compression/decompression and resizing. Your video card may (or may not) be a factor.

I think your best bet might be to try some other image manipulation tools or libraries. I'm thinking of things like ImageEn, Envision, Vampyre, ffmpeg, ImageMagick (or PascalMagick).

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy