From 764efd44833cfe484ffeafa87079d869a80fbc70 Mon Sep 17 00:00:00 2001 From: Yarchik Date: Thu, 2 Jul 2026 02:05:47 +0100 Subject: [PATCH] fix(plugin-color): compute sepia output channels from the original pixel sepia overwrote red, then read that new red when computing green, then read the new red and green when computing blue, so the green and blue outputs were wrong for any non-grayscale pixel. Hold the original r, g, b and derive each output channel from them. Regenerate the sepia snapshot, which had captured the incorrect output. --- .../src/__snapshots__/callbacks.test.ts.snap | 12 ++++----- plugins/plugin-color/src/index.ts | 12 ++++----- plugins/plugin-color/src/sepia.node.test.ts | 25 +++++++++++++++++++ 3 files changed, 37 insertions(+), 12 deletions(-) create mode 100644 plugins/plugin-color/src/sepia.node.test.ts diff --git a/packages/jimp/src/__snapshots__/callbacks.test.ts.snap b/packages/jimp/src/__snapshots__/callbacks.test.ts.snap index cabc6196..88a445e5 100644 --- a/packages/jimp/src/__snapshots__/callbacks.test.ts.snap +++ b/packages/jimp/src/__snapshots__/callbacks.test.ts.snap @@ -269,13 +269,13 @@ AA-8E-1Cᵃᵃ 39-55-C6ᵃᵃ exports[`Callbacks > with sepia 1`] = ` Visualization: -▥◇5 -4□◆ -6▥◇ +268 +▰▰◆ +▾▪▰ Data: -64-22-2Dᶠᶠ C4-F3-B7ᶠᶠ 30-3B-4Eᶠᶠ -FF-FF-E5ᶠᶠ F4-FF-FFᶠᶠ 94-5E-7Cᶠᶠ -64-22-2D⁷ᶠ C4-F3-B7⁷ᶠ 30-3B-4E⁷ᶠ +64-58-45ᶠᶠ C4-AE-88ᶠᶠ 30-2A-21ᶠᶠ +FF-FF-CDᶠᶠ F4-D9-A9ᶠᶠ 94-83-66ᶠᶠ +64-58-45⁷ᶠ C4-AE-88⁷ᶠ 30-2A-21⁷ᶠ `; diff --git a/plugins/plugin-color/src/index.ts b/plugins/plugin-color/src/index.ts index daca8e32..b5576ff1 100644 --- a/plugins/plugin-color/src/index.ts +++ b/plugins/plugin-color/src/index.ts @@ -510,13 +510,13 @@ export const methods = { */ sepia(image: I) { image.scan((_, __, idx) => { - let red = image.bitmap.data[idx]!; - let green = image.bitmap.data[idx + 1]!; - let blue = image.bitmap.data[idx + 2]!; + const r = image.bitmap.data[idx]!; + const g = image.bitmap.data[idx + 1]!; + const b = image.bitmap.data[idx + 2]!; - red = red * 0.393 + green * 0.769 + blue * 0.189; - green = red * 0.349 + green * 0.686 + blue * 0.168; - blue = red * 0.272 + green * 0.534 + blue * 0.131; + const red = r * 0.393 + g * 0.769 + b * 0.189; + const green = r * 0.349 + g * 0.686 + b * 0.168; + const blue = r * 0.272 + g * 0.534 + b * 0.131; image.bitmap.data[idx] = red < 255 ? red : 255; image.bitmap.data[idx + 1] = green < 255 ? green : 255; diff --git a/plugins/plugin-color/src/sepia.node.test.ts b/plugins/plugin-color/src/sepia.node.test.ts new file mode 100644 index 00000000..1232869b --- /dev/null +++ b/plugins/plugin-color/src/sepia.node.test.ts @@ -0,0 +1,25 @@ +import { expect, test, describe } from "vitest"; + +import { methods as color } from "./index.js"; + +function scanImage(data: number[]) { + return { + bitmap: { data: Uint8Array.from(data), width: data.length / 4, height: 1 }, + scan(cb: (x: number, y: number, idx: number) => void) { + for (let idx = 0; idx < this.bitmap.data.length; idx += 4) { + cb(idx / 4, 0, idx); + } + return this; + }, + }; +} + +describe("sepia", () => { + test("computes each output channel from the original pixel", () => { + const image = scanImage([255, 0, 0, 255]); + + color.sepia(image as any); + + expect(Array.from(image.bitmap.data)).toEqual([100, 88, 69, 255]); + }); +});