All formats

gen2brain/webp

LanguageGo
LicenseMIT (libwebp: BSD-3-Clause)
Repositorygithub.com/gen2brain/webp
Documentationpkg.go.dev/github.com/gen2brain/webp
Depends onnothing at build time (no cgo); uses a system libwebp at run time if one is installed
Read / writeyes / 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#