Jpegli, a revolutionary JPEG coding library, was recently introduced by the Google Open-Source Blog. This innovative tool maintains backward compatibility with the conventional JPEG standard while offering a significant improvement in compression ratio – approximately 35% for high-quality JPEG compression.
The primary objective of Jpegli is to surpass the efficiency and speed of traditional JPEG handling libraries. It adheres to the original JPEG standard for encoding and decoding, ensuring that compressed images retain their clarity and exhibit fewer artifacts. Furthermore, Jpegli boasts impressive performance, comparable to renowned libraries such as libjpeg-turbo and MozJPEG. It also supports encoding with more than 10 bits per component, enhancing the quality of the resultant images.
This guide will walk you through the process of creating a Jpegli image using its encoder and decoder implementation.
Step-by-Step Guide Constructing a Jpegli Image
The Jpegli JPEG encoder and decoder implementation is a component of the JPEG XL image format reference implementation, libjxl. The source code is available on GitHub for public access. Over time, it is anticipated that Jpegli will be incorporated into various libraries and programs. Users will then be able to install JPEG XL’s Jpegli support from the libjxl-tools package in their preferred Linux distribution.
In the interim, the tools/cjpegli and tools/djpegli can be utilized by building libjxl from the source. The following instructions have been tested in Ubuntu 22.04:
git clone https://github.com/libjxl/libjxl.git --recursive --shallow-submodules cd libjxl sudo apt install cmake pkg-config libbrotli-dev sudo apt install clang libstdc++-12-dev export CC=clang CXX=clang++ cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=OFF .. cmake --build . -- -j$(nproc)
Upon successful completion of the build, the usage for the decompression and compression utilities can be checked. The djpegli utility is used for decompression, and its usage is as follows:
jaufranc@CNX-LAPTOP-5:~/edev/sandbox/libjxl/build$ tools/djpegli Usage: tools/djpegli INPUT OUTPUT [OPTIONS...] INPUT The JPG input file. OUTPUT The output can be PNG, PFM or PPM/PGM/PNM --disable_output No output file will be written (for benchmarking) --bitdepth=8|16 Sets the output bitdepth for integer based formats, can be 8 (default) or 16. Has no impact on PFM output. --num_reps=N Sets the number of times to decompress the image. Used for benchmarking, the default is 1. --quiet Silence output (except for errors). -h, --help Prints this help message. All options are shown above.
The cjpegli utility is used for compression, and its usage is as follows:
jaufranc@CNX-LAPTOP-5:~/edev/sandbox/libjxl/build$ tools/cjpegli Usage: tools/cjpegli INPUT OUTPUT [OPTIONS...] INPUT the input can be PNG, APNG, GIF, EXR, PPM, PFM, or PGX OUTPUT the compressed JPG output file -d maxError, --distance=maxError Max. butteraugli distance, lower = higher quality. 1.0 = visually lossless (default). Recommended range: 0.5 .. 3.0. Allowed range: 0.0 ... 25.0. Mutually exclusive with --quality and --target_size. -q QUALITY, --quality=QUALITY Quality setting (is remapped to --distance). Default is quality 90. Quality values roughly match libjpeg quality. Recommended range: 68 .. 96. Allowed range: 1 .. 100. Mutually exclusive with --distance and --target_size. --chroma_subsampling=444|440|422|420 Chroma subsampling setting. -p N, --progressive_level=N Progressive level setting. Range: 0 .. 2. Default: 2. Higher number is more scans, 0 means sequential. -v, --verbose Verbose output; can be repeated, also applies to help (!). -h, --help Prints this help message. Add -v (up to a total of 2 times) to see more options.
A PNG screenshot was used for testing the compression first:
jaufranc@CNX-LAPTOP-5:~/edev/sandbox/libjxl/build/tools$ time ./cjpegli screenshot.png screenshot.jpg Read 1291x1132 image, 164009 bytes. Encoding [YUV d1.000 AQ p2 OPT] Compressed to 137052 bytes (0.750 bpp). 1291 x 1132, 45.812 MP/s [45.81, 45.81], , 1 reps, 1 threads. real 0m0.057s user 0m0.044s sys 0m0.012s
The task was completed successfully, and the resulting file could be opened with the GNOME image viewer. There were very small differences against the PNG file in terms of quality after zooming on specific zones (text), but the file size was smaller:
ls -lh screenshot.* -rw-rw-r-- 1 jaufranc jaufranc 134K Apr 4 17:49 screenshot.jpg -rw-rw-r-- 1 jaufranc jaufranc 161K Apr 4 17:48 screenshot.png
The decompress command works in a similar way:
$ time ./djpegli screenshot.jpg screenshot-decode.png Read 137052 compressed bytes. 1291 x 1132, 42.052 MP/s [42.05, 42.05], , 1 reps, 1 threads. real 0m0.097s user 0m0.078s sys 0m0.013s
The resulting PNG file is much larger than the original, but that’s normal due to the artifact created by the JPEG compression:
$ ls -l screenshot* -rw-rw-r-- 1 jaufranc jaufranc 330728 Apr 4 18:06 screenshot-decode.png -rw-rw-r-- 1 jaufranc jaufranc 137052 Apr 4 17:49 screenshot.jpg -rw-rw-r-- 1 jaufranc jaufranc 164009 Apr 4 17:48 screenshot.png
It’s easy to try with various image files and compare the results against jpeg-turbo, MozJPEG, or graphical tools like GIMP, making sure to use the same compression settings. This allows for a comprehensive evaluation of the performance and quality of Jpegli.