Usage

Installation and setup

To use jpeglib, first install it using pip:

$ pip3 install jpeglib

Import the package with

>>> import jpeglib

Warning

Compression comes with loss and thus different jpeg implementations might produce slightly different results. The library jpeglib brings solution as being able to select the library in runtime.

To better address this, jpeglib comes with unit tests, where you can check, how different the outputs are compared to other popular Python packages.

You can specify a particular libjpeg version to use with set_libjpeg_version().

>>> jpeglib.version.set('6b')

Currently supported are

  • libjpeg versions 6b, 7, 8, 8a, 8b, 8c, 8d, 9, 9a, 9b, 9c, 9d, 9e,

  • libjpeg-turbo versions turbo120, turbo130, turbo140, turbo150, turbo200, turbo210, and

  • mozjpeg versions mozjpeg101, mozjpeg201, mozjpeg300, and mozjpeg403.

Note

Feel free to switch to supported libjpeg-turbo versions, but do not rely that all SIMD extensions, supported by libjpeg-turbo, are used. An effort has been made to integrate libjpeg-turbo, but SIMD configuration is rather complex, so I cannot guarrantee full support at this moment.

To see that SIMD is used at all, I measured the time of execution and compared it to libjpeg. Via jpeglib on M1 Chip (Neon), libjpeg-turbo is significantly faster both in compression and decompression.

Spatial domain

In JPEG, the pixel data (such as RGB) in so called spatial domain are compressed and to get them, the image has to be decompressed. Similarly to save pixels as JPEG, they are compressed.

Reading the spatial domain

Decompress input file input.jpeg into spatial representation in numpy array with

>>> im = jpeglib.read_spatial("input.jpeg")
>>> im.spatial

The output channels depend on the source file. You can explicitly request returning RGB

>>> im = jpeglib.read_spatial("input.jpeg", out_color_space=jpeglib.JCS_RGB)
>>> rgb = im.spatial

For more parameters check out the documentation of the function jpeglib.JPEG.read_spatial and the class of the returned object jpeglib.spatial_jpeg.SpatialJPEG

Writing the spatial domain

Compression of a spatial domain to an output file output.jpeg is done with

>>> im.write_spatial("output.jpeg")

Compression parameters connected with the JPEG, such as dimensions, colorspace or markers are attributes of the object and can be overwritten. Others are parameters of the function.

>>> im.samp_factor = ((1,2),(1,1),(1,1))
>>> im.samp_factor = '4:4:0'  # alternative
>>> im.write_spatial("output.jpeg", dct_method=jpeglib.JDCT_FLOAT)

The color space is chosen based on reading. All the parameter options are listen in the jpeglib.spatial_jpeg.SpatialJPEG.write_spatial documentation.

DCT coefficients

DCT (Discrete cosine transform) is one of the steps during JPEG compression and decompression. Read more about it in JPEG compression glossary.

Unlike spatial domain writing, reading and writing of DCT coefficients is lossless.

Reading the DCT coefficients

Acquire the quantized DCT coefficients of an input file input.jpeg with

>>> im = jpeglib.read_dct("input.jpeg")
>>> im.Y; im.Cb; im.Cr; im.qt

The four members are tensors of luminance (Y) and chrominance (Cb, Cr) DCT coefficients and quantization tables (qt). Read more information in the jpeglib.functional.read_dct documentation.

To get dequantized DCT coefficients, multiply the tensors by quantization table.

>>> Y_deq = im.Y * im.qt[0]
>>> Cb_deq = im.Cb * im.qt[1]
>>> Cr_deq = im.Cr * im.qt[2]

Writing the DCT coefficients

Write the quantized coefficients to an output file output.jpeg with

>>> im.write_dct("output.jpeg")

The function reference can be found in the jpeglib.dct_jpeg.DCTJPEG.write_dct documentation.

jpegio format

Existing package jpegio already offers interface to work with DCT coefficients and quantization tables. To make an easy transition to jpeglib, we offer an simple abstraction of the jpegio interface.

>>> im = jpeglib.read_dct("input.jpeg")
>>> im = jpeglib.to_jpegio(im)
>>> im.coef_arrays[0][:8,-8:]   # -> im.Y[0,-1]
>>> im.coef_arrays[1][-8:,8:16] # -> im.Cr[-1,1]
>>> im.quant_tables[0]          # -> im.qt[0]