detached ea79ba3

feat(favicon): decode WebP favicons safely

commit
ea79ba36a62c0a6cf571ab490c651cd461c27be7
author
brice · · 2026-07-14 15:14 UTC
committer
brice · · 2026-07-14 17:20 UTC
parent
45b5ee0
signature
GPG VerifiedCD88F9E564E0102646FB6077A1A07C7C7C3E349D · arch-gpg Verified for the committer email
25 files · +3576 -11
M README.md +3 -2
@@ -134,7 +134,7 @@ Dumber uses Chromium Embedded Framework by default. WebKitGTK is available as a
134134 On Arch Linux, install the CEF runtime with:
135135
136136 ```bash
137-sudo pacman -S cef
137+sudo pacman -S cef libwebp
138138 ```
139139
140140 For hardware video decoding, `cef-vaapi` is also available from the AUR as an optional CEF build.
@@ -179,7 +179,7 @@ CEF OSR frame rate adapts to the active Wayland monitor refresh rate when both `
179179 **Arch Linux:**
180180
181181 ```bash
182-sudo pacman -S cef webkitgtk-6.0 gtk4 gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugin-va
182+sudo pacman -S cef webkitgtk-6.0 gtk4 libwebp gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugin-va
183183 ```
184184
185185 **Debian/Ubuntu:**
@@ -213,6 +213,7 @@ Set `ENV=dev` to use `.dev/dumber/` for config and data instead of XDG paths.
213213 - CEF runtime (default backend)
214214 - WebKitGTK 6.0 development/runtime packages (fallback backend and runtime checks)
215215 - Brotli for compressed systemviews assets
216+- libwebp runtime for WebP favicon decoding (for example `libwebp` on Arch)
216217
217218 Systemviews assets are generated with `go tool templ` and Go's `js/wasm` toolchain; no root Node toolchain is required.
218219
@@ -134,7 +134,7 @@ Dumber uses Chromium Embedded Framework by default. WebKitGTK is available as a
134 On Arch Linux, install the CEF runtime with:134 On Arch Linux, install the CEF runtime with:
135 135
136 ```bash136 ```bash
137-sudo pacman -S cef137+sudo pacman -S cef libwebp
138 ```138 ```
139 139
140 For hardware video decoding, `cef-vaapi` is also available from the AUR as an optional CEF build.140 For hardware video decoding, `cef-vaapi` is also available from the AUR as an optional CEF build.
@@ -179,7 +179,7 @@ CEF OSR frame rate adapts to the active Wayland monitor refresh rate when both `
179 **Arch Linux:**179 **Arch Linux:**
180 180
181 ```bash181 ```bash
182-sudo pacman -S cef webkitgtk-6.0 gtk4 gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugin-va182+sudo pacman -S cef webkitgtk-6.0 gtk4 libwebp gst-plugins-base gst-plugins-good gst-plugins-bad gst-plugin-va
183 ```183 ```
184 184
185 **Debian/Ubuntu:**185 **Debian/Ubuntu:**
@@ -213,6 +213,7 @@ Set `ENV=dev` to use `.dev/dumber/` for config and data instead of XDG paths.
213 - CEF runtime (default backend)213 - CEF runtime (default backend)
214 - WebKitGTK 6.0 development/runtime packages (fallback backend and runtime checks)214 - WebKitGTK 6.0 development/runtime packages (fallback backend and runtime checks)
215 - Brotli for compressed systemviews assets215 - Brotli for compressed systemviews assets
216+- libwebp runtime for WebP favicon decoding (for example `libwebp` on Arch)
216 217
217 Systemviews assets are generated with `go tool templ` and Go's `js/wasm` toolchain; no root Node toolchain is required.218 Systemviews assets are generated with `go tool templ` and Go's `js/wasm` toolchain; no root Node toolchain is required.
218 219
M aur/dumber-browser-bin/.SRCINFO +1 -0
@@ -8,6 +8,7 @@ pkgbase = dumber-browser-bin
88 depends = gtk4
99 depends = cef
1010 depends = webkitgtk-6.0
11+ depends = libwebp
1112 optdepends = gst-plugins-base: Base media codecs
1213 optdepends = gst-plugins-good: Additional media codecs
1314 optdepends = gst-plugins-bad: Extended media codecs
@@ -8,6 +8,7 @@ pkgbase = dumber-browser-bin
8 depends = gtk48 depends = gtk4
9 depends = cef9 depends = cef
10 depends = webkitgtk-6.010 depends = webkitgtk-6.0
11+ depends = libwebp
11 optdepends = gst-plugins-base: Base media codecs12 optdepends = gst-plugins-base: Base media codecs
12 optdepends = gst-plugins-good: Additional media codecs13 optdepends = gst-plugins-good: Additional media codecs
13 optdepends = gst-plugins-bad: Extended media codecs14 optdepends = gst-plugins-bad: Extended media codecs
M aur/dumber-browser-bin/PKGBUILD +1 -1
@@ -6,7 +6,7 @@ pkgdesc="A minimal keyboard-driven browser for tiling WMs"
66 arch=('x86_64')
77 url="https://github.com/bnema/dumber"
88 license=('MIT')
9-depends=('gtk4' 'cef' 'webkitgtk-6.0')
9+depends=('gtk4' 'cef' 'webkitgtk-6.0' 'libwebp')
1010 optdepends=(
1111 'gst-plugins-base: Base media codecs'
1212 'gst-plugins-good: Additional media codecs'
@@ -6,7 +6,7 @@ pkgdesc="A minimal keyboard-driven browser for tiling WMs"
6 arch=('x86_64')6 arch=('x86_64')
7 url="https://github.com/bnema/dumber"7 url="https://github.com/bnema/dumber"
8 license=('MIT')8 license=('MIT')
9-depends=('gtk4' 'cef' 'webkitgtk-6.0')9+depends=('gtk4' 'cef' 'webkitgtk-6.0' 'libwebp')
10 optdepends=(10 optdepends=(
11 'gst-plugins-base: Base media codecs'11 'gst-plugins-base: Base media codecs'
12 'gst-plugins-good: Additional media codecs'12 'gst-plugins-good: Additional media codecs'
M aur/dumber-browser-git/.SRCINFO +1 -0
@@ -11,6 +11,7 @@ pkgbase = dumber-browser-git
1111 depends = gtk4
1212 depends = cef
1313 depends = webkitgtk-6.0
14+ depends = libwebp
1415 optdepends = gst-plugins-base: Base media codecs
1516 optdepends = gst-plugins-good: Additional media codecs
1617 optdepends = gst-plugins-bad: Extended media codecs
@@ -11,6 +11,7 @@ pkgbase = dumber-browser-git
11 depends = gtk411 depends = gtk4
12 depends = cef12 depends = cef
13 depends = webkitgtk-6.013 depends = webkitgtk-6.0
14+ depends = libwebp
14 optdepends = gst-plugins-base: Base media codecs15 optdepends = gst-plugins-base: Base media codecs
15 optdepends = gst-plugins-good: Additional media codecs16 optdepends = gst-plugins-good: Additional media codecs
16 optdepends = gst-plugins-bad: Extended media codecs17 optdepends = gst-plugins-bad: Extended media codecs
M aur/dumber-browser-git/PKGBUILD +1 -1
@@ -7,7 +7,7 @@ arch=('x86_64')
77 url="https://github.com/bnema/dumber"
88 license=('MIT')
99 makedepends=('go>=1.26' 'git' 'brotli')
10-depends=('gtk4' 'cef' 'webkitgtk-6.0')
10+depends=('gtk4' 'cef' 'webkitgtk-6.0' 'libwebp')
1111 optdepends=(
1212 'gst-plugins-base: Base media codecs'
1313 'gst-plugins-good: Additional media codecs'
@@ -7,7 +7,7 @@ arch=('x86_64')
7 url="https://github.com/bnema/dumber"7 url="https://github.com/bnema/dumber"
8 license=('MIT')8 license=('MIT')
9 makedepends=('go>=1.26' 'git' 'brotli')9 makedepends=('go>=1.26' 'git' 'brotli')
10-depends=('gtk4' 'cef' 'webkitgtk-6.0')10+depends=('gtk4' 'cef' 'webkitgtk-6.0' 'libwebp')
11 optdepends=(11 optdepends=(
12 'gst-plugins-base: Base media codecs'12 'gst-plugins-base: Base media codecs'
13 'gst-plugins-good: Additional media codecs'13 'gst-plugins-good: Additional media codecs'
M flatpak/dev.bnema.Dumber.yml +1 -0
@@ -1,6 +1,7 @@
11 id: dev.bnema.Dumber
22 runtime: org.gnome.Platform
33 runtime-version: '49'
4+# org.gnome.Platform provides libwebp at runtime for purego WebP favicon decoding.
45 sdk: org.gnome.Sdk
56 command: dumber
67
@@ -1,6 +1,7 @@
1 id: dev.bnema.Dumber1 id: dev.bnema.Dumber
2 runtime: org.gnome.Platform2 runtime: org.gnome.Platform
3 runtime-version: '49'3 runtime-version: '49'
4+# org.gnome.Platform provides libwebp at runtime for purego WebP favicon decoding.
4 sdk: org.gnome.Sdk5 sdk: org.gnome.Sdk
5 command: dumber6 command: dumber
6 7
M go.mod +3 -0
@@ -10,6 +10,7 @@ require (
1010 github.com/bnema/purego-cef2gtk v0.8.4-0.20260714160309-bbd397409ebe
1111 github.com/bnema/purego-pipewire v0.1.5-0.20260714124450-6504b9cdf02a
1212 github.com/bnema/purego-sqlite v0.1.4-0.20260714131321-3614fe683b9c
13+ github.com/bnema/purego-webp v0.2.1-0.20260714121650-bc33db63042a
1314 github.com/bnema/puregotk v0.7.1-0.20260714170452-0b6b9b901234
1415 github.com/charmbracelet/bubbles v1.0.0
1516 github.com/charmbracelet/bubbletea v1.3.10
@@ -82,3 +83,5 @@ require (
8283 )
8384
8485 tool github.com/a-h/templ/cmd/templ
86+
87+replace github.com/bnema/purego-webp => ./third_party/purego-webp
@@ -10,6 +10,7 @@ require (
10 github.com/bnema/purego-cef2gtk v0.8.4-0.20260714160309-bbd397409ebe10 github.com/bnema/purego-cef2gtk v0.8.4-0.20260714160309-bbd397409ebe
11 github.com/bnema/purego-pipewire v0.1.5-0.20260714124450-6504b9cdf02a11 github.com/bnema/purego-pipewire v0.1.5-0.20260714124450-6504b9cdf02a
12 github.com/bnema/purego-sqlite v0.1.4-0.20260714131321-3614fe683b9c12 github.com/bnema/purego-sqlite v0.1.4-0.20260714131321-3614fe683b9c
13+ github.com/bnema/purego-webp v0.2.1-0.20260714121650-bc33db63042a
13 github.com/bnema/puregotk v0.7.1-0.20260714170452-0b6b9b90123414 github.com/bnema/puregotk v0.7.1-0.20260714170452-0b6b9b901234
14 github.com/charmbracelet/bubbles v1.0.015 github.com/charmbracelet/bubbles v1.0.0
15 github.com/charmbracelet/bubbletea v1.3.1016 github.com/charmbracelet/bubbletea v1.3.10
@@ -82,3 +83,5 @@ require (
82 )83 )
83 84
84 tool github.com/a-h/templ/cmd/templ85 tool github.com/a-h/templ/cmd/templ
86+
87+replace github.com/bnema/purego-webp => ./third_party/purego-webp
M internal/application/usecase/favicon_test.go +19 -0
@@ -404,6 +404,25 @@ func TestFaviconObserveConversionErrorDoesNotMutateExistingAssets(t *testing.T)
404404 }
405405 }
406406
407+func TestFaviconObserveUnavailableWebPPreservesCachedAssets(t *testing.T) {
408+ fx := newFaviconFixture(t)
409+ fx.seedOriginal([]byte("old"))
410+ fx.blobs.png["example.com"] = []byte("old-png")
411+ fx.blobs.sized["example.com"] = map[int][]byte{32: []byte("old-32")}
412+ fx.converter.errByContentType = map[string]error{"image/webp": ErrFaviconMiss}
413+
414+ _, err := fx.uc.Observe(context.Background(), "https://example.com", "https://example.com/favicon.webp", []byte("webp"), favicon.SourceEngine, "image/webp")
415+ if !errors.Is(err, ErrFaviconMiss) {
416+ t.Fatalf("Observe err=%v, want favicon miss", err)
417+ }
418+ if string(fx.blobs.original["example.com"]) != "old" || string(fx.blobs.png["example.com"]) != "old-png" || string(fx.blobs.sized["example.com"][32]) != "old-32" {
419+ t.Fatalf("cached assets changed after unavailable WebP decoder")
420+ }
421+ if fx.blobs.writeOriginals != 0 || fx.blobs.removeDerived != 0 || fx.invalidators.calls != 0 {
422+ t.Fatalf("unavailable decoder mutated cache: writes=%d removes=%d invalidations=%d", fx.blobs.writeOriginals, fx.blobs.removeDerived, fx.invalidators.calls)
423+ }
424+}
425+
407426 func TestFaviconEnsureSizedPropagatesReadSizedErrors(t *testing.T) {
408427 fx := newFaviconFixture(t)
409428 fx.seedOriginal([]byte("old"))
@@ -404,6 +404,25 @@ func TestFaviconObserveConversionErrorDoesNotMutateExistingAssets(t *testing.T)
404 }404 }
405 }405 }
406 406
407+func TestFaviconObserveUnavailableWebPPreservesCachedAssets(t *testing.T) {
408+ fx := newFaviconFixture(t)
409+ fx.seedOriginal([]byte("old"))
410+ fx.blobs.png["example.com"] = []byte("old-png")
411+ fx.blobs.sized["example.com"] = map[int][]byte{32: []byte("old-32")}
412+ fx.converter.errByContentType = map[string]error{"image/webp": ErrFaviconMiss}
413+
414+ _, err := fx.uc.Observe(context.Background(), "https://example.com", "https://example.com/favicon.webp", []byte("webp"), favicon.SourceEngine, "image/webp")
415+ if !errors.Is(err, ErrFaviconMiss) {
416+ t.Fatalf("Observe err=%v, want favicon miss", err)
417+ }
418+ if string(fx.blobs.original["example.com"]) != "old" || string(fx.blobs.png["example.com"]) != "old-png" || string(fx.blobs.sized["example.com"][32]) != "old-32" {
419+ t.Fatalf("cached assets changed after unavailable WebP decoder")
420+ }
421+ if fx.blobs.writeOriginals != 0 || fx.blobs.removeDerived != 0 || fx.invalidators.calls != 0 {
422+ t.Fatalf("unavailable decoder mutated cache: writes=%d removes=%d invalidations=%d", fx.blobs.writeOriginals, fx.blobs.removeDerived, fx.invalidators.calls)
423+ }
424+}
425+
407 func TestFaviconEnsureSizedPropagatesReadSizedErrors(t *testing.T) {426 func TestFaviconEnsureSizedPropagatesReadSizedErrors(t *testing.T) {
408 fx := newFaviconFixture(t)427 fx := newFaviconFixture(t)
409 fx.seedOriginal([]byte("old"))428 fx.seedOriginal([]byte("old"))
M internal/infrastructure/favicon/converter.go +19 -7
@@ -16,17 +16,25 @@ import (
1616 )
1717
1818 // ImageConverter converts safe favicon image formats into normalized PNGs.
19-type ImageConverter struct{}
19+type ImageConverter struct {
20+ webp *webPDecoder
21+}
22+
23+func NewImageConverter() *ImageConverter { return &ImageConverter{webp: newDefaultWebPDecoder()} }
2024
21-func NewImageConverter() *ImageConverter { return &ImageConverter{} }
25+// newImageConverterWithWebPRuntime provides an infrastructure test seam while
26+// application ports remain independent of the libwebp implementation.
27+func newImageConverterWithWebPRuntime(runtime webpRuntime) *ImageConverter {
28+ return &ImageConverter{webp: newWebPDecoder(runtime)}
29+}
2230
23-func (*ImageConverter) Convert(ctx context.Context, original []byte, contentType string, sizes []int) (*appport.ConvertedFavicon, error) {
31+func (c *ImageConverter) Convert(ctx context.Context, original []byte, contentType string, sizes []int) (*appport.ConvertedFavicon, error) {
2432 _ = ctx
2533 if len(original) == 0 {
2634 return nil, fmt.Errorf("%w: empty image", appport.ErrFaviconMiss)
2735 }
2836
29- img, err := decodeFaviconImage(original, normalizeContentType(contentType))
37+ img, err := decodeFaviconImage(original, normalizeContentType(contentType), c.webp)
3038 if err != nil {
3139 return nil, err
3240 }
@@ -48,7 +56,7 @@ func (*ImageConverter) Convert(ctx context.Context, original []byte, contentType
4856 return out, nil
4957 }
5058
51-func decodeFaviconImage(data []byte, ct string) (image.Image, error) {
59+func decodeFaviconImage(data []byte, ct string, webp *webPDecoder) (image.Image, error) {
5260 switch ct {
5361 case "image/svg+xml":
5462 return nil, fmt.Errorf("%w: svg favicon conversion is disabled", appport.ErrFaviconMiss)
@@ -59,9 +67,13 @@ func decodeFaviconImage(data []byte, ct string) (image.Image, error) {
5967 }
6068 return img, nil
6169 case "image/webp":
62- return nil, fmt.Errorf("%w: webp favicon conversion is disabled", appport.ErrFaviconMiss)
70+ img, err := webp.Decode(data)
71+ if err != nil {
72+ return nil, fmt.Errorf("%w: decode webp favicon: %w", appport.ErrFaviconMiss, err)
73+ }
74+ return img, nil
6375 }
64- if ct != "" && ct != "image/png" && ct != "image/jpeg" && ct != "image/gif" && ct != "image/webp" {
76+ if ct != "" && ct != "image/png" && ct != "image/jpeg" && ct != "image/gif" {
6577 return nil, fmt.Errorf("%w: unsupported favicon content type %s", appport.ErrFaviconMiss, ct)
6678 }
6779 img, _, err := image.Decode(bytes.NewReader(data))
@@ -16,17 +16,25 @@ import (
16 )16 )
17 17
18 // ImageConverter converts safe favicon image formats into normalized PNGs.18 // ImageConverter converts safe favicon image formats into normalized PNGs.
19-type ImageConverter struct{}19+type ImageConverter struct {
20+ webp *webPDecoder
21+}
22+
23+func NewImageConverter() *ImageConverter { return &ImageConverter{webp: newDefaultWebPDecoder()} }
20 24
21-func NewImageConverter() *ImageConverter { return &ImageConverter{} }25+// newImageConverterWithWebPRuntime provides an infrastructure test seam while
26+// application ports remain independent of the libwebp implementation.
27+func newImageConverterWithWebPRuntime(runtime webpRuntime) *ImageConverter {
28+ return &ImageConverter{webp: newWebPDecoder(runtime)}
29+}
22 30
23-func (*ImageConverter) Convert(ctx context.Context, original []byte, contentType string, sizes []int) (*appport.ConvertedFavicon, error) {31+func (c *ImageConverter) Convert(ctx context.Context, original []byte, contentType string, sizes []int) (*appport.ConvertedFavicon, error) {
24 _ = ctx32 _ = ctx
25 if len(original) == 0 {33 if len(original) == 0 {
26 return nil, fmt.Errorf("%w: empty image", appport.ErrFaviconMiss)34 return nil, fmt.Errorf("%w: empty image", appport.ErrFaviconMiss)
27 }35 }
28 36
29- img, err := decodeFaviconImage(original, normalizeContentType(contentType))37+ img, err := decodeFaviconImage(original, normalizeContentType(contentType), c.webp)
30 if err != nil {38 if err != nil {
31 return nil, err39 return nil, err
32 }40 }
@@ -48,7 +56,7 @@ func (*ImageConverter) Convert(ctx context.Context, original []byte, contentType
48 return out, nil56 return out, nil
49 }57 }
50 58
51-func decodeFaviconImage(data []byte, ct string) (image.Image, error) {59+func decodeFaviconImage(data []byte, ct string, webp *webPDecoder) (image.Image, error) {
52 switch ct {60 switch ct {
53 case "image/svg+xml":61 case "image/svg+xml":
54 return nil, fmt.Errorf("%w: svg favicon conversion is disabled", appport.ErrFaviconMiss)62 return nil, fmt.Errorf("%w: svg favicon conversion is disabled", appport.ErrFaviconMiss)
@@ -59,9 +67,13 @@ func decodeFaviconImage(data []byte, ct string) (image.Image, error) {
59 }67 }
60 return img, nil68 return img, nil
61 case "image/webp":69 case "image/webp":
62- return nil, fmt.Errorf("%w: webp favicon conversion is disabled", appport.ErrFaviconMiss)70+ img, err := webp.Decode(data)
71+ if err != nil {
72+ return nil, fmt.Errorf("%w: decode webp favicon: %w", appport.ErrFaviconMiss, err)
73+ }
74+ return img, nil
63 }75 }
64- if ct != "" && ct != "image/png" && ct != "image/jpeg" && ct != "image/gif" && ct != "image/webp" {76+ if ct != "" && ct != "image/png" && ct != "image/jpeg" && ct != "image/gif" {
65 return nil, fmt.Errorf("%w: unsupported favicon content type %s", appport.ErrFaviconMiss, ct)77 return nil, fmt.Errorf("%w: unsupported favicon content type %s", appport.ErrFaviconMiss, ct)
66 }78 }
67 img, _, err := image.Decode(bytes.NewReader(data))79 img, _, err := image.Decode(bytes.NewReader(data))
A internal/infrastructure/favicon/testdata/alpha.webp +0 -0 binary file: no text diff

binary file: no text diff

A internal/infrastructure/favicon/webp_decoder.go +93 -0
@@ -0,0 +1,93 @@
1+package favicon
2+
3+import (
4+ "errors"
5+ "image"
6+ "math"
7+
8+ "github.com/bnema/purego-webp/libwebp"
9+)
10+
11+const (
12+ // maxWebPInputBytes bounds untrusted compressed favicon input before it is
13+ // handed to libwebp.
14+ maxWebPInputBytes = 5 << 20
15+ // maxWebPDimension and maxWebPPixels bound the final RGBA allocation.
16+ maxWebPDimension = 4096
17+ maxWebPPixels = 4 << 20
18+)
19+
20+var (
21+ errWebPInputTooLarge = errors.New("webp favicon input exceeds size limit")
22+ errWebPImageTooLarge = errors.New("webp favicon dimensions exceed size limit")
23+ errWebPInvalidMetadata = errors.New("invalid webp favicon metadata")
24+)
25+
26+// webpRuntime is the narrow infrastructure seam around the dynamically loaded
27+// libwebp binding. It deliberately exposes only Go values, keeping backend
28+// types out of ports and the domain.
29+type webpRuntime interface {
30+ Info(data []byte) (width, height int, err error)
31+ DecodeRGBAInto(data, pix []byte, stride, width, height int) error
32+}
33+
34+type libwebpRuntime struct{}
35+
36+func (libwebpRuntime) Info(data []byte) (int, int, error) {
37+ width, height, ok, err := libwebp.WebPGetInfo(data)
38+ if err != nil {
39+ return 0, 0, err
40+ }
41+ if !ok {
42+ return 0, 0, errWebPInvalidMetadata
43+ }
44+ return width, height, nil
45+}
46+
47+func (libwebpRuntime) DecodeRGBAInto(data, pix []byte, stride, width, height int) error {
48+ return libwebp.WebPDecodeRGBAIntoWithInfo(data, pix, stride, width, height)
49+}
50+
51+// webPDecoder owns the failure boundary for the optional libwebp runtime.
52+type webPDecoder struct{ runtime webpRuntime }
53+
54+func newWebPDecoder(runtime webpRuntime) *webPDecoder { return &webPDecoder{runtime: runtime} }
55+
56+func newDefaultWebPDecoder() *webPDecoder { return newWebPDecoder(libwebpRuntime{}) }
57+
58+func (d *webPDecoder) Decode(data []byte) (*image.NRGBA, error) {
59+ if len(data) == 0 {
60+ return nil, errWebPInvalidMetadata
61+ }
62+ if len(data) > maxWebPInputBytes {
63+ return nil, errWebPInputTooLarge
64+ }
65+ if d == nil || d.runtime == nil {
66+ return nil, errors.New("webp decoder unavailable")
67+ }
68+ width, height, err := d.runtime.Info(data)
69+ if err != nil {
70+ return nil, err
71+ }
72+ if width <= 0 || height <= 0 {
73+ return nil, errWebPInvalidMetadata
74+ }
75+ if width > maxWebPDimension || height > maxWebPDimension || width > maxWebPPixels/height {
76+ return nil, errWebPImageTooLarge
77+ }
78+ if width > math.MaxInt/4 {
79+ return nil, errWebPImageTooLarge
80+ }
81+ stride := width * 4
82+ if height > math.MaxInt/stride {
83+ return nil, errWebPImageTooLarge
84+ }
85+
86+ // Allocate exactly the destination buffer used by libwebp; no native image
87+ // buffer or second decoded copy crosses this adapter boundary.
88+ img := image.NewNRGBA(image.Rect(0, 0, width, height))
89+ if err := d.runtime.DecodeRGBAInto(data, img.Pix, img.Stride, width, height); err != nil {
90+ return nil, err
91+ }
92+ return img, nil
93+}
@@ -0,0 +1,93 @@
1+package favicon
2+
3+import (
4+ "errors"
5+ "image"
6+ "math"
7+
8+ "github.com/bnema/purego-webp/libwebp"
9+)
10+
11+const (
12+ // maxWebPInputBytes bounds untrusted compressed favicon input before it is
13+ // handed to libwebp.
14+ maxWebPInputBytes = 5 << 20
15+ // maxWebPDimension and maxWebPPixels bound the final RGBA allocation.
16+ maxWebPDimension = 4096
17+ maxWebPPixels = 4 << 20
18+)
19+
20+var (
21+ errWebPInputTooLarge = errors.New("webp favicon input exceeds size limit")
22+ errWebPImageTooLarge = errors.New("webp favicon dimensions exceed size limit")
23+ errWebPInvalidMetadata = errors.New("invalid webp favicon metadata")
24+)
25+
26+// webpRuntime is the narrow infrastructure seam around the dynamically loaded
27+// libwebp binding. It deliberately exposes only Go values, keeping backend
28+// types out of ports and the domain.
29+type webpRuntime interface {
30+ Info(data []byte) (width, height int, err error)
31+ DecodeRGBAInto(data, pix []byte, stride, width, height int) error
32+}
33+
34+type libwebpRuntime struct{}
35+
36+func (libwebpRuntime) Info(data []byte) (int, int, error) {
37+ width, height, ok, err := libwebp.WebPGetInfo(data)
38+ if err != nil {
39+ return 0, 0, err
40+ }
41+ if !ok {
42+ return 0, 0, errWebPInvalidMetadata
43+ }
44+ return width, height, nil
45+}
46+
47+func (libwebpRuntime) DecodeRGBAInto(data, pix []byte, stride, width, height int) error {
48+ return libwebp.WebPDecodeRGBAIntoWithInfo(data, pix, stride, width, height)
49+}
50+
51+// webPDecoder owns the failure boundary for the optional libwebp runtime.
52+type webPDecoder struct{ runtime webpRuntime }
53+
54+func newWebPDecoder(runtime webpRuntime) *webPDecoder { return &webPDecoder{runtime: runtime} }
55+
56+func newDefaultWebPDecoder() *webPDecoder { return newWebPDecoder(libwebpRuntime{}) }
57+
58+func (d *webPDecoder) Decode(data []byte) (*image.NRGBA, error) {
59+ if len(data) == 0 {
60+ return nil, errWebPInvalidMetadata
61+ }
62+ if len(data) > maxWebPInputBytes {
63+ return nil, errWebPInputTooLarge
64+ }
65+ if d == nil || d.runtime == nil {
66+ return nil, errors.New("webp decoder unavailable")
67+ }
68+ width, height, err := d.runtime.Info(data)
69+ if err != nil {
70+ return nil, err
71+ }
72+ if width <= 0 || height <= 0 {
73+ return nil, errWebPInvalidMetadata
74+ }
75+ if width > maxWebPDimension || height > maxWebPDimension || width > maxWebPPixels/height {
76+ return nil, errWebPImageTooLarge
77+ }
78+ if width > math.MaxInt/4 {
79+ return nil, errWebPImageTooLarge
80+ }
81+ stride := width * 4
82+ if height > math.MaxInt/stride {
83+ return nil, errWebPImageTooLarge
84+ }
85+
86+ // Allocate exactly the destination buffer used by libwebp; no native image
87+ // buffer or second decoded copy crosses this adapter boundary.
88+ img := image.NewNRGBA(image.Rect(0, 0, width, height))
89+ if err := d.runtime.DecodeRGBAInto(data, img.Pix, img.Stride, width, height); err != nil {
90+ return nil, err
91+ }
92+ return img, nil
93+}
A internal/infrastructure/favicon/webp_decoder_test.go +92 -0
@@ -0,0 +1,92 @@
1+package favicon
2+
3+import (
4+ "bytes"
5+ "context"
6+ "errors"
7+ "image"
8+ "image/color"
9+ "image/png"
10+ "os"
11+ "testing"
12+
13+ appport "github.com/bnema/dumber/internal/application/port"
14+)
15+
16+func TestConverterWebPConvertsAlphaFixture(t *testing.T) {
17+ data, err := os.ReadFile("testdata/alpha.webp")
18+ if err != nil {
19+ t.Fatal(err)
20+ }
21+ conv := NewImageConverter()
22+ out, err := conv.Convert(context.Background(), data, "image/webp", []int{32})
23+ if err != nil {
24+ t.Fatal(err)
25+ }
26+ img, err := png.Decode(bytes.NewReader(out.PNG))
27+ if err != nil {
28+ t.Fatal(err)
29+ }
30+ if got := color.NRGBAModel.Convert(img.At(0, 0)).(color.NRGBA); got.A != 64 || got.R != 255 {
31+ t.Fatalf("alpha pixel = %#v, want red alpha 64", got)
32+ }
33+ if sized, err := png.Decode(bytes.NewReader(out.SizedPNG[32])); err != nil || sized.Bounds() != image.Rect(0, 0, 32, 32) {
34+ t.Fatalf("sized WebP = %v, %v", sized.Bounds(), err)
35+ }
36+}
37+
38+func TestConverterWebPFailuresAreFaviconMisses(t *testing.T) {
39+ for _, tc := range []struct {
40+ name string
41+ data []byte
42+ dec webpRuntime
43+ }{
44+ {name: "truncated", data: []byte("RIFF\x04\x00\x00\x00WEBPVP8 "), dec: &fakeWebPRuntime{infoErr: errors.New("truncated")}},
45+ {name: "unavailable", data: []byte("webp"), dec: &fakeWebPRuntime{infoErr: errors.New("libwebp unavailable")}},
46+ } {
47+ t.Run(tc.name, func(t *testing.T) {
48+ conv := newImageConverterWithWebPRuntime(tc.dec)
49+ if _, err := conv.Convert(context.Background(), tc.data, "image/webp", nil); !errors.Is(err, appport.ErrFaviconMiss) {
50+ t.Fatalf("err = %v, want favicon miss", err)
51+ }
52+ })
53+ }
54+}
55+
56+func TestWebPDecoderRejectsInputAndDecodedLimitsBeforeAllocation(t *testing.T) {
57+ for _, tc := range []struct {
58+ name string
59+ data []byte
60+ width, height int
61+ }{
62+ {name: "input", data: bytes.Repeat([]byte("x"), maxWebPInputBytes+1), width: 1, height: 1},
63+ {name: "dimension", data: []byte("webp"), width: maxWebPDimension + 1, height: 1},
64+ {name: "pixels", data: []byte("webp"), width: maxWebPDimension, height: maxWebPDimension},
65+ } {
66+ t.Run(tc.name, func(t *testing.T) {
67+ runtime := &fakeWebPRuntime{width: tc.width, height: tc.height}
68+ _, err := newWebPDecoder(runtime).Decode(tc.data)
69+ if err == nil {
70+ t.Fatal("Decode succeeded")
71+ }
72+ if runtime.decodeCalls != 0 {
73+ t.Fatalf("decode calls = %d, want no allocation/decode", runtime.decodeCalls)
74+ }
75+ })
76+ }
77+}
78+
79+type fakeWebPRuntime struct {
80+ width, height int
81+ infoErr error
82+ decodeCalls int
83+}
84+
85+func (r *fakeWebPRuntime) Info(_ []byte) (int, int, error) { return r.width, r.height, r.infoErr }
86+func (r *fakeWebPRuntime) DecodeRGBAInto(_, pix []byte, _, _, _ int) error {
87+ r.decodeCalls++
88+ for i := range pix {
89+ pix[i] = 0xff
90+ }
91+ return nil
92+}
@@ -0,0 +1,92 @@
1+package favicon
2+
3+import (
4+ "bytes"
5+ "context"
6+ "errors"
7+ "image"
8+ "image/color"
9+ "image/png"
10+ "os"
11+ "testing"
12+
13+ appport "github.com/bnema/dumber/internal/application/port"
14+)
15+
16+func TestConverterWebPConvertsAlphaFixture(t *testing.T) {
17+ data, err := os.ReadFile("testdata/alpha.webp")
18+ if err != nil {
19+ t.Fatal(err)
20+ }
21+ conv := NewImageConverter()
22+ out, err := conv.Convert(context.Background(), data, "image/webp", []int{32})
23+ if err != nil {
24+ t.Fatal(err)
25+ }
26+ img, err := png.Decode(bytes.NewReader(out.PNG))
27+ if err != nil {
28+ t.Fatal(err)
29+ }
30+ if got := color.NRGBAModel.Convert(img.At(0, 0)).(color.NRGBA); got.A != 64 || got.R != 255 {
31+ t.Fatalf("alpha pixel = %#v, want red alpha 64", got)
32+ }
33+ if sized, err := png.Decode(bytes.NewReader(out.SizedPNG[32])); err != nil || sized.Bounds() != image.Rect(0, 0, 32, 32) {
34+ t.Fatalf("sized WebP = %v, %v", sized.Bounds(), err)
35+ }
36+}
37+
38+func TestConverterWebPFailuresAreFaviconMisses(t *testing.T) {
39+ for _, tc := range []struct {
40+ name string
41+ data []byte
42+ dec webpRuntime
43+ }{
44+ {name: "truncated", data: []byte("RIFF\x04\x00\x00\x00WEBPVP8 "), dec: &fakeWebPRuntime{infoErr: errors.New("truncated")}},
45+ {name: "unavailable", data: []byte("webp"), dec: &fakeWebPRuntime{infoErr: errors.New("libwebp unavailable")}},
46+ } {
47+ t.Run(tc.name, func(t *testing.T) {
48+ conv := newImageConverterWithWebPRuntime(tc.dec)
49+ if _, err := conv.Convert(context.Background(), tc.data, "image/webp", nil); !errors.Is(err, appport.ErrFaviconMiss) {
50+ t.Fatalf("err = %v, want favicon miss", err)
51+ }
52+ })
53+ }
54+}
55+
56+func TestWebPDecoderRejectsInputAndDecodedLimitsBeforeAllocation(t *testing.T) {
57+ for _, tc := range []struct {
58+ name string
59+ data []byte
60+ width, height int
61+ }{
62+ {name: "input", data: bytes.Repeat([]byte("x"), maxWebPInputBytes+1), width: 1, height: 1},
63+ {name: "dimension", data: []byte("webp"), width: maxWebPDimension + 1, height: 1},
64+ {name: "pixels", data: []byte("webp"), width: maxWebPDimension, height: maxWebPDimension},
65+ } {
66+ t.Run(tc.name, func(t *testing.T) {
67+ runtime := &fakeWebPRuntime{width: tc.width, height: tc.height}
68+ _, err := newWebPDecoder(runtime).Decode(tc.data)
69+ if err == nil {
70+ t.Fatal("Decode succeeded")
71+ }
72+ if runtime.decodeCalls != 0 {
73+ t.Fatalf("decode calls = %d, want no allocation/decode", runtime.decodeCalls)
74+ }
75+ })
76+ }
77+}
78+
79+type fakeWebPRuntime struct {
80+ width, height int
81+ infoErr error
82+ decodeCalls int
83+}
84+
85+func (r *fakeWebPRuntime) Info(_ []byte) (int, int, error) { return r.width, r.height, r.infoErr }
86+func (r *fakeWebPRuntime) DecodeRGBAInto(_, pix []byte, _, _, _ int) error {
87+ r.decodeCalls++
88+ for i := range pix {
89+ pix[i] = 0xff
90+ }
91+ return nil
92+}
A third_party/purego-webp/LICENSE +21 -0
@@ -0,0 +1,21 @@
1+MIT License
2+
3+Copyright (c) 2026 bnema
4+
5+Permission is hereby granted, free of charge, to any person obtaining a copy
6+of this software and associated documentation files (the "Software"), to deal
7+in the Software without restriction, including without limitation the rights
8+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+copies of the Software, and to permit persons to whom the Software is
10+furnished to do so, subject to the following conditions:
11+
12+The above copyright notice and this permission notice shall be included in all
13+copies or substantial portions of the Software.
14+
15+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+SOFTWARE.
@@ -0,0 +1,21 @@
1+MIT License
2+
3+Copyright (c) 2026 bnema
4+
5+Permission is hereby granted, free of charge, to any person obtaining a copy
6+of this software and associated documentation files (the "Software"), to deal
7+in the Software without restriction, including without limitation the rights
8+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+copies of the Software, and to permit persons to whom the Software is
10+furnished to do so, subject to the following conditions:
11+
12+The above copyright notice and this permission notice shall be included in all
13+copies or substantial portions of the Software.
14+
15+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+SOFTWARE.
A third_party/purego-webp/UPSTREAM +4 -0
@@ -0,0 +1,4 @@
1+Source: https://github.com/bnema/purego-webp
2+Commit: bc33db63042a1087e349e2e8cb3d42b57df784d9
3+Patch: loader import uses Dumber's existing github.com/bnema/purego runtime.
4+Reason: both purego implementations export the same syscall linknames and cannot coexist in one binary.
@@ -0,0 +1,4 @@
1+Source: https://github.com/bnema/purego-webp
2+Commit: bc33db63042a1087e349e2e8cb3d42b57df784d9
3+Patch: loader import uses Dumber's existing github.com/bnema/purego runtime.
4+Reason: both purego implementations export the same syscall linknames and cannot coexist in one binary.
A third_party/purego-webp/go.mod +5 -0
@@ -0,0 +1,5 @@
1+module github.com/bnema/purego-webp
2+
3+go 1.26
4+
5+require github.com/bnema/purego v0.11.0-bnema.4
@@ -0,0 +1,5 @@
1+module github.com/bnema/purego-webp
2+
3+go 1.26
4+
5+require github.com/bnema/purego v0.11.0-bnema.4
A third_party/purego-webp/internal/libwebp/generated_symbols.go +513 -0
@@ -0,0 +1,513 @@
1+// Code generated by ./cmd/gen; DO NOT EDIT.
2+
3+package libwebp
4+
5+var (
6+ xWebPGetInfo func(data *byte, dataSize uintptr, width *int32, height *int32) int32
7+ xWebPDecodeRGBA func(data *byte, dataSize uintptr, width *int32, height *int32) *byte
8+ xWebPDecodeARGB func(data *byte, dataSize uintptr, width *int32, height *int32) *byte
9+ xWebPDecodeBGRA func(data *byte, dataSize uintptr, width *int32, height *int32) *byte
10+ xWebPDecodeRGB func(data *byte, dataSize uintptr, width *int32, height *int32) *byte
11+ xWebPDecodeBGR func(data *byte, dataSize uintptr, width *int32, height *int32) *byte
12+ xWebPDecodeRGBAInto func(data *byte, dataSize uintptr, outputBuffer *byte, outputBufferSize uintptr, outputStride int32) *byte
13+ xWebPDecodeARGBInto func(data *byte, dataSize uintptr, outputBuffer *byte, outputBufferSize uintptr, outputStride int32) *byte
14+ xWebPDecodeBGRAInto func(data *byte, dataSize uintptr, outputBuffer *byte, outputBufferSize uintptr, outputStride int32) *byte
15+ xWebPDecodeRGBInto func(data *byte, dataSize uintptr, outputBuffer *byte, outputBufferSize uintptr, outputStride int32) *byte
16+ xWebPDecodeBGRInto func(data *byte, dataSize uintptr, outputBuffer *byte, outputBufferSize uintptr, outputStride int32) *byte
17+ xWebPDecodeYUV func(data *byte, dataSize uintptr, width *int32, height *int32, u **byte, v **byte, stride *int32, uvStride *int32) *byte
18+ xWebPDecodeYUVInto func(data *byte, dataSize uintptr, luma *byte, lumaSize uintptr, lumaStride int32, u *byte, uSize uintptr, uStride int32, v *byte, vSize uintptr, vStride int32) *byte
19+ xWebPGetFeaturesInternal func(data *byte, dataSize uintptr, features *WebPBitstreamFeatures, abiVersion int32) VP8StatusCode
20+ xWebPInitDecBufferInternal func(buffer *WebPDecBuffer, abiVersion int32) int32
21+ xWebPFreeDecBuffer func(buffer *WebPDecBuffer)
22+ xWebPInitDecoderConfigInternal func(config *WebPDecoderConfig, abiVersion int32) int32
23+ xWebPValidateDecoderConfig func(config *WebPDecoderConfig) int32
24+ xWebPDecode func(data *byte, dataSize uintptr, config *WebPDecoderConfig) VP8StatusCode
25+ xWebPINewDecoder func(outputBuffer *WebPDecBuffer) uintptr
26+ xWebPINewRGB func(csp int32, outputBuffer *byte, outputBufferSize uintptr, outputStride int32) uintptr
27+ xWebPINewYUVA func(luma *byte, lumaSize uintptr, lumaStride int32, u *byte, uSize uintptr, uStride int32, v *byte, vSize uintptr, vStride int32, a *byte, aSize uintptr, aStride int32) uintptr
28+ xWebPINewYUV func(luma *byte, lumaSize uintptr, lumaStride int32, u *byte, uSize uintptr, uStride int32, v *byte, vSize uintptr, vStride int32) uintptr
29+ xWebPIDelete func(idec uintptr)
30+ xWebPIAppend func(idec uintptr, data *byte, dataSize uintptr) VP8StatusCode
31+ xWebPIUpdate func(idec uintptr, data *byte, dataSize uintptr) VP8StatusCode
32+ xWebPIDecGetRGB func(idec uintptr, lastY *int32, width *int32, height *int32, stride *int32) *byte
33+ xWebPIDecGetYUVA func(idec uintptr, lastY *int32, u **byte, v **byte, a **byte, width *int32, height *int32, stride *int32, uvStride *int32, aStride *int32) *byte
34+ xWebPIDecodedArea func(idec uintptr, left *int32, top *int32, width *int32, height *int32) *WebPDecBuffer
35+ xWebPIDecode func(data *byte, dataSize uintptr, config *WebPDecoderConfig) uintptr
36+ xWebPEncodeRGBA func(rgba *byte, width int32, height int32, stride int32, quality float32, output **byte) uintptr
37+ xWebPEncodeRGB func(rgb *byte, width int32, height int32, stride int32, quality float32, output **byte) uintptr
38+ xWebPEncodeBGR func(bgr *byte, width int32, height int32, stride int32, quality float32, output **byte) uintptr
39+ xWebPEncodeBGRA func(bgra *byte, width int32, height int32, stride int32, quality float32, output **byte) uintptr
40+ xWebPEncodeLosslessRGBA func(rgba *byte, width int32, height int32, stride int32, output **byte) uintptr
41+ xWebPEncodeLosslessRGB func(rgb *byte, width int32, height int32, stride int32, output **byte) uintptr
42+ xWebPEncodeLosslessBGR func(bgr *byte, width int32, height int32, stride int32, output **byte) uintptr
43+ xWebPEncodeLosslessBGRA func(bgra *byte, width int32, height int32, stride int32, output **byte) uintptr
44+ xWebPConfigInitInternal func(config *WebPConfig, preset int32, quality float32, abiVersion int32) int32
45+ xWebPConfigLosslessPreset func(config *WebPConfig, level int32) int32
46+ xWebPValidateConfig func(config *WebPConfig) int32
47+ xWebPMemoryWriterInit func(writer *WebPMemoryWriter)
48+ xWebPMemoryWriterClear func(writer *WebPMemoryWriter)
49+ xWebPMemoryWrite func(data *byte, dataSize uintptr, picture *WebPPicture) int32
50+ xWebPPictureInitInternal func(picture *WebPPicture, abiVersion int32) int32
51+ xWebPPictureAlloc func(picture *WebPPicture) int32
52+ xWebPPictureFree func(picture *WebPPicture)
53+ xWebPPictureCopy func(src *WebPPicture, dst *WebPPicture) int32
54+ xWebPPictureCrop func(picture *WebPPicture, left int32, top int32, width int32, height int32) int32
55+ xWebPPictureView func(src *WebPPicture, left int32, top int32, width int32, height int32, dst *WebPPicture) int32
56+ xWebPPictureIsView func(picture *WebPPicture) int32
57+ xWebPPictureRescale func(picture *WebPPicture, width int32, height int32) int32
58+ xWebPPictureImportRGB func(picture *WebPPicture, rgb *byte, rgbStride int32) int32
59+ xWebPPictureImportRGBA func(picture *WebPPicture, rgba *byte, rgbaStride int32) int32
60+ xWebPPictureImportRGBX func(picture *WebPPicture, rgbx *byte, rgbxStride int32) int32
61+ xWebPPictureImportBGR func(picture *WebPPicture, bgr *byte, bgrStride int32) int32
62+ xWebPPictureImportBGRA func(picture *WebPPicture, bgra *byte, bgraStride int32) int32
63+ xWebPPictureImportBGRX func(picture *WebPPicture, bgrx *byte, bgrxStride int32) int32
64+ xWebPPictureARGBToYUVA func(picture *WebPPicture, colorspace int32) int32
65+ xWebPPictureARGBToYUVADithered func(picture *WebPPicture, colorspace int32, dithering float32) int32
66+ xWebPPictureSharpARGBToYUVA func(picture *WebPPicture) int32
67+ xWebPPictureSmartARGBToYUVA func(picture *WebPPicture) int32
68+ xWebPPictureYUVAToARGB func(picture *WebPPicture) int32
69+ xWebPCleanupTransparentArea func(picture *WebPPicture)
70+ xWebPPictureHasTransparency func(picture *WebPPicture) int32
71+ xWebPBlendAlpha func(picture *WebPPicture, backgroundRGB uint32)
72+ xWebPPlaneDistortion func(src *byte, srcStride uintptr, ref *byte, refStride uintptr, width int32, height int32, xStep uintptr, distType int32, distortion *float32, result *float32) int32
73+ xWebPPictureDistortion func(src *WebPPicture, ref *WebPPicture, metricType int32, result *float32) int32
74+ xWebPEncode func(config *WebPConfig, picture *WebPPicture) int32
75+ xWebPFree func(ptr uintptr)
76+ xWebPGetDecoderVersion func() int32
77+ xWebPGetEncoderVersion func() int32
78+)
79+
80+func WebPGetInfo(data *byte, dataSize uintptr, width *int32, height *int32) int32 {
81+ return xWebPGetInfo(data, dataSize, width, height)
82+}
83+func WebPDecodeRGBA(data *byte, dataSize uintptr, width *int32, height *int32) *byte {
84+ return xWebPDecodeRGBA(data, dataSize, width, height)
85+}
86+func WebPDecodeARGB(data *byte, dataSize uintptr, width *int32, height *int32) *byte {
87+ return xWebPDecodeARGB(data, dataSize, width, height)
88+}
89+func WebPDecodeBGRA(data *byte, dataSize uintptr, width *int32, height *int32) *byte {
90+ return xWebPDecodeBGRA(data, dataSize, width, height)
91+}
92+func WebPDecodeRGB(data *byte, dataSize uintptr, width *int32, height *int32) *byte {
93+ return xWebPDecodeRGB(data, dataSize, width, height)
94+}
95+func WebPDecodeBGR(data *byte, dataSize uintptr, width *int32, height *int32) *byte {
96+ return xWebPDecodeBGR(data, dataSize, width, height)
97+}
98+func WebPDecodeRGBAInto(data *byte, dataSize uintptr, outputBuffer *byte, outputBufferSize uintptr, outputStride int32) *byte {
99+ return xWebPDecodeRGBAInto(data, dataSize, outputBuffer, outputBufferSize, outputStride)
100+}
101+func WebPDecodeARGBInto(data *byte, dataSize uintptr, outputBuffer *byte, outputBufferSize uintptr, outputStride int32) *byte {
102+ return xWebPDecodeARGBInto(data, dataSize, outputBuffer, outputBufferSize, outputStride)
103+}
104+func WebPDecodeBGRAInto(data *byte, dataSize uintptr, outputBuffer *byte, outputBufferSize uintptr, outputStride int32) *byte {
105+ return xWebPDecodeBGRAInto(data, dataSize, outputBuffer, outputBufferSize, outputStride)
106+}
107+func WebPDecodeRGBInto(data *byte, dataSize uintptr, outputBuffer *byte, outputBufferSize uintptr, outputStride int32) *byte {
108+ return xWebPDecodeRGBInto(data, dataSize, outputBuffer, outputBufferSize, outputStride)
109+}
110+func WebPDecodeBGRInto(data *byte, dataSize uintptr, outputBuffer *byte, outputBufferSize uintptr, outputStride int32) *byte {
111+ return xWebPDecodeBGRInto(data, dataSize, outputBuffer, outputBufferSize, outputStride)
112+}
113+func WebPDecodeYUV(data *byte, dataSize uintptr, width *int32, height *int32, u **byte, v **byte, stride *int32, uvStride *int32) *byte {
114+ return xWebPDecodeYUV(data, dataSize, width, height, u, v, stride, uvStride)
115+}
116+func WebPDecodeYUVInto(data *byte, dataSize uintptr, luma *byte, lumaSize uintptr, lumaStride int32, u *byte, uSize uintptr, uStride int32, v *byte, vSize uintptr, vStride int32) *byte {
117+ return xWebPDecodeYUVInto(data, dataSize, luma, lumaSize, lumaStride, u, uSize, uStride, v, vSize, vStride)
118+}
119+func WebPGetFeaturesInternal(data *byte, dataSize uintptr, features *WebPBitstreamFeatures, abiVersion int32) VP8StatusCode {
120+ return xWebPGetFeaturesInternal(data, dataSize, features, abiVersion)
121+}
122+func WebPInitDecBufferInternal(buffer *WebPDecBuffer, abiVersion int32) int32 {
123+ return xWebPInitDecBufferInternal(buffer, abiVersion)
124+}
125+func WebPFreeDecBuffer(buffer *WebPDecBuffer) {
126+ xWebPFreeDecBuffer(buffer)
127+}
128+func WebPInitDecoderConfigInternal(config *WebPDecoderConfig, abiVersion int32) int32 {
129+ return xWebPInitDecoderConfigInternal(config, abiVersion)
130+}
131+func WebPValidateDecoderConfig(config *WebPDecoderConfig) int32 {
132+ return xWebPValidateDecoderConfig(config)
133+}
134+func WebPDecode(data *byte, dataSize uintptr, config *WebPDecoderConfig) VP8StatusCode {
135+ return xWebPDecode(data, dataSize, config)
136+}
137+func WebPINewDecoder(outputBuffer *WebPDecBuffer) uintptr {
138+ return xWebPINewDecoder(outputBuffer)
139+}
140+func WebPINewRGB(csp int32, outputBuffer *byte, outputBufferSize uintptr, outputStride int32) uintptr {
141+ return xWebPINewRGB(csp, outputBuffer, outputBufferSize, outputStride)
142+}
143+func WebPINewYUVA(luma *byte, lumaSize uintptr, lumaStride int32, u *byte, uSize uintptr, uStride int32, v *byte, vSize uintptr, vStride int32, a *byte, aSize uintptr, aStride int32) uintptr {
144+ return xWebPINewYUVA(luma, lumaSize, lumaStride, u, uSize, uStride, v, vSize, vStride, a, aSize, aStride)
145+}
146+func WebPINewYUV(luma *byte, lumaSize uintptr, lumaStride int32, u *byte, uSize uintptr, uStride int32, v *byte, vSize uintptr, vStride int32) uintptr {
147+ return xWebPINewYUV(luma, lumaSize, lumaStride, u, uSize, uStride, v, vSize, vStride)
148+}
149+func WebPIDelete(idec uintptr) {
150+ xWebPIDelete(idec)
151+}
152+func WebPIAppend(idec uintptr, data *byte, dataSize uintptr) VP8StatusCode {
153+ return xWebPIAppend(idec, data, dataSize)
154+}
155+func WebPIUpdate(idec uintptr, data *byte, dataSize uintptr) VP8StatusCode {
156+ return xWebPIUpdate(idec, data, dataSize)
157+}
158+func WebPIDecGetRGB(idec uintptr, lastY *int32, width *int32, height *int32, stride *int32) *byte {
159+ return xWebPIDecGetRGB(idec, lastY, width, height, stride)
160+}
161+func WebPIDecGetYUVA(idec uintptr, lastY *int32, u **byte, v **byte, a **byte, width *int32, height *int32, stride *int32, uvStride *int32, aStride *int32) *byte {
162+ return xWebPIDecGetYUVA(idec, lastY, u, v, a, width, height, stride, uvStride, aStride)
163+}
164+func WebPIDecodedArea(idec uintptr, left *int32, top *int32, width *int32, height *int32) *WebPDecBuffer {
165+ return xWebPIDecodedArea(idec, left, top, width, height)
166+}
167+func WebPIDecode(data *byte, dataSize uintptr, config *WebPDecoderConfig) uintptr {
168+ return xWebPIDecode(data, dataSize, config)
169+}
170+func WebPEncodeRGBA(rgba *byte, width int32, height int32, stride int32, quality float32, output **byte) uintptr {
171+ return xWebPEncodeRGBA(rgba, width, height, stride, quality, output)
172+}
173+func WebPEncodeRGB(rgb *byte, width int32, height int32, stride int32, quality float32, output **byte) uintptr {
174+ return xWebPEncodeRGB(rgb, width, height, stride, quality, output)
175+}
176+func WebPEncodeBGR(bgr *byte, width int32, height int32, stride int32, quality float32, output **byte) uintptr {
177+ return xWebPEncodeBGR(bgr, width, height, stride, quality, output)
178+}
179+func WebPEncodeBGRA(bgra *byte, width int32, height int32, stride int32, quality float32, output **byte) uintptr {
180+ return xWebPEncodeBGRA(bgra, width, height, stride, quality, output)
181+}
182+func WebPEncodeLosslessRGBA(rgba *byte, width int32, height int32, stride int32, output **byte) uintptr {
183+ return xWebPEncodeLosslessRGBA(rgba, width, height, stride, output)
184+}
185+func WebPEncodeLosslessRGB(rgb *byte, width int32, height int32, stride int32, output **byte) uintptr {
186+ return xWebPEncodeLosslessRGB(rgb, width, height, stride, output)
187+}
188+func WebPEncodeLosslessBGR(bgr *byte, width int32, height int32, stride int32, output **byte) uintptr {
189+ return xWebPEncodeLosslessBGR(bgr, width, height, stride, output)
190+}
191+func WebPEncodeLosslessBGRA(bgra *byte, width int32, height int32, stride int32, output **byte) uintptr {
192+ return xWebPEncodeLosslessBGRA(bgra, width, height, stride, output)
193+}
194+func WebPConfigInitInternal(config *WebPConfig, preset int32, quality float32, abiVersion int32) int32 {
195+ return xWebPConfigInitInternal(config, preset, quality, abiVersion)
196+}
197+func WebPConfigLosslessPreset(config *WebPConfig, level int32) int32 {
198+ return xWebPConfigLosslessPreset(config, level)
199+}
200+func WebPValidateConfig(config *WebPConfig) int32 {
201+ return xWebPValidateConfig(config)
202+}
203+func WebPMemoryWriterInit(writer *WebPMemoryWriter) {
204+ xWebPMemoryWriterInit(writer)
205+}
206+func WebPMemoryWriterClear(writer *WebPMemoryWriter) {
207+ xWebPMemoryWriterClear(writer)
208+}
209+func WebPMemoryWrite(data *byte, dataSize uintptr, picture *WebPPicture) int32 {
210+ return xWebPMemoryWrite(data, dataSize, picture)
211+}
212+func WebPPictureInitInternal(picture *WebPPicture, abiVersion int32) int32 {
213+ return xWebPPictureInitInternal(picture, abiVersion)
214+}
215+func WebPPictureAlloc(picture *WebPPicture) int32 {
216+ return xWebPPictureAlloc(picture)
217+}
218+func WebPPictureFree(picture *WebPPicture) {
219+ xWebPPictureFree(picture)
220+}
221+func WebPPictureCopy(src *WebPPicture, dst *WebPPicture) int32 {
222+ return xWebPPictureCopy(src, dst)
223+}
224+func WebPPictureCrop(picture *WebPPicture, left int32, top int32, width int32, height int32) int32 {
225+ return xWebPPictureCrop(picture, left, top, width, height)
226+}
227+func WebPPictureView(src *WebPPicture, left int32, top int32, width int32, height int32, dst *WebPPicture) int32 {
228+ return xWebPPictureView(src, left, top, width, height, dst)
229+}
230+func WebPPictureIsView(picture *WebPPicture) int32 {
231+ return xWebPPictureIsView(picture)
232+}
233+func WebPPictureRescale(picture *WebPPicture, width int32, height int32) int32 {
234+ return xWebPPictureRescale(picture, width, height)
235+}
236+func WebPPictureImportRGB(picture *WebPPicture, rgb *byte, rgbStride int32) int32 {
237+ return xWebPPictureImportRGB(picture, rgb, rgbStride)
238+}
239+func WebPPictureImportRGBA(picture *WebPPicture, rgba *byte, rgbaStride int32) int32 {
240+ return xWebPPictureImportRGBA(picture, rgba, rgbaStride)
241+}
242+func WebPPictureImportRGBX(picture *WebPPicture, rgbx *byte, rgbxStride int32) int32 {
243+ return xWebPPictureImportRGBX(picture, rgbx, rgbxStride)
244+}
245+func WebPPictureImportBGR(picture *WebPPicture, bgr *byte, bgrStride int32) int32 {
246+ return xWebPPictureImportBGR(picture, bgr, bgrStride)
247+}
248+func WebPPictureImportBGRA(picture *WebPPicture, bgra *byte, bgraStride int32) int32 {
249+ return xWebPPictureImportBGRA(picture, bgra, bgraStride)
250+}
251+func WebPPictureImportBGRX(picture *WebPPicture, bgrx *byte, bgrxStride int32) int32 {
252+ return xWebPPictureImportBGRX(picture, bgrx, bgrxStride)
253+}
254+func WebPPictureARGBToYUVA(picture *WebPPicture, colorspace int32) int32 {
255+ return xWebPPictureARGBToYUVA(picture, colorspace)
256+}
257+func WebPPictureARGBToYUVADithered(picture *WebPPicture, colorspace int32, dithering float32) int32 {
258+ return xWebPPictureARGBToYUVADithered(picture, colorspace, dithering)
259+}
260+func WebPPictureSharpARGBToYUVA(picture *WebPPicture) int32 {
261+ return xWebPPictureSharpARGBToYUVA(picture)
262+}
263+func WebPPictureSmartARGBToYUVA(picture *WebPPicture) int32 {
264+ return xWebPPictureSmartARGBToYUVA(picture)
265+}
266+func WebPPictureYUVAToARGB(picture *WebPPicture) int32 {
267+ return xWebPPictureYUVAToARGB(picture)
268+}
269+func WebPCleanupTransparentArea(picture *WebPPicture) {
270+ xWebPCleanupTransparentArea(picture)
271+}
272+func WebPPictureHasTransparency(picture *WebPPicture) int32 {
273+ return xWebPPictureHasTransparency(picture)
274+}
275+func WebPBlendAlpha(picture *WebPPicture, backgroundRGB uint32) {
276+ xWebPBlendAlpha(picture, backgroundRGB)
277+}
278+func WebPPlaneDistortion(src *byte, srcStride uintptr, ref *byte, refStride uintptr, width int32, height int32, xStep uintptr, distType int32, distortion *float32, result *float32) int32 {
279+ return xWebPPlaneDistortion(src, srcStride, ref, refStride, width, height, xStep, distType, distortion, result)
280+}
281+func WebPPictureDistortion(src *WebPPicture, ref *WebPPicture, metricType int32, result *float32) int32 {
282+ return xWebPPictureDistortion(src, ref, metricType, result)
283+}
284+func WebPEncode(config *WebPConfig, picture *WebPPicture) int32 {
285+ return xWebPEncode(config, picture)
286+}
287+func WebPFree(ptr uintptr) {
288+ xWebPFree(ptr)
289+}
290+func WebPGetDecoderVersion() int32 {
291+ return xWebPGetDecoderVersion()
292+}
293+func WebPGetEncoderVersion() int32 {
294+ return xWebPGetEncoderVersion()
295+}
296+func registerAll(lib uintptr) error {
297+ if err := register(lib, &xWebPGetInfo, "WebPGetInfo"); err != nil {
298+ return err
299+ }
300+ if err := register(lib, &xWebPDecodeRGBA, "WebPDecodeRGBA"); err != nil {
301+ return err
302+ }
303+ if err := register(lib, &xWebPDecodeARGB, "WebPDecodeARGB"); err != nil {
304+ return err
305+ }
306+ if err := register(lib, &xWebPDecodeBGRA, "WebPDecodeBGRA"); err != nil {
307+ return err
308+ }
309+ if err := register(lib, &xWebPDecodeRGB, "WebPDecodeRGB"); err != nil {
310+ return err
311+ }
312+ if err := register(lib, &xWebPDecodeBGR, "WebPDecodeBGR"); err != nil {
313+ return err
314+ }
315+ if err := register(lib, &xWebPDecodeRGBAInto, "WebPDecodeRGBAInto"); err != nil {
316+ return err
317+ }
318+ if err := register(lib, &xWebPDecodeARGBInto, "WebPDecodeARGBInto"); err != nil {
319+ return err
320+ }
321+ if err := register(lib, &xWebPDecodeBGRAInto, "WebPDecodeBGRAInto"); err != nil {
322+ return err
323+ }
324+ if err := register(lib, &xWebPDecodeRGBInto, "WebPDecodeRGBInto"); err != nil {
325+ return err
326+ }
327+ if err := register(lib, &xWebPDecodeBGRInto, "WebPDecodeBGRInto"); err != nil {
328+ return err
329+ }
330+ if err := register(lib, &xWebPDecodeYUV, "WebPDecodeYUV"); err != nil {
331+ return err
332+ }
333+ if err := register(lib, &xWebPDecodeYUVInto, "WebPDecodeYUVInto"); err != nil {
334+ return err
335+ }
336+ if err := register(lib, &xWebPGetFeaturesInternal, "WebPGetFeaturesInternal"); err != nil {
337+ return err
338+ }
339+ if err := register(lib, &xWebPInitDecBufferInternal, "WebPInitDecBufferInternal"); err != nil {
340+ return err
341+ }
342+ if err := register(lib, &xWebPFreeDecBuffer, "WebPFreeDecBuffer"); err != nil {
343+ return err
344+ }
345+ if err := register(lib, &xWebPInitDecoderConfigInternal, "WebPInitDecoderConfigInternal"); err != nil {
346+ return err
347+ }
348+ registerOptional(lib, &xWebPValidateDecoderConfig, "WebPValidateDecoderConfig")
349+ if err := register(lib, &xWebPDecode, "WebPDecode"); err != nil {
350+ return err
351+ }
352+ if err := register(lib, &xWebPINewDecoder, "WebPINewDecoder"); err != nil {
353+ return err
354+ }
355+ if err := register(lib, &xWebPINewRGB, "WebPINewRGB"); err != nil {
356+ return err
357+ }
358+ if err := register(lib, &xWebPINewYUVA, "WebPINewYUVA"); err != nil {
359+ return err
360+ }
361+ if err := register(lib, &xWebPINewYUV, "WebPINewYUV"); err != nil {
362+ return err
363+ }
364+ if err := register(lib, &xWebPIDelete, "WebPIDelete"); err != nil {
365+ return err
366+ }
367+ if err := register(lib, &xWebPIAppend, "WebPIAppend"); err != nil {
368+ return err
369+ }
370+ if err := register(lib, &xWebPIUpdate, "WebPIUpdate"); err != nil {
371+ return err
372+ }
373+ if err := register(lib, &xWebPIDecGetRGB, "WebPIDecGetRGB"); err != nil {
374+ return err
375+ }
376+ if err := register(lib, &xWebPIDecGetYUVA, "WebPIDecGetYUVA"); err != nil {
377+ return err
378+ }
379+ if err := register(lib, &xWebPIDecodedArea, "WebPIDecodedArea"); err != nil {
380+ return err
381+ }
382+ if err := register(lib, &xWebPIDecode, "WebPIDecode"); err != nil {
383+ return err
384+ }
385+ if err := register(lib, &xWebPEncodeRGBA, "WebPEncodeRGBA"); err != nil {
386+ return err
387+ }
388+ if err := register(lib, &xWebPEncodeRGB, "WebPEncodeRGB"); err != nil {
389+ return err
390+ }
391+ if err := register(lib, &xWebPEncodeBGR, "WebPEncodeBGR"); err != nil {
392+ return err
393+ }
394+ if err := register(lib, &xWebPEncodeBGRA, "WebPEncodeBGRA"); err != nil {
395+ return err
396+ }
397+ if err := register(lib, &xWebPEncodeLosslessRGBA, "WebPEncodeLosslessRGBA"); err != nil {
398+ return err
399+ }
400+ if err := register(lib, &xWebPEncodeLosslessRGB, "WebPEncodeLosslessRGB"); err != nil {
401+ return err
402+ }
403+ if err := register(lib, &xWebPEncodeLosslessBGR, "WebPEncodeLosslessBGR"); err != nil {
404+ return err
405+ }
406+ if err := register(lib, &xWebPEncodeLosslessBGRA, "WebPEncodeLosslessBGRA"); err != nil {
407+ return err
408+ }
409+ if err := register(lib, &xWebPConfigInitInternal, "WebPConfigInitInternal"); err != nil {
410+ return err
411+ }
412+ if err := register(lib, &xWebPConfigLosslessPreset, "WebPConfigLosslessPreset"); err != nil {
413+ return err
414+ }
415+ if err := register(lib, &xWebPValidateConfig, "WebPValidateConfig"); err != nil {
416+ return err
417+ }
418+ if err := register(lib, &xWebPMemoryWriterInit, "WebPMemoryWriterInit"); err != nil {
419+ return err
420+ }
421+ if err := register(lib, &xWebPMemoryWriterClear, "WebPMemoryWriterClear"); err != nil {
422+ return err
423+ }
424+ if err := register(lib, &xWebPMemoryWrite, "WebPMemoryWrite"); err != nil {
425+ return err
426+ }
427+ if err := register(lib, &xWebPPictureInitInternal, "WebPPictureInitInternal"); err != nil {
428+ return err
429+ }
430+ if err := register(lib, &xWebPPictureAlloc, "WebPPictureAlloc"); err != nil {
431+ return err
432+ }
433+ if err := register(lib, &xWebPPictureFree, "WebPPictureFree"); err != nil {
434+ return err
435+ }
436+ if err := register(lib, &xWebPPictureCopy, "WebPPictureCopy"); err != nil {
437+ return err
438+ }
439+ if err := register(lib, &xWebPPictureCrop, "WebPPictureCrop"); err != nil {
440+ return err
441+ }
442+ if err := register(lib, &xWebPPictureView, "WebPPictureView"); err != nil {
443+ return err
444+ }
445+ if err := register(lib, &xWebPPictureIsView, "WebPPictureIsView"); err != nil {
446+ return err
447+ }
448+ if err := register(lib, &xWebPPictureRescale, "WebPPictureRescale"); err != nil {
449+ return err
450+ }
451+ if err := register(lib, &xWebPPictureImportRGB, "WebPPictureImportRGB"); err != nil {
452+ return err
453+ }
454+ if err := register(lib, &xWebPPictureImportRGBA, "WebPPictureImportRGBA"); err != nil {
455+ return err
456+ }
457+ if err := register(lib, &xWebPPictureImportRGBX, "WebPPictureImportRGBX"); err != nil {
458+ return err
459+ }
460+ if err := register(lib, &xWebPPictureImportBGR, "WebPPictureImportBGR"); err != nil {
461+ return err
462+ }
463+ if err := register(lib, &xWebPPictureImportBGRA, "WebPPictureImportBGRA"); err != nil {
464+ return err
465+ }
466+ if err := register(lib, &xWebPPictureImportBGRX, "WebPPictureImportBGRX"); err != nil {
467+ return err
468+ }
469+ if err := register(lib, &xWebPPictureARGBToYUVA, "WebPPictureARGBToYUVA"); err != nil {
470+ return err
471+ }
472+ if err := register(lib, &xWebPPictureARGBToYUVADithered, "WebPPictureARGBToYUVADithered"); err != nil {
473+ return err
474+ }
475+ if err := register(lib, &xWebPPictureSharpARGBToYUVA, "WebPPictureSharpARGBToYUVA"); err != nil {
476+ return err
477+ }
478+ if err := register(lib, &xWebPPictureSmartARGBToYUVA, "WebPPictureSmartARGBToYUVA"); err != nil {
479+ return err
480+ }
481+ if err := register(lib, &xWebPPictureYUVAToARGB, "WebPPictureYUVAToARGB"); err != nil {
482+ return err
483+ }
484+ if err := register(lib, &xWebPCleanupTransparentArea, "WebPCleanupTransparentArea"); err != nil {
485+ return err
486+ }
487+ if err := register(lib, &xWebPPictureHasTransparency, "WebPPictureHasTransparency"); err != nil {
488+ return err
489+ }
490+ if err := register(lib, &xWebPBlendAlpha, "WebPBlendAlpha"); err != nil {
491+ return err
492+ }
493+ if err := register(lib, &xWebPPlaneDistortion, "WebPPlaneDistortion"); err != nil {
494+ return err
495+ }
496+ if err := register(lib, &xWebPPictureDistortion, "WebPPictureDistortion"); err != nil {
497+ return err
498+ }
499+ if err := register(lib, &xWebPEncode, "WebPEncode"); err != nil {
500+ return err
501+ }
502+ if err := register(lib, &xWebPFree, "WebPFree"); err != nil {
503+ return err
504+ }
505+ if err := register(lib, &xWebPGetDecoderVersion, "WebPGetDecoderVersion"); err != nil {
506+ return err
507+ }
508+ if err := register(lib, &xWebPGetEncoderVersion, "WebPGetEncoderVersion"); err != nil {
509+ return err
510+ }
511+
512+ return nil
513+}
@@ -0,0 +1,513 @@
1+// Code generated by ./cmd/gen; DO NOT EDIT.
2+
3+package libwebp
4+
5+var (
6+ xWebPGetInfo func(data *byte, dataSize uintptr, width *int32, height *int32) int32
7+ xWebPDecodeRGBA func(data *byte, dataSize uintptr, width *int32, height *int32) *byte
8+ xWebPDecodeARGB func(data *byte, dataSize uintptr, width *int32, height *int32) *byte
9+ xWebPDecodeBGRA func(data *byte, dataSize uintptr, width *int32, height *int32) *byte
10+ xWebPDecodeRGB func(data *byte, dataSize uintptr, width *int32, height *int32) *byte
11+ xWebPDecodeBGR func(data *byte, dataSize uintptr, width *int32, height *int32) *byte
12+ xWebPDecodeRGBAInto func(data *byte, dataSize uintptr, outputBuffer *byte, outputBufferSize uintptr, outputStride int32) *byte
13+ xWebPDecodeARGBInto func(data *byte, dataSize uintptr, outputBuffer *byte, outputBufferSize uintptr, outputStride int32) *byte
14+ xWebPDecodeBGRAInto func(data *byte, dataSize uintptr, outputBuffer *byte, outputBufferSize uintptr, outputStride int32) *byte
15+ xWebPDecodeRGBInto func(data *byte, dataSize uintptr, outputBuffer *byte, outputBufferSize uintptr, outputStride int32) *byte
16+ xWebPDecodeBGRInto func(data *byte, dataSize uintptr, outputBuffer *byte, outputBufferSize uintptr, outputStride int32) *byte
17+ xWebPDecodeYUV func(data *byte, dataSize uintptr, width *int32, height *int32, u **byte, v **byte, stride *int32, uvStride *int32) *byte
18+ xWebPDecodeYUVInto func(data *byte, dataSize uintptr, luma *byte, lumaSize uintptr, lumaStride int32, u *byte, uSize uintptr, uStride int32, v *byte, vSize uintptr, vStride int32) *byte
19+ xWebPGetFeaturesInternal func(data *byte, dataSize uintptr, features *WebPBitstreamFeatures, abiVersion int32) VP8StatusCode
20+ xWebPInitDecBufferInternal func(buffer *WebPDecBuffer, abiVersion int32) int32
21+ xWebPFreeDecBuffer func(buffer *WebPDecBuffer)
22+ xWebPInitDecoderConfigInternal func(config *WebPDecoderConfig, abiVersion int32) int32
23+ xWebPValidateDecoderConfig func(config *WebPDecoderConfig) int32
24+ xWebPDecode func(data *byte, dataSize uintptr, config *WebPDecoderConfig) VP8StatusCode
25+ xWebPINewDecoder func(outputBuffer *WebPDecBuffer) uintptr
26+ xWebPINewRGB func(csp int32, outputBuffer *byte, outputBufferSize uintptr, outputStride int32) uintptr
27+ xWebPINewYUVA func(luma *byte, lumaSize uintptr, lumaStride int32, u *byte, uSize uintptr, uStride int32, v *byte, vSize uintptr, vStride int32, a *byte, aSize uintptr, aStride int32) uintptr
28+ xWebPINewYUV func(luma *byte, lumaSize uintptr, lumaStride int32, u *byte, uSize uintptr, uStride int32, v *byte, vSize uintptr, vStride int32) uintptr
29+ xWebPIDelete func(idec uintptr)
30+ xWebPIAppend func(idec uintptr, data *byte, dataSize uintptr) VP8StatusCode
31+ xWebPIUpdate func(idec uintptr, data *byte, dataSize uintptr) VP8StatusCode
32+ xWebPIDecGetRGB func(idec uintptr, lastY *int32, width *int32, height *int32, stride *int32) *byte
33+ xWebPIDecGetYUVA func(idec uintptr, lastY *int32, u **byte, v **byte, a **byte, width *int32, height *int32, stride *int32, uvStride *int32, aStride *int32) *byte
34+ xWebPIDecodedArea func(idec uintptr, left *int32, top *int32, width *int32, height *int32) *WebPDecBuffer
35+ xWebPIDecode func(data *byte, dataSize uintptr, config *WebPDecoderConfig) uintptr
36+ xWebPEncodeRGBA func(rgba *byte, width int32, height int32, stride int32, quality float32, output **byte) uintptr
37+ xWebPEncodeRGB func(rgb *byte, width int32, height int32, stride int32, quality float32, output **byte) uintptr
38+ xWebPEncodeBGR func(bgr *byte, width int32, height int32, stride int32, quality float32, output **byte) uintptr
39+ xWebPEncodeBGRA func(bgra *byte, width int32, height int32, stride int32, quality float32, output **byte) uintptr
40+ xWebPEncodeLosslessRGBA func(rgba *byte, width int32, height int32, stride int32, output **byte) uintptr
41+ xWebPEncodeLosslessRGB func(rgb *byte, width int32, height int32, stride int32, output **byte) uintptr
42+ xWebPEncodeLosslessBGR func(bgr *byte, width int32, height int32, stride int32, output **byte) uintptr
43+ xWebPEncodeLosslessBGRA func(bgra *byte, width int32, height int32, stride int32, output **byte) uintptr
44+ xWebPConfigInitInternal func(config *WebPConfig, preset int32, quality float32, abiVersion int32) int32
45+ xWebPConfigLosslessPreset func(config *WebPConfig, level int32) int32
46+ xWebPValidateConfig func(config *WebPConfig) int32
47+ xWebPMemoryWriterInit func(writer *WebPMemoryWriter)
48+ xWebPMemoryWriterClear func(writer *WebPMemoryWriter)
49+ xWebPMemoryWrite func(data *byte, dataSize uintptr, picture *WebPPicture) int32
50+ xWebPPictureInitInternal func(picture *WebPPicture, abiVersion int32) int32
51+ xWebPPictureAlloc func(picture *WebPPicture) int32
52+ xWebPPictureFree func(picture *WebPPicture)
53+ xWebPPictureCopy func(src *WebPPicture, dst *WebPPicture) int32
54+ xWebPPictureCrop func(picture *WebPPicture, left int32, top int32, width int32, height int32) int32
55+ xWebPPictureView func(src *WebPPicture, left int32, top int32, width int32, height int32, dst *WebPPicture) int32
56+ xWebPPictureIsView func(picture *WebPPicture) int32
57+ xWebPPictureRescale func(picture *WebPPicture, width int32, height int32) int32
58+ xWebPPictureImportRGB func(picture *WebPPicture, rgb *byte, rgbStride int32) int32
59+ xWebPPictureImportRGBA func(picture *WebPPicture, rgba *byte, rgbaStride int32) int32
60+ xWebPPictureImportRGBX func(picture *WebPPicture, rgbx *byte, rgbxStride int32) int32
61+ xWebPPictureImportBGR func(picture *WebPPicture, bgr *byte, bgrStride int32) int32
62+ xWebPPictureImportBGRA func(picture *WebPPicture, bgra *byte, bgraStride int32) int32
63+ xWebPPictureImportBGRX func(picture *WebPPicture, bgrx *byte, bgrxStride int32) int32
64+ xWebPPictureARGBToYUVA func(picture *WebPPicture, colorspace int32) int32
65+ xWebPPictureARGBToYUVADithered func(picture *WebPPicture, colorspace int32, dithering float32) int32
66+ xWebPPictureSharpARGBToYUVA func(picture *WebPPicture) int32
67+ xWebPPictureSmartARGBToYUVA func(picture *WebPPicture) int32
68+ xWebPPictureYUVAToARGB func(picture *WebPPicture) int32
69+ xWebPCleanupTransparentArea func(picture *WebPPicture)
70+ xWebPPictureHasTransparency func(picture *WebPPicture) int32
71+ xWebPBlendAlpha func(picture *WebPPicture, backgroundRGB uint32)
72+ xWebPPlaneDistortion func(src *byte, srcStride uintptr, ref *byte, refStride uintptr, width int32, height int32, xStep uintptr, distType int32, distortion *float32, result *float32) int32
73+ xWebPPictureDistortion func(src *WebPPicture, ref *WebPPicture, metricType int32, result *float32) int32
74+ xWebPEncode func(config *WebPConfig, picture *WebPPicture) int32
75+ xWebPFree func(ptr uintptr)
76+ xWebPGetDecoderVersion func() int32
77+ xWebPGetEncoderVersion func() int32
78+)
79+
80+func WebPGetInfo(data *byte, dataSize uintptr, width *int32, height *int32) int32 {
81+ return xWebPGetInfo(data, dataSize, width, height)
82+}
83+func WebPDecodeRGBA(data *byte, dataSize uintptr, width *int32, height *int32) *byte {
84+ return xWebPDecodeRGBA(data, dataSize, width, height)
85+}
86+func WebPDecodeARGB(data *byte, dataSize uintptr, width *int32, height *int32) *byte {
87+ return xWebPDecodeARGB(data, dataSize, width, height)
88+}
89+func WebPDecodeBGRA(data *byte, dataSize uintptr, width *int32, height *int32) *byte {
90+ return xWebPDecodeBGRA(data, dataSize, width, height)
91+}
92+func WebPDecodeRGB(data *byte, dataSize uintptr, width *int32, height *int32) *byte {
93+ return xWebPDecodeRGB(data, dataSize, width, height)
94+}
95+func WebPDecodeBGR(data *byte, dataSize uintptr, width *int32, height *int32) *byte {
96+ return xWebPDecodeBGR(data, dataSize, width, height)
97+}
98+func WebPDecodeRGBAInto(data *byte, dataSize uintptr, outputBuffer *byte, outputBufferSize uintptr, outputStride int32) *byte {
99+ return xWebPDecodeRGBAInto(data, dataSize, outputBuffer, outputBufferSize, outputStride)
100+}
101+func WebPDecodeARGBInto(data *byte, dataSize uintptr, outputBuffer *byte, outputBufferSize uintptr, outputStride int32) *byte {
102+ return xWebPDecodeARGBInto(data, dataSize, outputBuffer, outputBufferSize, outputStride)
103+}
104+func WebPDecodeBGRAInto(data *byte, dataSize uintptr, outputBuffer *byte, outputBufferSize uintptr, outputStride int32) *byte {
105+ return xWebPDecodeBGRAInto(data, dataSize, outputBuffer, outputBufferSize, outputStride)
106+}
107+func WebPDecodeRGBInto(data *byte, dataSize uintptr, outputBuffer *byte, outputBufferSize uintptr, outputStride int32) *byte {
108+ return xWebPDecodeRGBInto(data, dataSize, outputBuffer, outputBufferSize, outputStride)
109+}
110+func WebPDecodeBGRInto(data *byte, dataSize uintptr, outputBuffer *byte, outputBufferSize uintptr, outputStride int32) *byte {
111+ return xWebPDecodeBGRInto(data, dataSize, outputBuffer, outputBufferSize, outputStride)
112+}
113+func WebPDecodeYUV(data *byte, dataSize uintptr, width *int32, height *int32, u **byte, v **byte, stride *int32, uvStride *int32) *byte {
114+ return xWebPDecodeYUV(data, dataSize, width, height, u, v, stride, uvStride)
115+}
116+func WebPDecodeYUVInto(data *byte, dataSize uintptr, luma *byte, lumaSize uintptr, lumaStride int32, u *byte, uSize uintptr, uStride int32, v *byte, vSize uintptr, vStride int32) *byte {
117+ return xWebPDecodeYUVInto(data, dataSize, luma, lumaSize, lumaStride, u, uSize, uStride, v, vSize, vStride)
118+}
119+func WebPGetFeaturesInternal(data *byte, dataSize uintptr, features *WebPBitstreamFeatures, abiVersion int32) VP8StatusCode {
120+ return xWebPGetFeaturesInternal(data, dataSize, features, abiVersion)
121+}
122+func WebPInitDecBufferInternal(buffer *WebPDecBuffer, abiVersion int32) int32 {
123+ return xWebPInitDecBufferInternal(buffer, abiVersion)
124+}
125+func WebPFreeDecBuffer(buffer *WebPDecBuffer) {
126+ xWebPFreeDecBuffer(buffer)
127+}
128+func WebPInitDecoderConfigInternal(config *WebPDecoderConfig, abiVersion int32) int32 {
129+ return xWebPInitDecoderConfigInternal(config, abiVersion)
130+}
131+func WebPValidateDecoderConfig(config *WebPDecoderConfig) int32 {
132+ return xWebPValidateDecoderConfig(config)
133+}
134+func WebPDecode(data *byte, dataSize uintptr, config *WebPDecoderConfig) VP8StatusCode {
135+ return xWebPDecode(data, dataSize, config)
136+}
137+func WebPINewDecoder(outputBuffer *WebPDecBuffer) uintptr {
138+ return xWebPINewDecoder(outputBuffer)
139+}
140+func WebPINewRGB(csp int32, outputBuffer *byte, outputBufferSize uintptr, outputStride int32) uintptr {
141+ return xWebPINewRGB(csp, outputBuffer, outputBufferSize, outputStride)
142+}
143+func WebPINewYUVA(luma *byte, lumaSize uintptr, lumaStride int32, u *byte, uSize uintptr, uStride int32, v *byte, vSize uintptr, vStride int32, a *byte, aSize uintptr, aStride int32) uintptr {
144+ return xWebPINewYUVA(luma, lumaSize, lumaStride, u, uSize, uStride, v, vSize, vStride, a, aSize, aStride)
145+}
146+func WebPINewYUV(luma *byte, lumaSize uintptr, lumaStride int32, u *byte, uSize uintptr, uStride int32, v *byte, vSize uintptr, vStride int32) uintptr {
147+ return xWebPINewYUV(luma, lumaSize, lumaStride, u, uSize, uStride, v, vSize, vStride)
148+}
149+func WebPIDelete(idec uintptr) {
150+ xWebPIDelete(idec)
151+}
152+func WebPIAppend(idec uintptr, data *byte, dataSize uintptr) VP8StatusCode {
153+ return xWebPIAppend(idec, data, dataSize)
154+}
155+func WebPIUpdate(idec uintptr, data *byte, dataSize uintptr) VP8StatusCode {
156+ return xWebPIUpdate(idec, data, dataSize)
157+}
158+func WebPIDecGetRGB(idec uintptr, lastY *int32, width *int32, height *int32, stride *int32) *byte {
159+ return xWebPIDecGetRGB(idec, lastY, width, height, stride)
160+}
161+func WebPIDecGetYUVA(idec uintptr, lastY *int32, u **byte, v **byte, a **byte, width *int32, height *int32, stride *int32, uvStride *int32, aStride *int32) *byte {
162+ return xWebPIDecGetYUVA(idec, lastY, u, v, a, width, height, stride, uvStride, aStride)
163+}
164+func WebPIDecodedArea(idec uintptr, left *int32, top *int32, width *int32, height *int32) *WebPDecBuffer {
165+ return xWebPIDecodedArea(idec, left, top, width, height)
166+}
167+func WebPIDecode(data *byte, dataSize uintptr, config *WebPDecoderConfig) uintptr {
168+ return xWebPIDecode(data, dataSize, config)
169+}
170+func WebPEncodeRGBA(rgba *byte, width int32, height int32, stride int32, quality float32, output **byte) uintptr {
171+ return xWebPEncodeRGBA(rgba, width, height, stride, quality, output)
172+}
173+func WebPEncodeRGB(rgb *byte, width int32, height int32, stride int32, quality float32, output **byte) uintptr {
174+ return xWebPEncodeRGB(rgb, width, height, stride, quality, output)
175+}
176+func WebPEncodeBGR(bgr *byte, width int32, height int32, stride int32, quality float32, output **byte) uintptr {
177+ return xWebPEncodeBGR(bgr, width, height, stride, quality, output)
178+}
179+func WebPEncodeBGRA(bgra *byte, width int32, height int32, stride int32, quality float32, output **byte) uintptr {
180+ return xWebPEncodeBGRA(bgra, width, height, stride, quality, output)
181+}
182+func WebPEncodeLosslessRGBA(rgba *byte, width int32, height int32, stride int32, output **byte) uintptr {
183+ return xWebPEncodeLosslessRGBA(rgba, width, height, stride, output)
184+}
185+func WebPEncodeLosslessRGB(rgb *byte, width int32, height int32, stride int32, output **byte) uintptr {
186+ return xWebPEncodeLosslessRGB(rgb, width, height, stride, output)
187+}
188+func WebPEncodeLosslessBGR(bgr *byte, width int32, height int32, stride int32, output **byte) uintptr {
189+ return xWebPEncodeLosslessBGR(bgr, width, height, stride, output)
190+}
191+func WebPEncodeLosslessBGRA(bgra *byte, width int32, height int32, stride int32, output **byte) uintptr {
192+ return xWebPEncodeLosslessBGRA(bgra, width, height, stride, output)
193+}
194+func WebPConfigInitInternal(config *WebPConfig, preset int32, quality float32, abiVersion int32) int32 {
195+ return xWebPConfigInitInternal(config, preset, quality, abiVersion)
196+}
197+func WebPConfigLosslessPreset(config *WebPConfig, level int32) int32 {
198+ return xWebPConfigLosslessPreset(config, level)
199+}
200+func WebPValidateConfig(config *WebPConfig) int32 {
201+ return xWebPValidateConfig(config)
202+}
203+func WebPMemoryWriterInit(writer *WebPMemoryWriter) {
204+ xWebPMemoryWriterInit(writer)
205+}
206+func WebPMemoryWriterClear(writer *WebPMemoryWriter) {
207+ xWebPMemoryWriterClear(writer)
208+}
209+func WebPMemoryWrite(data *byte, dataSize uintptr, picture *WebPPicture) int32 {
210+ return xWebPMemoryWrite(data, dataSize, picture)
211+}
212+func WebPPictureInitInternal(picture *WebPPicture, abiVersion int32) int32 {
213+ return xWebPPictureInitInternal(picture, abiVersion)
214+}
215+func WebPPictureAlloc(picture *WebPPicture) int32 {
216+ return xWebPPictureAlloc(picture)
217+}
218+func WebPPictureFree(picture *WebPPicture) {
219+ xWebPPictureFree(picture)
220+}
221+func WebPPictureCopy(src *WebPPicture, dst *WebPPicture) int32 {
222+ return xWebPPictureCopy(src, dst)
223+}
224+func WebPPictureCrop(picture *WebPPicture, left int32, top int32, width int32, height int32) int32 {
225+ return xWebPPictureCrop(picture, left, top, width, height)
226+}
227+func WebPPictureView(src *WebPPicture, left int32, top int32, width int32, height int32, dst *WebPPicture) int32 {
228+ return xWebPPictureView(src, left, top, width, height, dst)
229+}
230+func WebPPictureIsView(picture *WebPPicture) int32 {
231+ return xWebPPictureIsView(picture)
232+}
233+func WebPPictureRescale(picture *WebPPicture, width int32, height int32) int32 {
234+ return xWebPPictureRescale(picture, width, height)
235+}
236+func WebPPictureImportRGB(picture *WebPPicture, rgb *byte, rgbStride int32) int32 {
237+ return xWebPPictureImportRGB(picture, rgb, rgbStride)
238+}
239+func WebPPictureImportRGBA(picture *WebPPicture, rgba *byte, rgbaStride int32) int32 {
240+ return xWebPPictureImportRGBA(picture, rgba, rgbaStride)
241+}
242+func WebPPictureImportRGBX(picture *WebPPicture, rgbx *byte, rgbxStride int32) int32 {
243+ return xWebPPictureImportRGBX(picture, rgbx, rgbxStride)
244+}
245+func WebPPictureImportBGR(picture *WebPPicture, bgr *byte, bgrStride int32) int32 {
246+ return xWebPPictureImportBGR(picture, bgr, bgrStride)
247+}
248+func WebPPictureImportBGRA(picture *WebPPicture, bgra *byte, bgraStride int32) int32 {
249+ return xWebPPictureImportBGRA(picture, bgra, bgraStride)
250+}
251+func WebPPictureImportBGRX(picture *WebPPicture, bgrx *byte, bgrxStride int32) int32 {
252+ return xWebPPictureImportBGRX(picture, bgrx, bgrxStride)
253+}
254+func WebPPictureARGBToYUVA(picture *WebPPicture, colorspace int32) int32 {
255+ return xWebPPictureARGBToYUVA(picture, colorspace)
256+}
257+func WebPPictureARGBToYUVADithered(picture *WebPPicture, colorspace int32, dithering float32) int32 {
258+ return xWebPPictureARGBToYUVADithered(picture, colorspace, dithering)
259+}
260+func WebPPictureSharpARGBToYUVA(picture *WebPPicture) int32 {
261+ return xWebPPictureSharpARGBToYUVA(picture)
262+}
263+func WebPPictureSmartARGBToYUVA(picture *WebPPicture) int32 {
264+ return xWebPPictureSmartARGBToYUVA(picture)
265+}
266+func WebPPictureYUVAToARGB(picture *WebPPicture) int32 {
267+ return xWebPPictureYUVAToARGB(picture)
268+}
269+func WebPCleanupTransparentArea(picture *WebPPicture) {
270+ xWebPCleanupTransparentArea(picture)
271+}
272+func WebPPictureHasTransparency(picture *WebPPicture) int32 {
273+ return xWebPPictureHasTransparency(picture)
274+}
275+func WebPBlendAlpha(picture *WebPPicture, backgroundRGB uint32) {
276+ xWebPBlendAlpha(picture, backgroundRGB)
277+}
278+func WebPPlaneDistortion(src *byte, srcStride uintptr, ref *byte, refStride uintptr, width int32, height int32, xStep uintptr, distType int32, distortion *float32, result *float32) int32 {
279+ return xWebPPlaneDistortion(src, srcStride, ref, refStride, width, height, xStep, distType, distortion, result)
280+}
281+func WebPPictureDistortion(src *WebPPicture, ref *WebPPicture, metricType int32, result *float32) int32 {
282+ return xWebPPictureDistortion(src, ref, metricType, result)
283+}
284+func WebPEncode(config *WebPConfig, picture *WebPPicture) int32 {
285+ return xWebPEncode(config, picture)
286+}
287+func WebPFree(ptr uintptr) {
288+ xWebPFree(ptr)
289+}
290+func WebPGetDecoderVersion() int32 {
291+ return xWebPGetDecoderVersion()
292+}
293+func WebPGetEncoderVersion() int32 {
294+ return xWebPGetEncoderVersion()
295+}
296+func registerAll(lib uintptr) error {
297+ if err := register(lib, &xWebPGetInfo, "WebPGetInfo"); err != nil {
298+ return err
299+ }
300+ if err := register(lib, &xWebPDecodeRGBA, "WebPDecodeRGBA"); err != nil {
301+ return err
302+ }
303+ if err := register(lib, &xWebPDecodeARGB, "WebPDecodeARGB"); err != nil {
304+ return err
305+ }
306+ if err := register(lib, &xWebPDecodeBGRA, "WebPDecodeBGRA"); err != nil {
307+ return err
308+ }
309+ if err := register(lib, &xWebPDecodeRGB, "WebPDecodeRGB"); err != nil {
310+ return err
311+ }
312+ if err := register(lib, &xWebPDecodeBGR, "WebPDecodeBGR"); err != nil {
313+ return err
314+ }
315+ if err := register(lib, &xWebPDecodeRGBAInto, "WebPDecodeRGBAInto"); err != nil {
316+ return err
317+ }
318+ if err := register(lib, &xWebPDecodeARGBInto, "WebPDecodeARGBInto"); err != nil {
319+ return err
320+ }
321+ if err := register(lib, &xWebPDecodeBGRAInto, "WebPDecodeBGRAInto"); err != nil {
322+ return err
323+ }
324+ if err := register(lib, &xWebPDecodeRGBInto, "WebPDecodeRGBInto"); err != nil {
325+ return err
326+ }
327+ if err := register(lib, &xWebPDecodeBGRInto, "WebPDecodeBGRInto"); err != nil {
328+ return err
329+ }
330+ if err := register(lib, &xWebPDecodeYUV, "WebPDecodeYUV"); err != nil {
331+ return err
332+ }
333+ if err := register(lib, &xWebPDecodeYUVInto, "WebPDecodeYUVInto"); err != nil {
334+ return err
335+ }
336+ if err := register(lib, &xWebPGetFeaturesInternal, "WebPGetFeaturesInternal"); err != nil {
337+ return err
338+ }
339+ if err := register(lib, &xWebPInitDecBufferInternal, "WebPInitDecBufferInternal"); err != nil {
340+ return err
341+ }
342+ if err := register(lib, &xWebPFreeDecBuffer, "WebPFreeDecBuffer"); err != nil {
343+ return err
344+ }
345+ if err := register(lib, &xWebPInitDecoderConfigInternal, "WebPInitDecoderConfigInternal"); err != nil {
346+ return err
347+ }
348+ registerOptional(lib, &xWebPValidateDecoderConfig, "WebPValidateDecoderConfig")
349+ if err := register(lib, &xWebPDecode, "WebPDecode"); err != nil {
350+ return err
351+ }
352+ if err := register(lib, &xWebPINewDecoder, "WebPINewDecoder"); err != nil {
353+ return err
354+ }
355+ if err := register(lib, &xWebPINewRGB, "WebPINewRGB"); err != nil {
356+ return err
357+ }
358+ if err := register(lib, &xWebPINewYUVA, "WebPINewYUVA"); err != nil {
359+ return err
360+ }
361+ if err := register(lib, &xWebPINewYUV, "WebPINewYUV"); err != nil {
362+ return err
363+ }
364+ if err := register(lib, &xWebPIDelete, "WebPIDelete"); err != nil {
365+ return err
366+ }
367+ if err := register(lib, &xWebPIAppend, "WebPIAppend"); err != nil {
368+ return err
369+ }
370+ if err := register(lib, &xWebPIUpdate, "WebPIUpdate"); err != nil {
371+ return err
372+ }
373+ if err := register(lib, &xWebPIDecGetRGB, "WebPIDecGetRGB"); err != nil {
374+ return err
375+ }
376+ if err := register(lib, &xWebPIDecGetYUVA, "WebPIDecGetYUVA"); err != nil {
377+ return err
378+ }
379+ if err := register(lib, &xWebPIDecodedArea, "WebPIDecodedArea"); err != nil {
380+ return err
381+ }
382+ if err := register(lib, &xWebPIDecode, "WebPIDecode"); err != nil {
383+ return err
384+ }
385+ if err := register(lib, &xWebPEncodeRGBA, "WebPEncodeRGBA"); err != nil {
386+ return err
387+ }
388+ if err := register(lib, &xWebPEncodeRGB, "WebPEncodeRGB"); err != nil {
389+ return err
390+ }
391+ if err := register(lib, &xWebPEncodeBGR, "WebPEncodeBGR"); err != nil {
392+ return err
393+ }
394+ if err := register(lib, &xWebPEncodeBGRA, "WebPEncodeBGRA"); err != nil {
395+ return err
396+ }
397+ if err := register(lib, &xWebPEncodeLosslessRGBA, "WebPEncodeLosslessRGBA"); err != nil {
398+ return err
399+ }
400+ if err := register(lib, &xWebPEncodeLosslessRGB, "WebPEncodeLosslessRGB"); err != nil {
401+ return err
402+ }
403+ if err := register(lib, &xWebPEncodeLosslessBGR, "WebPEncodeLosslessBGR"); err != nil {
404+ return err
405+ }
406+ if err := register(lib, &xWebPEncodeLosslessBGRA, "WebPEncodeLosslessBGRA"); err != nil {
407+ return err
408+ }
409+ if err := register(lib, &xWebPConfigInitInternal, "WebPConfigInitInternal"); err != nil {
410+ return err
411+ }
412+ if err := register(lib, &xWebPConfigLosslessPreset, "WebPConfigLosslessPreset"); err != nil {
413+ return err
414+ }
415+ if err := register(lib, &xWebPValidateConfig, "WebPValidateConfig"); err != nil {
416+ return err
417+ }
418+ if err := register(lib, &xWebPMemoryWriterInit, "WebPMemoryWriterInit"); err != nil {
419+ return err
420+ }
421+ if err := register(lib, &xWebPMemoryWriterClear, "WebPMemoryWriterClear"); err != nil {
422+ return err
423+ }
424+ if err := register(lib, &xWebPMemoryWrite, "WebPMemoryWrite"); err != nil {
425+ return err
426+ }
427+ if err := register(lib, &xWebPPictureInitInternal, "WebPPictureInitInternal"); err != nil {
428+ return err
429+ }
430+ if err := register(lib, &xWebPPictureAlloc, "WebPPictureAlloc"); err != nil {
431+ return err
432+ }
433+ if err := register(lib, &xWebPPictureFree, "WebPPictureFree"); err != nil {
434+ return err
435+ }
436+ if err := register(lib, &xWebPPictureCopy, "WebPPictureCopy"); err != nil {
437+ return err
438+ }
439+ if err := register(lib, &xWebPPictureCrop, "WebPPictureCrop"); err != nil {
440+ return err
441+ }
442+ if err := register(lib, &xWebPPictureView, "WebPPictureView"); err != nil {
443+ return err
444+ }
445+ if err := register(lib, &xWebPPictureIsView, "WebPPictureIsView"); err != nil {
446+ return err
447+ }
448+ if err := register(lib, &xWebPPictureRescale, "WebPPictureRescale"); err != nil {
449+ return err
450+ }
451+ if err := register(lib, &xWebPPictureImportRGB, "WebPPictureImportRGB"); err != nil {
452+ return err
453+ }
454+ if err := register(lib, &xWebPPictureImportRGBA, "WebPPictureImportRGBA"); err != nil {
455+ return err
456+ }
457+ if err := register(lib, &xWebPPictureImportRGBX, "WebPPictureImportRGBX"); err != nil {
458+ return err
459+ }
460+ if err := register(lib, &xWebPPictureImportBGR, "WebPPictureImportBGR"); err != nil {
461+ return err
462+ }
463+ if err := register(lib, &xWebPPictureImportBGRA, "WebPPictureImportBGRA"); err != nil {
464+ return err
465+ }
466+ if err := register(lib, &xWebPPictureImportBGRX, "WebPPictureImportBGRX"); err != nil {
467+ return err
468+ }
469+ if err := register(lib, &xWebPPictureARGBToYUVA, "WebPPictureARGBToYUVA"); err != nil {
470+ return err
471+ }
472+ if err := register(lib, &xWebPPictureARGBToYUVADithered, "WebPPictureARGBToYUVADithered"); err != nil {
473+ return err
474+ }
475+ if err := register(lib, &xWebPPictureSharpARGBToYUVA, "WebPPictureSharpARGBToYUVA"); err != nil {
476+ return err
477+ }
478+ if err := register(lib, &xWebPPictureSmartARGBToYUVA, "WebPPictureSmartARGBToYUVA"); err != nil {
479+ return err
480+ }
481+ if err := register(lib, &xWebPPictureYUVAToARGB, "WebPPictureYUVAToARGB"); err != nil {
482+ return err
483+ }
484+ if err := register(lib, &xWebPCleanupTransparentArea, "WebPCleanupTransparentArea"); err != nil {
485+ return err
486+ }
487+ if err := register(lib, &xWebPPictureHasTransparency, "WebPPictureHasTransparency"); err != nil {
488+ return err
489+ }
490+ if err := register(lib, &xWebPBlendAlpha, "WebPBlendAlpha"); err != nil {
491+ return err
492+ }
493+ if err := register(lib, &xWebPPlaneDistortion, "WebPPlaneDistortion"); err != nil {
494+ return err
495+ }
496+ if err := register(lib, &xWebPPictureDistortion, "WebPPictureDistortion"); err != nil {
497+ return err
498+ }
499+ if err := register(lib, &xWebPEncode, "WebPEncode"); err != nil {
500+ return err
501+ }
502+ if err := register(lib, &xWebPFree, "WebPFree"); err != nil {
503+ return err
504+ }
505+ if err := register(lib, &xWebPGetDecoderVersion, "WebPGetDecoderVersion"); err != nil {
506+ return err
507+ }
508+ if err := register(lib, &xWebPGetEncoderVersion, "WebPGetEncoderVersion"); err != nil {
509+ return err
510+ }
511+
512+ return nil
513+}
A third_party/purego-webp/internal/libwebp/loader.go +86 -0
@@ -0,0 +1,86 @@
1+package libwebp
2+
3+import (
4+ "errors"
5+ "fmt"
6+ "runtime"
7+ "sync"
8+
9+ "github.com/bnema/purego"
10+)
11+
12+var (
13+ loadOnce sync.Once
14+ loadErr error
15+)
16+
17+func EnsureLoaded() error {
18+ loadOnce.Do(func() {
19+ h, err := openLib()
20+ if err != nil {
21+ loadErr = err
22+ return
23+ }
24+
25+ if err := registerAll(h); err != nil {
26+ loadErr = err
27+ }
28+ })
29+
30+ return loadErr
31+}
32+
33+func Available() bool {
34+ return EnsureLoaded() == nil
35+}
36+
37+func register(lib uintptr, fnPtr interface{}, symbol string) error {
38+ addr, err := purego.Dlsym(lib, symbol)
39+ if err != nil {
40+ return fmt.Errorf("resolve %s: %w", symbol, err)
41+ }
42+ purego.RegisterFunc(fnPtr, addr)
43+ return nil
44+}
45+
46+// registerOptional resolves symbol from lib and registers fnPtr if found.
47+// Missing symbols are silently ignored; the function pointer is left nil.
48+func registerOptional(lib uintptr, fnPtr interface{}, symbol string) {
49+ addr, err := purego.Dlsym(lib, symbol)
50+ if err != nil {
51+ return
52+ }
53+ purego.RegisterFunc(fnPtr, addr)
54+}
55+
56+// ValidateDecoderConfigAvailable reports whether WebPValidateDecoderConfig
57+// was found in the loaded libwebp. It was added in libwebp 1.6.0 (2025-03).
58+func ValidateDecoderConfigAvailable() bool {
59+ return EnsureLoaded() == nil && xWebPValidateDecoderConfig != nil
60+}
61+
62+func openLib() (uintptr, error) {
63+ var errs []error
64+ for _, name := range candidateLibNames() {
65+ lib, err := purego.Dlopen(name, purego.RTLD_NOW|purego.RTLD_GLOBAL)
66+ if err == nil {
67+ return lib, nil
68+ }
69+ errs = append(errs, fmt.Errorf("%s: %w", name, err))
70+ }
71+
72+ return 0, errors.Join(errs...)
73+}
74+
75+func candidateLibNames() []string {
76+ switch runtime.GOOS {
77+ case "linux":
78+ return []string{"libwebp.so", "libwebp.so.8", "libwebp.so.7", "libwebp.so.6"}
79+ case "darwin":
80+ return []string{"libwebp.dylib"}
81+ case "windows":
82+ return []string{"libwebp.dll", "webp.dll"}
83+ default:
84+ return []string{"libwebp.so"}
85+ }
86+}
@@ -0,0 +1,86 @@
1+package libwebp
2+
3+import (
4+ "errors"
5+ "fmt"
6+ "runtime"
7+ "sync"
8+
9+ "github.com/bnema/purego"
10+)
11+
12+var (
13+ loadOnce sync.Once
14+ loadErr error
15+)
16+
17+func EnsureLoaded() error {
18+ loadOnce.Do(func() {
19+ h, err := openLib()
20+ if err != nil {
21+ loadErr = err
22+ return
23+ }
24+
25+ if err := registerAll(h); err != nil {
26+ loadErr = err
27+ }
28+ })
29+
30+ return loadErr
31+}
32+
33+func Available() bool {
34+ return EnsureLoaded() == nil
35+}
36+
37+func register(lib uintptr, fnPtr interface{}, symbol string) error {
38+ addr, err := purego.Dlsym(lib, symbol)
39+ if err != nil {
40+ return fmt.Errorf("resolve %s: %w", symbol, err)
41+ }
42+ purego.RegisterFunc(fnPtr, addr)
43+ return nil
44+}
45+
46+// registerOptional resolves symbol from lib and registers fnPtr if found.
47+// Missing symbols are silently ignored; the function pointer is left nil.
48+func registerOptional(lib uintptr, fnPtr interface{}, symbol string) {
49+ addr, err := purego.Dlsym(lib, symbol)
50+ if err != nil {
51+ return
52+ }
53+ purego.RegisterFunc(fnPtr, addr)
54+}
55+
56+// ValidateDecoderConfigAvailable reports whether WebPValidateDecoderConfig
57+// was found in the loaded libwebp. It was added in libwebp 1.6.0 (2025-03).
58+func ValidateDecoderConfigAvailable() bool {
59+ return EnsureLoaded() == nil && xWebPValidateDecoderConfig != nil
60+}
61+
62+func openLib() (uintptr, error) {
63+ var errs []error
64+ for _, name := range candidateLibNames() {
65+ lib, err := purego.Dlopen(name, purego.RTLD_NOW|purego.RTLD_GLOBAL)
66+ if err == nil {
67+ return lib, nil
68+ }
69+ errs = append(errs, fmt.Errorf("%s: %w", name, err))
70+ }
71+
72+ return 0, errors.Join(errs...)
73+}
74+
75+func candidateLibNames() []string {
76+ switch runtime.GOOS {
77+ case "linux":
78+ return []string{"libwebp.so", "libwebp.so.8", "libwebp.so.7", "libwebp.so.6"}
79+ case "darwin":
80+ return []string{"libwebp.dylib"}
81+ case "windows":
82+ return []string{"libwebp.dll", "webp.dll"}
83+ default:
84+ return []string{"libwebp.so"}
85+ }
86+}
A third_party/purego-webp/internal/libwebp/types.go +164 -0
@@ -0,0 +1,164 @@
1+package libwebp
2+
3+type VP8StatusCode int32
4+
5+const (
6+ VP8StatusOK VP8StatusCode = 0
7+ VP8StatusOutOfMemory VP8StatusCode = 1
8+ VP8StatusInvalidParam VP8StatusCode = 2
9+ VP8StatusBitstreamError VP8StatusCode = 3
10+ VP8StatusUnsupportedFeat VP8StatusCode = 4
11+ VP8StatusSuspended VP8StatusCode = 5
12+ VP8StatusUserAbort VP8StatusCode = 6
13+ VP8StatusNotEnoughData VP8StatusCode = 7
14+ WebPDecoderABIVersion int32 = 0x0210
15+ WebPEncoderABIVersion int32 = 0x0210
16+)
17+
18+type WebPBitstreamFeatures struct {
19+ Width int32
20+ Height int32
21+ HasAlpha int32
22+ HasAnimation int32
23+ Format int32
24+ Pad [5]uint32
25+}
26+
27+type WebPRGBABuffer struct {
28+ RGBA uintptr
29+ Stride int32
30+ _ int32
31+ Size uintptr
32+}
33+
34+type WebPYUVABuffer struct {
35+ Y uintptr
36+ U uintptr
37+ V uintptr
38+ A uintptr
39+ YStride int32
40+ UStride int32
41+ VStride int32
42+ AStride int32
43+ YSize uintptr
44+ USize uintptr
45+ VSize uintptr
46+ ASize uintptr
47+}
48+
49+// WebPDecBuffer matches the C layout used by decode.h.
50+// The union field is represented as raw bytes and should be manipulated only
51+// through dedicated helper functions/wrappers.
52+type WebPDecBuffer struct {
53+ Colorspace int32
54+ Width int32
55+ Height int32
56+ IsExternalMemory int32
57+ BufferUnion [80]byte
58+ Pad [4]uint32
59+ PrivateMemory uintptr
60+}
61+
62+type WebPDecoderOptions struct {
63+ BypassFiltering int32
64+ NoFancyUpsampling int32
65+ UseCropping int32
66+ CropLeft int32
67+ CropTop int32
68+ CropWidth int32
69+ CropHeight int32
70+ UseScaling int32
71+ ScaledWidth int32
72+ ScaledHeight int32
73+ UseThreads int32
74+ DitheringStrength int32
75+ Flip int32
76+ AlphaDitheringStrength int32
77+ Pad [5]uint32
78+}
79+
80+type WebPDecoderConfig struct {
81+ Input WebPBitstreamFeatures
82+ Output WebPDecBuffer
83+ Options WebPDecoderOptions
84+}
85+
86+type WebPConfig struct {
87+ Lossless int32
88+ Quality float32
89+ Method int32
90+ ImageHint int32
91+ TargetSize int32
92+ TargetPSNR float32
93+ Segments int32
94+ SnsStrength int32
95+ FilterStrength int32
96+ FilterSharpness int32
97+ FilterType int32
98+ Autofilter int32
99+ AlphaCompression int32
100+ AlphaFiltering int32
101+ AlphaQuality int32
102+ Pass int32
103+ ShowCompressed int32
104+ Preprocessing int32
105+ Partitions int32
106+ PartitionLimit int32
107+ EmulateJpegSize int32
108+ ThreadLevel int32
109+ LowMemory int32
110+ NearLossless int32
111+ Exact int32
112+ UseDeltaPalette int32
113+ UseSharpYuv int32
114+ QMin int32
115+ QMax int32
116+}
117+
118+type WebPMemoryWriter struct {
119+ Mem uintptr
120+ Size uintptr
121+ MaxSize uintptr
122+ Pad [1]uint32
123+}
124+
125+type WebPPicture struct {
126+ UseArgb int32
127+ Colorspace int32
128+ Width int32
129+ Height int32
130+ Y uintptr
131+ U uintptr
132+ V uintptr
133+ YStride int32
134+ UvStride int32
135+ A uintptr
136+ AStride int32
137+ Pad1 [2]uint32
138+
139+ Argb uintptr
140+ ArgbStride int32
141+ Pad2 [3]uint32
142+
143+ Writer uintptr
144+ CustomPtr uintptr
145+
146+ ExtraInfoType int32
147+ ExtraInfo uintptr
148+
149+ Stats uintptr
150+
151+ ErrorCode int32
152+ ProgressHook uintptr
153+ UserData uintptr
154+
155+ Pad3 [3]uint32
156+
157+ Pad4 uintptr
158+ Pad5 uintptr
159+ Pad6 [8]uint32
160+
161+ Memory uintptr
162+ MemoryArgb uintptr
163+ Pad7 [2]uintptr
164+}
@@ -0,0 +1,164 @@
1+package libwebp
2+
3+type VP8StatusCode int32
4+
5+const (
6+ VP8StatusOK VP8StatusCode = 0
7+ VP8StatusOutOfMemory VP8StatusCode = 1
8+ VP8StatusInvalidParam VP8StatusCode = 2
9+ VP8StatusBitstreamError VP8StatusCode = 3
10+ VP8StatusUnsupportedFeat VP8StatusCode = 4
11+ VP8StatusSuspended VP8StatusCode = 5
12+ VP8StatusUserAbort VP8StatusCode = 6
13+ VP8StatusNotEnoughData VP8StatusCode = 7
14+ WebPDecoderABIVersion int32 = 0x0210
15+ WebPEncoderABIVersion int32 = 0x0210
16+)
17+
18+type WebPBitstreamFeatures struct {
19+ Width int32
20+ Height int32
21+ HasAlpha int32
22+ HasAnimation int32
23+ Format int32
24+ Pad [5]uint32
25+}
26+
27+type WebPRGBABuffer struct {
28+ RGBA uintptr
29+ Stride int32
30+ _ int32
31+ Size uintptr
32+}
33+
34+type WebPYUVABuffer struct {
35+ Y uintptr
36+ U uintptr
37+ V uintptr
38+ A uintptr
39+ YStride int32
40+ UStride int32
41+ VStride int32
42+ AStride int32
43+ YSize uintptr
44+ USize uintptr
45+ VSize uintptr
46+ ASize uintptr
47+}
48+
49+// WebPDecBuffer matches the C layout used by decode.h.
50+// The union field is represented as raw bytes and should be manipulated only
51+// through dedicated helper functions/wrappers.
52+type WebPDecBuffer struct {
53+ Colorspace int32
54+ Width int32
55+ Height int32
56+ IsExternalMemory int32
57+ BufferUnion [80]byte
58+ Pad [4]uint32
59+ PrivateMemory uintptr
60+}
61+
62+type WebPDecoderOptions struct {
63+ BypassFiltering int32
64+ NoFancyUpsampling int32
65+ UseCropping int32
66+ CropLeft int32
67+ CropTop int32
68+ CropWidth int32
69+ CropHeight int32
70+ UseScaling int32
71+ ScaledWidth int32
72+ ScaledHeight int32
73+ UseThreads int32
74+ DitheringStrength int32
75+ Flip int32
76+ AlphaDitheringStrength int32
77+ Pad [5]uint32
78+}
79+
80+type WebPDecoderConfig struct {
81+ Input WebPBitstreamFeatures
82+ Output WebPDecBuffer
83+ Options WebPDecoderOptions
84+}
85+
86+type WebPConfig struct {
87+ Lossless int32
88+ Quality float32
89+ Method int32
90+ ImageHint int32
91+ TargetSize int32
92+ TargetPSNR float32
93+ Segments int32
94+ SnsStrength int32
95+ FilterStrength int32
96+ FilterSharpness int32
97+ FilterType int32
98+ Autofilter int32
99+ AlphaCompression int32
100+ AlphaFiltering int32
101+ AlphaQuality int32
102+ Pass int32
103+ ShowCompressed int32
104+ Preprocessing int32
105+ Partitions int32
106+ PartitionLimit int32
107+ EmulateJpegSize int32
108+ ThreadLevel int32
109+ LowMemory int32
110+ NearLossless int32
111+ Exact int32
112+ UseDeltaPalette int32
113+ UseSharpYuv int32
114+ QMin int32
115+ QMax int32
116+}
117+
118+type WebPMemoryWriter struct {
119+ Mem uintptr
120+ Size uintptr
121+ MaxSize uintptr
122+ Pad [1]uint32
123+}
124+
125+type WebPPicture struct {
126+ UseArgb int32
127+ Colorspace int32
128+ Width int32
129+ Height int32
130+ Y uintptr
131+ U uintptr
132+ V uintptr
133+ YStride int32
134+ UvStride int32
135+ A uintptr
136+ AStride int32
137+ Pad1 [2]uint32
138+
139+ Argb uintptr
140+ ArgbStride int32
141+ Pad2 [3]uint32
142+
143+ Writer uintptr
144+ CustomPtr uintptr
145+
146+ ExtraInfoType int32
147+ ExtraInfo uintptr
148+
149+ Stats uintptr
150+
151+ ErrorCode int32
152+ ProgressHook uintptr
153+ UserData uintptr
154+
155+ Pad3 [3]uint32
156+
157+ Pad4 uintptr
158+ Pad5 uintptr
159+ Pad6 [8]uint32
160+
161+ Memory uintptr
162+ MemoryArgb uintptr
163+ Pad7 [2]uintptr
164+}
A third_party/purego-webp/libwebp/libwebp.go +880 -0
@@ -0,0 +1,880 @@
1+// Package libwebp exposes C-first bindings to libwebp using purego.
2+//
3+// The API mirrors libwebp function naming and behavior as closely as possible,
4+// while using Go slices and errors for safety in common call paths.
5+package libwebp
6+
7+import (
8+ "errors"
9+ "fmt"
10+ "math"
11+ "unsafe"
12+
13+ lowlevel "github.com/bnema/purego-webp/internal/libwebp"
14+)
15+
16+var (
17+ // ErrInvalidData indicates invalid or empty input bitstream/data.
18+ ErrInvalidData = errors.New("libwebp: invalid webp data")
19+ // ErrDecodeFailed indicates libwebp decode failure.
20+ ErrDecodeFailed = errors.New("libwebp: decode failed")
21+ // ErrEncodeFailed indicates libwebp encode failure.
22+ ErrEncodeFailed = errors.New("libwebp: encode failed")
23+ // ErrInvalidDimension indicates invalid image width/height.
24+ ErrInvalidDimension = errors.New("libwebp: invalid dimensions")
25+ // ErrInvalidStride indicates invalid row stride for the provided buffer.
26+ ErrInvalidStride = errors.New("libwebp: invalid stride")
27+ // ErrBufferTooSmall indicates the destination buffer cannot hold output.
28+ ErrBufferTooSmall = errors.New("libwebp: output buffer too small")
29+ // ErrNotAvailable indicates the function is not available in the loaded
30+ // libwebp version. Use the corresponding Available() helper to check first.
31+ ErrNotAvailable = errors.New("libwebp: function not available in loaded library version")
32+)
33+
34+// VP8StatusCode is the status enum used by libwebp decode APIs.
35+type VP8StatusCode int32
36+
37+const (
38+ VP8StatusOK VP8StatusCode = 0
39+ VP8StatusOutOfMemory VP8StatusCode = 1
40+ VP8StatusInvalidParam VP8StatusCode = 2
41+ VP8StatusBitstreamError VP8StatusCode = 3
42+ VP8StatusUnsupportedFeat VP8StatusCode = 4
43+ VP8StatusSuspended VP8StatusCode = 5
44+ VP8StatusUserAbort VP8StatusCode = 6
45+ VP8StatusNotEnoughData VP8StatusCode = 7
46+)
47+
48+type BitstreamFeatures struct {
49+ Width int
50+ Height int
51+ HasAlpha bool
52+ HasAnimation bool
53+ Format int
54+}
55+
56+// DecBuffer is the low-level decode output buffer struct from libwebp.
57+type DecBuffer = lowlevel.WebPDecBuffer
58+
59+// DecoderOptions is the low-level decoder options struct from libwebp.
60+type DecoderOptions = lowlevel.WebPDecoderOptions
61+
62+// DecoderConfig is the low-level decoder config struct from libwebp.
63+type DecoderConfig = lowlevel.WebPDecoderConfig
64+
65+// Config is the low-level encoder config struct from libwebp.
66+type Config = lowlevel.WebPConfig
67+
68+// MemoryWriter is libwebp's in-memory writer struct.
69+type MemoryWriter = lowlevel.WebPMemoryWriter
70+
71+// Picture is the low-level picture struct used by advanced encode APIs.
72+type Picture = lowlevel.WebPPicture
73+
74+const (
75+ // Encoder presets used by WebPConfigPreset.
76+ PresetDefault = 0
77+ PresetPicture = 1
78+ PresetPhoto = 2
79+ PresetDrawing = 3
80+ PresetIcon = 4
81+ PresetText = 5
82+
83+ HintDefault = 0
84+ HintPicture = 1
85+ HintPhoto = 2
86+ HintGraph = 3
87+ HintLast = 4
88+
89+ // Decode output colorspace/mode constants from decode.h.
90+ ModeRGB = 0
91+ ModeRGBA = 1
92+ ModeBGR = 2
93+ ModeBGRA = 3
94+ ModeARGB = 4
95+ ModeRGBA4444 = 5
96+ ModeRGB565 = 6
97+ ModergbA = 7
98+ ModebgrA = 8
99+ ModeArgb = 9
100+ ModergbA4444 = 10
101+ ModeYUV = 11
102+ ModeYUVA = 12
103+ ModeLast = 13
104+)
105+
106+// Available reports whether libwebp can be loaded in the current environment.
107+func Available() bool {
108+ return lowlevel.Available()
109+}
110+
111+// Version returns decoder and encoder library versions (packed hex format).
112+func Version() (decoder uint32, encoder uint32, err error) {
113+ if err := lowlevel.EnsureLoaded(); err != nil {
114+ return 0, 0, err
115+ }
116+
117+ return uint32(lowlevel.WebPGetDecoderVersion()), uint32(lowlevel.WebPGetEncoderVersion()), nil
118+}
119+
120+// WebPGetInfo validates the bitstream and returns image dimensions.
121+func WebPGetInfo(data []byte) (width, height int, ok bool, err error) {
122+ if err := lowlevel.EnsureLoaded(); err != nil {
123+ return 0, 0, false, err
124+ }
125+ if len(data) == 0 {
126+ return 0, 0, false, nil
127+ }
128+
129+ var w, h int32
130+ ret := lowlevel.WebPGetInfo(&data[0], uintptr(len(data)), &w, &h)
131+ return int(w), int(h), ret != 0, nil
132+}
133+
134+// WebPGetFeatures returns parsed bitstream features and decode status.
135+func WebPGetFeatures(data []byte) (features BitstreamFeatures, status VP8StatusCode, err error) {
136+ if err := lowlevel.EnsureLoaded(); err != nil {
137+ return BitstreamFeatures{}, 0, err
138+ }
139+ if len(data) == 0 {
140+ return BitstreamFeatures{}, VP8StatusNotEnoughData, nil
141+ }
142+
143+ var raw lowlevel.WebPBitstreamFeatures
144+ status = VP8StatusCode(lowlevel.WebPGetFeaturesInternal(&data[0], uintptr(len(data)), &raw, lowlevel.WebPDecoderABIVersion))
145+
146+ return BitstreamFeatures{
147+ Width: int(raw.Width),
148+ Height: int(raw.Height),
149+ HasAlpha: raw.HasAlpha != 0,
150+ HasAnimation: raw.HasAnimation != 0,
151+ Format: int(raw.Format),
152+ }, status, nil
153+}
154+
155+// WebPInitDecBuffer initializes a decode buffer with ABI-checked defaults.
156+func WebPInitDecBuffer(buffer *DecBuffer) (ok bool, err error) {
157+ if err := lowlevel.EnsureLoaded(); err != nil {
158+ return false, err
159+ }
160+ if buffer == nil {
161+ return false, ErrInvalidData
162+ }
163+
164+ return lowlevel.WebPInitDecBufferInternal(buffer, lowlevel.WebPDecoderABIVersion) != 0, nil
165+}
166+
167+// WebPFreeDecBuffer releases any memory owned by the decode buffer.
168+func WebPFreeDecBuffer(buffer *DecBuffer) error {
169+ if err := lowlevel.EnsureLoaded(); err != nil {
170+ return err
171+ }
172+ if buffer == nil {
173+ return nil
174+ }
175+
176+ lowlevel.WebPFreeDecBuffer(buffer)
177+ return nil
178+}
179+
180+// WebPInitDecoderConfig initializes a decoder config with ABI-checked defaults.
181+func WebPInitDecoderConfig(config *DecoderConfig) (ok bool, err error) {
182+ if err := lowlevel.EnsureLoaded(); err != nil {
183+ return false, err
184+ }
185+ if config == nil {
186+ return false, ErrInvalidData
187+ }
188+
189+ return lowlevel.WebPInitDecoderConfigInternal(config, lowlevel.WebPDecoderABIVersion) != 0, nil
190+}
191+
192+// WebPValidateDecoderConfigAvailable reports whether WebPValidateDecoderConfig
193+// is available in the loaded libwebp. The symbol was added in libwebp 1.6.0
194+// (released 2025-03); most distributions still ship an earlier version.
195+func WebPValidateDecoderConfigAvailable() bool {
196+ return lowlevel.ValidateDecoderConfigAvailable()
197+}
198+
199+// WebPValidateDecoderConfig validates decoder config values.
200+// It returns ErrNotAvailable if the loaded libwebp predates 1.6.0.
201+func WebPValidateDecoderConfig(config *DecoderConfig) (ok bool, err error) {
202+ if err := lowlevel.EnsureLoaded(); err != nil {
203+ return false, err
204+ }
205+ if !lowlevel.ValidateDecoderConfigAvailable() {
206+ return false, ErrNotAvailable
207+ }
208+ if config == nil {
209+ return false, ErrInvalidData
210+ }
211+
212+ return lowlevel.WebPValidateDecoderConfig(config) != 0, nil
213+}
214+
215+// WebPConfigInit initializes encoder config to default preset/quality.
216+func WebPConfigInit(config *Config) (ok bool, err error) {
217+ if err := lowlevel.EnsureLoaded(); err != nil {
218+ return false, err
219+ }
220+ if config == nil {
221+ return false, ErrInvalidData
222+ }
223+
224+ return lowlevel.WebPConfigInitInternal(config, PresetDefault, 75, lowlevel.WebPEncoderABIVersion) != 0, nil
225+}
226+
227+// WebPConfigPreset initializes encoder config with the given preset and quality.
228+func WebPConfigPreset(config *Config, preset int32, quality float32) (ok bool, err error) {
229+ if err := lowlevel.EnsureLoaded(); err != nil {
230+ return false, err
231+ }
232+ if config == nil {
233+ return false, ErrInvalidData
234+ }
235+
236+ return lowlevel.WebPConfigInitInternal(config, preset, quality, lowlevel.WebPEncoderABIVersion) != 0, nil
237+}
238+
239+// WebPConfigLosslessPreset applies a built-in lossless level preset.
240+func WebPConfigLosslessPreset(config *Config, level int32) (ok bool, err error) {
241+ if err := lowlevel.EnsureLoaded(); err != nil {
242+ return false, err
243+ }
244+ if config == nil {
245+ return false, ErrInvalidData
246+ }
247+
248+ return lowlevel.WebPConfigLosslessPreset(config, level) != 0, nil
249+}
250+
251+// WebPValidateConfig validates encoder config values.
252+func WebPValidateConfig(config *Config) (ok bool, err error) {
253+ if err := lowlevel.EnsureLoaded(); err != nil {
254+ return false, err
255+ }
256+ if config == nil {
257+ return false, ErrInvalidData
258+ }
259+
260+ return lowlevel.WebPValidateConfig(config) != 0, nil
261+}
262+
263+// WebPPictureInit initializes a picture struct with ABI-checked defaults.
264+func WebPPictureInit(picture *Picture) (ok bool, err error) {
265+ if err := lowlevel.EnsureLoaded(); err != nil {
266+ return false, err
267+ }
268+ if picture == nil {
269+ return false, ErrInvalidData
270+ }
271+
272+ return lowlevel.WebPPictureInitInternal(picture, lowlevel.WebPEncoderABIVersion) != 0, nil
273+}
274+
275+// WebPMemoryWriterInit initializes a memory writer instance.
276+func WebPMemoryWriterInit(writer *MemoryWriter) error {
277+ if err := lowlevel.EnsureLoaded(); err != nil {
278+ return err
279+ }
280+ if writer == nil {
281+ return ErrInvalidData
282+ }
283+
284+ lowlevel.WebPMemoryWriterInit(writer)
285+ return nil
286+}
287+
288+// WebPMemoryWriterClear frees memory owned by a memory writer.
289+func WebPMemoryWriterClear(writer *MemoryWriter) error {
290+ if err := lowlevel.EnsureLoaded(); err != nil {
291+ return err
292+ }
293+ if writer == nil {
294+ return nil
295+ }
296+
297+ lowlevel.WebPMemoryWriterClear(writer)
298+ return nil
299+}
300+
301+// WebPEncode runs advanced encoding with explicit config and picture structs.
302+func WebPEncode(config *Config, picture *Picture) (ok bool, err error) {
303+ if err := lowlevel.EnsureLoaded(); err != nil {
304+ return false, err
305+ }
306+ if config == nil || picture == nil {
307+ return false, ErrInvalidData
308+ }
309+
310+ return lowlevel.WebPEncode(config, picture) != 0, nil
311+}
312+
313+// WebPINewDecoder creates an incremental decoder using the provided output buffer.
314+func WebPINewDecoder(outputBuffer *DecBuffer) (uintptr, error) {
315+ if err := lowlevel.EnsureLoaded(); err != nil {
316+ return 0, err
317+ }
318+
319+ idec := lowlevel.WebPINewDecoder(outputBuffer)
320+ if idec == 0 {
321+ return 0, ErrDecodeFailed
322+ }
323+
324+ return idec, nil
325+}
326+
327+// WebPINewRGB creates an incremental decoder producing packed RGB-family output.
328+func WebPINewRGB(csp int32, outputBuffer []byte, outputStride int32) (uintptr, error) {
329+ if err := lowlevel.EnsureLoaded(); err != nil {
330+ return 0, err
331+ }
332+
333+ ptr, size := ptrAndSize(outputBuffer)
334+ idec := lowlevel.WebPINewRGB(csp, ptr, size, outputStride)
335+ if idec == 0 {
336+ return 0, ErrDecodeFailed
337+ }
338+
339+ return idec, nil
340+}
341+
342+// WebPINewYUV creates an incremental decoder producing YUV planes.
343+func WebPINewYUV(luma []byte, lumaStride int32, u []byte, uStride int32, v []byte, vStride int32) (uintptr, error) {
344+ if err := lowlevel.EnsureLoaded(); err != nil {
345+ return 0, err
346+ }
347+
348+ lumaPtr, lumaSize := ptrAndSize(luma)
349+ uPtr, uSize := ptrAndSize(u)
350+ vPtr, vSize := ptrAndSize(v)
351+
352+ idec := lowlevel.WebPINewYUV(lumaPtr, lumaSize, lumaStride, uPtr, uSize, uStride, vPtr, vSize, vStride)
353+ if idec == 0 {
354+ return 0, ErrDecodeFailed
355+ }
356+
357+ return idec, nil
358+}
359+
360+// WebPINewYUVA creates an incremental decoder producing YUVA planes.
361+func WebPINewYUVA(luma []byte, lumaStride int32, u []byte, uStride int32, v []byte, vStride int32, a []byte, aStride int32) (uintptr, error) {
362+ if err := lowlevel.EnsureLoaded(); err != nil {
363+ return 0, err
364+ }
365+
366+ lumaPtr, lumaSize := ptrAndSize(luma)
367+ uPtr, uSize := ptrAndSize(u)
368+ vPtr, vSize := ptrAndSize(v)
369+ aPtr, aSize := ptrAndSize(a)
370+
371+ idec := lowlevel.WebPINewYUVA(lumaPtr, lumaSize, lumaStride, uPtr, uSize, uStride, vPtr, vSize, vStride, aPtr, aSize, aStride)
372+ if idec == 0 {
373+ return 0, ErrDecodeFailed
374+ }
375+
376+ return idec, nil
377+}
378+
379+// WebPIDelete destroys an incremental decoder instance.
380+func WebPIDelete(idec uintptr) error {
381+ if err := lowlevel.EnsureLoaded(); err != nil {
382+ return err
383+ }
384+ if idec == 0 {
385+ return nil
386+ }
387+
388+ lowlevel.WebPIDelete(idec)
389+ return nil
390+}
391+
392+// WebPIAppend appends data to an incremental decoder.
393+func WebPIAppend(idec uintptr, data []byte) (VP8StatusCode, error) {
394+ if err := lowlevel.EnsureLoaded(); err != nil {
395+ return 0, err
396+ }
397+ if idec == 0 || len(data) == 0 {
398+ return VP8StatusInvalidParam, ErrInvalidData
399+ }
400+
401+ return VP8StatusCode(lowlevel.WebPIAppend(idec, &data[0], uintptr(len(data)))), nil
402+}
403+
404+// WebPIUpdate updates an incremental decoder with a full prefix buffer.
405+func WebPIUpdate(idec uintptr, data []byte) (VP8StatusCode, error) {
406+ if err := lowlevel.EnsureLoaded(); err != nil {
407+ return 0, err
408+ }
409+ if idec == 0 || len(data) == 0 {
410+ return VP8StatusInvalidParam, ErrInvalidData
411+ }
412+
413+ return VP8StatusCode(lowlevel.WebPIUpdate(idec, &data[0], uintptr(len(data)))), nil
414+}
415+
416+// WebPIDecode creates an incremental decoder with optional config and input.
417+func WebPIDecode(data []byte, config *DecoderConfig) (uintptr, error) {
418+ if err := lowlevel.EnsureLoaded(); err != nil {
419+ return 0, err
420+ }
421+ if len(data) == 0 {
422+ return 0, ErrInvalidData
423+ }
424+
425+ idec := lowlevel.WebPIDecode(&data[0], uintptr(len(data)), config)
426+ if idec == 0 {
427+ return 0, ErrDecodeFailed
428+ }
429+
430+ return idec, nil
431+}
432+
433+// WebPIDecodedArea returns decoded displayable area metadata.
434+func WebPIDecodedArea(idec uintptr, left, top, width, height *int32) (*DecBuffer, error) {
435+ if err := lowlevel.EnsureLoaded(); err != nil {
436+ return nil, err
437+ }
438+ if idec == 0 {
439+ return nil, ErrInvalidData
440+ }
441+
442+ buf := lowlevel.WebPIDecodedArea(idec, left, top, width, height)
443+ if buf == nil {
444+ return nil, ErrDecodeFailed
445+ }
446+
447+ return buf, nil
448+}
449+
450+// WebPIDecGetRGB returns current incremental packed RGB-family output pointer.
451+func WebPIDecGetRGB(idec uintptr, lastY, width, height, stride *int32) (uintptr, error) {
452+ if err := lowlevel.EnsureLoaded(); err != nil {
453+ return 0, err
454+ }
455+ if idec == 0 {
456+ return 0, ErrInvalidData
457+ }
458+
459+ ptr := lowlevel.WebPIDecGetRGB(idec, lastY, width, height, stride)
460+ if ptr == nil {
461+ return 0, ErrDecodeFailed
462+ }
463+
464+ return uintptr(unsafe.Pointer(ptr)), nil
465+}
466+
467+// WebPIDecGetYUVA returns current incremental YUVA luma pointer.
468+func WebPIDecGetYUVA(idec uintptr, lastY *int32, u, v, a **byte, width, height, stride, uvStride, aStride *int32) (uintptr, error) {
469+ if err := lowlevel.EnsureLoaded(); err != nil {
470+ return 0, err
471+ }
472+ if idec == 0 {
473+ return 0, ErrInvalidData
474+ }
475+
476+ ptr := lowlevel.WebPIDecGetYUVA(idec, lastY, u, v, a, width, height, stride, uvStride, aStride)
477+ if ptr == nil {
478+ return 0, ErrDecodeFailed
479+ }
480+
481+ return uintptr(unsafe.Pointer(ptr)), nil
482+}
483+
484+// WebPIDecGetYUV is a compatibility wrapper for YUV output without alpha.
485+func WebPIDecGetYUV(idec uintptr, lastY *int32, u, v **byte, width, height, stride, uvStride *int32) (uintptr, error) {
486+ var a *byte
487+ return WebPIDecGetYUVA(idec, lastY, u, v, &a, width, height, stride, uvStride, nil)
488+}
489+
490+// WebPDecode performs advanced one-shot decode using DecoderConfig.
491+func WebPDecode(data []byte, config *DecoderConfig) (status VP8StatusCode, err error) {
492+ if err := lowlevel.EnsureLoaded(); err != nil {
493+ return 0, err
494+ }
495+ if len(data) == 0 {
496+ return VP8StatusNotEnoughData, nil
497+ }
498+ if config == nil {
499+ return VP8StatusInvalidParam, ErrInvalidData
500+ }
501+
502+ return VP8StatusCode(lowlevel.WebPDecode(&data[0], uintptr(len(data)), config)), nil
503+}
504+
505+// WebPDecodeRGBA decodes to packed RGBA and returns an owned Go buffer.
506+func WebPDecodeRGBA(data []byte) (pix []byte, width, height, stride int, err error) {
507+ return decodeToOwnedBuffer(data, 4, lowlevel.WebPDecodeRGBA)
508+}
509+
510+// WebPDecodeARGB decodes to packed ARGB and returns an owned Go buffer.
511+func WebPDecodeARGB(data []byte) (pix []byte, width, height, stride int, err error) {
512+ return decodeToOwnedBuffer(data, 4, lowlevel.WebPDecodeARGB)
513+}
514+
515+// WebPDecodeBGRA decodes to packed BGRA and returns an owned Go buffer.
516+func WebPDecodeBGRA(data []byte) (pix []byte, width, height, stride int, err error) {
517+ return decodeToOwnedBuffer(data, 4, lowlevel.WebPDecodeBGRA)
518+}
519+
520+// WebPDecodeRGB decodes to packed RGB and returns an owned Go buffer.
521+func WebPDecodeRGB(data []byte) (pix []byte, width, height, stride int, err error) {
522+ return decodeToOwnedBuffer(data, 3, lowlevel.WebPDecodeRGB)
523+}
524+
525+// WebPDecodeBGR decodes to packed BGR and returns an owned Go buffer.
526+func WebPDecodeBGR(data []byte) (pix []byte, width, height, stride int, err error) {
527+ return decodeToOwnedBuffer(data, 3, lowlevel.WebPDecodeBGR)
528+}
529+
530+// WebPDecodeRGBAInto decodes into a caller-provided RGBA buffer.
531+func WebPDecodeRGBAInto(data []byte, outputBuffer []byte, outputStride int) (width, height int, err error) {
532+ return decodeInto(data, outputBuffer, outputStride, 4, lowlevel.WebPDecodeRGBAInto)
533+}
534+
535+// WebPDecodeRGBAIntoWithInfo decodes into a caller-provided RGBA buffer using
536+// dimensions already validated by WebPGetInfo, avoiding a second parse.
537+func WebPDecodeRGBAIntoWithInfo(data []byte, outputBuffer []byte, outputStride, width, height int) error {
538+ return decodeIntoWithInfo(data, outputBuffer, outputStride, width, height, 4, lowlevel.WebPDecodeRGBAInto)
539+}
540+
541+// WebPDecodeARGBInto decodes into a caller-provided ARGB buffer.
542+func WebPDecodeARGBInto(data []byte, outputBuffer []byte, outputStride int) (width, height int, err error) {
543+ return decodeInto(data, outputBuffer, outputStride, 4, lowlevel.WebPDecodeARGBInto)
544+}
545+
546+// WebPDecodeBGRAInto decodes into a caller-provided BGRA buffer.
547+func WebPDecodeBGRAInto(data []byte, outputBuffer []byte, outputStride int) (width, height int, err error) {
548+ return decodeInto(data, outputBuffer, outputStride, 4, lowlevel.WebPDecodeBGRAInto)
549+}
550+
551+// WebPDecodeRGBInto decodes into a caller-provided RGB buffer.
552+func WebPDecodeRGBInto(data []byte, outputBuffer []byte, outputStride int) (width, height int, err error) {
553+ return decodeInto(data, outputBuffer, outputStride, 3, lowlevel.WebPDecodeRGBInto)
554+}
555+
556+// WebPDecodeBGRInto decodes into a caller-provided BGR buffer.
557+func WebPDecodeBGRInto(data []byte, outputBuffer []byte, outputStride int) (width, height int, err error) {
558+ return decodeInto(data, outputBuffer, outputStride, 3, lowlevel.WebPDecodeBGRInto)
559+}
560+
561+// WebPDecodeYUV decodes to planar YUV and returns owned Go buffers.
562+func WebPDecodeYUV(data []byte) (y, u, v []byte, width, height, yStride, uvStride int, err error) {
563+ if err := lowlevel.EnsureLoaded(); err != nil {
564+ return nil, nil, nil, 0, 0, 0, 0, err
565+ }
566+ if len(data) == 0 {
567+ return nil, nil, nil, 0, 0, 0, 0, ErrInvalidData
568+ }
569+
570+ var w, h int32
571+ var uPtr, vPtr *byte
572+ var ys, uvs int32
573+ yPtr := lowlevel.WebPDecodeYUV(&data[0], uintptr(len(data)), &w, &h, &uPtr, &vPtr, &ys, &uvs)
574+ if yPtr == nil {
575+ return nil, nil, nil, 0, 0, 0, 0, ErrDecodeFailed
576+ }
577+ defer lowlevel.WebPFree(uintptr(unsafe.Pointer(yPtr)))
578+
579+ width = int(w)
580+ height = int(h)
581+ if width <= 0 || height <= 0 {
582+ return nil, nil, nil, 0, 0, 0, 0, ErrInvalidDimension
583+ }
584+
585+ yStride = int(ys)
586+ uvStride = int(uvs)
587+ uvHeight := (height + 1) / 2
588+
589+ y = make([]byte, yStride*height)
590+ u = make([]byte, uvStride*uvHeight)
591+ v = make([]byte, uvStride*uvHeight)
592+
593+ copy(y, unsafe.Slice(yPtr, len(y)))
594+ copy(u, unsafe.Slice(uPtr, len(u)))
595+ copy(v, unsafe.Slice(vPtr, len(v)))
596+
597+ return y, u, v, width, height, yStride, uvStride, nil
598+}
599+
600+// WebPDecodeYUVInto decodes into caller-provided Y, U and V planes.
601+func WebPDecodeYUVInto(data []byte, luma []byte, lumaStride int, u []byte, uStride int, v []byte, vStride int) (width, height int, err error) {
602+ if err := lowlevel.EnsureLoaded(); err != nil {
603+ return 0, 0, err
604+ }
605+ if len(data) == 0 {
606+ return 0, 0, ErrInvalidData
607+ }
608+ if len(luma) == 0 || len(u) == 0 || len(v) == 0 {
609+ return 0, 0, ErrBufferTooSmall
610+ }
611+
612+ w, h, ok, err := WebPGetInfo(data)
613+ if err != nil {
614+ return 0, 0, err
615+ }
616+ if !ok {
617+ return 0, 0, ErrInvalidData
618+ }
619+ if lumaStride < w {
620+ return 0, 0, ErrInvalidStride
621+ }
622+ uvWidth := (w + 1) / 2
623+ uvHeight := (h + 1) / 2
624+ if uStride < uvWidth || vStride < uvWidth {
625+ return 0, 0, ErrInvalidStride
626+ }
627+ if len(luma) < lumaStride*h || len(u) < uStride*uvHeight || len(v) < vStride*uvHeight {
628+ return 0, 0, ErrBufferTooSmall
629+ }
630+
631+ ptr := lowlevel.WebPDecodeYUVInto(
632+ &data[0],
633+ uintptr(len(data)),
634+ &luma[0],
635+ uintptr(len(luma)),
636+ int32(lumaStride),
637+ &u[0],
638+ uintptr(len(u)),
639+ int32(uStride),
640+ &v[0],
641+ uintptr(len(v)),
642+ int32(vStride),
643+ )
644+ if ptr == nil {
645+ return 0, 0, ErrDecodeFailed
646+ }
647+
648+ return w, h, nil
649+}
650+
651+// WebPEncodeRGBA encodes packed RGBA pixels with lossy quality.
652+func WebPEncodeRGBA(rgba []byte, width, height, stride int, quality float32) ([]byte, error) {
653+ return encodeWithQuality(rgba, width, height, stride, 4, quality, lowlevel.WebPEncodeRGBA)
654+}
655+
656+// WebPEncodeBGRA encodes packed BGRA pixels with lossy quality.
657+func WebPEncodeBGRA(bgra []byte, width, height, stride int, quality float32) ([]byte, error) {
658+ return encodeWithQuality(bgra, width, height, stride, 4, quality, lowlevel.WebPEncodeBGRA)
659+}
660+
661+// WebPEncodeRGB encodes packed RGB pixels with lossy quality.
662+func WebPEncodeRGB(rgb []byte, width, height, stride int, quality float32) ([]byte, error) {
663+ return encodeWithQuality(rgb, width, height, stride, 3, quality, lowlevel.WebPEncodeRGB)
664+}
665+
666+// WebPEncodeBGR encodes packed BGR pixels with lossy quality.
667+func WebPEncodeBGR(bgr []byte, width, height, stride int, quality float32) ([]byte, error) {
668+ return encodeWithQuality(bgr, width, height, stride, 3, quality, lowlevel.WebPEncodeBGR)
669+}
670+
671+// WebPEncodeLosslessRGBA encodes packed RGBA pixels in lossless mode.
672+func WebPEncodeLosslessRGBA(rgba []byte, width, height, stride int) ([]byte, error) {
673+ return encodeLossless(rgba, width, height, stride, 4, lowlevel.WebPEncodeLosslessRGBA)
674+}
675+
676+// WebPEncodeLosslessBGRA encodes packed BGRA pixels in lossless mode.
677+func WebPEncodeLosslessBGRA(bgra []byte, width, height, stride int) ([]byte, error) {
678+ return encodeLossless(bgra, width, height, stride, 4, lowlevel.WebPEncodeLosslessBGRA)
679+}
680+
681+// WebPEncodeLosslessRGB encodes packed RGB pixels in lossless mode.
682+func WebPEncodeLosslessRGB(rgb []byte, width, height, stride int) ([]byte, error) {
683+ return encodeLossless(rgb, width, height, stride, 3, lowlevel.WebPEncodeLosslessRGB)
684+}
685+
686+// WebPEncodeLosslessBGR encodes packed BGR pixels in lossless mode.
687+func WebPEncodeLosslessBGR(bgr []byte, width, height, stride int) ([]byte, error) {
688+ return encodeLossless(bgr, width, height, stride, 3, lowlevel.WebPEncodeLosslessBGR)
689+}
690+
691+type decodeFunc func(data *byte, dataSize uintptr, width *int32, height *int32) *byte
692+
693+type decodeIntoFunc func(data *byte, dataSize uintptr, outputBuffer *byte, outputBufferSize uintptr, outputStride int32) *byte
694+
695+func decodeInto(data []byte, outputBuffer []byte, outputStride int, bytesPerPixel int, fn decodeIntoFunc) (width, height int, err error) {
696+ if err := lowlevel.EnsureLoaded(); err != nil {
697+ return 0, 0, err
698+ }
699+ if len(data) == 0 {
700+ return 0, 0, ErrInvalidData
701+ }
702+ if len(outputBuffer) == 0 {
703+ return 0, 0, ErrBufferTooSmall
704+ }
705+ w, h, ok, err := WebPGetInfo(data)
706+ if err != nil {
707+ return 0, 0, err
708+ }
709+ if !ok {
710+ return 0, 0, ErrInvalidData
711+ }
712+ if err := decodeIntoWithInfo(data, outputBuffer, outputStride, w, h, bytesPerPixel, fn); err != nil {
713+ return 0, 0, err
714+ }
715+ return w, h, nil
716+}
717+
718+func decodeIntoWithInfo(data []byte, outputBuffer []byte, outputStride, width, height, bytesPerPixel int, fn decodeIntoFunc) error {
719+ if err := lowlevel.EnsureLoaded(); err != nil {
720+ return err
721+ }
722+ if len(data) == 0 {
723+ return ErrInvalidData
724+ }
725+ if len(outputBuffer) == 0 {
726+ return ErrBufferTooSmall
727+ }
728+ minimumStride, _, err := checkedDecodeLayout(width, height, bytesPerPixel)
729+ if err != nil {
730+ return err
731+ }
732+ if outputStride < minimumStride || outputStride > math.MaxInt32 {
733+ return ErrInvalidStride
734+ }
735+ required, ok := checkedProduct(outputStride, height)
736+ if !ok || len(outputBuffer) < required {
737+ return ErrBufferTooSmall
738+ }
739+ if fn(&data[0], uintptr(len(data)), &outputBuffer[0], uintptr(len(outputBuffer)), int32(outputStride)) == nil {
740+ return ErrDecodeFailed
741+ }
742+ return nil
743+}
744+
745+func decodeToOwnedBuffer(data []byte, bytesPerPixel int, fn decodeFunc) (pix []byte, width, height, stride int, err error) {
746+ if err := lowlevel.EnsureLoaded(); err != nil {
747+ return nil, 0, 0, 0, err
748+ }
749+ if len(data) == 0 {
750+ return nil, 0, 0, 0, ErrInvalidData
751+ }
752+
753+ var w, h int32
754+ ptr := fn(&data[0], uintptr(len(data)), &w, &h)
755+ if ptr == nil {
756+ return nil, 0, 0, 0, ErrDecodeFailed
757+ }
758+ defer lowlevel.WebPFree(uintptr(unsafe.Pointer(ptr)))
759+
760+ width = int(w)
761+ height = int(h)
762+ stride, bufLen, err := checkedDecodeLayout(width, height, bytesPerPixel)
763+ if err != nil {
764+ return nil, 0, 0, 0, err
765+ }
766+ pix = make([]byte, bufLen)
767+ copy(pix, unsafe.Slice(ptr, bufLen))
768+
769+ return pix, width, height, stride, nil
770+}
771+
772+type encodeLossyFunc func(pix *byte, width int32, height int32, stride int32, quality float32, output **byte) uintptr
773+
774+func encodeWithQuality(pix []byte, width, height, stride, bytesPerPixel int, quality float32, fn encodeLossyFunc) ([]byte, error) {
775+ if err := lowlevel.EnsureLoaded(); err != nil {
776+ return nil, err
777+ }
778+ if err := validatePixelInput(pix, width, height, stride, bytesPerPixel); err != nil {
779+ return nil, err
780+ }
781+
782+ var out *byte
783+ size := fn(&pix[0], int32(width), int32(height), int32(stride), quality, &out)
784+ if size == 0 || out == nil {
785+ return nil, ErrEncodeFailed
786+ }
787+ defer lowlevel.WebPFree(uintptr(unsafe.Pointer(out)))
788+
789+ b := make([]byte, int(size))
790+ copy(b, unsafe.Slice(out, int(size)))
791+
792+ return b, nil
793+}
794+
795+type encodeLosslessFunc func(pix *byte, width int32, height int32, stride int32, output **byte) uintptr
796+
797+func encodeLossless(pix []byte, width, height, stride, bytesPerPixel int, fn encodeLosslessFunc) ([]byte, error) {
798+ if err := lowlevel.EnsureLoaded(); err != nil {
799+ return nil, err
800+ }
801+ if err := validatePixelInput(pix, width, height, stride, bytesPerPixel); err != nil {
802+ return nil, err
803+ }
804+
805+ var out *byte
806+ size := fn(&pix[0], int32(width), int32(height), int32(stride), &out)
807+ if size == 0 || out == nil {
808+ return nil, ErrEncodeFailed
809+ }
810+ defer lowlevel.WebPFree(uintptr(unsafe.Pointer(out)))
811+
812+ b := make([]byte, int(size))
813+ copy(b, unsafe.Slice(out, int(size)))
814+
815+ return b, nil
816+}
817+
818+func validatePixelInput(pix []byte, width, height, stride, bytesPerPixel int) error {
819+ minimumStride, _, err := checkedDecodeLayout(width, height, bytesPerPixel)
820+ if err != nil {
821+ return err
822+ }
823+ if stride < minimumStride || stride > math.MaxInt32 {
824+ return ErrInvalidStride
825+ }
826+ required, ok := checkedProduct(stride, height)
827+ if !ok {
828+ return ErrInvalidDimension
829+ }
830+ if len(pix) < required {
831+ return fmt.Errorf("libwebp: pixel buffer too small: got=%d need>=%d", len(pix), required)
832+ }
833+ return nil
834+}
835+
836+// checkedDecodeLayout validates the dimensions and packed output layout before
837+// values are passed to libwebp, whose output stride parameter is a C int.
838+func checkedDecodeLayout(width, height, bytesPerPixel int) (stride, size int, err error) {
839+ if width <= 0 || height <= 0 {
840+ return 0, 0, ErrInvalidDimension
841+ }
842+ if bytesPerPixel <= 0 || width > math.MaxInt32/bytesPerPixel {
843+ return 0, 0, ErrInvalidStride
844+ }
845+ stride = width * bytesPerPixel
846+ size, ok := checkedProduct(stride, height)
847+ if !ok {
848+ return 0, 0, ErrInvalidDimension
849+ }
850+ return stride, size, nil
851+}
852+
853+func checkedProduct(a, b int) (int, bool) {
854+ if a < 0 || b < 0 || (a != 0 && b > int(^uint(0)>>1)/a) {
855+ return 0, false
856+ }
857+ return a * b, true
858+}
859+
860+// WebPIsPremultipliedMode reports whether the decode colorspace is premultiplied.
861+func WebPIsPremultipliedMode(mode int) bool {
862+ return mode == ModergbA || mode == ModebgrA || mode == ModeArgb || mode == ModergbA4444
863+}
864+
865+// WebPIsAlphaMode reports whether the decode colorspace contains alpha.
866+func WebPIsAlphaMode(mode int) bool {
867+ return mode == ModeRGBA || mode == ModeBGRA || mode == ModeARGB || mode == ModeRGBA4444 || mode == ModeYUVA || WebPIsPremultipliedMode(mode)
868+}
869+
870+// WebPIsRGBMode reports whether the decode colorspace is RGB-family.
871+func WebPIsRGBMode(mode int) bool {
872+ return mode < ModeYUV
873+}
874+
875+func ptrAndSize(b []byte) (*byte, uintptr) {
876+ if len(b) == 0 {
877+ return nil, 0
878+ }
879+ return &b[0], uintptr(len(b))
880+}
@@ -0,0 +1,880 @@
1+// Package libwebp exposes C-first bindings to libwebp using purego.
2+//
3+// The API mirrors libwebp function naming and behavior as closely as possible,
4+// while using Go slices and errors for safety in common call paths.
5+package libwebp
6+
7+import (
8+ "errors"
9+ "fmt"
10+ "math"
11+ "unsafe"
12+
13+ lowlevel "github.com/bnema/purego-webp/internal/libwebp"
14+)
15+
16+var (
17+ // ErrInvalidData indicates invalid or empty input bitstream/data.
18+ ErrInvalidData = errors.New("libwebp: invalid webp data")
19+ // ErrDecodeFailed indicates libwebp decode failure.
20+ ErrDecodeFailed = errors.New("libwebp: decode failed")
21+ // ErrEncodeFailed indicates libwebp encode failure.
22+ ErrEncodeFailed = errors.New("libwebp: encode failed")
23+ // ErrInvalidDimension indicates invalid image width/height.
24+ ErrInvalidDimension = errors.New("libwebp: invalid dimensions")
25+ // ErrInvalidStride indicates invalid row stride for the provided buffer.
26+ ErrInvalidStride = errors.New("libwebp: invalid stride")
27+ // ErrBufferTooSmall indicates the destination buffer cannot hold output.
28+ ErrBufferTooSmall = errors.New("libwebp: output buffer too small")
29+ // ErrNotAvailable indicates the function is not available in the loaded
30+ // libwebp version. Use the corresponding Available() helper to check first.
31+ ErrNotAvailable = errors.New("libwebp: function not available in loaded library version")
32+)
33+
34+// VP8StatusCode is the status enum used by libwebp decode APIs.
35+type VP8StatusCode int32
36+
37+const (
38+ VP8StatusOK VP8StatusCode = 0
39+ VP8StatusOutOfMemory VP8StatusCode = 1
40+ VP8StatusInvalidParam VP8StatusCode = 2
41+ VP8StatusBitstreamError VP8StatusCode = 3
42+ VP8StatusUnsupportedFeat VP8StatusCode = 4
43+ VP8StatusSuspended VP8StatusCode = 5
44+ VP8StatusUserAbort VP8StatusCode = 6
45+ VP8StatusNotEnoughData VP8StatusCode = 7
46+)
47+
48+type BitstreamFeatures struct {
49+ Width int
50+ Height int
51+ HasAlpha bool
52+ HasAnimation bool
53+ Format int
54+}
55+
56+// DecBuffer is the low-level decode output buffer struct from libwebp.
57+type DecBuffer = lowlevel.WebPDecBuffer
58+
59+// DecoderOptions is the low-level decoder options struct from libwebp.
60+type DecoderOptions = lowlevel.WebPDecoderOptions
61+
62+// DecoderConfig is the low-level decoder config struct from libwebp.
63+type DecoderConfig = lowlevel.WebPDecoderConfig
64+
65+// Config is the low-level encoder config struct from libwebp.
66+type Config = lowlevel.WebPConfig
67+
68+// MemoryWriter is libwebp's in-memory writer struct.
69+type MemoryWriter = lowlevel.WebPMemoryWriter
70+
71+// Picture is the low-level picture struct used by advanced encode APIs.
72+type Picture = lowlevel.WebPPicture
73+
74+const (
75+ // Encoder presets used by WebPConfigPreset.
76+ PresetDefault = 0
77+ PresetPicture = 1
78+ PresetPhoto = 2
79+ PresetDrawing = 3
80+ PresetIcon = 4
81+ PresetText = 5
82+
83+ HintDefault = 0
84+ HintPicture = 1
85+ HintPhoto = 2
86+ HintGraph = 3
87+ HintLast = 4
88+
89+ // Decode output colorspace/mode constants from decode.h.
90+ ModeRGB = 0
91+ ModeRGBA = 1
92+ ModeBGR = 2
93+ ModeBGRA = 3
94+ ModeARGB = 4
95+ ModeRGBA4444 = 5
96+ ModeRGB565 = 6
97+ ModergbA = 7
98+ ModebgrA = 8
99+ ModeArgb = 9
100+ ModergbA4444 = 10
101+ ModeYUV = 11
102+ ModeYUVA = 12
103+ ModeLast = 13
104+)
105+
106+// Available reports whether libwebp can be loaded in the current environment.
107+func Available() bool {
108+ return lowlevel.Available()
109+}
110+
111+// Version returns decoder and encoder library versions (packed hex format).
112+func Version() (decoder uint32, encoder uint32, err error) {
113+ if err := lowlevel.EnsureLoaded(); err != nil {
114+ return 0, 0, err
115+ }
116+
117+ return uint32(lowlevel.WebPGetDecoderVersion()), uint32(lowlevel.WebPGetEncoderVersion()), nil
118+}
119+
120+// WebPGetInfo validates the bitstream and returns image dimensions.
121+func WebPGetInfo(data []byte) (width, height int, ok bool, err error) {
122+ if err := lowlevel.EnsureLoaded(); err != nil {
123+ return 0, 0, false, err
124+ }
125+ if len(data) == 0 {
126+ return 0, 0, false, nil
127+ }
128+
129+ var w, h int32
130+ ret := lowlevel.WebPGetInfo(&data[0], uintptr(len(data)), &w, &h)
131+ return int(w), int(h), ret != 0, nil
132+}
133+
134+// WebPGetFeatures returns parsed bitstream features and decode status.
135+func WebPGetFeatures(data []byte) (features BitstreamFeatures, status VP8StatusCode, err error) {
136+ if err := lowlevel.EnsureLoaded(); err != nil {
137+ return BitstreamFeatures{}, 0, err
138+ }
139+ if len(data) == 0 {
140+ return BitstreamFeatures{}, VP8StatusNotEnoughData, nil
141+ }
142+
143+ var raw lowlevel.WebPBitstreamFeatures
144+ status = VP8StatusCode(lowlevel.WebPGetFeaturesInternal(&data[0], uintptr(len(data)), &raw, lowlevel.WebPDecoderABIVersion))
145+
146+ return BitstreamFeatures{
147+ Width: int(raw.Width),
148+ Height: int(raw.Height),
149+ HasAlpha: raw.HasAlpha != 0,
150+ HasAnimation: raw.HasAnimation != 0,
151+ Format: int(raw.Format),
152+ }, status, nil
153+}
154+
155+// WebPInitDecBuffer initializes a decode buffer with ABI-checked defaults.
156+func WebPInitDecBuffer(buffer *DecBuffer) (ok bool, err error) {
157+ if err := lowlevel.EnsureLoaded(); err != nil {
158+ return false, err
159+ }
160+ if buffer == nil {
161+ return false, ErrInvalidData
162+ }
163+
164+ return lowlevel.WebPInitDecBufferInternal(buffer, lowlevel.WebPDecoderABIVersion) != 0, nil
165+}
166+
167+// WebPFreeDecBuffer releases any memory owned by the decode buffer.
168+func WebPFreeDecBuffer(buffer *DecBuffer) error {
169+ if err := lowlevel.EnsureLoaded(); err != nil {
170+ return err
171+ }
172+ if buffer == nil {
173+ return nil
174+ }
175+
176+ lowlevel.WebPFreeDecBuffer(buffer)
177+ return nil
178+}
179+
180+// WebPInitDecoderConfig initializes a decoder config with ABI-checked defaults.
181+func WebPInitDecoderConfig(config *DecoderConfig) (ok bool, err error) {
182+ if err := lowlevel.EnsureLoaded(); err != nil {
183+ return false, err
184+ }
185+ if config == nil {
186+ return false, ErrInvalidData
187+ }
188+
189+ return lowlevel.WebPInitDecoderConfigInternal(config, lowlevel.WebPDecoderABIVersion) != 0, nil
190+}
191+
192+// WebPValidateDecoderConfigAvailable reports whether WebPValidateDecoderConfig
193+// is available in the loaded libwebp. The symbol was added in libwebp 1.6.0
194+// (released 2025-03); most distributions still ship an earlier version.
195+func WebPValidateDecoderConfigAvailable() bool {
196+ return lowlevel.ValidateDecoderConfigAvailable()
197+}
198+
199+// WebPValidateDecoderConfig validates decoder config values.
200+// It returns ErrNotAvailable if the loaded libwebp predates 1.6.0.
201+func WebPValidateDecoderConfig(config *DecoderConfig) (ok bool, err error) {
202+ if err := lowlevel.EnsureLoaded(); err != nil {
203+ return false, err
204+ }
205+ if !lowlevel.ValidateDecoderConfigAvailable() {
206+ return false, ErrNotAvailable
207+ }
208+ if config == nil {
209+ return false, ErrInvalidData
210+ }
211+
212+ return lowlevel.WebPValidateDecoderConfig(config) != 0, nil
213+}
214+
215+// WebPConfigInit initializes encoder config to default preset/quality.
216+func WebPConfigInit(config *Config) (ok bool, err error) {
217+ if err := lowlevel.EnsureLoaded(); err != nil {
218+ return false, err
219+ }
220+ if config == nil {
221+ return false, ErrInvalidData
222+ }
223+
224+ return lowlevel.WebPConfigInitInternal(config, PresetDefault, 75, lowlevel.WebPEncoderABIVersion) != 0, nil
225+}
226+
227+// WebPConfigPreset initializes encoder config with the given preset and quality.
228+func WebPConfigPreset(config *Config, preset int32, quality float32) (ok bool, err error) {
229+ if err := lowlevel.EnsureLoaded(); err != nil {
230+ return false, err
231+ }
232+ if config == nil {
233+ return false, ErrInvalidData
234+ }
235+
236+ return lowlevel.WebPConfigInitInternal(config, preset, quality, lowlevel.WebPEncoderABIVersion) != 0, nil
237+}
238+
239+// WebPConfigLosslessPreset applies a built-in lossless level preset.
240+func WebPConfigLosslessPreset(config *Config, level int32) (ok bool, err error) {
241+ if err := lowlevel.EnsureLoaded(); err != nil {
242+ return false, err
243+ }
244+ if config == nil {
245+ return false, ErrInvalidData
246+ }
247+
248+ return lowlevel.WebPConfigLosslessPreset(config, level) != 0, nil
249+}
250+
251+// WebPValidateConfig validates encoder config values.
252+func WebPValidateConfig(config *Config) (ok bool, err error) {
253+ if err := lowlevel.EnsureLoaded(); err != nil {
254+ return false, err
255+ }
256+ if config == nil {
257+ return false, ErrInvalidData
258+ }
259+
260+ return lowlevel.WebPValidateConfig(config) != 0, nil
261+}
262+
263+// WebPPictureInit initializes a picture struct with ABI-checked defaults.
264+func WebPPictureInit(picture *Picture) (ok bool, err error) {
265+ if err := lowlevel.EnsureLoaded(); err != nil {
266+ return false, err
267+ }
268+ if picture == nil {
269+ return false, ErrInvalidData
270+ }
271+
272+ return lowlevel.WebPPictureInitInternal(picture, lowlevel.WebPEncoderABIVersion) != 0, nil
273+}
274+
275+// WebPMemoryWriterInit initializes a memory writer instance.
276+func WebPMemoryWriterInit(writer *MemoryWriter) error {
277+ if err := lowlevel.EnsureLoaded(); err != nil {
278+ return err
279+ }
280+ if writer == nil {
281+ return ErrInvalidData
282+ }
283+
284+ lowlevel.WebPMemoryWriterInit(writer)
285+ return nil
286+}
287+
288+// WebPMemoryWriterClear frees memory owned by a memory writer.
289+func WebPMemoryWriterClear(writer *MemoryWriter) error {
290+ if err := lowlevel.EnsureLoaded(); err != nil {
291+ return err
292+ }
293+ if writer == nil {
294+ return nil
295+ }
296+
297+ lowlevel.WebPMemoryWriterClear(writer)
298+ return nil
299+}
300+
301+// WebPEncode runs advanced encoding with explicit config and picture structs.
302+func WebPEncode(config *Config, picture *Picture) (ok bool, err error) {
303+ if err := lowlevel.EnsureLoaded(); err != nil {
304+ return false, err
305+ }
306+ if config == nil || picture == nil {
307+ return false, ErrInvalidData
308+ }
309+
310+ return lowlevel.WebPEncode(config, picture) != 0, nil
311+}
312+
313+// WebPINewDecoder creates an incremental decoder using the provided output buffer.
314+func WebPINewDecoder(outputBuffer *DecBuffer) (uintptr, error) {
315+ if err := lowlevel.EnsureLoaded(); err != nil {
316+ return 0, err
317+ }
318+
319+ idec := lowlevel.WebPINewDecoder(outputBuffer)
320+ if idec == 0 {
321+ return 0, ErrDecodeFailed
322+ }
323+
324+ return idec, nil
325+}
326+
327+// WebPINewRGB creates an incremental decoder producing packed RGB-family output.
328+func WebPINewRGB(csp int32, outputBuffer []byte, outputStride int32) (uintptr, error) {
329+ if err := lowlevel.EnsureLoaded(); err != nil {
330+ return 0, err
331+ }
332+
333+ ptr, size := ptrAndSize(outputBuffer)
334+ idec := lowlevel.WebPINewRGB(csp, ptr, size, outputStride)
335+ if idec == 0 {
336+ return 0, ErrDecodeFailed
337+ }
338+
339+ return idec, nil
340+}
341+
342+// WebPINewYUV creates an incremental decoder producing YUV planes.
343+func WebPINewYUV(luma []byte, lumaStride int32, u []byte, uStride int32, v []byte, vStride int32) (uintptr, error) {
344+ if err := lowlevel.EnsureLoaded(); err != nil {
345+ return 0, err
346+ }
347+
348+ lumaPtr, lumaSize := ptrAndSize(luma)
349+ uPtr, uSize := ptrAndSize(u)
350+ vPtr, vSize := ptrAndSize(v)
351+
352+ idec := lowlevel.WebPINewYUV(lumaPtr, lumaSize, lumaStride, uPtr, uSize, uStride, vPtr, vSize, vStride)
353+ if idec == 0 {
354+ return 0, ErrDecodeFailed
355+ }
356+
357+ return idec, nil
358+}
359+
360+// WebPINewYUVA creates an incremental decoder producing YUVA planes.
361+func WebPINewYUVA(luma []byte, lumaStride int32, u []byte, uStride int32, v []byte, vStride int32, a []byte, aStride int32) (uintptr, error) {
362+ if err := lowlevel.EnsureLoaded(); err != nil {
363+ return 0, err
364+ }
365+
366+ lumaPtr, lumaSize := ptrAndSize(luma)
367+ uPtr, uSize := ptrAndSize(u)
368+ vPtr, vSize := ptrAndSize(v)
369+ aPtr, aSize := ptrAndSize(a)
370+
371+ idec := lowlevel.WebPINewYUVA(lumaPtr, lumaSize, lumaStride, uPtr, uSize, uStride, vPtr, vSize, vStride, aPtr, aSize, aStride)
372+ if idec == 0 {
373+ return 0, ErrDecodeFailed
374+ }
375+
376+ return idec, nil
377+}
378+
379+// WebPIDelete destroys an incremental decoder instance.
380+func WebPIDelete(idec uintptr) error {
381+ if err := lowlevel.EnsureLoaded(); err != nil {
382+ return err
383+ }
384+ if idec == 0 {
385+ return nil
386+ }
387+
388+ lowlevel.WebPIDelete(idec)
389+ return nil
390+}
391+
392+// WebPIAppend appends data to an incremental decoder.
393+func WebPIAppend(idec uintptr, data []byte) (VP8StatusCode, error) {
394+ if err := lowlevel.EnsureLoaded(); err != nil {
395+ return 0, err
396+ }
397+ if idec == 0 || len(data) == 0 {
398+ return VP8StatusInvalidParam, ErrInvalidData
399+ }
400+
401+ return VP8StatusCode(lowlevel.WebPIAppend(idec, &data[0], uintptr(len(data)))), nil
402+}
403+
404+// WebPIUpdate updates an incremental decoder with a full prefix buffer.
405+func WebPIUpdate(idec uintptr, data []byte) (VP8StatusCode, error) {
406+ if err := lowlevel.EnsureLoaded(); err != nil {
407+ return 0, err
408+ }
409+ if idec == 0 || len(data) == 0 {
410+ return VP8StatusInvalidParam, ErrInvalidData
411+ }
412+
413+ return VP8StatusCode(lowlevel.WebPIUpdate(idec, &data[0], uintptr(len(data)))), nil
414+}
415+
416+// WebPIDecode creates an incremental decoder with optional config and input.
417+func WebPIDecode(data []byte, config *DecoderConfig) (uintptr, error) {
418+ if err := lowlevel.EnsureLoaded(); err != nil {
419+ return 0, err
420+ }
421+ if len(data) == 0 {
422+ return 0, ErrInvalidData
423+ }
424+
425+ idec := lowlevel.WebPIDecode(&data[0], uintptr(len(data)), config)
426+ if idec == 0 {
427+ return 0, ErrDecodeFailed
428+ }
429+
430+ return idec, nil
431+}
432+
433+// WebPIDecodedArea returns decoded displayable area metadata.
434+func WebPIDecodedArea(idec uintptr, left, top, width, height *int32) (*DecBuffer, error) {
435+ if err := lowlevel.EnsureLoaded(); err != nil {
436+ return nil, err
437+ }
438+ if idec == 0 {
439+ return nil, ErrInvalidData
440+ }
441+
442+ buf := lowlevel.WebPIDecodedArea(idec, left, top, width, height)
443+ if buf == nil {
444+ return nil, ErrDecodeFailed
445+ }
446+
447+ return buf, nil
448+}
449+
450+// WebPIDecGetRGB returns current incremental packed RGB-family output pointer.
451+func WebPIDecGetRGB(idec uintptr, lastY, width, height, stride *int32) (uintptr, error) {
452+ if err := lowlevel.EnsureLoaded(); err != nil {
453+ return 0, err
454+ }
455+ if idec == 0 {
456+ return 0, ErrInvalidData
457+ }
458+
459+ ptr := lowlevel.WebPIDecGetRGB(idec, lastY, width, height, stride)
460+ if ptr == nil {
461+ return 0, ErrDecodeFailed
462+ }
463+
464+ return uintptr(unsafe.Pointer(ptr)), nil
465+}
466+
467+// WebPIDecGetYUVA returns current incremental YUVA luma pointer.
468+func WebPIDecGetYUVA(idec uintptr, lastY *int32, u, v, a **byte, width, height, stride, uvStride, aStride *int32) (uintptr, error) {
469+ if err := lowlevel.EnsureLoaded(); err != nil {
470+ return 0, err
471+ }
472+ if idec == 0 {
473+ return 0, ErrInvalidData
474+ }
475+
476+ ptr := lowlevel.WebPIDecGetYUVA(idec, lastY, u, v, a, width, height, stride, uvStride, aStride)
477+ if ptr == nil {
478+ return 0, ErrDecodeFailed
479+ }
480+
481+ return uintptr(unsafe.Pointer(ptr)), nil
482+}
483+
484+// WebPIDecGetYUV is a compatibility wrapper for YUV output without alpha.
485+func WebPIDecGetYUV(idec uintptr, lastY *int32, u, v **byte, width, height, stride, uvStride *int32) (uintptr, error) {
486+ var a *byte
487+ return WebPIDecGetYUVA(idec, lastY, u, v, &a, width, height, stride, uvStride, nil)
488+}
489+
490+// WebPDecode performs advanced one-shot decode using DecoderConfig.
491+func WebPDecode(data []byte, config *DecoderConfig) (status VP8StatusCode, err error) {
492+ if err := lowlevel.EnsureLoaded(); err != nil {
493+ return 0, err
494+ }
495+ if len(data) == 0 {
496+ return VP8StatusNotEnoughData, nil
497+ }
498+ if config == nil {
499+ return VP8StatusInvalidParam, ErrInvalidData
500+ }
501+
502+ return VP8StatusCode(lowlevel.WebPDecode(&data[0], uintptr(len(data)), config)), nil
503+}
504+
505+// WebPDecodeRGBA decodes to packed RGBA and returns an owned Go buffer.
506+func WebPDecodeRGBA(data []byte) (pix []byte, width, height, stride int, err error) {
507+ return decodeToOwnedBuffer(data, 4, lowlevel.WebPDecodeRGBA)
508+}
509+
510+// WebPDecodeARGB decodes to packed ARGB and returns an owned Go buffer.
511+func WebPDecodeARGB(data []byte) (pix []byte, width, height, stride int, err error) {
512+ return decodeToOwnedBuffer(data, 4, lowlevel.WebPDecodeARGB)
513+}
514+
515+// WebPDecodeBGRA decodes to packed BGRA and returns an owned Go buffer.
516+func WebPDecodeBGRA(data []byte) (pix []byte, width, height, stride int, err error) {
517+ return decodeToOwnedBuffer(data, 4, lowlevel.WebPDecodeBGRA)
518+}
519+
520+// WebPDecodeRGB decodes to packed RGB and returns an owned Go buffer.
521+func WebPDecodeRGB(data []byte) (pix []byte, width, height, stride int, err error) {
522+ return decodeToOwnedBuffer(data, 3, lowlevel.WebPDecodeRGB)
523+}
524+
525+// WebPDecodeBGR decodes to packed BGR and returns an owned Go buffer.
526+func WebPDecodeBGR(data []byte) (pix []byte, width, height, stride int, err error) {
527+ return decodeToOwnedBuffer(data, 3, lowlevel.WebPDecodeBGR)
528+}
529+
530+// WebPDecodeRGBAInto decodes into a caller-provided RGBA buffer.
531+func WebPDecodeRGBAInto(data []byte, outputBuffer []byte, outputStride int) (width, height int, err error) {
532+ return decodeInto(data, outputBuffer, outputStride, 4, lowlevel.WebPDecodeRGBAInto)
533+}
534+
535+// WebPDecodeRGBAIntoWithInfo decodes into a caller-provided RGBA buffer using
536+// dimensions already validated by WebPGetInfo, avoiding a second parse.
537+func WebPDecodeRGBAIntoWithInfo(data []byte, outputBuffer []byte, outputStride, width, height int) error {
538+ return decodeIntoWithInfo(data, outputBuffer, outputStride, width, height, 4, lowlevel.WebPDecodeRGBAInto)
539+}
540+
541+// WebPDecodeARGBInto decodes into a caller-provided ARGB buffer.
542+func WebPDecodeARGBInto(data []byte, outputBuffer []byte, outputStride int) (width, height int, err error) {
543+ return decodeInto(data, outputBuffer, outputStride, 4, lowlevel.WebPDecodeARGBInto)
544+}
545+
546+// WebPDecodeBGRAInto decodes into a caller-provided BGRA buffer.
547+func WebPDecodeBGRAInto(data []byte, outputBuffer []byte, outputStride int) (width, height int, err error) {
548+ return decodeInto(data, outputBuffer, outputStride, 4, lowlevel.WebPDecodeBGRAInto)
549+}
550+
551+// WebPDecodeRGBInto decodes into a caller-provided RGB buffer.
552+func WebPDecodeRGBInto(data []byte, outputBuffer []byte, outputStride int) (width, height int, err error) {
553+ return decodeInto(data, outputBuffer, outputStride, 3, lowlevel.WebPDecodeRGBInto)
554+}
555+
556+// WebPDecodeBGRInto decodes into a caller-provided BGR buffer.
557+func WebPDecodeBGRInto(data []byte, outputBuffer []byte, outputStride int) (width, height int, err error) {
558+ return decodeInto(data, outputBuffer, outputStride, 3, lowlevel.WebPDecodeBGRInto)
559+}
560+
561+// WebPDecodeYUV decodes to planar YUV and returns owned Go buffers.
562+func WebPDecodeYUV(data []byte) (y, u, v []byte, width, height, yStride, uvStride int, err error) {
563+ if err := lowlevel.EnsureLoaded(); err != nil {
564+ return nil, nil, nil, 0, 0, 0, 0, err
565+ }
566+ if len(data) == 0 {
567+ return nil, nil, nil, 0, 0, 0, 0, ErrInvalidData
568+ }
569+
570+ var w, h int32
571+ var uPtr, vPtr *byte
572+ var ys, uvs int32
573+ yPtr := lowlevel.WebPDecodeYUV(&data[0], uintptr(len(data)), &w, &h, &uPtr, &vPtr, &ys, &uvs)
574+ if yPtr == nil {
575+ return nil, nil, nil, 0, 0, 0, 0, ErrDecodeFailed
576+ }
577+ defer lowlevel.WebPFree(uintptr(unsafe.Pointer(yPtr)))
578+
579+ width = int(w)
580+ height = int(h)
581+ if width <= 0 || height <= 0 {
582+ return nil, nil, nil, 0, 0, 0, 0, ErrInvalidDimension
583+ }
584+
585+ yStride = int(ys)
586+ uvStride = int(uvs)
587+ uvHeight := (height + 1) / 2
588+
589+ y = make([]byte, yStride*height)
590+ u = make([]byte, uvStride*uvHeight)
591+ v = make([]byte, uvStride*uvHeight)
592+
593+ copy(y, unsafe.Slice(yPtr, len(y)))
594+ copy(u, unsafe.Slice(uPtr, len(u)))
595+ copy(v, unsafe.Slice(vPtr, len(v)))
596+
597+ return y, u, v, width, height, yStride, uvStride, nil
598+}
599+
600+// WebPDecodeYUVInto decodes into caller-provided Y, U and V planes.
601+func WebPDecodeYUVInto(data []byte, luma []byte, lumaStride int, u []byte, uStride int, v []byte, vStride int) (width, height int, err error) {
602+ if err := lowlevel.EnsureLoaded(); err != nil {
603+ return 0, 0, err
604+ }
605+ if len(data) == 0 {
606+ return 0, 0, ErrInvalidData
607+ }
608+ if len(luma) == 0 || len(u) == 0 || len(v) == 0 {
609+ return 0, 0, ErrBufferTooSmall
610+ }
611+
612+ w, h, ok, err := WebPGetInfo(data)
613+ if err != nil {
614+ return 0, 0, err
615+ }
616+ if !ok {
617+ return 0, 0, ErrInvalidData
618+ }
619+ if lumaStride < w {
620+ return 0, 0, ErrInvalidStride
621+ }
622+ uvWidth := (w + 1) / 2
623+ uvHeight := (h + 1) / 2
624+ if uStride < uvWidth || vStride < uvWidth {
625+ return 0, 0, ErrInvalidStride
626+ }
627+ if len(luma) < lumaStride*h || len(u) < uStride*uvHeight || len(v) < vStride*uvHeight {
628+ return 0, 0, ErrBufferTooSmall
629+ }
630+
631+ ptr := lowlevel.WebPDecodeYUVInto(
632+ &data[0],
633+ uintptr(len(data)),
634+ &luma[0],
635+ uintptr(len(luma)),
636+ int32(lumaStride),
637+ &u[0],
638+ uintptr(len(u)),
639+ int32(uStride),
640+ &v[0],
641+ uintptr(len(v)),
642+ int32(vStride),
643+ )
644+ if ptr == nil {
645+ return 0, 0, ErrDecodeFailed
646+ }
647+
648+ return w, h, nil
649+}
650+
651+// WebPEncodeRGBA encodes packed RGBA pixels with lossy quality.
652+func WebPEncodeRGBA(rgba []byte, width, height, stride int, quality float32) ([]byte, error) {
653+ return encodeWithQuality(rgba, width, height, stride, 4, quality, lowlevel.WebPEncodeRGBA)
654+}
655+
656+// WebPEncodeBGRA encodes packed BGRA pixels with lossy quality.
657+func WebPEncodeBGRA(bgra []byte, width, height, stride int, quality float32) ([]byte, error) {
658+ return encodeWithQuality(bgra, width, height, stride, 4, quality, lowlevel.WebPEncodeBGRA)
659+}
660+
661+// WebPEncodeRGB encodes packed RGB pixels with lossy quality.
662+func WebPEncodeRGB(rgb []byte, width, height, stride int, quality float32) ([]byte, error) {
663+ return encodeWithQuality(rgb, width, height, stride, 3, quality, lowlevel.WebPEncodeRGB)
664+}
665+
666+// WebPEncodeBGR encodes packed BGR pixels with lossy quality.
667+func WebPEncodeBGR(bgr []byte, width, height, stride int, quality float32) ([]byte, error) {
668+ return encodeWithQuality(bgr, width, height, stride, 3, quality, lowlevel.WebPEncodeBGR)
669+}
670+
671+// WebPEncodeLosslessRGBA encodes packed RGBA pixels in lossless mode.
672+func WebPEncodeLosslessRGBA(rgba []byte, width, height, stride int) ([]byte, error) {
673+ return encodeLossless(rgba, width, height, stride, 4, lowlevel.WebPEncodeLosslessRGBA)
674+}
675+
676+// WebPEncodeLosslessBGRA encodes packed BGRA pixels in lossless mode.
677+func WebPEncodeLosslessBGRA(bgra []byte, width, height, stride int) ([]byte, error) {
678+ return encodeLossless(bgra, width, height, stride, 4, lowlevel.WebPEncodeLosslessBGRA)
679+}
680+
681+// WebPEncodeLosslessRGB encodes packed RGB pixels in lossless mode.
682+func WebPEncodeLosslessRGB(rgb []byte, width, height, stride int) ([]byte, error) {
683+ return encodeLossless(rgb, width, height, stride, 3, lowlevel.WebPEncodeLosslessRGB)
684+}
685+
686+// WebPEncodeLosslessBGR encodes packed BGR pixels in lossless mode.
687+func WebPEncodeLosslessBGR(bgr []byte, width, height, stride int) ([]byte, error) {
688+ return encodeLossless(bgr, width, height, stride, 3, lowlevel.WebPEncodeLosslessBGR)
689+}
690+
691+type decodeFunc func(data *byte, dataSize uintptr, width *int32, height *int32) *byte
692+
693+type decodeIntoFunc func(data *byte, dataSize uintptr, outputBuffer *byte, outputBufferSize uintptr, outputStride int32) *byte
694+
695+func decodeInto(data []byte, outputBuffer []byte, outputStride int, bytesPerPixel int, fn decodeIntoFunc) (width, height int, err error) {
696+ if err := lowlevel.EnsureLoaded(); err != nil {
697+ return 0, 0, err
698+ }
699+ if len(data) == 0 {
700+ return 0, 0, ErrInvalidData
701+ }
702+ if len(outputBuffer) == 0 {
703+ return 0, 0, ErrBufferTooSmall
704+ }
705+ w, h, ok, err := WebPGetInfo(data)
706+ if err != nil {
707+ return 0, 0, err
708+ }
709+ if !ok {
710+ return 0, 0, ErrInvalidData
711+ }
712+ if err := decodeIntoWithInfo(data, outputBuffer, outputStride, w, h, bytesPerPixel, fn); err != nil {
713+ return 0, 0, err
714+ }
715+ return w, h, nil
716+}
717+
718+func decodeIntoWithInfo(data []byte, outputBuffer []byte, outputStride, width, height, bytesPerPixel int, fn decodeIntoFunc) error {
719+ if err := lowlevel.EnsureLoaded(); err != nil {
720+ return err
721+ }
722+ if len(data) == 0 {
723+ return ErrInvalidData
724+ }
725+ if len(outputBuffer) == 0 {
726+ return ErrBufferTooSmall
727+ }
728+ minimumStride, _, err := checkedDecodeLayout(width, height, bytesPerPixel)
729+ if err != nil {
730+ return err
731+ }
732+ if outputStride < minimumStride || outputStride > math.MaxInt32 {
733+ return ErrInvalidStride
734+ }
735+ required, ok := checkedProduct(outputStride, height)
736+ if !ok || len(outputBuffer) < required {
737+ return ErrBufferTooSmall
738+ }
739+ if fn(&data[0], uintptr(len(data)), &outputBuffer[0], uintptr(len(outputBuffer)), int32(outputStride)) == nil {
740+ return ErrDecodeFailed
741+ }
742+ return nil
743+}
744+
745+func decodeToOwnedBuffer(data []byte, bytesPerPixel int, fn decodeFunc) (pix []byte, width, height, stride int, err error) {
746+ if err := lowlevel.EnsureLoaded(); err != nil {
747+ return nil, 0, 0, 0, err
748+ }
749+ if len(data) == 0 {
750+ return nil, 0, 0, 0, ErrInvalidData
751+ }
752+
753+ var w, h int32
754+ ptr := fn(&data[0], uintptr(len(data)), &w, &h)
755+ if ptr == nil {
756+ return nil, 0, 0, 0, ErrDecodeFailed
757+ }
758+ defer lowlevel.WebPFree(uintptr(unsafe.Pointer(ptr)))
759+
760+ width = int(w)
761+ height = int(h)
762+ stride, bufLen, err := checkedDecodeLayout(width, height, bytesPerPixel)
763+ if err != nil {
764+ return nil, 0, 0, 0, err
765+ }
766+ pix = make([]byte, bufLen)
767+ copy(pix, unsafe.Slice(ptr, bufLen))
768+
769+ return pix, width, height, stride, nil
770+}
771+
772+type encodeLossyFunc func(pix *byte, width int32, height int32, stride int32, quality float32, output **byte) uintptr
773+
774+func encodeWithQuality(pix []byte, width, height, stride, bytesPerPixel int, quality float32, fn encodeLossyFunc) ([]byte, error) {
775+ if err := lowlevel.EnsureLoaded(); err != nil {
776+ return nil, err
777+ }
778+ if err := validatePixelInput(pix, width, height, stride, bytesPerPixel); err != nil {
779+ return nil, err
780+ }
781+
782+ var out *byte
783+ size := fn(&pix[0], int32(width), int32(height), int32(stride), quality, &out)
784+ if size == 0 || out == nil {
785+ return nil, ErrEncodeFailed
786+ }
787+ defer lowlevel.WebPFree(uintptr(unsafe.Pointer(out)))
788+
789+ b := make([]byte, int(size))
790+ copy(b, unsafe.Slice(out, int(size)))
791+
792+ return b, nil
793+}
794+
795+type encodeLosslessFunc func(pix *byte, width int32, height int32, stride int32, output **byte) uintptr
796+
797+func encodeLossless(pix []byte, width, height, stride, bytesPerPixel int, fn encodeLosslessFunc) ([]byte, error) {
798+ if err := lowlevel.EnsureLoaded(); err != nil {
799+ return nil, err
800+ }
801+ if err := validatePixelInput(pix, width, height, stride, bytesPerPixel); err != nil {
802+ return nil, err
803+ }
804+
805+ var out *byte
806+ size := fn(&pix[0], int32(width), int32(height), int32(stride), &out)
807+ if size == 0 || out == nil {
808+ return nil, ErrEncodeFailed
809+ }
810+ defer lowlevel.WebPFree(uintptr(unsafe.Pointer(out)))
811+
812+ b := make([]byte, int(size))
813+ copy(b, unsafe.Slice(out, int(size)))
814+
815+ return b, nil
816+}
817+
818+func validatePixelInput(pix []byte, width, height, stride, bytesPerPixel int) error {
819+ minimumStride, _, err := checkedDecodeLayout(width, height, bytesPerPixel)
820+ if err != nil {
821+ return err
822+ }
823+ if stride < minimumStride || stride > math.MaxInt32 {
824+ return ErrInvalidStride
825+ }
826+ required, ok := checkedProduct(stride, height)
827+ if !ok {
828+ return ErrInvalidDimension
829+ }
830+ if len(pix) < required {
831+ return fmt.Errorf("libwebp: pixel buffer too small: got=%d need>=%d", len(pix), required)
832+ }
833+ return nil
834+}
835+
836+// checkedDecodeLayout validates the dimensions and packed output layout before
837+// values are passed to libwebp, whose output stride parameter is a C int.
838+func checkedDecodeLayout(width, height, bytesPerPixel int) (stride, size int, err error) {
839+ if width <= 0 || height <= 0 {
840+ return 0, 0, ErrInvalidDimension
841+ }
842+ if bytesPerPixel <= 0 || width > math.MaxInt32/bytesPerPixel {
843+ return 0, 0, ErrInvalidStride
844+ }
845+ stride = width * bytesPerPixel
846+ size, ok := checkedProduct(stride, height)
847+ if !ok {
848+ return 0, 0, ErrInvalidDimension
849+ }
850+ return stride, size, nil
851+}
852+
853+func checkedProduct(a, b int) (int, bool) {
854+ if a < 0 || b < 0 || (a != 0 && b > int(^uint(0)>>1)/a) {
855+ return 0, false
856+ }
857+ return a * b, true
858+}
859+
860+// WebPIsPremultipliedMode reports whether the decode colorspace is premultiplied.
861+func WebPIsPremultipliedMode(mode int) bool {
862+ return mode == ModergbA || mode == ModebgrA || mode == ModeArgb || mode == ModergbA4444
863+}
864+
865+// WebPIsAlphaMode reports whether the decode colorspace contains alpha.
866+func WebPIsAlphaMode(mode int) bool {
867+ return mode == ModeRGBA || mode == ModeBGRA || mode == ModeARGB || mode == ModeRGBA4444 || mode == ModeYUVA || WebPIsPremultipliedMode(mode)
868+}
869+
870+// WebPIsRGBMode reports whether the decode colorspace is RGB-family.
871+func WebPIsRGBMode(mode int) bool {
872+ return mode < ModeYUV
873+}
874+
875+func ptrAndSize(b []byte) (*byte, uintptr) {
876+ if len(b) == 0 {
877+ return nil, 0
878+ }
879+ return &b[0], uintptr(len(b))
880+}
A vendor/github.com/bnema/purego-webp/LICENSE +21 -0 generated file: collapsed
A vendor/github.com/bnema/purego-webp/internal/libwebp/generated_symbols.go +513 -0 generated file: collapsed
A vendor/github.com/bnema/purego-webp/internal/libwebp/loader.go +86 -0 generated file: collapsed
A vendor/github.com/bnema/purego-webp/internal/libwebp/types.go +164 -0 generated file: collapsed
A vendor/github.com/bnema/purego-webp/libwebp/libwebp.go +880 -0 generated file: collapsed
M vendor/modules.txt +5 -0 generated file: collapsed

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 8

Tags 42

↑↓ moveenter openesc close