fix: restore-photo colorize hang and AVIF decode failures

- Fix dispatcher pipe deadlock: drain stdout pipe in a background thread
  to prevent blocking when ONNX runtime output exceeds 64KB pipe buffer
- Add 5-minute SSE stall timeout so the UI shows an error instead of
  hanging forever when async AI processing stalls
- Guard CPU colorization: skip for images >2MP on CPU and when DDColor
  model is not installed, with clear user-facing messages
- Add AVIF decode fallback via ImageMagick for bitstream variants that
  Sharp's bundled libheif cannot decode (affects all tools)
This commit is contained in:
SnapOtter
2026-05-13 15:42:24 +08:00
parent 917c1ff773
commit 3760885342
6 changed files with 143 additions and 18 deletions
+25
View File
@@ -90,6 +90,31 @@ export async function decodeToSharpCompat(
}
}
/**
* Last-resort decode: convert any image to PNG via ImageMagick.
* Used when Sharp's bundled decoders fail (e.g. AVIF 2.0 bitstreams).
*/
export async function decodeAnyFormat(buffer: Buffer, format: string): Promise<Buffer> {
const cmd = await findMagickCmd();
const id = randomUUID();
const ext = format || "img";
const inputPath = join(tmpdir(), `any-in-${id}.${ext}`);
const outputPath = join(tmpdir(), `any-out-${id}.png`);
try {
await writeFile(inputPath, buffer);
await execFileAsync(
cmd,
magickArgs(cmd, [inputPath, "-colorspace", "sRGB", `png:${outputPath}`]),
{ timeout: 120_000 },
);
return await readFile(outputPath);
} finally {
await rm(inputPath, { force: true }).catch(() => {});
await rm(outputPath, { force: true }).catch(() => {});
}
}
// ── ImageMagick helpers ────────────────────────────────────────
let cachedMagickCmd: string | null = null;