'Jpeg to Bmp conversion takes unreasonable amount of time

I have this function that takes 4.2 seconds to convert a jpg to bmp. Why it takes so long? Can I make if faster?
IrfanView loads and converts the file in only a fraction of that time.

I thought that is spends most of the time in JPG.LoadFromFile. But when I measured the time I was surprised to see it spends most of the time in BMP.Assing(JPG).

function ConvertJPG2BMP(CONST FileName: string): TBitmap;
VAR JPG: TJpegImage;
begin
 Result:= NIL;
 JPG:= TJpegImage.Create;
 TRY
   JPG.LoadFromFile(FileName);
   if  (JPG.Width > 0) AND (JPG.Width  < 32768)
   AND (JPG.Height> 0) AND (JPG.Height < 32768) then
    begin
      Result:= TBitmap.Create;
      TRY
        Result.HandleType:= bmDIB;

        // Fuji_FinePix_F550.JPG    [3200x1800] [1.44MB] 
        Result.Assign(JPG);  <--- 4 seconds!!
      EXCEPT
        FreeAndNil(Result);
      END;
    end;
 FINALLY
   FreeAndNil(JPG);
 end;
end;


Solution 1:[1]

Since I wanted to test the slightly older functions once, it is a good opportunity to do this now.

The sources used are here

These have been changed a bit in the code below.

Somewhat adapted source code of OP's function ConvertJPG2BMP() (2512 : ms)

enter image description here

function ConvertJPG2BMP(CONST FileName: string): TBitmap;
VAR
 JPG: TJpegImage;
begin
 Result:= NIL;
 JPG:= TJpegImage.Create;
 TRY
   JPG.LoadFromFile(FileName);
   if  (JPG.Width > 0) AND (JPG.Width  < 32768)
   AND (JPG.Height> 0) AND (JPG.Height < 32768) then
    begin
      Result:= TBitmap.Create;
      TRY
        Result.PixelFormat := pf24bit;
        Result.Width  := JPG.Width;
        Result.Height := JPG.Height;
        Result.HandleType:= bmDIB;
        // 2018-10-17 14.04.23.jpg    [2560x1920] [1.66MB]
        Result.Assign(JPG); 
        Result.SaveToFile('F:\ProgramFiles\Embarcadero\dtx\Projects\Bmp-DIB\JPG2BMP.bmp');
      EXCEPT
        FreeAndNil(Result);
      END;
    end;
 FINALLY
   FreeAndNil(JPG);
 end;
end;

The source for the TWICImage usage (296 : ms)

There is another class in Vcl.Graphics? called TWICImage that handles images supported by the Microsoft Imaging Component

Including BMP, GIF, ICO, JPEG, PNG, TIF and Windows Media Photo


enter image description here

procedure LoadImageFromStream(Stream: TStream; Image: TImage);
var
  wic: TWICImage;
  Bitmap: TBitmap;
begin
  Stream.Position := 0;
  wic := TWICImage.Create;
  try
    wic.LoadFromStream(Stream);
    Image.Picture.Assign(wic);
    Bitmap := TBitmap.Create;
    try
      Bitmap.PixelFormat := pf24bit;
      Bitmap.Width  := Image.Picture.Width;
      Bitmap.Height := Image.Picture.Height;
      Bitmap.Canvas.Draw(0, 0, Image.Picture.Graphic);
      Bitmap.SaveToFile('F:\ProgramFiles\Embarcadero\dtx\Projects\Bmp-DIB\TWICImage.bmp');
    finally
      Bitmap.Free;
    end;
  finally
    wic.Free;
  end;
end;

procedure RenderImage(const Filename: string);
var
  fs: TFileStream;
begin
  fs := TFileStream.Create(Filename, fmOpenRead);
  try
    LoadImageFromStream(fs, Form1.Image1);
  finally
    fs.Free;
  end;
end;

GetTickCount for all tested routines.

procedure TForm1.Button1Click(Sender: TObject);
var
MyDIB   : TBitmap;
loadStr : string;
XStart,Xend   : LongWord;
begin
loadStr := 'F:\ProgramFiles\Embarcadero\dtx\Projects\Bmp-DIB\2018-10-17 14.04.23.jpg';
XStart := GetTickCount;

if RadioGroup1.ItemIndex = 0 then MyDIB := ConvertJPG2BMP(loadStr);// ConvertJPG2BMP()
if RadioGroup1.ItemIndex = 1 then TestBmp(loadStr);
if RadioGroup1.ItemIndex = 2 then RenderImage(loadStr);// TWICImage
if RadioGroup1.ItemIndex = 3 then GetOleGraphic(loadStr);

Xend := GetTickCount;
Label1.Caption := IntToStr(xEnd-XStart) + ' : MS' ;

end;

The generated images are identical to the file size only from the function GetOleGraphic() is a smaller file produced with a worse resolution?

here the source used for the GetOleGraphic()

enter image description here

Solution 2:[2]

Here is a compact version of WIC image loader posted by moskito-x above.
Please VOTE HIS answer not mine. My answer here is only to provide the compact version and some details.

{-----------------------------------------------
  Uses TWICImage

  Advantages:  
      8+ times faster than Delphi's JPG function
      Works with: animated GIF, PNG, JPG
  
  Drawbacks: 
      Fails with JPEG2K
      No EXIF support
      Platform dependent
 -----------------------------------------------}

function LoadImageWic(CONST FileName: string): TBitmap;
VAR
   wic: TWICImage;
begin
  wic := TWICImage.Create;
  TRY
   wic.LoadFromFile(FileName);
   Result := TBitmap.Create;
   TRY
     Result.Assign(wic);
   EXCEPT
     FreeAndNil(Result);
   END;
  FINALLY
    FreeAndNil(wic);
  END;
end;

Solution 3:[3]

Just try to decompress the jpeg using our Open Source SynGDIPlus unit.

We found it much faster than the Delphi built-in jpeg.pas unit.

The latest revision can be retrieved from github.

As an alternative, you may try to use our fast Jpeg decoder using SSE2 but it doesn't handle all kind of Jpegs, and it is for Win32 only.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Server Overflow
Solution 2
Solution 3 David Heffernan