Files
image-studio/platform/browser/maskRaster.test.ts
syntaxbullet ff762b8f17 feat: add inpaint region functionality and related tools
- Enhanced cursor behavior for new tools: semantic select, mask lasso, and mask rectangle.
- Updated mask edit state to include mask asset ID and kind.
- Implemented inpaint region commands for adding, applying, and removing inpaint regions.
- Introduced new operations for lasso and semantic selection tools.
- Created UI components for candidate review and inpaint region management.
- Added tests for inpaint region commands to ensure functionality.
- Updated various components to support new inpaint features and improve user experience.
2026-07-11 16:41:22 +02:00

57 lines
2.2 KiB
TypeScript

import { describe, expect, test } from "bun:test";
import { blurMaskValues, cropMaskValuesToRgba, dilateMaskValues, erodeMaskValues, expandRectWithinBounds, invertMaskValues, limitMaskValues } 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));
});
test("clips AI edit regions to a retained source crop", () => {
expect([...limitMaskValues(new Uint8ClampedArray(16).fill(255), 4, 4, { x: 1, y: 1, w: 2, h: 2 })]).toEqual([
0, 0, 0, 0,
0, 255, 255, 0,
0, 255, 255, 0,
0, 0, 0, 0,
]);
});
});
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;
}