From d36a8f5601258d80b7cc29cce093f5e7c7ac3528 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Bj=C3=B8rn=20Erik=20Pedersen?= Date: Tue, 13 Jan 2026 12:28:47 +0100 Subject: [PATCH] Decode webp.ImageConfig natively This has 2 main benefits: 1. When you only need width/height, we don't need to spin up a WASM runtime. 2. When all processed images are cached in the file cache, we don't need to spin up a WASM runtime. The above is only really visible for smaller sites, but it's annoying to potentially have a site building in 15ms take e.g. 200ms because of WASM startup time. Fixes #14371 --- go.mod | 4 ++-- go.sum | 4 ++++ resources/images/codec.go | 26 +++++++++++++++++++++++++- resources/images/exif/exif.go | 2 +- 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index b2f609c83..f4c3031f7 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/bep/golibsass v1.2.0 github.com/bep/goportabletext v0.1.0 github.com/bep/helpers v0.6.0 - github.com/bep/imagemeta v0.12.1 + github.com/bep/imagemeta v0.13.0 github.com/bep/lazycache v0.8.0 github.com/bep/logg v0.4.0 github.com/bep/mclib v1.20400.20402 @@ -78,7 +78,7 @@ require ( golang.org/x/mod v0.31.0 golang.org/x/net v0.48.0 golang.org/x/sync v0.19.0 - golang.org/x/text v0.32.0 + golang.org/x/text v0.33.0 golang.org/x/tools v0.40.0 google.golang.org/api v0.255.0 rsc.io/qr v0.2.0 diff --git a/go.sum b/go.sum index 7708058ae..59ab21bee 100644 --- a/go.sum +++ b/go.sum @@ -162,6 +162,8 @@ github.com/bep/helpers v0.6.0 h1:qtqMCK8XPFNM9hp5Ztu9piPjxNNkk8PIyUVjg6v8Bsw= github.com/bep/helpers v0.6.0/go.mod h1:IOZlgx5PM/R/2wgyCatfsgg5qQ6rNZJNDpWGXqDR044= github.com/bep/imagemeta v0.12.1 h1:43sIg/XJhXLVOo6troJFj9dyUr1jH+VN2UjO4/l26cQ= github.com/bep/imagemeta v0.12.1/go.mod h1:23AF6O+4fUi9avjiydpKLStUNtJr5hJB4rarG18JpN8= +github.com/bep/imagemeta v0.13.0 h1:xVwqXjxAjtfM5xv9fth8lHq+JsTUy16Ym+HI+sLhMBU= +github.com/bep/imagemeta v0.13.0/go.mod h1:3psQjuZwn53rPCa86ai0p4KKnO+QArpuWLRdi5/30q8= github.com/bep/lazycache v0.8.0 h1:lE5frnRjxaOFbkPZ1YL6nijzOPPz6zeXasJq8WpG4L8= github.com/bep/lazycache v0.8.0/go.mod h1:BQ5WZepss7Ko91CGdWz8GQZi/fFnCcyWupv8gyTeKwk= github.com/bep/logg v0.4.0 h1:luAo5mO4ZkhA5M1iDVDqDqnBBnlHjmtZF6VAyTp+nCQ= @@ -722,6 +724,8 @@ golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/text v0.33.0 h1:B3njUFyqtHDUI5jMn1YIr5B0IE2U0qck04r6d4KPAxE= +golang.org/x/text v0.33.0/go.mod h1:LuMebE6+rBincTi9+xWTY8TztLzKHc/9C1uBCG27+q8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/resources/images/codec.go b/resources/images/codec.go index b36c1b15b..b70d05456 100644 --- a/resources/images/codec.go +++ b/resources/images/codec.go @@ -18,6 +18,7 @@ import ( "errors" "fmt" "image" + "image/color" "image/color/palette" "image/draw" "image/gif" @@ -25,6 +26,7 @@ import ( "image/png" "io" + "github.com/bep/imagemeta" "github.com/gohugoio/hugo/common/himage" "golang.org/x/image/bmp" "golang.org/x/image/tiff" @@ -203,8 +205,30 @@ func (d *Codec) DecodeConfig(r io.Reader) (image.Config, string, error) { if err != nil { return image.Config{}, "", err } + r = rr if format == WEBP { - cfg, err := d.webp.DecodeConfig(rr) + if rs, ok := r.(io.ReadSeeker); ok { + rs.Seek(0, 0) + // Avoid spinning up a WASM runtime if we don't have to. + res, err := imagemeta.Decode( + imagemeta.Options{ + R: rs, + ImageFormat: imagemeta.WebP, + Sources: imagemeta.CONFIG, + }, + ) + if err == nil { + return image.Config{ + Width: res.ImageConfig.Width, + Height: res.ImageConfig.Height, + ColorModel: color.RGBAModel, + }, "webp", nil + } + rs.Seek(0, 0) + r = rs + } + // Fallback to the webp codec config decode. + cfg, err := d.webp.DecodeConfig(r) return cfg, "webp", err } diff --git a/resources/images/exif/exif.go b/resources/images/exif/exif.go index a7f0e0757..8819cd6fe 100644 --- a/resources/images/exif/exif.go +++ b/resources/images/exif/exif.go @@ -187,7 +187,7 @@ func (d *Decoder) Decode(filename string, format imagemeta.ImageFormat, r io.Rea } } - err = imagemeta.Decode( + _, err = imagemeta.Decode( imagemeta.Options{ R: r.(io.ReadSeeker), ImageFormat: format, -- 2.39.5