[fpc-pascal] Performance problems with Image Conversions

Andrew Brunner atbrunner at aurawin.com
Sun Feb 24 05:58:08 CET 2013


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

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();
     if (dstCanvas<>nil) then
       dstCanvas.Free();
     if (FReader<>nil) then
       FReader.Free();
     if FWriter<>nil then
       FWriter.Free();
     if srcImg<>nil then
       srcImg.Free();
     if dstImg<>nil then
       dstImg.Free();
   end;
begin
   Result:=false;
   if SameText(srcKind,Image.Kind.GIF.Name) then begin
     sContentType:=hHTTP.ctPNG;
     dstKind:=Image.Kind.PNG.Name;
     FTransparent:=true;
   end else if SameText(srcKind,Image.Kind.PNG.Name) then begin
     dstKind:=Image.Kind.PNG.Name;
     FTransparent:=true;
   end else begin
     sContentType:=hHTTP.ctJPG;
     dstKind:=Image.Kind.JPG.Name;
     FTransparent:=false;
   end;
   cReader:=FPImage.ImageHandlers.ImageReader[srcKind];
   cWriter:=FPImage.ImageHandlers.ImageWriter[dstKind];
   dstCanvas:=nil; srcCanvas:=nil; FReader:=nil; FWriter:=nil; 
srcImg:=nil; dstImg:=nil;
   Result:=(cReader<>nil) and (cWriter<>nil);
   if Result then begin
     Try
       FReader:=cReader.Create();
       FWriter:=cWriter.Create();

       if SameText(dstKind,Image.Kind.PNG.Name) then begin
         TFPWriterPNG(FWriter).Indexed:=false;
         TFPWriterPNG(FWriter).UseAlpha:=true;
       end;

       srcImg:=TFPMemoryImage.Create(0,0);
       srcImg.UsePalette:=false;
       Stream.Position:=0;
       Try
         srcImg.LoadFromStream(Stream,FReader);
         Stream.Position:=0;

         if (srcImg.Width>=srcImg.Height) then begin
           Factor:=iX/srcImg.Width;
         end else begin
           Factor:=iY/srcImg.Height;
         end;

         if (srcImg.Width>iX) or (srcImg.Height>iY) then begin
           if FTransparent then begin
             if SameText(srcKind,Image.Kind.GIF.Name) then begin
               FTransparent:=TFPReaderGIF(FReader).Transparent;
               TFPWriterPNG(FWriter).UseAlpha:=true;
             end;
           end;

           iX:= Round(srcImg.Width * Factor);
           iY:= Round(srcImg.Height * Factor);

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

           Stream.Size:=0;
           dstImg.SaveToStream(Stream,FWriter);
           Stream.Position:=0;
           Result:=true;
         end;
       Except
         Stream.Size:=0;
         Stream.Position:=0;
         Result:=false;
       end;
     Finally
       FreeImageData();
     end;
   end;
end;

Further, when a user views images via my preview app, I don't send the 
originals, I scale those too using the same methods.  The speed is 
killing my server's performance.

Does anyone have any idea how to speed up the underlining code?

-- 
Andrew Brunner

Aurawin LLC
15843 Garrison Circle
Austin, TX 78717

https://aurawin.com

Aurawin is a great new way to store, share, and explore all your content
featuring our innovative cloud social computing platform.



More information about the fpc-pascal mailing list