Files
image-studio/platform/browser/maskRaster.test.ts
syntaxbullet 03493a1c32 feat: add generation cancel job functionality and improve job handling
- Introduced `generationCancelJob` command ID in `commands/ids.ts`.
- Added `GenerationCancelJobPayload` type in `commands/payloads.ts`.
- Enhanced job status to include "cancelled" in `editor/state.ts`.
- Updated `runGenerationJob` to accept an `AbortSignal` and handle cancellation.
- Implemented cancellation logic in `runGenerate` and related functions.
- Added tests for job cancellation in `operations/generation/workflow.test.ts`.
- Improved layer rendering logic to prevent stack overflow in `editor/document-indexes.ts`.
- Added raster size assertions in `platform/browser/rasterLimits.ts` for image processing limits.
- Enhanced image file handling to check for size limits in `platform/browser/imageFiles.ts`.
- Updated UI components to reflect job cancellation state in `view/GenerationJobStatus.tsx` and `view/bottom-controls/GenerateActionControls.tsx`.
2026-07-11 11:37:21 +02:00

48 lines
1.9 KiB
TypeScript

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;
}