This repository demonstrates a bug in Hugo 0.153.x where the quality parameter is ignored when processing WebP images.
Affected Versions: Hugo 0.153.0 - 0.153.3 (current HEAD)
Impact: Unable to control WebP compression quality; filtering functions like .Resize "... webp q50" generally fail to apply the specific quality, defaulting to the global site configuration (typically q75).
Hugo 0.153.0 introduced a new WebAssembly-based WebP encoder (via PR #14234). This new encoder is initialized once with the global site configuration's quality setting. It subsequently ignores the specific quality parameters passed during individual image processing calls (e.g., via Resize, Fit, etc.).
As a result, an image processed with q1 and q100 will result in identical binary output, differing significantly from expected behavior.
- Clone this repository.
- Run
hugo. - Inspect the output in
public/.
hugo
ls -la public/images/*.webpAll files are identical in size (~49KB), regardless of the requested quality:
-rw-r--r-- ... 49432 ... test_hu_..._q1.webp
-rw-r--r-- ... 49432 ... test_hu_..._q10.webp
-rw-r--r-- ... 49432 ... test_hu_..._q25.webp
-rw-r--r-- ... 49432 ... test_hu_..._q50.webp
-rw-r--r-- ... 49432 ... test_hu_..._q75.webp
Using cwebp directly shows the expected size variance:
- q1: ~6 KB
- q75: ~49 KB
The bug is in the plumbing between Hugo's image processor and the new WASM encoder.
In resources/images/image.go, the codec is created once using cfg.Config.Imaging.Quality (the global default).
// resources/images/image.go L140
webpCodec, err := wasmDispatchers.NewWepCodec(cfg.Config.Imaging.Quality, cfg.Config.Imaging.Hint)In resources/images/codec.go, the EncodeTo method receives the specific conf (which contains the correct user-requested quality), but it is ignored for WebP.
// resources/images/codec.go L64
func (d *Codec) EncodeTo(conf ImageConfig, w io.Writer, img image.Image) error {
switch conf.TargetFormat {
case JPEG:
// Correctly uses conf.Quality
return jpeg.Encode(w, img, &jpeg.Options{Quality: conf.Quality})
// ...
case WEBP:
// BUG: conf (and conf.Quality) is ignored.
// d.webp is the pre-configured instance from step 1.
return d.webp.Encode(w, img)In internal/warpc/webp.go, the encoder uses the quality field stored in the struct during initialization.
// internal/warpc/webp.go L314
Options: map[string]any{
"quality": d.quality, // Uses fixed quality from initialization
// ...
},The WebpCodec.Encode method (and the CodecStdlib interface) needs to support passing ImageConfig or at least the quality parameter, rather than relying on the struct's initial state.