Change pixel_subsampling from shift to divide
diff --git a/doc/note/pixel-subsampling.md b/doc/note/pixel-subsampling.md
index ee64478..08f8ea2 100644
--- a/doc/note/pixel-subsampling.md
+++ b/doc/note/pixel-subsampling.md
@@ -2,12 +2,12 @@
`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.
+typically one pixel per sample. For YCbCr pixel formats (i.e. the native
+formats of JPEG and WebP lossy images), the luma channel (Y) is also typically
+one pixel per sample but the chroma channels (Cb, Cr) are often 2 or 4 pixels
+per sample. In JPEG terminology, 4:4:4, 4:2:2 or 4:2:0 subsampling correspond
+to 1, 2 or 4 pixels per [chroma
+sample](https://en.wikipedia.org/wiki/Chroma_subsampling).
Equivalently, `wuffs_base__pixel_subsampling` encodes the mapping of pixel
space coordinates `(x, y)` to sample space coordinates `(i, j)`, also known as
@@ -23,21 +23,22 @@
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`.
+- `i = (x + bias_x) / denominator_x`.
+- `j = (y + bias_y) / denominator_y`.
-where biases and shifts are in the range `0 ..= 3` and `0 ..= 2` respectively.
+where biases and denominators are in the range `0 ..= 3` and `1 ..= 4`
+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`).
+For example, consider a 10×3 image with what JPEG calls 4:1:1 subsampling,
+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
+`denominator_x = 2`, so that the 6th pixel column (`x = 5`) maps to the 2nd
+sample column (`i = 1`).
```
Pixel space:
@@ -49,7 +50,7 @@
|t21 t21 t22|t23 u24 u25|u26 u27 v28 v29|
+-----------+-----------+---------------+
-Sample space:
+Chroma sample space:
+-----+
|l m n|
| |
@@ -62,7 +63,8 @@
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`.
+columns (`t` and `u`). `denominator_x = 2`, the same as before, but now `bias_x
+= 3`.
```
Pixel space:
@@ -70,7 +72,7 @@
|t23 u24 u25|
+-----------+
-Sample space:
+Chroma sample space:
+---+
|t u|
+---+
@@ -79,13 +81,16 @@
## 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:
+For each plane `p`, the adjusted denominator is defined to be one less than the
+denominator. The plane's four numbers (two biases and two adjusted
+denominators) are each in the range `0 ..= 3`, and are each encodable in two
+bits. Four groups of two bits combine to form an 8 bit unsigned integer:
```
-e_p = (bias_x << 6) | (shift_x << 4) | (bias_y << 2) | (shift_y << 0)
+e_p = (bias_x << 6) | (adj_denom_x << 4) | (bias_y << 2) | (adj_denom_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:
@@ -93,7 +98,26 @@
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
+For example, visualizing 4:2:2 YCbCr (with no bias):
+
+```
+Pixel space:
++-------------------+
+|l00 l01 m02 m03 n04|
+| |
+|p10 p11 q12 q13 r14|
++-------------------+
+
+Chroma sample space:
++-----+
+|l m n|
+| |
+|p q r|
++-----+
+```
+
+This corresponds to a `denominator_x` of 1, 2 and 2 for the three planes (Y,
+Cb, Cr) and a `denominator_y` of 1, 1 and 1. The `uint32_t` encoding is
`0x101000`.
diff --git a/internal/cgen/base/image-public.h b/internal/cgen/base/image-public.h
index a7a83b7..e242af1 100644
--- a/internal/cgen/base/image-public.h
+++ b/internal/cgen/base/image-public.h
@@ -150,9 +150,9 @@
#define WUFFS_BASE__PIXEL_SUBSAMPLING__420 \
((wuffs_base__pixel_subsampling)0x111100)
#define WUFFS_BASE__PIXEL_SUBSAMPLING__411 \
- ((wuffs_base__pixel_subsampling)0x202000)
+ ((wuffs_base__pixel_subsampling)0x303000)
#define WUFFS_BASE__PIXEL_SUBSAMPLING__410 \
- ((wuffs_base__pixel_subsampling)0x212100)
+ ((wuffs_base__pixel_subsampling)0x313100)
static inline uint32_t //
wuffs_base__pixel_subsampling__bias_x(wuffs_base__pixel_subsampling s,
@@ -162,10 +162,10 @@
}
static inline uint32_t //
-wuffs_base__pixel_subsampling__shift_x(wuffs_base__pixel_subsampling s,
- uint32_t plane) {
+wuffs_base__pixel_subsampling__denominator_x(wuffs_base__pixel_subsampling s,
+ uint32_t plane) {
uint32_t shift = ((plane & 0x03) * 8) + 4;
- return (s >> shift) & 0x03;
+ return ((s >> shift) & 0x03) + 1;
}
static inline uint32_t //
@@ -176,10 +176,10 @@
}
static inline uint32_t //
-wuffs_base__pixel_subsampling__shift_y(wuffs_base__pixel_subsampling s,
- uint32_t plane) {
+wuffs_base__pixel_subsampling__denominator_y(wuffs_base__pixel_subsampling s,
+ uint32_t plane) {
uint32_t shift = ((plane & 0x03) * 8) + 0;
- return (s >> shift) & 0x03;
+ return ((s >> shift) & 0x03) + 1;
}
// --------
diff --git a/internal/cgen/data.go b/internal/cgen/data.go
index 121ce05..29e7c7e 100644
--- a/internal/cgen/data.go
+++ b/internal/cgen/data.go
@@ -110,8 +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 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\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)0x303000)\n#define WUFFS_BASE__PIXEL_SUBSAMPLING__410 \\\n ((wuffs_base__pixel_subsampling)0x313100)\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__denominator_x(wuffs_base__pixel_subsampling s,\n uint32_t plane) {\n uint32_t shift = ((plane & 0x03) * 8) + 4;\n return ((s >> shift) & 0x03) + 1;\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__denominator_y(wuffs_base__pixel_subsampling s,\n uint32_t plane) {\n uint32_t shift = ((plane & 0x03) * 8) + 0;\n return ((s >> shift) & 0x03) + 1;\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 2bfa358..8fb3b69 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -1545,9 +1545,9 @@
#define WUFFS_BASE__PIXEL_SUBSAMPLING__420 \
((wuffs_base__pixel_subsampling)0x111100)
#define WUFFS_BASE__PIXEL_SUBSAMPLING__411 \
- ((wuffs_base__pixel_subsampling)0x202000)
+ ((wuffs_base__pixel_subsampling)0x303000)
#define WUFFS_BASE__PIXEL_SUBSAMPLING__410 \
- ((wuffs_base__pixel_subsampling)0x212100)
+ ((wuffs_base__pixel_subsampling)0x313100)
static inline uint32_t //
wuffs_base__pixel_subsampling__bias_x(wuffs_base__pixel_subsampling s,
@@ -1557,10 +1557,10 @@
}
static inline uint32_t //
-wuffs_base__pixel_subsampling__shift_x(wuffs_base__pixel_subsampling s,
- uint32_t plane) {
+wuffs_base__pixel_subsampling__denominator_x(wuffs_base__pixel_subsampling s,
+ uint32_t plane) {
uint32_t shift = ((plane & 0x03) * 8) + 4;
- return (s >> shift) & 0x03;
+ return ((s >> shift) & 0x03) + 1;
}
static inline uint32_t //
@@ -1571,10 +1571,10 @@
}
static inline uint32_t //
-wuffs_base__pixel_subsampling__shift_y(wuffs_base__pixel_subsampling s,
- uint32_t plane) {
+wuffs_base__pixel_subsampling__denominator_y(wuffs_base__pixel_subsampling s,
+ uint32_t plane) {
uint32_t shift = ((plane & 0x03) * 8) + 0;
- return (s >> shift) & 0x03;
+ return ((s >> shift) & 0x03) + 1;
}
// --------