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) - IntPtr(aBitmap.ScanLine); 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.