There's a great deal of confusion around chroma subsampling notation. Chroma subsampling is generally expressed using J:a:b notation but the meaning of the notation varies between different sources and software. Furthermore, JPEG uses a different format internally which is sometimes exposed in user interfaces. This article attempts to shed some light on the different notations and how they are related.

## Common notation

• J specifies a block of J × 2 pixels for luma. Typically, J is 4.
• a is the number of chroma samples in the first row.
• b is the number of chroma samples in the second row. This is either 0 or equal to a.

Chroma subsampling can also be expressed as fractions of the luma resolution. For example 4:2:2 means that the chroma resolution is halved horizontally while vertically it has full resolution. Let's denote the relative horizontal and vertical chroma resolutions with H and V. Here's a table of common chroma subsamplings in both of notations alongside a visual representation:

Table 1
J:a:b H V Luma Chroma
4:4:4 1⁄1 1⁄1  4:4:0 1⁄1 1⁄2  4:2:2 1⁄2 1⁄1  4:2:0 1⁄2 1⁄2  4:1:1 1⁄4 1⁄1  4:1:0 1⁄4 1⁄2  ## Understanding sampling factors

The typical JPEG has three channels: Y', CB and CR where Y' stores the luma of the image while CB and CR store the chroma. To enable subsampling, each channel has a horizontal and a vertical sampling factor. In total the image has six sampling factors which are typically notated as $$h_1$$×$$v_1$$, $$h_2$$×$$v_2$$, $$h_3$$×$$v_3$$. Possible values for the sampling factors are integers 1, 2, 3 and 4.

The sampling factors of each channel express the channel's resolution in relation to the largest sampling factors. For example, in sampling factors 2×3, 1×2, 2×1, the largest horizontal and the vertical sampling factor which are 2 and 3 respectively. Here's an interactive animation on how an image with these sampling factors is decoded:

More formally, we first calculate the largest horizontal and vertical sampling factors:

\begin{aligned} h_{max} &= \text{max}\{h_1, h_2, h_3\} \\ v_{max} &= \text{max}\{v_1, v_2, v_3\} \end{aligned}

Then, the relative resolutions are the following:

• the first channel has $$h_1/h_{max}$$ horizontal and $$v_1/v_{max}$$ vertical resolution
• the second channel has $$h_2/h_{max}$$ horizontal and $$v_2/v_{max}$$ vertical resolution
• the third channel has $$h_3/h_{max}$$ horizontal and $$v_3/v_{max}$$ vertical resolution

Let's take a look at sampling factors 2×3, 1×2, 2×1 again. First, we calculate the largest sampling factors $$h_{max} = 2$$ and $$v_{max} = 3$$. Then, the relative resolutions are the following:

• the first channel has 2⁄2 horizontal and 3⁄3 vertical resolution
• the second channel has 1⁄2 horizontal and 2⁄3 vertical resolution
• the third channel has 2⁄2 horizontal and 1⁄3 vertical resolution

Additionally, the following inequality must hold:

$h_1 v_1 + h_2 v_2 + h_3 v_3 \leq 10$

This means that sampling factors such as 4×3, 2×1, 2×3 are invalid because $$4 \cdot 3 + 2 \cdot 1 + 2 \cdot 3 = 20$$ is greater than $$10$$.

## Chroma subsampling with sampling factors

Next, let's investigate how we can express chroma subsampling with sampling factors. For chroma subsampling the luma channel must have the largest sampling factors and the sampling factors of both chroma channels must be equal. Here's a table of common chroma subsamplings with corresponding sampling factors:

Table 2
J:a:b H V Sampling factors
4:4:4 1⁄1 1⁄1 1×1, 1×1, 1×1
4:4:0 1⁄1 1⁄2 1×2, 1×1, 1×1
4:2:2 1⁄2 1⁄1 2×1, 1×1, 1×1
4:2:0 1⁄2 1⁄2 2×2, 1×1, 1×1
4:1:1 1⁄4 1⁄1 4×1, 1×1, 1×1
4:1:0 1⁄4 1⁄2 4×2, 1×1, 1×1

In the table, sampling factors of the second and third channel are all equal to 1. Sometimes these factors are omitted and the sampling factors of the first channel are interpreted as the dimensions of a chroma sample in pixels. For example, 1×2 is shorthand for sampling factors 1×2, 1×1, 1×1 or, put in another way, the chroma sample is 1 pixel wide and 2 pixels tall.

Because the sampling factors express ratios, they can represent the same chroma subsampling in multiple ways. Table 3 shows alternative ways of storing chroma subsampling. These should be avoided because they may not work properly in all software (see this libjpeg-turbo issue for reference).

Table 3
J:a:b H V Sampling factors
4:4:4 3⁄3 1⁄1 3×1, 3×1, 3×1
4:4:4 2⁄2 1⁄1 2×1, 2×1, 2×1
4:4:4 1⁄1 3⁄3 1×3, 1×3, 1×3
4:4:4 1⁄1 2⁄2 1×2, 1×2, 1×2
4:4:0 2⁄2 1⁄2 2×2, 2×1, 2×1
4:4:0 1⁄1 2⁄4 1×4, 1×2, 1×2
4:2:2 2⁄4 1⁄1 4×1, 2×1, 2×1
4:2:2 1⁄2 2⁄2 2×2, 1×2, 1×2

Finally, table 4 lists the rest of chroma subsamplings that can be expressed with sampling factors. These are either rarely used subsamplings, vertical versions of common options or weird fractional subsamplings.

Table 4
J:a:b H V Sampling factors
3:1:1 1⁄3 2⁄2 3×2, 1×2, 1×2
3:1:1 1⁄3 1⁄1 3×1, 1×1, 1×1
3:1:0 1⁄3 1⁄2 3×2, 1×1, 1×1
n/a 3⁄4 1⁄1 4×1, 3×1, 3×1
n/a 2⁄3 1⁄2 3×2, 2×1, 2×1
n/a 2⁄3 1⁄1 3×1, 2×1, 2×1
n/a 2⁄2 1⁄3 2×3, 2×1, 2×1
n/a 1⁄2 2⁄3 2×3, 1×2, 1×2
n/a 1⁄2 1⁄4 2×4, 1×1, 1×1
n/a 1⁄2 1⁄3 2×3, 1×1, 1×1
n/a 1⁄1 3⁄4 1×4, 1×3, 1×3
n/a 1⁄1 2⁄3 1×3, 1×2, 1×2
n/a 1⁄1 1⁄4 1×4, 1×1, 1×1
n/a 1⁄1 1⁄3 1×3, 1×1, 1×1

In conclusion, sampling factors are very flexible as they can express anything from typical chroma subsampling to different subsampling of CB and CR channels and luma subsampling. They allow multiple ways of representing the same subsampling but you should probably use the values from table 2.

## Using sampling factors

How do we go about using the sampling factors in practise? In cjpeg we can specify 4:2:2 chroma subsampling with -sample option:

cjpeg -sample 2x1,1x1,1x1 -outfile output.jpg input.ppm


or use the following shorthand:

cjpeg -sample 2x1 -outfile output.jpg input.ppm


ImageMagick has a similar option called -sampling-factor:

magick input.ppm -sampling-factor 2x1 output.jpg


In libjpeg we can specify chroma subsampling with h_samp_factor and v_samp_factor:

struct jpeg_compress_struct cinfo;
jpeg_create_compress(&cinfo);

cinfo.image_width = 300;
cinfo.image_height = 200;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;

jpeg_set_defaults(&cinfo);

cinfo.comp_info.h_samp_factor = 2;
cinfo.comp_info.v_samp_factor = 1;
cinfo.comp_info.h_samp_factor = 1;
cinfo.comp_info.v_samp_factor = 1;
cinfo.comp_info.h_samp_factor = 1;
cinfo.comp_info.v_samp_factor = 1;