#1 Re: Fast JPEG decoder » Please work again on this » 2017-04-20 21:31:22

Fast forward to 2017, Delphi 10.2 Tokyo, Windows 10 x64 Creators Update:

Looks like GDI+ is now faster than JpegDec and JpegTurbo, 12919 x 4719 jpeg:

SynGDIPlus: 692 ms
SynGDIPlus: 689 ms
SynGDIPlus: 692 ms
SynGDIPlus: 681 ms
SynGDIPlus: 701 ms
SynGDIPlus: 686 ms
SynGDIPlus: 687 ms
SynGDIPlus: 693 ms
SynGDIPlus: 686 ms
SynGDIPlus: 681 ms

SSE2 JpegDecoder: 827 ms
SSE2 JpegDecoder: 835 ms
SSE2 JpegDecoder: 842 ms
SSE2 JpegDecoder: 833 ms
SSE2 JpegDecoder: 833 ms
SSE2 JpegDecoder: 848 ms
SSE2 JpegDecoder: 849 ms
SSE2 JpegDecoder: 827 ms
SSE2 JpegDecoder: 833 ms
SSE2 JpegDecoder: 843 ms

libJpeg: 712 ms
libJpeg: 715 ms
libJpeg: 716 ms
libJpeg: 709 ms
libJpeg: 715 ms
libJpeg: 711 ms
libJpeg: 716 ms
libJpeg: 716 ms

#3 GDI+ » 64-bit TJpegImage ignores CompressionQuality » 2014-11-01 14:40:40

Himeko
Replies: 2

There seems to be an issue when using SynGdiPlus.TJpegImage compiled with a 64-bit exe, the CompressionQuality setting is ignored:

Passing a bitmap to the jpeg with CompressionQuality in 32-bit at 100 gives a 280KB jpeg file, while in 64-bit it's 80 KB; setting the value to anything i.e 10 has the same result.

#4 Re: Low level and performance » How to unzip or zip files content » 2014-09-20 13:56:02

That works. In the case of 2 files I found with this issue, "i" was 1233 and 2714 after the loop (I set 65535 max)

Another issue with some other files:

"Zip error: ZIP format size=0"

In 2 cases I found (working fine with winrar etc), both zzipSize and zfullSize were 0

#5 Re: Low level and performance » How to unzip or zip files content » 2014-09-19 23:45:47

Reporting a possible issue: I'm getting an exception "ZIP format." with a very specific zip file, after calling

TZipRead.Create(zip)

it triggers here in SynZip.pas

  for i := 0 to 127 do begin // resources size may be rounded up to alignment
    lhr := @BufZip[Size-sizeof(TLastHeader)];
    if lhr^.signature+1=(LASTHEADER_SIGNATURE+1) then
      break;
    dec(Size);
    if Size<=sizeof(lhr^) then
      break;
  end;
  if lhr^.signature+1<>(LASTHEADER_SIGNATURE+1) then begin
    UnMap;
    raise ESynZipException.Create('ZIP format');
  end;

The file opens fine with winrar and 7zip, and if I make a new file with the contents (unpack and repack with winrar), it works fine as well with SynZip

#7 Re: Low level and performance » How to unzip or zip files content » 2014-09-19 19:56:37

That works great, didn't see the overloads somehow, thanks.

ps: does the board support watching threads? it would be nice to be able to receive email notifications of replies.

#8 Re: Low level and performance » How to unzip or zip files content » 2014-09-19 14:36:22

Congrats, once again your code is the fastest of various I tried:

KAzip (very old component/library, had to update it for unicode/modern delphi)
Delphi's
Synopse

Both for listing and extracting your unit was the fastest after a series of benchmarks (listing the contents of 1000 zips, then extracting 1 a few times over).
Synopse was in both cases some ~10-20% faster than the other 2.

How do you extract a file btw? maybe my proc can be improved someway:

   ss: TZipRead;
   aa: RawByteString;

  ss := TZipRead.Create(zip);
  c := ss.NameToIndex(fil);
  SetLength(aa,ss.Entry[c].infoLocal.zfullSize);
  aa := ss.UnZip(c);
  With TFileStream.Create(s,fmCreate) do begin
    Write(aa[1],ss.Entry[c].infoLocal.zfullSize);
    Free;
  end;

#9 Re: Fast JPEG decoder » Please work again on this » 2014-08-16 12:36:55

Found an ever faster one than all those: the latest libjpeg from this jp guy:
http://cetus.sakura.ne.jp/softlab/jpeg- … html#win32

SynGDIPlus: 981 ms
XE6 jpeg: 5486 ms
Intel JIL: 2912 ms
SSE2 JpegDecoder: 873 ms
JpegTurbo: 766 ms

SSE2 JpegDecoder: 871 ms
SSE2 JpegDecoder: 888 ms
SSE2 JpegDecoder: 889 ms
JpegTurbo: 765 ms
JpegTurbo: 763 ms
JpegTurbo: 761 ms

For smaller files it seems your SSE2 one is still faster though, probably less stuff to init etc.

ps: no way to subscribe to thread replies?

~edit

this is the culprit of the slowdown, the way it converts the jpeg into a bitmap after decompression, slower than the decoding

  // reading image
  jpeg_start_decompress(@jpeg);

  // allocate row
  GetMem(prow, jpeg.output_width * 3);

  Inherited SetSize(jpeg.output_width, jpeg.output_height);
  Inherited PixelFormat := pf24bit;
  For y := 0 To jpeg.output_height - 1 Do
  Begin
    // reading row
   jpeg_read_scanlines(@jpeg, @prow, 1);
   rowD := scanline[y];
    For x := 0 To jpeg.output_width - 1 Do
    Begin
      rowD[x].RgbtRed   := prow[x].rgbtBlue;
      rowD[x].rgbtGreen := prow[x].rgbtGreen;
      rowD[x].rgbtBlue  := prow[x].RgbtRed;
    End;
    // do anything with the data
  End;
  // freeing row
  FreeMem(prow);

#10 Re: Fast JPEG decoder » Stretch jpeg » 2014-08-12 19:44:26

GR32 is very fast for anti-aliased resampling: http://graphics32.org/wiki/Main/Graphics32

I use TKernelResampler + TLanczosKernel for scaling down.

basically,

     GR32, GR32_Resamplers,

load jpeg into a TBitmap32 (assign)
R: TKernelResampler;
R := TKernelResampler.Create(Src);
R.Kernel := TLanczosKernel.Create;
Dst.Draw(Dst.BoundsRect, Src.BoundsRect, Src);

Dst = empty bitmap32
Src = bitmap32 containing the jpeg

#11 Re: Fast JPEG decoder » Please work again on this » 2014-08-12 18:25:57

Thanks smile that's ok, speedup makes up for larger files. I've started changing all my apps that used jpeg/pngimage to GDIPlus after these tests today smile (except for 32-bit only apps that mostly load jpeg, will keep using the SSE2 one there)

Interesting fact:

32-bit load:
SynGDIPlus: 1021 ms
XE6 jpeg: 5626 ms

64-bit load:
SynGDIPlus: 867 ms
XE6 jpeg: 2745 ms

--

32-bit save:
GDIPlus PNG: 1561 ms
XE6 PNG: 3293 ms

64-bit save:
GDIPlus PNG: 1736 ms
XE6 PNG: 4059 ms

#12 Re: Fast JPEG decoder » Please work again on this » 2014-08-12 17:25:29

Windows7 x64

CPU is i5-2500K at 4 Ghz.

#13 Re: Fast JPEG decoder » Please work again on this » 2014-08-12 17:24:10

Saving PNG seems also much faster, however file size is bigger

1622 x 976

GDIPlus PNG: 123 ms 3.32 MB
GDIPlus PNG: 125 ms
XE6 PNG: 480 ms 2.34 MB
XE6 PNG: 484 ms

GDI
aQQH0Jx.png

Delphi
DmbMaOs.png

12919 x 4719

GDIPlus PNG: 6510 ms
GDIPlus PNG: 6612 ms
XE6 PNG: 44193 ms
XE6 PNG: 44436 ms


GDI 103 MB
Delphi 64 MB

GDI
EtTSFGc.png

Delphi
OSN8vc8.png

Saving with Jpeg 100%

SynGDIPlus: 1298 ms
SynGDIPlus: 1283 ms
XE6 jpeg: 5576 ms
XE6 jpeg: 5623 ms

GDI 22,4 MB
XE6 25,2 MB oO

Jpeg 85%

SynGDIPlus: 906 ms
SynGDIPlus: 896 ms
XE6 jpeg: 5573 ms
XE6 jpeg: 5639 ms

#14 Re: Fast JPEG decoder » Please work again on this » 2014-08-12 16:37:59

Oh, now it works with that. Strange I didn't need that for the Jpeg tests before oO

GDIPlus PNG: 1577 ms
GDIPlus PNG: 1547 ms
XE6 PNG: 3450 ms
XE6 PNG: 3449 ms

SynGDIPlus: 987 ms
SynGDIPlus: 967 ms
JpegTurbo: 923 ms
JpegTurbo: 936 ms
SSE2 JpegDecoder: 885 ms
SSE2 JpegDecoder: 892 ms
XE6 jpeg: 5587 ms
XE6 jpeg: 5596 ms
Intel JIL: 2942 ms
Intel JIL: 2934 ms

#15 Re: Fast JPEG decoder » Please work again on this » 2014-08-12 16:11:47

Same results with SynPicture which is basically the same

     k: TSynPicture;
begin
//  p := SynGDIPlus.TPNGImage.Create;
k := TSynPicture.Create;
  PerfTimerInit;
k.LoadFromFile('z:\bigjpeg.png');
//  p.LoadFromFile('z:\bigjpeg.png');
  b := k.ToBitmap;
  x := PerfTimerStopMS;
  k.Free;
  b.Free;
  Memo1.Lines.Add('GDIPlus PNG: '+IntToStr(x)+' ms');
end;

= 0ms and empty bitmap

#16 Re: Fast JPEG decoder » Please work again on this » 2014-08-12 14:12:35

Btw is there a special way to load PNG through GDIPlus? I was testing the same for PNG with XE6 vs GDI+, but the image comes out empty

procedure TForm1.Button7Click(Sender: TObject);
Var  p: SynGDIPlus.TPNGImage;
     x: Int64;
     b: TBitmap;
begin
  p := SynGDIPlus.TPNGImage.Create;
  PerfTimerInit;
  p.LoadFromFile('z:\bigjpeg.png');
  b := p.ToBitmap;
  x := PerfTimerStopMS;
  p.Free;
  b.Free;
  Memo1.Lines.Add('GDIPlus PNG: '+IntToStr(x)+' ms');
end;

#17 Re: Fast JPEG decoder » Please work again on this » 2014-08-12 13:44:25

Well I guess the GDI one is not THAT much slower than the SSE2, but why use it vs a faster decoder smile

I always use a failsafe in case the jpeg type isn't supported anyway. Guess I'll change that to use GDI version when it fails (would rather not include the extra DLLs for libjpegturbo).

Seeing that it's so fast, I thought maybe further optimizations are possible with later extensions.

function FastJpegFileToBitmap(fle: string): Graphics.TBitmap;
Var PJ: PJpegDecode;
     j: TJpegImage;
     m: TMemoryStream;
     err: TJpegDecodeError;
begin
  Result := nil;

  m := TMemoryStream.Create;
  With m do begin
    Try
      LoadFromFile(fle);
    Except
      m.Free;
      Exit;
    End;
    try
      Err := jpegdec.JpegDecode(Memory,Size,PJ);
    except
      On E:Exception
       do ShowMessage('JpegDecode Error: '+fle+' / '+e.Message);
    end;
    if Err <> JPEG_SUCCESS then begin
      m.Free;
      PJ^.Free;
      // use default
      j := TJPEGImage.Create;
      j.Performance := jpBestSpeed;
      try
        Result := Graphics.TBitmap.Create;
        j.LoadFromFile(fle);
        With Result do begin
          Height := j.Height;
          Width  := j.Width;
          Assign(j);
        end;
      except
        FreeAndNil(Result);
        FreeAndNil(j);
        Exit;
      end;
      FreeAndNil(j);
      Exit;
    end;
    // SSE Jpeg success
    Result := PJ^.ToBitmap;
    PJ^.Free;
  end;
  m.Free;
end;

#18 Re: Fast JPEG decoder » Please work again on this » 2014-08-12 09:01:02

It seems to be still faster than libJpegTurbo (2012)

https://code.google.com/p/delphi-libjpeg-turbo/

JpegTurbo: 913 ms
JpegTurbo: 929 ms
JpegTurbo: 943 ms
JpegTurbo: 954 ms

SSE2 JpegDecoder: 890 ms
SSE2 JpegDecoder: 897 ms
SSE2 JpegDecoder: 907 ms
SSE2 JpegDecoder: 907 ms

#19 Re: Fast JPEG decoder » Please work again on this » 2014-08-12 08:37:02

711x400 jpeg

SynGDIPlus: 6 ms
XE6 jpeg: 28 ms
Intel JIL: 12 ms
SSE2 JpegDecoder: 3 ms

SynGDIPlus: 5 ms
XE6 jpeg: 21 ms
Intel JIL: 16 ms
SSE2 JpegDecoder: 3 ms

SynGDIPlus: 6 ms
XE6 jpeg: 35 ms
Intel JIL: 20 ms
SSE2 JpegDecoder: 3 ms

#20 Re: Fast JPEG decoder » Please work again on this » 2014-08-12 08:30:13

Got any sample code to use that in Delphi?

Did a quick test, your decoder is really impressive smile

25,2 MB jpeg file of 12919 x 4719 loaded from a RAMdisk:

myCJNmC.png

SynGDIPlus: 976 ms
SynGDIPlus: 1016 ms
SynGDIPlus: 1001 ms
SSE2 JpegDecoder: 914 ms
SSE2 JpegDecoder: 909 ms
SSE2 JpegDecoder: 893 ms

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, jpeg;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    Button2: TButton;
    Button3: TButton;
    Button4: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

Uses DebugStuff,SynPDF,SynGDIPlus,MyJpeg,MyGraphicsStuff;

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
Var  j: SynGDIPlus.TJpegImage;
     b: TBitmap;
     x: Int64;
begin
  j := SynGDIPlus.TJpegImage.Create;
  PerfTimerInit;
  j.LoadFromFile('z:\bigjpeg.jpg');
  b := j.ToBitmap;
  x := PerfTimerStopMS;
  j.Free;
  b.Free;
  Memo1.Lines.Add('SynGDIPlus: '+IntToStr(x)+' ms');
end;

procedure TForm1.Button2Click(Sender: TObject);
Var  j: jpeg.TJpegImage;
     x: Int64;
     b: TBitmap;
begin
  j := jpeg.TJpegImage.Create;
  b := TBitmap.Create;
  PerfTimerInit;
  j.LoadFromFile('z:\bigjpeg.jpg');
  //j.DIBNeeded;
  b.Assign(j);
  x := PerfTimerStopMS;
  j.Free;
  Memo1.Lines.Add('XE6 jpeg: '+IntToStr(x)+' ms');
end;

procedure TForm1.Button3Click(Sender: TObject);
Var  j: MyJpeg.TJpegImage;
     x: Int64;
     b: TBitmap;
begin
  j := MyJpeg.TJpegImage.Create;
  b := TBitmap.Create;
  PerfTimerInit;
  j.LoadFromFile('z:\bigjpeg.jpg');
  b.Assign(j);
  x := PerfTimerStopMS;
  j.Free;
  b.Free;
  Memo1.Lines.Add('Intel JIL: '+IntToStr(x)+' ms');
end;

procedure TForm1.Button4Click(Sender: TObject);
Var  x: Int64;
     b: TBitmap;
begin
  // jpegdec.JpegDecode(Memory,Size,PJ);
  PerfTimerInit;
  b := FastJpegFileToBitmap('z:\bigjpeg.jpg');
  x := PerfTimerStopMS;
  b.Free;
  Memo1.Lines.Add('SSE2 JpegDecoder: '+IntToStr(x)+' ms');
end;

end.

#21 Fast JPEG decoder » Please work again on this » 2014-08-12 07:48:32

Himeko
Replies: 20

Hi, I've been using this for a while and so far it's still the fastest decoder available for Delphi to my knowledge:

5-8 times faster than XE6 TJpegImage
3 times faster than the older Intel's libJpeg (IJL 1.5/2.0)
25-50% faster than libJpeg9a used in FreeImage (http://freeimage.sourceforge.net/features.html)

Maybe you could work on this again some day smile

Board footer

Powered by FluxBB