diff --git a/core/artwork/thumbhash/testdata/alpha.png b/core/artwork/thumbhash/testdata/alpha.png index abcefdd5f..6ac85943a 100644 Binary files a/core/artwork/thumbhash/testdata/alpha.png and b/core/artwork/thumbhash/testdata/alpha.png differ diff --git a/core/artwork/thumbhash/testdata/gen_fixtures.mjs b/core/artwork/thumbhash/testdata/gen_fixtures.mjs index 68ddab959..b2e488b51 100644 --- a/core/artwork/thumbhash/testdata/gen_fixtures.mjs +++ b/core/artwork/thumbhash/testdata/gen_fixtures.mjs @@ -39,7 +39,20 @@ const png = (w, h, rgba) => { ]) } +// A ramp has exactly-zero DCT coefficients, and a zero coefficient's nibble is decided by float +// rounding noise, so no two summation orders agree on it. Dither gives every coefficient signal. +let seed = 0 +const dither = () => { + seed ^= seed << 13 + seed ^= seed >>> 17 + seed ^= seed << 5 + seed >>>= 0 + return (seed % 9) - 4 +} +const shade = (v) => Math.max(0, Math.min(255, v + dither())) + const make = (w, h, fn) => { + seed = 0x9e3779b9 const rgba = new Uint8Array(w * h * 4) for (let y = 0; y < h; y++) for (let x = 0; x < w; x++) fn(rgba, (y * w + x) * 4, x, y, w, h) @@ -47,9 +60,9 @@ const make = (w, h, fn) => { } const gradient = (rgba, i, x, y, w, h) => { - rgba[i] = Math.floor((255 * x) / w) - rgba[i + 1] = Math.floor((255 * y) / h) - rgba[i + 2] = Math.floor((255 * (x + y)) / (w + h)) + rgba[i] = shade(Math.floor((255 * x) / w)) + rgba[i + 1] = shade(Math.floor((255 * y) / h)) + rgba[i + 2] = shade(Math.floor((255 * (x + y)) / (w + h))) rgba[i + 3] = 255 } const solid = (rgba, i) => { @@ -61,10 +74,10 @@ const solid = (rgba, i) => { // RGB must vary with position too: a constant color composited over its own average cancels to a // flat L/P/Q (the bug this fixture exists to catch), so pair a color gradient with the alpha ramp. const alphaRamp = (rgba, i, x, y, w, h) => { - rgba[i] = Math.floor((255 * x) / w) - rgba[i + 1] = Math.floor((255 * y) / h) - rgba[i + 2] = Math.floor((255 * (x + y)) / (w + h)) - rgba[i + 3] = Math.floor((255 * x) / w) + rgba[i] = shade(Math.floor((255 * x) / w)) + rgba[i + 1] = shade(Math.floor((255 * y) / h)) + rgba[i + 2] = shade(Math.floor((255 * (x + y)) / (w + h))) + rgba[i + 3] = shade(Math.floor((255 * (x + 2 * y)) / (w + 2 * h))) } const out = new URL('.', import.meta.url).pathname diff --git a/core/artwork/thumbhash/testdata/golden.json b/core/artwork/thumbhash/testdata/golden.json index e38b76638..578986e75 100644 --- a/core/artwork/thumbhash/testdata/golden.json +++ b/core/artwork/thumbhash/testdata/golden.json @@ -1,8 +1,8 @@ { - "alpha.png": "JFiKBQw3s4ewiId3eBtPOfuEgHd4iIh4eA==", - "landscape.png": "3wcOFJpwd3dxd3eHh3ePgAj4hw==", - "portrait.png": "3/cNFBpxB4d3d3d4d3eAjwj3eA==", + "alpha.png": "JOiFBQ4nkIexh3p4iA8uB+lYhIeAh3d4dw==", + "landscape.png": "3wcOFJpwh4eBh3d4iIePgAj3hw==", + "portrait.png": "3/cNFBqBB4iId4d3d4iAjwj4hw==", "solid.png": "HoUBBwB4eHeHd3hweId3h3h4B2+Ih4gA", - "square.png": "HwgOBxpwd4dwd3h3h3eHd3d3+PiIgI8H", + "square.png": "H/gNBxpwh4dwd3eIiHd3iHeHeJ+dcH8I", "tiny.png": "HoU9tx4I9wiIh4hwj3CI+AiIcH/494cP" } diff --git a/core/artwork/thumbhash/testdata/landscape.png b/core/artwork/thumbhash/testdata/landscape.png index 1ae8955ec..413851f47 100644 Binary files a/core/artwork/thumbhash/testdata/landscape.png and b/core/artwork/thumbhash/testdata/landscape.png differ diff --git a/core/artwork/thumbhash/testdata/portrait.png b/core/artwork/thumbhash/testdata/portrait.png index 0877f9e24..bc6e5f0de 100644 Binary files a/core/artwork/thumbhash/testdata/portrait.png and b/core/artwork/thumbhash/testdata/portrait.png differ diff --git a/core/artwork/thumbhash/testdata/square.png b/core/artwork/thumbhash/testdata/square.png index e5d1e1570..a81000cbc 100644 Binary files a/core/artwork/thumbhash/testdata/square.png and b/core/artwork/thumbhash/testdata/square.png differ