Entropy Coding and Decoding

Entropy coding turns the quantized coefficients of each block into the final bitstream. This note covers the coding stages, the decoder and a worked example.

Entropy Coding

  1. Code the DC coefficient as the difference from the DC coefficient of the previous tile. Neighbouring tiles have similar means, so the differences are small.
  2. Read the 63 AC coefficients in zig-zag order, from low to high frequency. The long tail of zeros collects at the end of the sequence.
  3. Run-length encode the sequence as pairs of the number of preceding zeros and the next nonzero value. A special end-of-block symbol replaces the trailing zeros.
  4. Huffman code the pairs.

The result of every tile is concatenated into 1 bitstream.

Zig-Zag Scan

The scan visits the 64 positions along anti-diagonals, alternating direction, starting at the DC position.

Zig-zag scan of a 8x8 block u v 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
Zig-zag scan order of a 8x8 block. Cell numbers give the position in the scan, starting at the DC coefficient in the top-left corner.

For an implementation, the scan is a lookup table. Entry kk is the row-major position (v * 8 + u) of the coefficient visited kk-th.

ZIGZAG = [
     0,  1,  8, 16,  9,  2,  3, 10,
    17, 24, 32, 25, 18, 11,  4,  5,
    12, 19, 26, 33, 40, 48, 41, 34,
    27, 20, 13,  6,  7, 14, 21, 28,
    35, 42, 49, 56, 57, 50, 43, 36,
    29, 22, 15, 23, 30, 37, 44, 51,
    58, 59, 52, 45, 38, 31, 39, 46,
    53, 60, 61, 54, 47, 55, 62, 63,
]

Scanning a block is zz[k] = block_flat[ZIGZAG[k]]. Unscanning is block_flat[ZIGZAG[k]] = zz[k].

Anti-diagonals have constant u+vu + v, so they have roughly constant spatial frequency. Coefficients along the scan therefore decay in expected magnitude, which groups the zeros into 1 long run at the end.

DC Coefficients

The DC coefficients of successive blocks of the same component are coded by differential pulse code modulation, a form of delta coding:

Diffk=Fq,k(0,0)−Fq,k−1(0,0)\text{Diff}_k = F_{q,k}(0, 0) - F_{q,k-1}(0, 0)
  • The predictor starts at 0 for the first block
  • Each component keeps its own predictor
  • Quantization comes before prediction, so the differences are of quantized values

Magnitude Categories

A nonzero integer aa is described by its category ss and ss extra bits.

s=⌊log⁡2∣a∣⌋+1s = \lfloor \log_2 |a| \rfloor + 1

Category ss covers the values ±[2s−1,2s−1]\pm[2^{s-1}, 2^s - 1]. Category 0 holds only the value 0.

Category ssValues
00
1−1,1-1, 1
2−3,−2,2,3-3, -2, 2, 3
3−7,…,−4,4,…,7-7, \dots, -4, 4, \dots, 7
4−15,…,−8,8,…,15-15, \dots, -8, 8, \dots, 15
ss±[2s−1,2s−1]\pm[2^{s-1}, 2^s - 1]

The extra bits identify the value inside its category.

  • For a>0a > 0, the extra bits are the ss low bits of the binary form of aa
  • For a<0a < 0, the extra bits are the ss low bits of a−1a - 1, which equals the one’s complement of ∣a∣|a| in ss bits

Examples:

  • a=5a = 5 has s=3s = 3 and extra bits 101
  • a=−5a = -5 has s=3s = 3 and extra bits 010
  • a=−3a = -3 has s=2s = 2 and extra bits 00

A leading extra bit of 1 always marks a positive value and 0 a negative value.

Baseline limits are s≤11s \le 11 for DC differences and s≤10s \le 10 for AC coefficients.

The DC difference is coded as the Huffman code of its category ss, followed by the ss extra bits.

AC Coefficients

Each nonzero AC coefficient is coded as a symbol byte followed by extra bits.

RS=16R+s\text{RS} = 16 R + s
Here:
RR

number of zeros since the previous nonzero coefficient, from 0 to 15

ss
category of the nonzero coefficient, from 1 to 10

The Huffman code of RS is followed by the ss extra bits of the coefficient.

Two special symbols exist.

  • EOB (0x00)
    End of block. Every remaining coefficient is 0. Omitted when coefficient 63 is nonzero.
  • ZRL (0xF0)
    Zero run length. Stands for 16 zeros with no nonzero value. Used repeatedly when a run exceeds 15.

A run of 20 zeros followed by the value 3 is coded as ZRL, then R=4R = 4, s=2s = 2.

Huffman Tables

A table is defined in the file by two lists.

  • BITS
    16 counts. Entry ll is the number of codes of length ll.
  • HUFFVAL
    The symbols in order of increasing code length.

The decoder rebuilds the codes canonically.

  1. Set code = 0.
  2. For each length l=1,…,16l = 1, \dots, 16, assign code to each of the BITS[l] symbols of that length in order, incrementing code after each.
  3. After finishing length ll, shift code left by 1.

Constraints:

  • Code lengths are at most 16 bits
  • The all-ones code of any length is never assigned

Baseline allows 2 DC tables and 2 AC tables. Typically 1 pair serves luminance and 1 pair serves chrominance. Each component is assigned 1 DC table and 1 AC table.

Annex K gives typical luminance tables. Selected codes:

SymbolCode
DC category 000
DC category 1010
DC category 2011
DC category 3100
DC category 4101
DC category 5110
AC EOB1010
AC R=0,s=1R=0, s=100
AC R=0,s=2R=0, s=201
AC R=0,s=3R=0, s=3100
AC R=0,s=4R=0, s=41011
AC R=1,s=1R=1, s=11100
AC R=1,s=2R=1, s=211011
AC R=2,s=1R=2, s=111100
AC R=5,s=1R=5, s=11111010
AC ZRL11111111001

Short codes go to the symbols that occur most often, namely small values after short zero runs.

Encoders may instead compute optimal tables from the image’s own symbol statistics, which saves roughly 5 to 10 percent of the file size.

Standard Huffman Tables

The complete Annex K definitions, which BITS and HUFFVAL fully determine. Each AC table holds the 160 symbols R⋅16+sR \cdot 16 + s for R∈[0,15]R \in [0, 15] and s∈[1,10]s \in [1, 10], plus EOB (0x00) and ZRL (0xF0). The DC tables hold the categories 0 to 11.

DC_LUM_BITS = [0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0]
DC_LUM_VALS = list(range(12))

DC_CHR_BITS = [0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0]
DC_CHR_VALS = list(range(12))

AC_LUM_BITS = [0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 125]
AC_LUM_VALS = bytes.fromhex(
    "01 02 03 00 04 11 05 12 21 31 41 06 13 51 61 07"
    "22 71 14 32 81 91 a1 08 23 42 b1 c1 15 52 d1 f0"
    "24 33 62 72 82 09 0a 16 17 18 19 1a 25 26 27 28"
    "29 2a 34 35 36 37 38 39 3a 43 44 45 46 47 48 49"
    "4a 53 54 55 56 57 58 59 5a 63 64 65 66 67 68 69"
    "6a 73 74 75 76 77 78 79 7a 83 84 85 86 87 88 89"
    "8a 92 93 94 95 96 97 98 99 9a a2 a3 a4 a5 a6 a7"
    "a8 a9 aa b2 b3 b4 b5 b6 b7 b8 b9 ba c2 c3 c4 c5"
    "c6 c7 c8 c9 ca d2 d3 d4 d5 d6 d7 d8 d9 da e1 e2"
    "e3 e4 e5 e6 e7 e8 e9 ea f1 f2 f3 f4 f5 f6 f7 f8"
    "f9 fa"
)

AC_CHR_BITS = [0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 119]
AC_CHR_VALS = bytes.fromhex(
    "00 01 02 03 11 04 05 21 31 06 12 41 51 07 61 71"
    "13 22 32 81 08 14 42 91 a1 b1 c1 09 23 33 52 f0"
    "15 62 72 d1 0a 16 24 34 e1 25 f1 17 18 19 1a 26"
    "27 28 29 2a 35 36 37 38 39 3a 43 44 45 46 47 48"
    "49 4a 53 54 55 56 57 58 59 5a 63 64 65 66 67 68"
    "69 6a 73 74 75 76 77 78 79 7a 82 83 84 85 86 87"
    "88 89 8a 92 93 94 95 96 97 98 99 9a a2 a3 a4 a5"
    "a6 a7 a8 a9 aa b2 b3 b4 b5 b6 b7 b8 b9 ba c2 c3"
    "c4 c5 c6 c7 c8 c9 ca d2 d3 d4 d5 d6 d7 d8 d9 da"
    "e2 e3 e4 e5 e6 e7 e8 e9 ea f2 f3 f4 f5 f6 f7 f8"
    "f9 fa"
)
  • Luminance tables serve the Y component and chrominance tables serve Cb and Cr
  • The BITS lists sum to 12 for DC tables and to 162 for AC tables

Byte Stuffing and Restart Markers

  • Byte stuffing
    Every 0xFF byte inside entropy-coded data is followed by a 0x00 byte. A marker is a 0xFF byte followed by a nonzero byte. Since the all-ones Huffman code is never assigned, a code cannot be mistaken for a marker.
  • Padding
    The final partial byte of a scan is filled with 1 bits.
  • Restart intervals
    An optional interval of NN MCUs makes the encoder byte-align the stream, emit a restart marker RST0 to RST7 (cycling) and reset all DC predictors to 0.

Restart intervals limit the damage from a bit error to 1 interval, since decoding can resynchronise at the next marker. They also allow parallel decoding.

Decoding

  1. Parse headers and build the Huffman and quantization tables.
  2. For each MCU, Huffman decode the DC difference and add it to the component’s predictor.
  3. Huffman decode AC symbols until EOB or 63 coefficients, expanding each run of zeros.
  4. Place the 64 values back from zig-zag order into an 8x8 array.
  5. Multiply by the quantization table.
  6. Apply the inverse DCT.
  7. Add 128 and clamp to [0,255][0, 255].
  8. Upsample the chroma planes to full resolution.
  9. Convert YCrCb to RGB.

For one block, steps 5 to 7 combine into:

f^(x,y)=clamp(round(IDCT(Fq(u,v) Q(u,v)))+128, 0, 255)\hat{f}(x, y) = \text{clamp}\left( \text{round}\left( \text{IDCT}\big(F_q(u, v)\, Q(u, v)\big) \right) + 128,\ 0,\ 255 \right)
Here:
Fq(u,v)F_q(u, v)
quantized coefficient from the entropy decoder
Q(u,v)Q(u, v)
quantization table entry
IDCT\text{IDCT}
inverse 2D DCT of the block
clamp(a,0,255)\text{clamp}(a, 0, 255)
aa limited to the range [0,255][0, 255]

The inverse DCT output is rounded, so decoders from different vendors can differ by at most a small amount per pixel. The standard bounds this difference through accuracy tests.

Worked Example

Subsampling Calculation

A 4×44 \times 4 region of CbC_b values under 4:2:0 has 4 groups of 2×22 \times 2 pixels.

[1001021101129810410811490921201189496122124]\begin{bmatrix} 100 & 102 & 110 & 112 \\ 98 & 104 & 108 & 114 \\ 90 & 92 & 120 & 118 \\ 94 & 96 & 122 & 124 \end{bmatrix}

Subsample the region to 4:2:0, restore it and find the error.

Solution Reveal Hide

The group averages are 101101, 111111, 9393 and 121121, so 16 values become 4.

[10111193121]\begin{bmatrix} 101 & 111 \\ 93 & 121 \end{bmatrix}

The decoder copies each value into its 2×22 \times 2 group.

[10110111111110110111111193931211219393121121]\begin{bmatrix} 101 & 101 & 111 & 111 \\ 101 & 101 & 111 & 111 \\ 93 & 93 & 121 & 121 \\ 93 & 93 & 121 & 121 \end{bmatrix}

The error (original minus restored) is:

[−11−11−33−33−3−1−1−31313]\begin{bmatrix} -1 & 1 & -1 & 1 \\ -3 & 3 & -3 & 3 \\ -3 & -1 & -1 & -3 \\ 1 & 3 & 1 & 3 \end{bmatrix}

The largest error is 3 on a scale of 255. The original values cannot be recovered.

The same applies to CrC_r. The 4×44 \times 4 pixels hold 48 samples (YY, CbC_b, CrC_r with 16 each) before and 16+4+4=2416 + 4 + 4 = 24 after.

First Block of an Image

The test image is a 512×768512 \times 768 photo of a lighthouse, encoded at quality 50. The first block is the top-left YY block of the first MCU. Encode it into JPEG symbols, starting from the pixel (0,0)(0, 0) with (R,G,B)=(75,93,94)(R, G, B) = (75, 93, 94).

Solution Reveal Hide

Colour conversion of the pixel (0,0)(0, 0):

Y=22.4+54.6+10.7=87.7Cb=128−12.7−30.8+47.0=131.5Cr=128+37.5−38.9−7.6=118.9\begin{aligned} Y &= 22.4 + 54.6 + 10.7 = 87.7 \\ C_b &= 128 - 12.7 - 30.8 + 47.0 = 131.5 \\ C_r &= 128 + 37.5 - 38.9 - 7.6 = 118.9 \end{aligned}

Level-shifted samples, rounded to 1 decimal place:

f=[−40.3−37.1−39.1−36.1−30.5−33.2−33.2−30.5−40.3−39.1−41.2−40.1−37.2−34.5−30.5−33.2−38.6−37.3−40.1−40.1−37.2−34.5−30.5−30.5−30.6−37.3−41.4−40.1−37.2−36.1−31.5−31.5−29.3−36.3−40.1−39.1−39.1−41.2−35.5−33.1−27.9−34.7−39.1−43.1−40.4−38.7−35.8−34.7−31.9−30.7−38.5−36.1−40.1−39.1−36.1−33.4−29.1−31.9−34.7−33.5−34.5−39.1−40.1−39.1]f = \begin{bmatrix} -40.3 & -37.1 & -39.1 & -36.1 & -30.5 & -33.2 & -33.2 & -30.5 \\ -40.3 & -39.1 & -41.2 & -40.1 & -37.2 & -34.5 & -30.5 & -33.2 \\ -38.6 & -37.3 & -40.1 & -40.1 & -37.2 & -34.5 & -30.5 & -30.5 \\ -30.6 & -37.3 & -41.4 & -40.1 & -37.2 & -36.1 & -31.5 & -31.5 \\ -29.3 & -36.3 & -40.1 & -39.1 & -39.1 & -41.2 & -35.5 & -33.1 \\ -27.9 & -34.7 & -39.1 & -43.1 & -40.4 & -38.7 & -35.8 & -34.7 \\ -31.9 & -30.7 & -38.5 & -36.1 & -40.1 & -39.1 & -36.1 & -33.4 \\ -29.1 & -31.9 & -34.7 & -33.5 & -34.5 & -39.1 & -40.1 & -39.1 \end{bmatrix}

DCT coefficients:

F=[−288.1−4.115.14.43.7−0.6−3.90.5−0.3−18.1−4.30.8−2.8−1.5−0.71.22.91.2−10.0−2.5−0.8−3.2−0.8−1.6−1.11.22.70.11.3−1.00.60.53.03.5−3.40.74.8−0.20.31.23.4−2.30.8−0.60.0−1.5−0.7−1.81.00.8−0.81.0−0.2−1.51.91.80.5−0.5−1.3−3.70.7−0.8−1.4−1.4]F = \begin{bmatrix} -288.1 & -4.1 & 15.1 & 4.4 & 3.7 & -0.6 & -3.9 & 0.5 \\ -0.3 & -18.1 & -4.3 & 0.8 & -2.8 & -1.5 & -0.7 & 1.2 \\ 2.9 & 1.2 & -10.0 & -2.5 & -0.8 & -3.2 & -0.8 & -1.6 \\ -1.1 & 1.2 & 2.7 & 0.1 & 1.3 & -1.0 & 0.6 & 0.5 \\ 3.0 & 3.5 & -3.4 & 0.7 & 4.8 & -0.2 & 0.3 & 1.2 \\ 3.4 & -2.3 & 0.8 & -0.6 & 0.0 & -1.5 & -0.7 & -1.8 \\ 1.0 & 0.8 & -0.8 & 1.0 & -0.2 & -1.5 & 1.9 & 1.8 \\ 0.5 & -0.5 & -1.3 & -3.7 & 0.7 & -0.8 & -1.4 & -1.4 \end{bmatrix}

Quantization with the luminance table at quality 50, which is the Annex K table unchanged:

Fq=[−1802000000−200000000−1000000000000000000000000000000000000000000000]F_q = \begin{bmatrix} -18 & 0 & 2 & 0 & 0 & 0 & 0 & 0 \\ 0 & -2 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & -1 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \\ 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 \end{bmatrix}

Only 4 of the 64 values are nonzero. The zig-zag scan gives:

−18, 0, 0, 0, −2, 2, 0,…,0⏟6, −1, 0,…,0⏟51-18,\ 0,\ 0,\ 0,\ -2,\ 2,\ \underbrace{0, \dots, 0}_{6},\ -1,\ \underbrace{0, \dots, 0}_{51}

Symbols, with the previous DC taken as 0:

  • DC
    Difference −18-18 with category s=5s = 5.
  • AC
    (R,s)(R, s) pairs (3,2)(3, 2) for −2-2, (0,2)(0, 2) for 22 and (6,1)(6, 1) for −1-1.
  • End
    EOB.

The 64 values reduce to 1 DC difference, 3 AC pairs and 1 EOB. With Huffman codes built for this image, each symbol is followed by its extra bits:

11110|01101  11110101|01  011|10  111010|0  010

The block takes 35 bits, against 64×8=51264 \times 8 = 512 bits for the original samples.

Written by November 3, 2026 10 min read
Was this helpful?