go-libwebp

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

lib.go (2829B)


      1 package webp
      2 
      3 import (
      4 	"fmt"
      5 	"image"
      6 	"io"
      7 	"runtime"
      8 	"sync"
      9 
     10 	"git.sr.ht/~jackmordaunt/go-libwebp/v2/lib/common"
     11 	"github.com/ebitengine/purego"
     12 )
     13 
     14 var (
     15 	_libwebp uintptr
     16 
     17 	WebPEncodeLosslessRGBA func(in uintptr, width int32, height int32, bps int32, out uintptr) (size uint64)
     18 	WebPEncodeRGBA         func(in uintptr, width int32, height int32, bps int32, quality float32, out uintptr) (size uint64)
     19 	WebPDecodeRGBA         func(data uintptr, size uint64, width uintptr, height uintptr) uintptr
     20 	WebPFree               func(ptr uintptr)
     21 )
     22 
     23 func genericLibraryName() string {
     24 	switch runtime.GOOS {
     25 	case "windows":
     26 		return "libwebp.dll"
     27 	case "darwin":
     28 		return "libwebp.dylib"
     29 	default:
     30 		return "libwebp.so"
     31 	}
     32 }
     33 
     34 func loadLibrary() (uintptr, error) {
     35 	handle, err := dlopen(libraryName)
     36 	if err != nil {
     37 		return dlopen(genericLibraryName())
     38 	}
     39 	return handle, err
     40 }
     41 
     42 // Init loads libwebp and binds the entry points. It is safe to call
     43 // repeatedly and from multiple goroutines; the attempt is made exactly once,
     44 // so a process without the shared object does not re-run a failing dlopen on
     45 // every encode.
     46 func Init() error {
     47 	initOnce.Do(func() { initErr = load() })
     48 	return initErr
     49 }
     50 
     51 var (
     52 	initOnce sync.Once
     53 	initErr  error
     54 )
     55 
     56 func load() (err error) {
     57 	_libwebp, err = loadLibrary()
     58 	if err != nil {
     59 		return fmt.Errorf("loading library: %w", err)
     60 	}
     61 
     62 	purego.RegisterLibFunc(&WebPEncodeLosslessRGBA, _libwebp, "WebPEncodeLosslessRGBA")
     63 	if WebPEncodeLosslessRGBA == nil {
     64 		return fmt.Errorf("failed to initialize function: WebPEncodeLosslessRGBA")
     65 	}
     66 
     67 	purego.RegisterLibFunc(&WebPEncodeRGBA, _libwebp, "WebPEncodeRGBA")
     68 	if WebPEncodeRGBA == nil {
     69 		return fmt.Errorf("failed to initialize function: WebPEncodeRGBA")
     70 	}
     71 
     72 	purego.RegisterLibFunc(&WebPDecodeRGBA, _libwebp, "WebPDecodeRGBA")
     73 	if WebPDecodeRGBA == nil {
     74 		return fmt.Errorf("failed to initialize function: WebPDecodeRGBA")
     75 	}
     76 
     77 	purego.RegisterLibFunc(&WebPFree, _libwebp, "WebPFree")
     78 	if WebPFree == nil {
     79 		return fmt.Errorf("failed to initialize function: WebPFree")
     80 	}
     81 
     82 	return nil
     83 }
     84 
     85 func DecodeImpl(buf []byte) (image.Image, error) {
     86 	if WebPDecodeRGBA == nil || WebPFree == nil {
     87 		return nil, fmt.Errorf("functions not initialized")
     88 	}
     89 	return common.Decode(buf, WebPDecodeRGBA, WebPFree)
     90 }
     91 
     92 func EncodeImpl(w io.Writer, m *image.NRGBA, quality float32) error {
     93 	if WebPEncodeRGBA == nil || WebPFree == nil {
     94 		return fmt.Errorf("functions not initialized")
     95 	}
     96 	if quality >= 1.0 {
     97 		return common.Encode(w, m, 100, wrappedLossless, WebPFree)
     98 	}
     99 	return common.Encode(w, m, quality*100, WebPEncodeRGBA, WebPFree)
    100 }
    101 
    102 // wrappedLossless drops the quality param and does a lossless encode.
    103 func wrappedLossless(in uintptr, w int32, h int32, bps int32, _ float32, out uintptr) uint64 {
    104 	return WebPEncodeLosslessRGBA(in, w, h, bps, out)
    105 }