mirror of
https://github.com/snapotter-hq/SnapOtter.git
synced 2026-08-03 07:46:42 +02:00
feat: add PPM/PGM/PBM CLI decoder fallback, QOI fixture and format-matrix entry
- Add ppm/pgm/pbm to CLI_DECODED_FORMATS with Sharp-first, ImageMagick fallback - Create sample.qoi test fixture (10x10 solid color) - Add QOI to format-matrix test FORMAT_SAMPLES - Mark PPM/PGM/PBM as needsCliDecoder in tests (Sharp doesn't support them natively)
This commit is contained in:
@@ -24,6 +24,9 @@ const CLI_DECODED_FORMATS = new Set([
|
|||||||
"dds",
|
"dds",
|
||||||
"cur",
|
"cur",
|
||||||
"dpx",
|
"dpx",
|
||||||
|
"ppm",
|
||||||
|
"pgm",
|
||||||
|
"pbm",
|
||||||
"fits",
|
"fits",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -78,6 +81,11 @@ export async function decodeToSharpCompat(
|
|||||||
return decodeFits(buffer);
|
return decodeFits(buffer);
|
||||||
case "qoi":
|
case "qoi":
|
||||||
return decodeQoi(buffer);
|
return decodeQoi(buffer);
|
||||||
|
case "ppm":
|
||||||
|
case "pgm":
|
||||||
|
case "pbm":
|
||||||
|
return decodeNetpbm(buffer, format);
|
||||||
|
return decodeQoi(buffer);
|
||||||
default:
|
default:
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
@@ -452,3 +460,27 @@ async function decodeQoi(buffer: Buffer): Promise<Buffer> {
|
|||||||
.png()
|
.png()
|
||||||
.toBuffer();
|
.toBuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Netpbm (PPM/PGM/PBM) decoder ──
|
||||||
|
|
||||||
|
async function decodeNetpbm(buffer: Buffer, format: string): Promise<Buffer> {
|
||||||
|
try {
|
||||||
|
return await sharp(buffer).png().toBuffer();
|
||||||
|
} catch {
|
||||||
|
const cmd = await findMagickCmd();
|
||||||
|
const id = randomUUID();
|
||||||
|
const ext = format === "pgm" ? "pgm" : format === "pbm" ? "pbm" : "ppm";
|
||||||
|
const inputPath = join(tmpdir(), `netpbm-in-${id}.${ext}`);
|
||||||
|
const outputPath = join(tmpdir(), `netpbm-out-${id}.png`);
|
||||||
|
try {
|
||||||
|
await writeFile(inputPath, buffer);
|
||||||
|
await execFileAsync(cmd, magickArgs(cmd, [inputPath, `png:${outputPath}`]), {
|
||||||
|
timeout: 120_000,
|
||||||
|
});
|
||||||
|
return await readFile(outputPath);
|
||||||
|
} finally {
|
||||||
|
await rm(inputPath, { force: true }).catch(() => {});
|
||||||
|
await rm(outputPath, { force: true }).catch(() => {});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Vendored
BIN
Binary file not shown.
@@ -207,7 +207,7 @@ const FORMAT_SAMPLES: FormatSample[] = [
|
|||||||
name: "PPM",
|
name: "PPM",
|
||||||
file: "sample.ppm",
|
file: "sample.ppm",
|
||||||
mime: "image/x-portable-pixmap",
|
mime: "image/x-portable-pixmap",
|
||||||
needsCliDecoder: false,
|
needsCliDecoder: true,
|
||||||
needsHeifDecoder: false,
|
needsHeifDecoder: false,
|
||||||
mayFailValidation: false,
|
mayFailValidation: false,
|
||||||
},
|
},
|
||||||
@@ -215,7 +215,7 @@ const FORMAT_SAMPLES: FormatSample[] = [
|
|||||||
name: "PGM",
|
name: "PGM",
|
||||||
file: "sample.pgm",
|
file: "sample.pgm",
|
||||||
mime: "image/x-portable-graymap",
|
mime: "image/x-portable-graymap",
|
||||||
needsCliDecoder: false,
|
needsCliDecoder: true,
|
||||||
needsHeifDecoder: false,
|
needsHeifDecoder: false,
|
||||||
mayFailValidation: false,
|
mayFailValidation: false,
|
||||||
},
|
},
|
||||||
@@ -223,7 +223,7 @@ const FORMAT_SAMPLES: FormatSample[] = [
|
|||||||
name: "PBM",
|
name: "PBM",
|
||||||
file: "sample.pbm",
|
file: "sample.pbm",
|
||||||
mime: "image/x-portable-bitmap",
|
mime: "image/x-portable-bitmap",
|
||||||
needsCliDecoder: false,
|
needsCliDecoder: true,
|
||||||
needsHeifDecoder: false,
|
needsHeifDecoder: false,
|
||||||
mayFailValidation: false,
|
mayFailValidation: false,
|
||||||
},
|
},
|
||||||
@@ -267,6 +267,14 @@ const FORMAT_SAMPLES: FormatSample[] = [
|
|||||||
needsHeifDecoder: false,
|
needsHeifDecoder: false,
|
||||||
mayFailValidation: false,
|
mayFailValidation: false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "QOI",
|
||||||
|
file: "sample.qoi",
|
||||||
|
mime: "image/x-qoi",
|
||||||
|
needsCliDecoder: true,
|
||||||
|
needsHeifDecoder: false,
|
||||||
|
mayFailValidation: false,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user