- 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`.
48 lines
1.9 KiB
TypeScript
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;
|
|
}
|