an image's header, by path, because ffprobe cannot read a HEIC
`/v1/probe` is ffprobe, which is the wrong tool for a still and fails at it loudly: a HEIC out of an iPhone is not a container it understands, so it rejects the file outright with "moov atom not found" rather than reporting no dimensions. So anything needing a photograph's size had nowhere to ask — and a caller building a width ladder needs exactly that, to know which rungs would be an upscale. sharp reads it, HEIC included, because `metadata()` only parses the header. That is precisely the part of a HEIC that works; the pixels are what its bundled libheif cannot reach, which is what decodable.ts routes around. No decode happens, so this needs no job slot. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+33
-1
@@ -1,6 +1,6 @@
|
||||
import { timingSafeEqual } from "node:crypto";
|
||||
import { ASSETS_DIR, MAX_CONCURRENT_JOBS, MAX_UPLOAD_BYTES, PORT, requireToken } from "./config";
|
||||
import { ApiError, invalid, notFound, toErrorResponse } from "./errors";
|
||||
import { ApiError, invalid, notFound, toErrorResponse, unprocessable } from "./errors";
|
||||
import { contentPath, deleteAsset, putAsset, readAsset } from "./assets/store";
|
||||
import { ffprobe } from "./probe/ffprobe";
|
||||
import { runSharp, type SharpRequest } from "./sharp/run";
|
||||
@@ -225,6 +225,38 @@ async function route(request: Request): Promise<Response> {
|
||||
return Response.json(await withSlot(() => ffprobe(target)));
|
||||
}
|
||||
|
||||
/*
|
||||
An image's header, by path.
|
||||
|
||||
Separate from `/v1/probe` because ffprobe is the wrong tool for a still and fails at it loudly: a
|
||||
HEIC out of an iPhone is not a media container it understands, and it rejects the file outright
|
||||
("moov atom not found") rather than reporting no dimensions. Anything that needs a photograph's
|
||||
size — a caller building a width ladder, and therefore needing to know which rungs would be an
|
||||
upscale — had nowhere to ask.
|
||||
|
||||
sharp reads it, including HEIC, because `metadata()` only parses the header. That is precisely the
|
||||
part of a HEIC that works; the pixels are what its bundled libheif cannot reach, which is what
|
||||
`decodable.ts` exists to route around. No decode happens here, so this is cheap and needs no job
|
||||
slot: it is a file header read, not an image operation.
|
||||
*/
|
||||
if (path === "/v1/image" && request.method === "GET") {
|
||||
const target = await safeInputPath(url.searchParams.get("path"), "path");
|
||||
const meta = await sharp(target)
|
||||
.metadata()
|
||||
.catch(() => {
|
||||
throw unprocessable(`Could not read that image: ${target}`);
|
||||
});
|
||||
return Response.json({
|
||||
format: meta.format ?? null,
|
||||
width: meta.width ?? null,
|
||||
height: meta.height ?? null,
|
||||
space: meta.space ?? null,
|
||||
hasAlpha: meta.hasAlpha ?? false,
|
||||
pages: meta.pages ?? 1,
|
||||
orientation: meta.orientation ?? null,
|
||||
});
|
||||
}
|
||||
|
||||
const asset = path.match(/^\/v1\/assets\/([^/]+)(\/content|\/probe)?$/);
|
||||
if (asset) {
|
||||
const [, id, suffix] = asset;
|
||||
|
||||
Reference in New Issue
Block a user