feat: add support for JXL, Camera RAW, ICO, TGA, PSD, EXR, HDR image formats

Extends the platform to handle 7 new image format families alongside
the existing AVIF support gap-fill. Uses the established HEIC decoder
pattern (CLI decode → PNG → Sharp) for formats Sharp can't handle
natively: Camera RAW via dcraw_emu/LibRaw, PSD/TGA/EXR/HDR via
ImageMagick. JXL and ICO are Sharp-native. Adds server-side preview
for non-browser-displayable formats and JXL as a new convert output
target. All 27 validateImageBuffer callers updated with filename for
extension-based format detection.
This commit is contained in:
ashim-hq
2026-04-21 09:59:57 +08:00
parent e94ac945bb
commit 2aadb66031
39 changed files with 583 additions and 43 deletions
@@ -8,6 +8,18 @@ const MAGIC_BYTES: Array<{ bytes: number[]; offset: number; format: string }> =
{ bytes: [0x49, 0x49, 0x2a, 0x00], offset: 0, format: "tiff" }, // Little-endian TIFF
{ bytes: [0x4d, 0x4d, 0x00, 0x2a], offset: 0, format: "tiff" }, // Big-endian TIFF
{ bytes: [0x42, 0x4d], offset: 0, format: "bmp" },
// AVIF (ftyp box at offset 4, brand verified in detectByMagicBytes)
{ bytes: [0x66, 0x74, 0x79, 0x70], offset: 4, format: "avif" },
// JXL ISOBMFF container
{ bytes: [0x00, 0x00, 0x00, 0x0c, 0x4a, 0x58, 0x4c, 0x20], offset: 0, format: "jxl" },
// JXL raw codestream
{ bytes: [0xff, 0x0a], offset: 0, format: "jxl" },
// ICO
{ bytes: [0x00, 0x00, 0x01, 0x00], offset: 0, format: "ico" },
// PSD ("8BPS")
{ bytes: [0x38, 0x42, 0x50, 0x53], offset: 0, format: "psd" },
// OpenEXR
{ bytes: [0x76, 0x2f, 0x31, 0x01], offset: 0, format: "exr" },
];
/**
@@ -49,6 +61,12 @@ function detectByMagicBytes(buffer: Buffer): string {
continue;
}
}
// For ftyp, verify AVIF brand at bytes 8-11
if (entry.format === "avif") {
if (buffer.length < 12) continue;
const brand = buffer.slice(8, 12).toString("ascii");
if (brand !== "avif" && brand !== "avis") continue;
}
return entry.format;
}
}