go-libwebp

Experimental translation from libwebp to Go source.
Log | Files | Refs | README | LICENSE

commit 8b9f86c3cf35e5319469a98f6a6a0a707757aadd
parent 61bcd809df050051345098e0c46884ccc52c8c97
Author: Jack Mordaunt <jackmordaunt.dev@gmail.com>
Date:   Wed,  3 Jan 2024 16:31:37 +0800

lib/dynamic: add decode and fix lossy panic with cgo

Due a bug in purego, we cannot use float parameters while cgo is enabled on linux.
When cgo is enabled, we force the use of lossless encoding.

Signed-off-by: Jack Mordaunt <jackmordaunt.dev@gmail.com>

Diffstat:
Alib/dynamic/webp/encode_cgo.go | 16++++++++++++++++
Alib/dynamic/webp/encode_default.go | 17+++++++++++++++++
Mlib/dynamic/webp/lib.go | 69++++++++++++++++++++-------------------------------------------------
Mlib/dynamic/webp/lib_darwin_amd64.go | 5+----
Mlib/dynamic/webp/lib_linux_amd64.go | 2+-
5 files changed, 55 insertions(+), 54 deletions(-)

diff --git a/lib/dynamic/webp/encode_cgo.go b/lib/dynamic/webp/encode_cgo.go @@ -0,0 +1,16 @@ +//go:build linux && cgo + +package webp + +import ( + "image" + "io" + + "git.sr.ht/~jackmordaunt/go-libwebp/lib/common" +) + +// HACK: always use lossless when cgo is activated on linux. cgo on linux provokes +// a bug in purego when using float arguments. +func encodeImpl(w io.Writer, m *image.RGBA, quality float32) error { + return common.Encode(w, m, quality, wrappedLossless, WebPFree) +} diff --git a/lib/dynamic/webp/encode_default.go b/lib/dynamic/webp/encode_default.go @@ -0,0 +1,17 @@ +//go:build !(linux && cgo) + +package webp + +import ( + "image" + "io" + + "git.sr.ht/~jackmordaunt/go-libwebp/lib/common" +) + +func encodeImpl(w io.Writer, m *image.RGBA, quality float32) error { + if quality >= 1.0 { + return common.Encode(w, m, quality, wrappedLossless, WebPFree) + } + return common.Encode(w, m, quality, WebPEncodeRGBA, WebPFree) +} diff --git a/lib/dynamic/webp/lib.go b/lib/dynamic/webp/lib.go @@ -2,17 +2,20 @@ package webp import ( "fmt" - "unsafe" + "image" + "io" + "git.sr.ht/~jackmordaunt/go-libwebp/lib/common" "github.com/ebitengine/purego" ) var ( _libwebp uintptr - _WebPEncodeLosslessRGBA func(uintptr, uintptr, uintptr, uintptr, uintptr) uintptr - _WebPEncodeRGBA func(uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) uintptr - _WebPFree func(uintptr) + WebPEncodeLosslessRGBA func(in uintptr, width int32, height int32, bps int32, out uintptr) (size uint64) + WebPEncodeRGBA func(in uintptr, width int32, height int32, bps int32, quality float32, out uintptr) (size uint64) + WebPDecodeRGBA func(data uintptr, size uint64, width uintptr, height uintptr) uintptr + WebPFree func(ptr uintptr) ) func loadLibrary() (uintptr, error) { @@ -33,55 +36,23 @@ func Init() (err error) { return err } - _WebPEncodeLosslessRGBA = func() (fn func(uintptr, uintptr, uintptr, uintptr, uintptr) uintptr) { - purego.RegisterLibFunc(&fn, _libwebp, "WebPEncodeLosslessRGBA") - return - }() - - _WebPEncodeRGBA = func() (fn func(uintptr, uintptr, uintptr, uintptr, uintptr, uintptr) uintptr) { - purego.RegisterLibFunc(&fn, _libwebp, "WebPEncodeRGBA") - return - }() - - _WebPFree = func() (fn func(uintptr)) { - purego.RegisterLibFunc(&fn, _libwebp, "WebPFree") - return - }() + purego.RegisterLibFunc(&WebPEncodeLosslessRGBA, _libwebp, "WebPEncodeLosslessRGBA") + purego.RegisterLibFunc(&WebPEncodeRGBA, _libwebp, "WebPEncodeRGBA") + purego.RegisterLibFunc(&WebPDecodeRGBA, _libwebp, "WebPDecodeRGBA") + purego.RegisterLibFunc(&WebPFree, _libwebp, "WebPFree") return nil } -func EncodeImpl( - in unsafe.Pointer, - w int32, - h int32, - bps int32, - q float32, - out unsafe.Pointer, -) uint64 { - Init() - var sz uintptr - if q >= 1.0 { - sz = _WebPEncodeLosslessRGBA( - uintptr(in), - uintptr(w), - uintptr(h), - uintptr(bps), - uintptr(out), - ) - } else { - sz = _WebPEncodeRGBA( - uintptr(in), - uintptr(w), - uintptr(h), - uintptr(bps), - uintptr(q), - uintptr(out), - ) - } - return uint64(sz) +func DecodeImpl(buf []byte) (image.Image, error) { + return common.Decode(buf, WebPDecodeRGBA, WebPFree) +} + +func EncodeImpl(w io.Writer, m *image.RGBA, quality float32) error { + return encodeImpl(w, m, quality) } -func FreeImpl(ptr unsafe.Pointer) { - _WebPFree(uintptr(ptr)) +// wrappedLossless drops the quality param and does a lossless encode. +func wrappedLossless(in uintptr, w int32, h int32, bps int32, _ float32, out uintptr) uint64 { + return WebPEncodeLosslessRGBA(in, w, h, bps, out) } diff --git a/lib/dynamic/webp/lib_darwin_amd64.go b/lib/dynamic/webp/lib_darwin_amd64.go @@ -8,9 +8,6 @@ import ( const libraryName = "libwebp.dylib" -//go:embed blobs/libwebp.dylib -var libraryData []byte - func dlopen(name string) (uintptr, error) { - return purego.Dlopen(libraryName, purego.RTLD_NOW|purego.RTLD_GLOBAL) + return purego.Dlopen(libraryName, purego.RTLD_LAZY|purego.RTLD_GLOBAL) } diff --git a/lib/dynamic/webp/lib_linux_amd64.go b/lib/dynamic/webp/lib_linux_amd64.go @@ -9,5 +9,5 @@ import ( const libraryName = "libwebp.so" func dlopen(name string) (uintptr, error) { - return purego.Dlopen(libraryName, purego.RTLD_NOW|purego.RTLD_GLOBAL) + return purego.Dlopen(libraryName, purego.RTLD_LAZY|purego.RTLD_GLOBAL) }