gen2brain/webp
| Language | Go |
|---|---|
| License | MIT (libwebp: BSD-3-Clause) |
| Repository | github.com/gen2brain/webp |
| Documentation | pkg.go.dev/github.com/gen2brain/webp |
| Depends on | nothing at build time (no cgo); uses a system libwebp at run time if one is installed |
| Read / write | yes / yes, lossy, lossless, alpha, animation |
gen2brain/webp is libwebp compiled to WebAssembly and translated into Go source, so it gives full libwebp features (lossy encoding, animation) in a pure Go build: cross-compiling and static binaries work. At startup it tries to load a shared libwebp through purego and uses it when found, which is faster; build with -tags nodynamic to always use the embedded code.
It registers with image.Decode and follows the standard Decode / Encode signatures, plus DecodeAll / EncodeAll for animation.
Installation#
Shell
go get github.com/gen2brain/webp
Basic usage: convert JPEG to WebP#
Go
package main
import (
"fmt"
"image/jpeg"
"log"
"os"
"github.com/gen2brain/webp"
)
func main() {
in, err := os.Open("photo.jpg")
if err != nil {
log.Fatal(err)
}
defer in.Close()
img, err := jpeg.Decode(in)
if err != nil {
log.Fatal(err)
}
out, err := os.Create("photo.webp")
if err != nil {
log.Fatal(err)
}
defer out.Close()
opts := webp.Options{Quality: 80, Method: webp.DefaultMethod} // Quality 0-100, Method 0 (fast) .. 6
if err := webp.Encode(out, img, opts); err != nil {
log.Fatal(err)
}
fmt.Println("done")
}
Decoding is webp.Decode(r); the result is a regular image.Image.
How to write a lossless WebP#
Go
err := webp.Encode(out, img, webp.Options{Lossless: true, Method: 6, Exact: true})
Exact keeps the RGB values of fully transparent pixels instead of zeroing them.
How to get WebP dimensions without decoding#
Go
cfg, err := webp.DecodeConfig(f)
if err != nil {
log.Fatal(err)
}
fmt.Println(cfg.Width, cfg.Height)
How to read the frames of an animated WebP#
Go
f, err := os.Open("anim.webp")
if err != nil {
log.Fatal(err)
}
defer f.Close()
anim, err := webp.DecodeAll(f)
if err != nil {
log.Fatal(err)
}
fmt.Printf("%d frames, loop count %d\n", len(anim.Image), anim.LoopCount)
for i, frame := range anim.Image {
fmt.Printf("frame %d: %v, %d ms\n", i, frame.Bounds(), anim.Delay[i])
}
How to create an animated WebP#
Go
anim := &webp.WEBP{
Image: []image.Image{frame1, frame2, frame3},
Delay: []int{100, 100, 100}, // milliseconds per frame
LoopCount: 0, // 0 = loop forever
}
out, err := os.Create("anim.webp")
if err != nil {
log.Fatal(err)
}
defer out.Close()
if err := webp.EncodeAll(out, anim, webp.Options{Quality: 75}); err != nil {
log.Fatal(err)
}
How to read Exif metadata#
Go
exif, err := webp.DecodeExif(f)
if err == webp.ErrNoExif {
fmt.Println("no Exif")
} else if err != nil {
log.Fatal(err)
} else {
fmt.Println(exif.Make, exif.Model, exif.DateTimeOriginal, exif.Orientation)
}
Pass webp.Options{AutoRotate: true} to Decode to apply the Exif orientation.
Tips#
webp.Dynamic()returnsnilwhen a system libwebp was loaded; use it to log which path is active.- The embedded path is slower than native libwebp; install
libwebpon servers that encode a lot.