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 }