Skip to Content

How to Create Jpegli JPEG Compressed Image

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.

How to Create Jpegli JPEG Compressed Image

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.