All formats

mozjpeg

LanguageC (usable from C++)
LicenseIJG License, BSD-3-Clause and zlib (permissive, same as libjpeg-turbo)
Repositorygithub.com/mozilla/mozjpeg
DocumentationREADME-mozilla.txt (extensions), libjpeg.txt (API)
Depends onnothing (libpng and zlib optional, for PNG input in cjpeg)
Read / writeyes / yes; its value is in encoding

mozjpeg is a fork of libjpeg-turbo that tunes the encoder for file size. With the same quality setting it produces files 5-15% smaller than libjpeg-turbo with the same or better visual quality. It does this with:

The library is API and ABI compatible with libjpeg (the jpeglib.h API) and includes the TurboJPEG API of the libjpeg-turbo 2.x line (tjCompress2, not the newer tj3* functions). Encoding is several times slower than libjpeg-turbo; decoding is the same code. Use it for images you compress once and serve many times. Squoosh, ImageOptim and libvips (when built against it) use mozjpeg.

Installation#

mozjpeg installs the same library names as libjpeg-turbo, so distributions don’t package it as a system library:

Shell
# macOS (keg-only: not linked into /usr/local, so it doesn't replace jpeg-turbo)
brew install mozjpeg
# Windows / Linux (vcpkg)
vcpkg install mozjpeg
# from source (needs CMake and NASM)
git clone https://github.com/mozilla/mozjpeg.git
cd mozjpeg && mkdir build && cd build
cmake -G"Unix Makefiles" -DCMAKE_INSTALL_PREFIX=/opt/mozjpeg ..
make && sudo make install

Link against /opt/mozjpeg/lib (or the Homebrew prefix) explicitly so you don’t pick up the system libjpeg-turbo.

Basic usage: compress an RGB buffer to JPEG#

With no extra calls, jpeg_set_defaults in mozjpeg selects the JCP_MAX_COMPRESSION profile: progressive, trellis quantization and optimized scans are on:

C
#include <stdio.h>
#include <jpeglib.h>

int save_jpeg(const char *path, const unsigned char *rgb, int width, int height, int quality) {
    FILE *out = fopen(path, "wb");
    if (!out) return 1;

    struct jpeg_compress_struct cinfo;
    struct jpeg_error_mgr jerr;
    cinfo.err = jpeg_std_error(&jerr);  // default handler prints and exits on error
    jpeg_create_compress(&cinfo);
    jpeg_stdio_dest(&cinfo, out);

    cinfo.image_width = width;
    cinfo.image_height = height;
    cinfo.input_components = 3;
    cinfo.in_color_space = JCS_RGB;
    jpeg_set_defaults(&cinfo);              // mozjpeg profile: smallest output
    jpeg_set_quality(&cinfo, quality, TRUE);

    jpeg_start_compress(&cinfo, TRUE);
    while (cinfo.next_scanline < cinfo.image_height) {
        JSAMPROW row = (JSAMPROW)&rgb[(size_t)cinfo.next_scanline * width * 3];
        jpeg_write_scanlines(&cinfo, &row, 1);
    }
    jpeg_finish_compress(&cinfo);
    jpeg_destroy_compress(&cinfo);
    fclose(out);
    return 0;
}

To write into memory instead of a file, replace jpeg_stdio_dest with jpeg_mem_dest(&cinfo, &buffer, &size) and free(buffer) when done.

How to make a baseline JPEG with mozjpeg#

Some old decoders and hardware only accept baseline files. Keep trellis quantization but turn off progressive scans after jpeg_set_defaults:

C
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, 80, TRUE);
cinfo.num_scans = 0;      // no progressive scan script
cinfo.scan_info = NULL;

How to set mozjpeg options (trellis, quantization tables)#

Extension parameters are set with jpeg_c_set_bool_param and jpeg_c_set_int_param. The compression profile must be chosen before jpeg_set_defaults, which applies it:

C
// fast, libjpeg-turbo-like output (baseline, no trellis)
jpeg_c_set_int_param(&cinfo, JINT_COMPRESS_PROFILE, JCP_FASTEST);
jpeg_set_defaults(&cinfo);

// or keep the default profile and change single options
jpeg_set_defaults(&cinfo);
jpeg_c_set_bool_param(&cinfo, JBOOLEAN_TRELLIS_QUANT, TRUE);
jpeg_c_set_bool_param(&cinfo, JBOOLEAN_OVERSHOOT_DERINGING, TRUE);  // text/graphics on white
jpeg_c_set_int_param(&cinfo, JINT_BASE_QUANT_TBL_IDX, 3);          // 0-8, 3 is the default
jpeg_set_quality(&cinfo, 80, TRUE);                                 // after changing the table set

How to compress images with cjpeg and jpegtran#

mozjpeg’s cjpeg reads PNG (when built with libpng), BMP, PPM and Targa:

Shell
# encode at quality 80 (progressive, trellis)
cjpeg -quality 80 -outfile out.jpg in.png
# 4:4:4 sampling for images with fine colored detail
cjpeg -quality 85 -sample 1x1 -outfile out.jpg in.png
# losslessly re-optimize an existing JPEG and drop metadata
jpegtran -copy none -optimize -progressive -outfile out.jpg in.jpg

Tips#