TurboJPEG rocks !

Units to support the TurboJPEG library is now available in the DWScript repository, you can find the relevant files in the Libraries\GraphicsLib folder, they have been tested with Delphi 10.3 in both Win32 and Win64. The DLLs are those of the latest 2.05 version.

The TurboJPEG library (aka “libjpeg-turbo”) provides a fast implementation of the libjpeg API, but the files here target the TurboJPEG core, rather than the libjpeg compatibility layer (see its documention).
The TurboJPEG API is less rich, but quite simple to use and very convenient.

Why would you want to use TurboJPEG ?

In my particular case when experimenting with real-time image analysis from a simple webcam (with provided a flow of JPEG images), I found that I could barely keep up, and the culprit turned out to be the LibJPEG implementation used by TJPEGImage. Of course, you can speed things up by decoding at half, quarter or even eighth size, or use multi-threading, but that is not exactly satisfying.

On that particular webcam JPEG flow, TurboJPEG is 20 times faster. With a single thread. End of debate.

As a nice bonus, compared to LibJPEG, using TurboJPEG is a simple affair: if you are working with files and memory buffers, TJ.LoadImage and TJ.SaveImage are all you need.

If you are working with TBitmap, it can still be used quite directly. For instance compressing a 24/32bit TBitmap to a progressive JPEG in memory can be accomplished with:

var format := TJPF_UNKNOWN;
case aBitmap.PixelFormat of
   pf32bit : format := TJPF_BGRA;
   pf24bit : format := TJPF_BGR;
end;
if format <> TJPF_UNKNOWN then begin
   var jpeg := TJ.InitCompress;
   try
      outBuf := nil;  // buffer that will be allocated by TurboJPEG
      outSize := 0;

      // compute the size of a scanline in Bytes
      var pitch := 0; 
      if aBitmap.Height > 1 then
         pitch := IntPtr(aBitmap.ScanLine[0]) - IntPtr(aBitmap.ScanLine[1]);
      if TJ.Compress2(jpeg, aBitmap.ScanLine[aBitmap.Height-1], aBitmap.Width, pitch, 
                      aBitmap.Height, format, @outBuf, @outSize,
                      TJSAMP_420, quality, TJFLAG_PROGRESSIVE or TJFLAG_BOTTOMUP) <> 0 then
         RaiseLastTurboJPEGError(jpeg);
      try
         ...do whatever you want with the JPEG data in outBuf...
      finally
         TJ.Free(outBuf); 
      end;   
   finally
      TJ.Destroy(jpeg);
   end;
end;

An interesting feature of the TurboJPEG functions that is leveraged above is the “pitch” parameter, which allows to specify the size of a ScanLine in bytes. This makes it simple to handle scanline padding, when the size of a scanline is different from Width * PixelSizeInBytes.

For decompression, use TJ.DecompressHeader2 to obtain the size of the decompressed JPEG image, size your TBitmap accordingly, and then use TJ.Decompress2 to decompress directly to it.

The TurboJPEG library can also perform a whole array of JPEG lossless transformations (90° rotations, flips, transpositions and crops). Those are performed on the DCT coefficients, so without requiring a full decompression.

Last but not least, while I did not investigate that aspect much, TurboJPEG compression performance does not come at the expense of size. It produced smaller JPEG files than TJPEGImage at the same quality setting, which hints that either arithmetic coding or a better Huffman compressor is used by default.

One thought on “TurboJPEG rocks !

  1. Thanks. I’ll probably need a 64 bit interface to libJpeg-Turbo in the near future. I already had one for 32 bits. And yes, it’s quite a significant improvement over the build in JPEG support.

Comments are closed.