fix(thumbnails): decode one frame of a png asked for as a still

An animated png carried every frame through imaging.Decode, which only the gif path guarded: a 465 KB file with 200 full-canvas frames allocated 226 MB, now 10 MB. png.Decode reads IDAT and ignores an animation's fdAT chunks.
This commit is contained in:
Dominik Schmidt committed 2026-10-20 17:58:01 +02:00
1 parent 951917e87f
commit 575a17967f
1 file changed
+10 -4
@@ -70,12 +70,18 @@ func extForSourceFormatImaging(src *imagingSource) string {
}
}
// decodeStill reads the pixels of the one frame that is resized here. An
// animated gif only reaches this path when a still format was asked for, and
// imaging.Decode would hold every frame of it in memory to return the first.
// decodeStill reads the pixels of the one frame that is resized here.
// imaging.Decode is DecodeAll plus SingleFrame, so for an animation it holds
// every frame in memory to return the first, and the frame guard only sees a
// gif. The stdlib decoders read the first frame alone: gif.Decode stops after
// it, png.Decode reads IDAT and ignores an animation's later fdAT chunks. The
// rest keeps the imaging path, which is also what reads a JPEG's orientation.
func decodeStill(src *imagingSource) (image.Image, error) {
if src.format == "gif" {
switch src.format {
case "gif":
return gif.Decode(bytes.NewReader(src.data))
case "png":
return png.Decode(bytes.NewReader(src.data))
}
return imaging.Decode(bytes.NewReader(src.data), imaging.AutoOrientation(true))