[fpc-pascal] Performance problems with Image Conversions

Michael Van Canneyt michael at freepascal.org
Sun Feb 24 11:44:42 CET 2013

On Sat, 23 Feb 2013, Andrew Brunner wrote:

> Hi guys,
> I just finished (a beta) of a collage app for Aurawin.  I'm seeing a huge 
> load on my servers when scaling images using the Image factory classes for 
> JPEG, and PNG.
> Prefix:
> 6 Core AMD 64 32GB RAM Ubuntu 12.10 x64
> 8 Core AMD 64 32GB RAM Ubuntu 12.10 x64
> FPC/Lazarus daily svn/trunk
> Overview:
> 1.) end-user grabs references to files (stored on my server)
> 2.) back-end core object scales camera photos to something more net friendly 
> 512px max to scale.
> 3.) server streams photos back to client over the web and
> 4.) server assembles XML stream of Mime encoded file data for things like
> https://aurawin.com/cb?3

Try to get rid of the XML, it is always going to be slow.
Using XML can slow your applications with a factor 6.
If you are mime-encoding an image, it'll be even more.

> Specifics
> The pics in this sample take about 30 seconds to go from their originals to 
> 512px.  The app waits for the collage to save to the cloud.  The problem gets 
> worse for larger collages with more images.
> iX,iY are no larger than 512
> class function Image.Transform(Stream:TStream; var 
> sContentType,srcKind,dstKind:string; var iX,iY:Integer):boolean;
> var
>  FReader      : TFPCustomImageReader;
>  FWriter      : TFPCustomImageWriter;
>  cReader      : TFPCustomImageReaderClass;
>  cWriter      : TFPCustomImageWriterClass;
>  Factor       : Double;
>  FTransparent : boolean;
>  dstImg       : TFPMemoryImage;
>  srcImg       : TFPMemoryImage;
>  srcCanvas    : TFPImageCanvas;
>  dstCanvas    : TFPImageCanvas;
>  procedure FreeImageData;
>  begin
>    if (srcCanvas<>nil) then
>      srcCanvas.Free();

Do a FreeAndNil(srcCanvas) here. 
1. Free already checks if the pointer is not nil.
   You do not need to check again.
2. FreeAndNil will make sure the pointer is Nil

>      srcImg:=TFPMemoryImage.Create(0,0);

Do not use TFPMemoryImage. 
It is a catch-all memory format, not optimized at all, using 64 bits for the images.
Instead, use e.g. TFPCompactImgRGBA8Bit if you need alpha or TFPCompactImgRGB8Bit if you do not need Alpha.

>          dstImg:=TFPMemoryImage.Create(iX,iY);
>          dstImg.UsePalette:=false;
>          dstCanvas:=TFPImageCanvas.create(dstImg);
>          dstCanvas.StretchDraw(0,0,iX,iY,srcImg);

Phew, this is also a real killer.

Do not draw on a canvas with stretchdraw. That will be slow as well; 
Rather, attempt to manipulate the image in memory by doing a stretch directly.
Choose an algorithm which is fast. The default interpolation will result in 
quite a lot of calculations.


More information about the fpc-pascal mailing list