From 70d55977c0eee3818879143b3893e105d319df18 Mon Sep 17 00:00:00 2001 From: sneak Date: Thu, 8 Jan 2026 11:55:45 -0800 Subject: [PATCH] Add WebP encoding support Uses github.com/gen2brain/webp - a CGO-free library that uses WASM via wazero runtime for encoding. WebP decoding was already supported. - Add gen2brain/webp dependency for encoding - Implement WebP encoding in processor.go - Add FormatWebP to SupportedOutputFormats - Re-enable WebP option in generator form dropdown - Mark WebP encoding as complete in TODO.md --- TODO.md | 2 +- go.mod | 3 +++ go.sum | 6 ++++++ internal/imgcache/processor.go | 11 ++++++++++- internal/templates/generator.html | 1 + 5 files changed, 21 insertions(+), 2 deletions(-) diff --git a/TODO.md b/TODO.md index a502922..0f8fbf4 100644 --- a/TODO.md +++ b/TODO.md @@ -5,7 +5,7 @@ Remaining tasks sorted by priority for a working 1.0 release. ## P0: Critical for 1.0 ### Image Processing -- [ ] Add WebP encoding support (currently returns error) +- [x] Add WebP encoding support (currently returns error) - [ ] Add AVIF encoding support (currently returns error) ### Manual Testing (verify auth/encrypted URLs work) diff --git a/go.mod b/go.mod index 6869ea4..4eec534 100644 --- a/go.mod +++ b/go.mod @@ -52,10 +52,12 @@ require ( github.com/coreos/go-systemd/v22 v22.5.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/dustin/go-humanize v1.0.1 // indirect + github.com/ebitengine/purego v0.8.3 // indirect github.com/emicklei/go-restful/v3 v3.12.1 // indirect github.com/fatih/color v1.16.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/fxamacker/cbor/v2 v2.9.0 // indirect + github.com/gen2brain/webp v0.5.5 // indirect github.com/go-jose/go-jose/v4 v4.0.5 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -109,6 +111,7 @@ require ( github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect github.com/ryanuber/go-glob v1.0.0 // indirect github.com/spf13/pflag v1.0.10 // indirect + github.com/tetratelabs/wazero v1.9.0 // indirect github.com/tidwall/gjson v1.18.0 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect diff --git a/go.sum b/go.sum index 9e7e92d..0e081d6 100644 --- a/go.sum +++ b/go.sum @@ -97,6 +97,8 @@ github.com/disintegration/imaging v1.6.2 h1:w1LecBlG2Lnp8B3jk5zSuNqd7b4DXhcjwek1 github.com/disintegration/imaging v1.6.2/go.mod h1:44/5580QXChDfwIclfc/PCwrr44amcmDAg8hxG0Ewe4= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/ebitengine/purego v0.8.3 h1:K+0AjQp63JEZTEMZiwsI9g0+hAMNohwUOtY0RPGexmc= +github.com/ebitengine/purego v0.8.3/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= github.com/emicklei/go-restful/v3 v3.12.1 h1:PJMDIM/ak7btuL8Ex0iYET9hxM3CI2sjZtzpL63nKAU= github.com/emicklei/go-restful/v3 v3.12.1/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= @@ -110,6 +112,8 @@ github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM= github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ= +github.com/gen2brain/webp v0.5.5 h1:MvQR75yIPU/9nSqYT5h13k4URaJK3gf9tgz/ksRbyEg= +github.com/gen2brain/webp v0.5.5/go.mod h1:xOSMzp4aROt2KFW++9qcK/RBTOVC2S9tJG66ip/9Oc0= github.com/getsentry/sentry-go v0.40.0 h1:VTJMN9zbTvqDqPwheRVLcp0qcUcM+8eFivvGocAaSbo= github.com/getsentry/sentry-go v0.40.0/go.mod h1:eRXCoh3uvmjQLY6qu63BjUZnaBu5L5WhMV1RwYO8W5s= github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE= @@ -379,6 +383,8 @@ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/tetratelabs/wazero v1.9.0 h1:IcZ56OuxrtaEz8UYNRHBrUa9bYeX9oVY93KspZZBf/I= +github.com/tetratelabs/wazero v1.9.0/go.mod h1:TSbcXCfFP0L2FGkRPxHphadXPjo1T6W+CseNNY7EkjM= github.com/tidwall/gjson v1.18.0 h1:FIDeeyB800efLX89e5a8Y0BNH+LOngJyGrIWxG2FKQY= github.com/tidwall/gjson v1.18.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= diff --git a/internal/imgcache/processor.go b/internal/imgcache/processor.go index dc95f59..75f81f6 100644 --- a/internal/imgcache/processor.go +++ b/internal/imgcache/processor.go @@ -12,6 +12,7 @@ import ( "io" "github.com/disintegration/imaging" + gowebp "github.com/gen2brain/webp" "golang.org/x/image/webp" ) @@ -122,6 +123,7 @@ func (p *ImageProcessor) SupportedOutputFormats() []ImageFormat { FormatJPEG, FormatPNG, FormatGIF, + FormatWebP, } } @@ -227,7 +229,14 @@ func (p *ImageProcessor) encode(img image.Image, format ImageFormat, quality int } case FormatWebP: - return nil, fmt.Errorf("%w: WebP encoding not supported", ErrUnsupportedOutputFormat) + options := gowebp.Options{ + Lossless: false, + Quality: quality, + } + err := gowebp.Encode(&buf, img, options) + if err != nil { + return nil, err + } case FormatAVIF: return nil, fmt.Errorf("%w: AVIF encoding not supported", ErrUnsupportedOutputFormat) diff --git a/internal/templates/generator.html b/internal/templates/generator.html index 84f9521..1621f7d 100644 --- a/internal/templates/generator.html +++ b/internal/templates/generator.html @@ -108,6 +108,7 @@ +