import { describe, expect, test } from "bun:test"; import { blurMaskValues, cropMaskValuesToRgba, dilateMaskValues, erodeMaskValues, expandRectWithinBounds, invertMaskValues } from "./maskRaster"; describe("mask raster utilities", () => { test("exports the normalized drawn mask without filling the whole crop", () => { const revealedMask = new Uint8ClampedArray(4 * 3).fill(255); revealedMask[1 * 4 + 2] = 0; const inpaintMask = invertMaskValues(revealedMask); const rgba = cropMaskValuesToRgba(inpaintMask, 4, 3, { x: 1, y: 0, w: 3, h: 3 }, 4, 4); const activePixels = activeRedPixels(rgba); expect(activePixels).toEqual([{ x: 1, y: 1 }]); for (let pixel = 0; pixel < rgba.length / 4; pixel += 1) expect(rgba[pixel * 4 + 3]).toBe(255); }); test("expands masked-area crops to the model minimum when possible", () => { expect(expandRectWithinBounds({ x: 20, y: 20, w: 4, h: 4 }, 4, { w: 100, h: 100 }, 8, 64)).toEqual({ x: 0, y: 0, w: 64, h: 64, }); expect(expandRectWithinBounds({ x: 80, y: 80, w: 4, h: 4 }, 4, { w: 100, h: 100 }, 8, 64)).toEqual({ x: 36, y: 36, w: 64, h: 64, }); }); test("uses separable mask kernels without changing square-kernel semantics", () => { const values = new Uint8ClampedArray([0, 0, 0, 0, 255, 0, 0, 0, 0]); expect([...dilateMaskValues(values, 3, 3, 1)]).toEqual(new Array(9).fill(255)); expect([...erodeMaskValues(new Uint8ClampedArray(new Array(9).fill(255)), 3, 3, 1)]).toEqual(new Array(9).fill(255)); expect([...blurMaskValues(values, 3, 3, 1)]).toEqual(new Array(9).fill(28)); }); }); function activeRedPixels(rgba: Uint8ClampedArray) { const width = 4; const pixels: Array<{ x: number; y: number }> = []; for (let pixel = 0; pixel < rgba.length / 4; pixel += 1) { if ((rgba[pixel * 4] ?? 0) > 127) pixels.push({ x: pixel % width, y: Math.floor(pixel / width) }); } return pixels; }