mirror of
https://github.com/Ku6epXBOCTuK/easy-png-tools.git
synced 2026-11-14 17:38:19 +00:00
126 lines
3.3 KiB
TypeScript
126 lines
3.3 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
addNoise,
|
|
defringe,
|
|
featherAlpha,
|
|
mulberry32,
|
|
pixelate,
|
|
shuffleBlocks,
|
|
silhouette,
|
|
} from "./pixel-fx";
|
|
import { makeImage } from "./test-helpers";
|
|
|
|
describe("pixelate", () => {
|
|
it("block averaged: 2x2 checker with block 2 -> one color", () => {
|
|
const img = makeImage(2, 2, [
|
|
[0, 0, 0, 255],
|
|
[200, 200, 200, 255],
|
|
[100, 100, 100, 255],
|
|
[140, 140, 140, 255],
|
|
]);
|
|
const out = pixelate(img, 2);
|
|
expect(out.data[0]).toBeCloseTo(110, 0);
|
|
expect(out.data[4]).toBeCloseTo(110, 0);
|
|
});
|
|
|
|
it("solid image unchanged", () => {
|
|
const img = makeImage(3, 3, new Array(9).fill([50, 60, 70, 255]));
|
|
expect([...pixelate(img, 2).data]).toEqual([...img.data]);
|
|
});
|
|
});
|
|
|
|
describe("shuffleBlocks / addNoise - seed determinism", () => {
|
|
it("same seed gives same shuffle", () => {
|
|
const img = makeImage(4, 1, [
|
|
[10, 0, 0, 255],
|
|
[20, 0, 0, 255],
|
|
[30, 0, 0, 255],
|
|
[40, 0, 0, 255],
|
|
]);
|
|
const a = shuffleBlocks(img, 1, 7);
|
|
const b = shuffleBlocks(img, 1, 7);
|
|
expect([...a.data]).toEqual([...b.data]);
|
|
});
|
|
|
|
it("pixel multiset preserved (permutation)", () => {
|
|
const img = makeImage(4, 1, [
|
|
[10, 0, 0, 255],
|
|
[20, 0, 0, 255],
|
|
[30, 0, 0, 255],
|
|
[40, 0, 0, 255],
|
|
]);
|
|
const out = [
|
|
...shuffleBlocks(img, 1, 99).data.filter((_, i) => i % 4 === 0),
|
|
].sort((x, y) => x - y);
|
|
expect(out).toEqual([10, 20, 30, 40]);
|
|
});
|
|
|
|
it("addNoise reproducible at same seed, amount=0 - identity", () => {
|
|
const img = makeImage(2, 2, new Array(4).fill([128, 64, 32, 255]));
|
|
const a = addNoise(img, 20, "mono", 5);
|
|
const b = addNoise(img, 20, "mono", 5);
|
|
expect([...a.data]).toEqual([...b.data]);
|
|
expect([...addNoise(img, 0, "mono", 999).data]).toEqual([...img.data]);
|
|
});
|
|
});
|
|
|
|
describe("featherAlpha", () => {
|
|
it("hard edge gets intermediate alphas", () => {
|
|
// left half opaque, right transparent
|
|
const img = makeImage(6, 1, [
|
|
[255, 0, 0, 255],
|
|
[255, 0, 0, 255],
|
|
[255, 0, 0, 255],
|
|
[255, 0, 0, 0],
|
|
[255, 0, 0, 0],
|
|
[255, 0, 0, 0],
|
|
]);
|
|
const out = featherAlpha(img, 1);
|
|
const alphas = [0, 1, 2].map((x) => out.data[x * 4 + 3]);
|
|
expect(alphas[0]).toBeGreaterThan(240);
|
|
expect(alphas.some((v) => v > 0 && v < 240)).toBe(true);
|
|
});
|
|
});
|
|
|
|
describe("defringe", () => {
|
|
it("semi-transparent pixel takes RGB from opaque neighbor", () => {
|
|
const img = makeImage(2, 1, [
|
|
[250, 250, 250, 255],
|
|
[255, 0, 0, 128],
|
|
]);
|
|
const out = defringe(img, 2);
|
|
expect(out.data[4]).toBe(250);
|
|
expect(out.data[6]).toBe(250);
|
|
expect(out.data[7]).toBe(128); // alpha preserved
|
|
});
|
|
|
|
it("fully transparent areas untouched", () => {
|
|
const img = makeImage(2, 1, [
|
|
[250, 250, 250, 255],
|
|
[0, 0, 0, 0],
|
|
]);
|
|
const out = defringe(img, 2);
|
|
expect(out.data[4 + 3]).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe("silhouette", () => {
|
|
it("visible pixels filled with color, below threshold - transparent", () => {
|
|
const img = makeImage(2, 1, [
|
|
[123, 45, 67, 255],
|
|
[123, 45, 67, 10],
|
|
]);
|
|
const out = silhouette(img, "#00ff00", 50);
|
|
expect([...out.data.slice(0, 4)]).toEqual([0, 255, 0, 255]);
|
|
expect(out.data[4 + 3]).toBe(0);
|
|
});
|
|
});
|
|
|
|
describe("mulberry32", () => {
|
|
it("sequence is deterministic", () => {
|
|
const a = mulberry32(42);
|
|
const b = mulberry32(42);
|
|
expect([a(), a(), a()]).toEqual([b(), b(), b()]);
|
|
});
|
|
});
|