62 lines
1.8 KiB
TypeScript
62 lines
1.8 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import {
|
|
adjustPixels,
|
|
estimateDeskew,
|
|
luminance,
|
|
otsuThreshold,
|
|
} from "../../src/scan/pixels";
|
|
|
|
function rgba(values: number[]) {
|
|
return new Uint8ClampedArray(
|
|
values.flatMap((value) => [value, value, value, 255]),
|
|
);
|
|
}
|
|
|
|
describe("document pixels", () => {
|
|
it("uses perceptual luminance", () => {
|
|
expect(luminance(255, 0, 0)).toBe(54);
|
|
expect(luminance(0, 255, 0)).toBe(182);
|
|
expect(luminance(0, 0, 255)).toBe(18);
|
|
});
|
|
|
|
it("finds a separating Otsu threshold", () => {
|
|
const threshold = otsuThreshold(rgba([5, 10, 15, 230, 240, 250]));
|
|
expect(threshold).toBeGreaterThanOrEqual(15);
|
|
expect(threshold).toBeLessThan(230);
|
|
});
|
|
|
|
it("creates an opaque black-and-white page", () => {
|
|
expect([
|
|
...adjustPixels(rgba([20, 220]), {
|
|
colourMode: "threshold",
|
|
threshold: 100,
|
|
brightness: 0,
|
|
contrast: 0,
|
|
}),
|
|
]).toEqual([0, 0, 0, 255, 255, 255, 255, 255]);
|
|
});
|
|
|
|
it("does not invent skew in an empty page", () => {
|
|
expect(estimateDeskew(rgba(new Array(20 * 20).fill(255)), 20, 20)).toBe(0);
|
|
});
|
|
|
|
it("returns the corrective angle for tilted text lines", () => {
|
|
const width = 120;
|
|
const height = 90;
|
|
const data = rgba(new Array(width * height).fill(255));
|
|
const slope = Math.tan((3 * Math.PI) / 180);
|
|
for (const baseline of [24, 44, 64]) {
|
|
for (let x = 8; x < width - 8; x += 1) {
|
|
const y = Math.round(baseline + (x - width / 2) * slope);
|
|
for (let thickness = -1; thickness <= 1; thickness += 1) {
|
|
const index = ((y + thickness) * width + x) * 4;
|
|
data[index] = 0;
|
|
data[index + 1] = 0;
|
|
data[index + 2] = 0;
|
|
}
|
|
}
|
|
}
|
|
expect(estimateDeskew(data, width, height)).toBeCloseTo(-3, 0);
|
|
});
|
|
});
|