martinbenes1996/jpeglib

Quantization table mismatch for quality factor 0

Closed this issue · 1 comments

This is probably a hardly relevant edge case, but nevertheless it may be surprising that jpeglib deviates from the command line tool cjpeg.

For quality factor 0 (and below), the quantization tables produced by jpeglib and the command line tool cjpeg differ. jpeglib defaults to the quantization table corresponding to QF75, while cjpeg produces the same quantization table as for QF1.

import jpeglib
import numpy as np

# Create a random 8x8 image
filepath = "/tmp/demo.jpg"
rng = np.random.default_rng(12345)
spatial_block = rng.integers(low=0, high=256, size=(8, 8)).astype(np.uint8)

# Create a jpeglib object
im = jpeglib.from_spatial(spatial_block[:, :, None])

# Write with JPEG quality 0
im.write_spatial(filepath, qt=0)

im = jpeglib.read_dct(filepath)
print(im.qt[0])
# Quantization table produced by jpeglib
[[ 8  6  5  8 12 20 26 31]
 [ 6  6  7 10 13 29 30 28]
 [ 7  7  8 12 20 29 35 28]
 [ 7  9 11 15 26 44 40 31]
 [ 9 11 19 28 34 55 52 39]
 [12 18 28 32 41 52 57 46]
 [25 32 39 44 52 61 60 51]
 [36 46 48 49 56 50 52 50]]

# Quantization table produced by cjpeg
800  550  500  800 1200 2000 2550 3050
600  600  700  950 1300 2900 3000 2750
700  650  800 1200 2000 2850 3450 2800
700  850 1100 1450 2550 4350 4000 3100
900 1100 1850 2800 3400 5450 5150 3850
1200 1750 2750 3200 4050 5200 5650 4600
2450 3200 3900 4350 5150 6050 6000 5050
3600 4600 4750 4900 5600 5000 5150 4950

Thank you for the point. What you describe is the default behavior of libjpeg, jpeglib passes the QF parameter as-is. cjpeg performs clipping of QF.

You are right, the behavior of cjpeg makes more sense. In the dev branch there is modification, which will clip QF below 1 to 1 and QF above 100 to 100, and raise warning.

It will be part of the next release.