govips
| Language | Go (cgo) |
|---|---|
| License | MIT (libvips is LGPL-2.1) |
| Repository | github.com/davidbyttow/govips |
| Documentation | pkg.go.dev/github.com/davidbyttow/govips/v2/vips, libvips jp2kload |
| Depends on | libvips 8.11+ built with OpenJPEG, cgo |
| Read / write | yes / yes; JP2 and J2K, 8 and 16 bits per sample, tiled output |
govips wraps libvips, a fast image processing library that streams images in small regions instead of loading them whole. libvips has JPEG 2000 support through OpenJPEG (the jp2kload and jp2ksave operations), so govips can decode, resize and encode JPEG 2000 with low memory use.
You need libvips installed with OpenJPEG enabled; the packages of most Linux distributions and Homebrew have it. Since it uses cgo, cross-compiling is harder than with pure Go code.
Installation#
# Debian / Ubuntu
sudo apt install libvips-dev
# macOS
brew install vips pkg-config
go get github.com/davidbyttow/govips/v2/vips
Check that your libvips has JPEG 2000: vips -l | grep jp2k should list VipsForeignLoadJp2kFile and VipsForeignSaveJp2kFile.
Basic usage: convert JPEG 2000 to PNG#
package main
import (
"fmt"
"log"
"os"
"github.com/davidbyttow/govips/v2/vips"
)
func main() {
vips.Startup(nil)
defer vips.Shutdown()
img, err := vips.NewImageFromFile("in.jp2")
if err != nil {
log.Fatal(err)
}
defer img.Close()
fmt.Printf("%d x %d, %d bands, format %s\n", img.Width(), img.Height(), img.Bands(), vips.ImageTypes[img.Format()])
buf, _, err := img.ExportPng(vips.NewPngExportParams())
if err != nil {
log.Fatal(err)
}
if err := os.WriteFile("out.png", buf, 0o644); err != nil {
log.Fatal(err)
}
}
How to encode JPEG 2000#
img, err := vips.NewImageFromFile("in.png")
if err != nil {
log.Fatal(err)
}
defer img.Close()
params := vips.NewJp2kExportParams()
params.Quality = 40 // lossy; ignored when Lossless is true
params.Lossless = false
params.TileWidth = 512 // tiles allow fast region decoding later
params.TileHeight = 512
buf, _, err := img.ExportJp2k(params)
if err != nil {
log.Fatal(err)
}
os.WriteFile("out.jp2", buf, 0o644)
How to load a lower resolution level#
libvips exposes the resolution levels of a JPEG 2000 file as pages: page 0 is full size, page 1 is half size, and so on.
params := vips.NewImportParams()
params.Page.Set(2) // 1/4 width and height
img, err := vips.LoadImageFromFile("big.jp2", params)
if err != nil {
log.Fatal(err)
}
defer img.Close()
How to make a thumbnail#
NewThumbnailFromFile loads only what it needs and resizes in one step:
thumb, err := vips.NewThumbnailFromFile("big.jp2", 256, 256, vips.InterestingNone)
if err != nil {
log.Fatal(err)
}
defer thumb.Close()
buf, _, _ := thumb.ExportJpeg(vips.NewJpegExportParams())
os.WriteFile("thumb.jpg", buf, 0o644)
Tips#
img.Format() == vips.ImageTypeJP2Ktells you the input was JPEG 2000; govips detects it from the magic bytes.- Some OpenJPEG versions decode tiled files incorrectly region by region. If you see artifacts, upgrade OpenJPEG or load with the libvips
oneshotoption using the command line:vips copy "in.jp2[oneshot]" out.png.