refactor: improve tool processing, dropzone, seam carving, and format encoding

- Refactor use-tool-processor and use-pipeline-processor hooks
- Enhance dropzone component with improved UX
- Improve seam carving with better error handling and tests
- Add JXL format encoding support to format-encoders
- Update tool routes for consistent format handling
- Add dropzone unit tests
This commit is contained in:
SnapOtter
2026-05-11 21:57:40 +08:00
parent 656a8d3d44
commit b06906025c
25 changed files with 1368 additions and 436 deletions
+28
View File
@@ -103,3 +103,31 @@ export async function encodeQoi(inputBuffer: Buffer): Promise<Buffer> {
const encoded = qoiEncode(new Uint8Array(data), info.width, info.height, 4);
return Buffer.from(encoded);
}
export async function encodeJxl(inputBuffer: Buffer, quality?: number): Promise<Buffer> {
const id = randomUUID();
const inputPath = join(tmpdir(), `jxl-enc-in-${id}.png`);
const outputPath = join(tmpdir(), `jxl-enc-out-${id}.jxl`);
try {
const pngBuffer = await sharp(inputBuffer).png().toBuffer();
await writeFile(inputPath, pngBuffer);
try {
const q = String(quality ?? 75);
await execFileAsync("cjxl", [inputPath, outputPath, "-q", q], {
timeout: 120_000,
});
return await readFile(outputPath);
} catch {
/* cjxl not available, fall back to ImageMagick */
}
const cmd = await findMagickCmd();
const q = quality ? ["-quality", String(quality)] : [];
await execFileAsync(cmd, magickArgs(cmd, [inputPath, ...q, `jxl:${outputPath}`]), {
timeout: 120_000,
});
return await readFile(outputPath);
} finally {
await rm(inputPath, { force: true }).catch(() => {});
await rm(outputPath, { force: true }).catch(() => {});
}
}