go-libwebp

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

commit eafaf278cfd93252ee33e0cddfa9385b93654c21
parent 515e5ffe955010e2d37bd28886d73f12ae59cc57
Author: Jack Mordaunt <jackmordaunt.dev@gmail.com>
Date:   Thu, 19 Oct 2023 13:55:12 +0800

webp/encode: use memory pinning

This commit uses memory pinning instead struct field to hold the uintptr.
This is the more correct way to do things.

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

Diffstat:
Mwebp/encode.go | 33+++++++++++++++++----------------
1 file changed, 17 insertions(+), 16 deletions(-)

diff --git a/webp/encode.go b/webp/encode.go @@ -4,6 +4,7 @@ import ( "fmt" "image" "io" + "runtime" "unsafe" "git.sr.ht/~jackmordaunt/go-libwebp/lib" @@ -35,13 +36,12 @@ func Quality(q float32) EncodeOption { } } -// FIXME: lossless errors out so it's disabled until fixed. // Lossless will ignore quality. -//func Lossless() EncodeOption { -// return func(enc *Encoder) { -// enc.Lossless = true -// } -//} +func Lossless() EncodeOption { + return func(enc *Encoder) { + enc.Lossless = true + } +} // Encoder implements webp encoding of an image. type Encoder struct { @@ -51,11 +51,6 @@ type Encoder struct { // Lossless indicates whether to use the lossless compression // strategy. If true, the Quality field is ignored. Lossless bool - - // out pointer contains the output memory address from webp. - // Must be a field because stack variables are optimized out - // by the runtime. - out uintptr } // Encode specified image as webp to w. @@ -82,6 +77,13 @@ func (enc *Encoder) encode(w io.Writer, m *image.RGBA) error { } func encode(enc *Encoder, w io.Writer, m *image.RGBA) error { + var out uintptr + outp := &out + + p := runtime.Pinner{} + p.Pin(outp) + defer p.Unpin() + tls := libc.NewTLS() defer tls.Close() @@ -106,21 +108,20 @@ func encode(enc *Encoder, w io.Writer, m *image.RGBA) error { // quality for libwebp is [0,100]. float32(enc.Quality*100), libc.Bool32(enc.Lossless), - uintptr(unsafe.Pointer(&enc.out)), + uintptr(unsafe.Pointer(outp)), ) - defer lib.WebPFree(tls, enc.out) + defer lib.WebPFree(tls, out) if size == 0 { return fmt.Errorf("encoding webp image: size %d", size) } - if enc.out == 0 { + if out == 0 { return fmt.Errorf("failed to allocate memory; probably errored") } - data := libc.GoBytes(enc.out, int(size)) - if _, err := w.Write(data); err != nil { + if _, err := w.Write(libc.GoBytes(out, int(size))); err != nil { return fmt.Errorf("writing webp data: %w", err) }