Skip to content

simonheimlicher/hugo-webp-quality-bug

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Hugo 0.153.x WebP Quality Bug

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).

Summary

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.

Reproduction Steps

  1. Clone this repository.
  2. Run hugo.
  3. Inspect the output in public/.
hugo
ls -la public/images/*.webp

Actual Results (Hugo 0.153.3)

All 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

Expected Results (Reference cwebp)

Using cwebp directly shows the expected size variance:

  • q1: ~6 KB
  • q75: ~49 KB

Root Cause Analysis

The bug is in the plumbing between Hugo's image processor and the new WASM encoder.

1. Codec Initialization Uses Global Config

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)

2. Encoder Ignores Per-Image Options

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)

3. WASM Wrapper Uses Stored Quality

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
    // ...
},

Solution

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.

About

Minimal reproduction: Hugo ignores WebP quality/hint parameters in image processing (v0.153.x)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages