Add doc/note/pixel-subsampling.md
diff --git a/doc/note/pixel-formats.md b/doc/note/pixel-formats.md
index 928491b..79e0051 100644
--- a/doc/note/pixel-formats.md
+++ b/doc/note/pixel-formats.md
@@ -114,6 +114,10 @@
 Alexandros Frantzis' [Pixel Format
 Guide](https://afrantzis.github.io/pixel-format-guide/).
 
-Do not manipulate a `wuffs_base__pixel_format`'s bits directly; they are
-private implementation details. Use functions such as
-`wuffs_base__pixel_format__num_planes` instead.
+
+## API Stability
+
+The `wuffs_base__pixel_format` bit packing is documented for explanation and to
+assist in debugging (e.g. `printf`'ing the bits in `%x` format). However, do
+not manipulate its bits directly; they are private implementation details. Use
+functions such as `wuffs_base__pixel_format__num_planes` instead.
diff --git a/doc/note/pixel-subsampling.md b/doc/note/pixel-subsampling.md
new file mode 100644
index 0000000..ee64478
--- /dev/null
+++ b/doc/note/pixel-subsampling.md
@@ -0,0 +1,105 @@
+# Pixel Subsampling
+
+`wuffs_base__pixel_subsampling` is a `uint32_t` that encodes whether samples
+cover one pixel or cover multiple pixels. RGBA or BGRA pixel formats are
+typically one pixel per sample. For YCbCr or YCgCo pixel formats (e.g. the
+native format of JPEG and WebP lossy images), the luma channel (Y) is also
+typically one pixel per sample but the chroma channels are often 2 or 4 pixels
+per sample. In JPEG terminology, 1, 2 or 4 pixels per [chroma
+sample](https://en.wikipedia.org/wiki/Chroma_subsampling) correspond to 4:4:4,
+4:2:2 or 4:2:0 subsampling.
+
+Equivalently, `wuffs_base__pixel_subsampling` encodes the mapping of pixel
+space coordinates `(x, y)` to sample space coordinates `(i, j)`, also known as
+pixel buffer indices. That mapping can differ for each plane `p`. A Wuffs image
+can have up to 4 planes or channels. For a depth of 8 bits (1 byte), the `p`'th
+plane's sample starts at `(planes[p].ptr + (j * planes[p].stride) + i)`.
+
+For interleaved pixel formats, which are always one pixel per sample, the
+mapping is trivial: `i = x` and `j = y`. For planar pixel formats, the mapping
+can differ due to chroma subsampling. For example, consider a three plane YCbCr
+pixel format with 4:2:2 subsampling. For the luma (Y) channel, there is one
+sample for every pixel, but for the chroma (Cb, Cr) channels, there is one
+sample for every two pixels: pairs of horizontally adjacent pixels form one
+macropixel, `i = x / 2` and `j == y`. In general, for a given `p`:
+
+- `i = (x + bias_x) >> shift_x`.
+- `j = (y + bias_y) >> shift_y`.
+
+where biases and shifts are in the range `0 ..= 3` and `0 ..= 2` respectively.
+
+In general, the biases will be zero after decoding an image. However, making
+a sub-image may change the bias, since the `(x, y)` coordinates are relative
+to the sub-image's top-left origin, but the backing pixel buffers were
+created relative to the original image's origin.
+
+For example, consider a 10×3 image with what JPEG calls 4:1:1 sampling, where
+each Chroma sample covers a macropixel (a block of pixels) 4 wide and 1 high.
+For a Chroma channel, there are 30 pixels and 9 samples. `bias_x = 0` and
+`shift_x = 2`, so that the 6th pixel column (`x = 5`) maps to the 2nd sample
+column (`i = 1`).
+
+```
+Pixel space:
++---------------------------------------+
+|l00 l01 l02 l03 m04 m05 m06 m07 n08 n09|
+|                                       |
+|p10 p11 p12 p13 q14 q15 q16 q17 r18 r19|
+|           +-----------+               |
+|t21 t21 t22|t23 u24 u25|u26 u27 v28 v29|
++-----------+-----------+---------------+
+
+Sample space:
++-----+
+|l m n|
+|     |
+|p q r|
+|     |
+|t u v|
++-----+
+```
+
+Now consider the 3×1 sub-image shown above. Even though its pixel width (3) is
+less than the macropixel width (4 columns per sample), as that sub-image shares
+the sample buffer with its containing image, it still straddles 2 sample
+columns (`t` and `u`). `shift_x = 2`, the same as before, but now `bias_x = 3`.
+
+```
+Pixel space:
++-----------+
+|t23 u24 u25|
++-----------+
+
+Sample space:
++---+
+|t u|
++---+
+```
+
+
+## Bit Packing
+
+For each plane `p`, each of those four numbers (two biases and two shifts) are
+encoded in two bits, which combine to form an 8 bit unsigned integer:
+
+```
+e_p = (bias_x << 6) | (shift_x << 4) | (bias_y << 2) | (shift_y << 0)
+```
+
+Those `e_p` values (`e_0` for the first plane, `e_1` for the second plane, etc)
+combine to form a `wuffs_base__pixel_subsampling` value:
+
+```
+pixsub = (e_3 << 24) | (e_2 << 16) | (e_1 << 8) | (e_0 << 0)
+```
+
+For example, 4:2:2 YCbCr (with no bias) is encoded in the `uint32_t` value
+`0x101000`.
+
+
+## API Stability
+
+The `wuffs_base__pixel_subsampling` bit packing is documented for explanation
+and to assist in debugging (e.g. `printf`'ing the bits in `%x` format).
+However, do not manipulate its bits directly; they are private implementation
+details. Use functions such as `wuffs_base__pixel_subsampling__bias_x` instead.
diff --git a/internal/cgen/base/image-public.h b/internal/cgen/base/image-public.h
index 8e088fc..a7a83b7 100644
--- a/internal/cgen/base/image-public.h
+++ b/internal/cgen/base/image-public.h
@@ -130,38 +130,12 @@
 
 // --------
 
-// wuffs_base__pixel_subsampling encodes the mapping of pixel space coordinates
-// (x, y) to pixel buffer indices (i, j). That mapping can differ for each
-// plane p. For a depth of 8 bits (1 byte), the p'th plane's sample starts at
-// (planes[p].ptr + (j * planes[p].stride) + i).
+// wuffs_base__pixel_subsampling encodes whether sample values cover one pixel
+// or cover multiple pixels.
 //
-// For interleaved pixel formats, the mapping is trivial: i = x and j = y. For
-// planar pixel formats, the mapping can differ due to chroma subsampling. For
-// example, consider a three plane YCbCr pixel format with 4:2:2 subsampling.
-// For the luma (Y) channel, there is one sample for every pixel, but for the
-// chroma (Cb, Cr) channels, there is one sample for every two pixels: pairs of
-// horizontally adjacent pixels form one macropixel, i = x / 2 and j == y. In
-// general, for a given p:
-//  - i = (x + bias_x) >> shift_x.
-//  - j = (y + bias_y) >> shift_y.
-// where biases and shifts are in the range 0..3 and 0..2 respectively.
+// See https://github.com/google/wuffs/blob/master/doc/note/pixel-subsampling.md
 //
-// In general, the biases will be zero after decoding an image. However, making
-// a sub-image may change the bias, since the (x, y) coordinates are relative
-// to the sub-image's top-left origin, but the backing pixel buffers were
-// created relative to the original image's origin.
-//
-// For each plane p, each of those four numbers (biases and shifts) are encoded
-// in two bits, which combine to form an 8 bit unsigned integer:
-//
-//  e_p = (bias_x << 6) | (shift_x << 4) | (bias_y << 2) | (shift_y << 0)
-//
-// Those e_p values (e_0 for the first plane, e_1 for the second plane, etc)
-// combine to form a wuffs_base__pixel_subsampling value:
-//
-//  pixsub = (e_3 << 24) | (e_2 << 16) | (e_1 << 8) | (e_0 << 0)
-//
-// Do not manipulate these bits directly; they are private implementation
+// Do not manipulate its bits directly; they are private implementation
 // details. Use methods such as wuffs_base__pixel_subsampling__bias_x instead.
 typedef uint32_t wuffs_base__pixel_subsampling;
 
diff --git a/internal/cgen/data.go b/internal/cgen/data.go
index 2935d54..121ce05 100644
--- a/internal/cgen/data.go
+++ b/internal/cgen/data.go
@@ -110,10 +110,8 @@
 	"ixel formats.\nstatic inline uint32_t  //\nwuffs_base__pixel_format__bits_per_pixel(wuffs_base__pixel_format f) {\n  if (((f >> 16) & 0x03) != 0) {\n    return 0;\n  }\n  return wuffs_base__pixel_format__bits_per_channel[0x0F & (f >> 0)] +\n         wuffs_base__pixel_format__bits_per_channel[0x0F & (f >> 4)] +\n         wuffs_base__pixel_format__bits_per_channel[0x0F & (f >> 8)] +\n         wuffs_base__pixel_format__bits_per_channel[0x0F & (f >> 12)];\n}\n\nstatic inline bool  //\nwuffs_base__pixel_format__is_indexed(wuffs_base__pixel_format f) {\n  return (f >> 18) & 0x01;\n}\n\nstatic inline bool  //\nwuffs_base__pixel_format__is_interleaved(wuffs_base__pixel_format f) {\n  return ((f >> 16) & 0x03) == 0;\n}\n\nstatic inline bool  //\nwuffs_base__pixel_format__is_planar(wuffs_base__pixel_format f) {\n  return ((f >> 16) & 0x03) != 0;\n}\n\nstatic inline uint32_t  //\nwuffs_base__pixel_format__num_planes(wuffs_base__pixel_format f) {\n  return ((f >> 16) & 0x03) + 1;\n}\n\n#define WUFFS_BASE__PIXEL_FORMAT__NUM_PLANES_MAX 4\n\n#define WUFFS_B" +
 	"ASE__PIXEL_FORMAT__INDEXED__INDEX_PLANE 0\n#define WUFFS_BASE__PIXEL_FORMAT__INDEXED__COLOR_PLANE 3\n\n" +
 	"" +
-	"// --------\n\n// wuffs_base__pixel_subsampling encodes the mapping of pixel space coordinates\n// (x, y) to pixel buffer indices (i, j). That mapping can differ for each\n// plane p. For a depth of 8 bits (1 byte), the p'th plane's sample starts at\n// (planes[p].ptr + (j * planes[p].stride) + i).\n//\n// For interleaved pixel formats, the mapping is trivial: i = x and j = y. For\n// planar pixel formats, the mapping can differ due to chroma subsampling. For\n// example, consider a three plane YCbCr pixel format with 4:2:2 subsampling.\n// For the luma (Y) channel, there is one sample for every pixel, but for the\n// chroma (Cb, Cr) channels, there is one sample for every two pixels: pairs of\n// horizontally adjacent pixels form one macropixel, i = x / 2 and j == y. In\n// general, for a given p:\n//  - i = (x + bias_x) >> shift_x.\n//  - j = (y + bias_y) >> shift_y.\n// where biases and shifts are in the range 0..3 and 0..2 respectively.\n//\n// In general, the biases will be zero after decoding an image. However, making\n//" +
-	" a sub-image may change the bias, since the (x, y) coordinates are relative\n// to the sub-image's top-left origin, but the backing pixel buffers were\n// created relative to the original image's origin.\n//\n// For each plane p, each of those four numbers (biases and shifts) are encoded\n// in two bits, which combine to form an 8 bit unsigned integer:\n//\n//  e_p = (bias_x << 6) | (shift_x << 4) | (bias_y << 2) | (shift_y << 0)\n//\n// Those e_p values (e_0 for the first plane, e_1 for the second plane, etc)\n// combine to form a wuffs_base__pixel_subsampling value:\n//\n//  pixsub = (e_3 << 24) | (e_2 << 16) | (e_1 << 8) | (e_0 << 0)\n//\n// Do not manipulate these bits directly; they are private implementation\n// details. Use methods such as wuffs_base__pixel_subsampling__bias_x instead.\ntypedef uint32_t wuffs_base__pixel_subsampling;\n\n#define WUFFS_BASE__PIXEL_SUBSAMPLING__NONE ((wuffs_base__pixel_subsampling)0)\n\n#define WUFFS_BASE__PIXEL_SUBSAMPLING__444 \\\n  ((wuffs_base__pixel_subsampling)0x000000)\n#define WUFFS_BAS" +
-	"E__PIXEL_SUBSAMPLING__440 \\\n  ((wuffs_base__pixel_subsampling)0x010100)\n#define WUFFS_BASE__PIXEL_SUBSAMPLING__422 \\\n  ((wuffs_base__pixel_subsampling)0x101000)\n#define WUFFS_BASE__PIXEL_SUBSAMPLING__420 \\\n  ((wuffs_base__pixel_subsampling)0x111100)\n#define WUFFS_BASE__PIXEL_SUBSAMPLING__411 \\\n  ((wuffs_base__pixel_subsampling)0x202000)\n#define WUFFS_BASE__PIXEL_SUBSAMPLING__410 \\\n  ((wuffs_base__pixel_subsampling)0x212100)\n\nstatic inline uint32_t  //\nwuffs_base__pixel_subsampling__bias_x(wuffs_base__pixel_subsampling s,\n                                      uint32_t plane) {\n  uint32_t shift = ((plane & 0x03) * 8) + 6;\n  return (s >> shift) & 0x03;\n}\n\nstatic inline uint32_t  //\nwuffs_base__pixel_subsampling__shift_x(wuffs_base__pixel_subsampling s,\n                                       uint32_t plane) {\n  uint32_t shift = ((plane & 0x03) * 8) + 4;\n  return (s >> shift) & 0x03;\n}\n\nstatic inline uint32_t  //\nwuffs_base__pixel_subsampling__bias_y(wuffs_base__pixel_subsampling s,\n                               " +
-	"       uint32_t plane) {\n  uint32_t shift = ((plane & 0x03) * 8) + 2;\n  return (s >> shift) & 0x03;\n}\n\nstatic inline uint32_t  //\nwuffs_base__pixel_subsampling__shift_y(wuffs_base__pixel_subsampling s,\n                                       uint32_t plane) {\n  uint32_t shift = ((plane & 0x03) * 8) + 0;\n  return (s >> shift) & 0x03;\n}\n\n" +
+	"// --------\n\n// wuffs_base__pixel_subsampling encodes whether sample values cover one pixel\n// or cover multiple pixels.\n//\n// See https://github.com/google/wuffs/blob/master/doc/note/pixel-subsampling.md\n//\n// Do not manipulate its bits directly; they are private implementation\n// details. Use methods such as wuffs_base__pixel_subsampling__bias_x instead.\ntypedef uint32_t wuffs_base__pixel_subsampling;\n\n#define WUFFS_BASE__PIXEL_SUBSAMPLING__NONE ((wuffs_base__pixel_subsampling)0)\n\n#define WUFFS_BASE__PIXEL_SUBSAMPLING__444 \\\n  ((wuffs_base__pixel_subsampling)0x000000)\n#define WUFFS_BASE__PIXEL_SUBSAMPLING__440 \\\n  ((wuffs_base__pixel_subsampling)0x010100)\n#define WUFFS_BASE__PIXEL_SUBSAMPLING__422 \\\n  ((wuffs_base__pixel_subsampling)0x101000)\n#define WUFFS_BASE__PIXEL_SUBSAMPLING__420 \\\n  ((wuffs_base__pixel_subsampling)0x111100)\n#define WUFFS_BASE__PIXEL_SUBSAMPLING__411 \\\n  ((wuffs_base__pixel_subsampling)0x202000)\n#define WUFFS_BASE__PIXEL_SUBSAMPLING__410 \\\n  ((wuffs_base__pixel_subsampling)0x212100)\n\ns" +
+	"tatic inline uint32_t  //\nwuffs_base__pixel_subsampling__bias_x(wuffs_base__pixel_subsampling s,\n                                      uint32_t plane) {\n  uint32_t shift = ((plane & 0x03) * 8) + 6;\n  return (s >> shift) & 0x03;\n}\n\nstatic inline uint32_t  //\nwuffs_base__pixel_subsampling__shift_x(wuffs_base__pixel_subsampling s,\n                                       uint32_t plane) {\n  uint32_t shift = ((plane & 0x03) * 8) + 4;\n  return (s >> shift) & 0x03;\n}\n\nstatic inline uint32_t  //\nwuffs_base__pixel_subsampling__bias_y(wuffs_base__pixel_subsampling s,\n                                      uint32_t plane) {\n  uint32_t shift = ((plane & 0x03) * 8) + 2;\n  return (s >> shift) & 0x03;\n}\n\nstatic inline uint32_t  //\nwuffs_base__pixel_subsampling__shift_y(wuffs_base__pixel_subsampling s,\n                                       uint32_t plane) {\n  uint32_t shift = ((plane & 0x03) * 8) + 0;\n  return (s >> shift) & 0x03;\n}\n\n" +
 	"" +
 	"// --------\n\ntypedef struct {\n  // Do not access the private_impl's fields directly. There is no API/ABI\n  // compatibility or safety guarantee if you do so.\n  struct {\n    wuffs_base__pixel_format pixfmt;\n    wuffs_base__pixel_subsampling pixsub;\n    uint32_t width;\n    uint32_t height;\n  } private_impl;\n\n#ifdef __cplusplus\n  inline void set(wuffs_base__pixel_format pixfmt,\n                  wuffs_base__pixel_subsampling pixsub,\n                  uint32_t width,\n                  uint32_t height);\n  inline void invalidate();\n  inline bool is_valid() const;\n  inline wuffs_base__pixel_format pixel_format() const;\n  inline wuffs_base__pixel_subsampling pixel_subsampling() const;\n  inline wuffs_base__rect_ie_u32 bounds() const;\n  inline uint32_t width() const;\n  inline uint32_t height() const;\n  inline uint64_t pixbuf_len() const;\n#endif  // __cplusplus\n\n} wuffs_base__pixel_config;\n\nstatic inline wuffs_base__pixel_config  //\nwuffs_base__null_pixel_config() {\n  wuffs_base__pixel_config ret;\n  ret.private_impl.pix" +
 	"fmt = 0;\n  ret.private_impl.pixsub = 0;\n  ret.private_impl.width = 0;\n  ret.private_impl.height = 0;\n  return ret;\n}\n\n// TODO: Should this function return bool? An error type?\nstatic inline void  //\nwuffs_base__pixel_config__set(wuffs_base__pixel_config* c,\n                              wuffs_base__pixel_format pixfmt,\n                              wuffs_base__pixel_subsampling pixsub,\n                              uint32_t width,\n                              uint32_t height) {\n  if (!c) {\n    return;\n  }\n  if (pixfmt) {\n    uint64_t wh = ((uint64_t)width) * ((uint64_t)height);\n    // TODO: handle things other than 1 byte per pixel.\n    if (wh <= ((uint64_t)SIZE_MAX)) {\n      c->private_impl.pixfmt = pixfmt;\n      c->private_impl.pixsub = pixsub;\n      c->private_impl.width = width;\n      c->private_impl.height = height;\n      return;\n    }\n  }\n\n  c->private_impl.pixfmt = 0;\n  c->private_impl.pixsub = 0;\n  c->private_impl.width = 0;\n  c->private_impl.height = 0;\n}\n\nstatic inline void  //\nwuffs_base__pixel_co" +
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index cbe1eab..2bfa358 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -1525,38 +1525,12 @@
 
 // --------
 
-// wuffs_base__pixel_subsampling encodes the mapping of pixel space coordinates
-// (x, y) to pixel buffer indices (i, j). That mapping can differ for each
-// plane p. For a depth of 8 bits (1 byte), the p'th plane's sample starts at
-// (planes[p].ptr + (j * planes[p].stride) + i).
+// wuffs_base__pixel_subsampling encodes whether sample values cover one pixel
+// or cover multiple pixels.
 //
-// For interleaved pixel formats, the mapping is trivial: i = x and j = y. For
-// planar pixel formats, the mapping can differ due to chroma subsampling. For
-// example, consider a three plane YCbCr pixel format with 4:2:2 subsampling.
-// For the luma (Y) channel, there is one sample for every pixel, but for the
-// chroma (Cb, Cr) channels, there is one sample for every two pixels: pairs of
-// horizontally adjacent pixels form one macropixel, i = x / 2 and j == y. In
-// general, for a given p:
-//  - i = (x + bias_x) >> shift_x.
-//  - j = (y + bias_y) >> shift_y.
-// where biases and shifts are in the range 0..3 and 0..2 respectively.
+// See https://github.com/google/wuffs/blob/master/doc/note/pixel-subsampling.md
 //
-// In general, the biases will be zero after decoding an image. However, making
-// a sub-image may change the bias, since the (x, y) coordinates are relative
-// to the sub-image's top-left origin, but the backing pixel buffers were
-// created relative to the original image's origin.
-//
-// For each plane p, each of those four numbers (biases and shifts) are encoded
-// in two bits, which combine to form an 8 bit unsigned integer:
-//
-//  e_p = (bias_x << 6) | (shift_x << 4) | (bias_y << 2) | (shift_y << 0)
-//
-// Those e_p values (e_0 for the first plane, e_1 for the second plane, etc)
-// combine to form a wuffs_base__pixel_subsampling value:
-//
-//  pixsub = (e_3 << 24) | (e_2 << 16) | (e_1 << 8) | (e_0 << 0)
-//
-// Do not manipulate these bits directly; they are private implementation
+// Do not manipulate its bits directly; they are private implementation
 // details. Use methods such as wuffs_base__pixel_subsampling__bias_x instead.
 typedef uint32_t wuffs_base__pixel_subsampling;