feat: release Colour Tools 0.1.0
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { extractPalette } from "../../src/palette/extract";
|
||||
import { extractPaletteSafely } from "../../src/palette/worker-client";
|
||||
|
||||
const makePixels = (
|
||||
colours: readonly (readonly [number, number, number, number])[],
|
||||
) => ({
|
||||
width: colours.length,
|
||||
height: 1,
|
||||
data: new Uint8ClampedArray(colours.flat()),
|
||||
});
|
||||
|
||||
describe("deterministic Oklab palette extraction", () => {
|
||||
it("returns dominant colours in coverage order", () => {
|
||||
const input = makePixels([
|
||||
[255, 0, 0, 255],
|
||||
[255, 0, 0, 255],
|
||||
[255, 0, 0, 255],
|
||||
[0, 0, 255, 255],
|
||||
]);
|
||||
const palette = extractPalette(input, { count: 2 });
|
||||
|
||||
expect(palette.map((colour) => colour.hex)).toEqual(["#FF0000", "#0000FF"]);
|
||||
expect(palette[0]?.coverage).toBeCloseTo(0.75, 8);
|
||||
expect(palette[1]?.coverage).toBeCloseTo(0.25, 8);
|
||||
});
|
||||
|
||||
it("produces byte-for-byte stable results for repeated runs", () => {
|
||||
const input = makePixels([
|
||||
[248, 245, 238, 255],
|
||||
[20, 80, 180, 255],
|
||||
[245, 140, 20, 255],
|
||||
[248, 245, 238, 255],
|
||||
[25, 85, 175, 220],
|
||||
[240, 145, 25, 255],
|
||||
]);
|
||||
|
||||
const first = extractPalette(input, { count: 3 });
|
||||
const second = extractPalette(input, { count: 3 });
|
||||
expect(second).toEqual(first);
|
||||
});
|
||||
|
||||
it("ignores fully transparent pixels and respects the alpha threshold", () => {
|
||||
const input = makePixels([
|
||||
[255, 0, 255, 0],
|
||||
[255, 0, 0, 15],
|
||||
[0, 255, 0, 255],
|
||||
[0, 0, 255, 255],
|
||||
]);
|
||||
const palette = extractPalette(input, { count: 3, minimumAlpha: 16 });
|
||||
|
||||
expect(palette.map((colour) => colour.hex)).toEqual(["#0000FF", "#00FF00"]);
|
||||
expect(
|
||||
palette.reduce((sum, colour) => sum + colour.coverage, 0),
|
||||
).toBeCloseTo(1, 8);
|
||||
});
|
||||
|
||||
it("handles a fully transparent image without inventing colours", () => {
|
||||
expect(extractPalette(makePixels([[10, 20, 30, 0]]), { count: 6 })).toEqual(
|
||||
[],
|
||||
);
|
||||
});
|
||||
|
||||
it("rejects malformed pixel buffers", () => {
|
||||
expect(() =>
|
||||
extractPalette(
|
||||
{ width: 2, height: 2, data: new Uint8ClampedArray(4) },
|
||||
{ count: 2 },
|
||||
),
|
||||
).toThrow("Invalid pixel buffer");
|
||||
});
|
||||
|
||||
it("falls back safely when Web Workers are unavailable", async () => {
|
||||
const input = makePixels([
|
||||
[255, 0, 0, 255],
|
||||
[0, 0, 255, 255],
|
||||
]);
|
||||
|
||||
vi.stubGlobal("Worker", undefined);
|
||||
try {
|
||||
await expect(
|
||||
extractPaletteSafely(input, { count: 2 }),
|
||||
).resolves.toHaveLength(2);
|
||||
} finally {
|
||||
vi.unstubAllGlobals();
|
||||
}
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user