Does the JPEG Library 9.x of IJG conform to the respective ITU/ISO Standard?

It is important to say in advance that in the larger part of the history of JPEG the library did not conform to the ITU-T Recommendation T.81 | ISO/IEC 10918-1. There were several reasons for this non-conformity.  On the one hand, the standard contains many specifications that are more or less not relevant for the library and its practical application (about 50% — today, the ISO produces 100% junk). On the other hand Tom Lane, the author of the first libjpeg, was not able to apply the recommendations fully because that was technically impossible. He was mostly interested in what makes sense programmatically. He seemed to favour the independence of his solution from the ITU/ISO and therefore called the organization Independent JPEG Group.

Now we think that IJG JPEG 9 is the first and only library that conforms completely to the ITU/ISO specification, or, at least, to those parts of it that are practically useful. By example we will prove this by two matters and in comparison to the fake “libjpeg-turbo” distribution, which, we think, does not conform to the specification. The matters of comparison are the DCT (mathematical basis for JPEG) and the conversion of color spaces.

Now the question is: what conforms to the standard?

Discrete Cosine Transform (DCT)

Let us first consider the mathematical definition of the DCT. We find the formula in several places. It is documented in the ITU-T Recommendation T.81 | ISO/IEC 10918-1. In chapter A.3.3 “FDCT and IDCT” we find exactly this formula. Unfortunately the document is not available for free in public, but you find the formula also in the introductory JPEG article by Greg Wallace on page 3 under: https://www.ijg.org/files/Wallace.JPEG.pdf.

In the IJG source code the IDCT (Inverse DCT) implementation is located in the file jidctint.c in the function jpeg_idct_islow. Let us look at the places where we have certain numbers. In the code of the fake “libjpeg-turbo”, that is identicat to libjpeg 6b from 1998, we find this: https://github.com/libjpeg-turbo/libjpeg-turbo/blob/master/jidctint.c#L235

z1 = MULTIPLY(z2 + z3, FIX_0_541196100);
tmp2 = z1 + MULTIPLY(z3, - FIX_1_847759065);
tmp3 = z1 + MULTIPLY(z2, FIX_0_765366865);

Above this you will find that it is an integer approximation of the following values:

FIX_0_541196100  stands for  FIX(0.541196100)
FIX_1_847759065  stands for  FIX(1.847759065)
FIX_0_765366865  stands for  FIX(0.765366865)

Now the question is: what kind of values are 0.541196100, 1.847759065, and 0.765366865 ? In the above specification we do not find these numbers. They may be approximations, but of what? How are these values calculated? We cannot trace these values from the source code and we cannot map them to the formula in the standard.  There is no reference from the source to the standard.

Now let us consider the code from the current IJG libjpeg 9f. You can find it also here: https://github.com/libjpeg-turbo/ijg/blob/master/jidctint.c#L247

z1 = MULTIPLY(z2 + z3, FIX_0_541196100);       /* c6 */
tmp2 = z1 + MULTIPLY(z2, FIX_0_765366865);     /* c2-c6 */
tmp3 = z1 - MULTIPLY(z3, FIX_1_847759065);     /* c2+c6 */

again this holds for:

FIX_0_541196100  stands for  FIX(0.541196100)
FIX_1_847759065  stands for  FIX(1.847759065)
FIX_0_765366865  stands for  FIX(0.765366865)

Now you find the remarks c6, c2–c6, and c2+c6 beside the dubious approximations. Above, in the head of the function, you find the following remark:

cK represents sqrt(2) * cos(K*pi/16).

With this you have the reference to the exact mathematical formula in the standard and you are now in the position to calculate the numbers by yourself:  c6 = sqrt(2) * cos(6*pi/16), c2 = sqrt(2) * cos(2*pi/16), from this you can compute c2–c6 and c2+c6 .

So this source code conforms to the abovementioned specification. All approximations in the IJG source code are referred to exact definitions. This is an important feature of reference code.

This approach has several advantages:

  1. You can calculate and verify all approximate numbers yourself.
  2. You can adapt the precision of the approximation to the requirements of your application.
  3. The accuracy of the approximation can be adapted to the requirements of future extentions  (radiance/HDR coding).

In the IJG source code we choose the exactness of the approximation by 9 decimal points. This approximation is application specific and changeable! Only the exact values are substantial and sustained! Therefore the original JPEG standard has only the exact formula. Consequently a JPEG source code can only be conform to the standard if it references every approximation to the exact formula.

That much about the DCT.

Color Space Conversion

You may observe that the examined case has no effect on the produced program and the processing of image data. But in the case of color space conversion the subject is different. You find the respective passages in the IJG source code in the files jccolor.c and jdcolor.c . Let us consider the case of jccolor.c for compression. For decompression (jdcolor.c) it is similar. The section in the code of the fake “libjpeg-turbo” that is derived from libjpeg 6b from 1998 is as follows: https://github.com/libjpeg-turbo/libjpeg-turbo/blob/master/jccolor.c#L39

* The conversion equations to be implemented are therefore
*      Y  =  0.29900 * R + 0.58700 * G + 0.11400 * B
*      Cb = -0.16874 * R - 0.33126 * G + 0.50000 * B  + CENTERJSAMPLE
*      Cr =  0.50000 * R - 0.41869 * G - 0.08131 * B  + CENTERJSAMPLE

You see that all numbers have five decimal points. There is no derivation from any exact formula. These numbers are also approximations.

In general a codec system requires reversibility. The reversibility with the corresponding equations in jdcolor.c is true only for the exact formulae, not for the approximations!

In the current IJG source code the equations are derived from the exact formulae, and a more precise approximation of the dependent numbers by 9 decimal points (same as with the DCT) is used: https://github.com/libjpeg-turbo/ijg/blob/master/jccolor.c#L29

* the conversion equations to be implemented are therefore
*    Y  =  0.299 * R + 0.587 * G + 0.114 * B
*    Cb = -0.168735892 * R - 0.331264108 * G + 0.5 * B + CENTERJSAMPLE
*    Cr =  0.5 * R - 0.418687589 * G - 0.081312411 * B + CENTERJSAMPLE

The better approximation leads to differences in the final program and has consequences for the image data! This required a rebuild of the test images in version 9a. See change.log:

Version 9a  19-Jan-2014
-----------------------

Add support for wide gamut color spaces (JFIF version 2).
Improve clarity and accuracy in color conversion modules.
Note: Requires rebuild of test images.

The calculation of the color space conversion is defined in the JPEG File Interchange Format (JFIF). The official reference for this is ITU-T Recommendation T.871 | ISO/IEC 10918-5: https://www.itu.int/rec/T-REC-T.871. You can also find these references at https://www.ijg.org/files/.

This version contains the exact formulae but there are still dependent numbers that have no defined origin. In the current IJG source code (jccolor.c, jdcolor.c) the complete derivation is given in a way that can not be found in any of the given documents.

The “ISO libjpeg” (of Thomas Richter) uses the same DCT algorithm with the given approximations and without reference to the exact values. In the case of colorspace conversion other, inconsistent, approximations are used without reference to the exact values.

The non-conforming versions are published by the ISO as “reference software”, while a conforming version is not provided: https://jpeg.org/jpeg/software.html.

This leads to the conclusion that the ISO is actually practicing serious misdirection and damaging of the value of the people.