v4: a still is scaled from its first frame alone, a second image in its file made the copy flash — an avatar came out as a WebP of two frames looping at 40 ms each, the picture then a blank. A still's file may hold more than one image, a phone's JPEG carrying a gain map or a depth map after the photo, and ffmpeg reads each as a frame: only the JPEG and PNG copies were held to one, the WebP keeping them all as it does a GIF's. scalableImage (lib/upload.ts) now says whether the image is an animation, which a GIF alone is, and scaleImage (lib/ffmpeg.ts) writes one frame of anything else, in every format; the image proxy scales through the same call. The copies already made stay, a copy being current while it has its upload's date: uploads/scaled is to be deleted once on an instance that ran the previous version, everything in it being made again on first request.
All checks were successful
Build and Publish Docker Image / build-and-push (push) Successful in 52s
Build and Deploy Static Documentation Site / build-and-push (push) Successful in 26s

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
khannurien
2026-10-10 19:40:14 +00:00
parent d2b7d21824
commit cbb770bff8
5 changed files with 68 additions and 25 deletions

View File

@@ -94,17 +94,27 @@ Deno.test("scalableImage: an animated WebP and what isn't an image are served as
assertEquals(scalableImage(webp(0x02)), null);
// A reader without WebP gets a PNG of what may be transparent, a JPEG of
// the rest.
assertEquals(scalableImage(webp(0x10)), { orientation: 1, compat: "png" });
const still = { orientation: 1, animated: false };
assertEquals(scalableImage(webp(0x10)), { ...still, compat: "png" });
assertEquals(
scalableImage(new TextEncoder().encode("RIFF\0\0\0\0WEBPVP8 ")),
{ orientation: 1, compat: "png" },
{ ...still, compat: "png" },
);
assertEquals(scalableImage(PNG), { orientation: 1, compat: "png" });
assertEquals(scalableImage(jpegWithOrientation(1, true))?.compat, "jpg");
assertEquals(scalableImage(new TextEncoder().encode("BM-a-bitmap")), {
orientation: 1,
assertEquals(scalableImage(PNG), { ...still, compat: "png" });
assertEquals(scalableImage(jpegWithOrientation(1, true)), {
...still,
compat: "jpg",
});
assertEquals(scalableImage(new TextEncoder().encode("BM-a-bitmap")), {
...still,
compat: "jpg",
});
// Only a GIF's frames are an animation to keep.
assertEquals(scalableImage(new TextEncoder().encode("GIF89a")), {
orientation: 1,
animated: true,
compat: "png",
});
assertEquals(scalableImage(new TextEncoder().encode("<svg/>")), null);
assertEquals(scalableImage(new Uint8Array()), null);
});