Vipsgen
Go binding generator for libvips image processing library
Install / Use
/learn @cshum/VipsgenREADME
vipsgen
vipsgen is a Go binding generator for libvips - a fast and efficient image processing library.
libvips is generally 4-8x faster than ImageMagick with low memory usage, thanks to its demand-driven, horizontally threaded architecture.
Existing Go libvips bindings rely on manually written code that is often incomplete, error-prone, and difficult to maintain as libvips evolves. vipsgen solves this by generating type-safe, robust, and fully documented Go bindings using GObject introspection.
- Comprehensive: Bindings for around 300 libvips operations
- Type-Safe: Proper Go types for all libvips C enums and structs
- Idiomatic: Clean Go APIs that feel natural to use
- Streaming:
VipsSourceandVipsTargetintegration with Goio.Readerandio.Writerfor streaming
You can use vipsgen in two ways:
- Import directly: Use the pre-generated library
github.com/cshum/vipsgen/vipsfor the latest default installation of libvips, or see pre-generated packages - Generate custom bindings: Run the vipsgen command to create bindings for your specific libvips version and installation
Quick Start
Use homebrew to install vips and pkg-config:
brew install vips pkg-config
On MacOS, vipsgen may not compile without first setting an environment variable:
export CGO_CFLAGS_ALLOW="-Xpreprocessor"
Use the package directly:
go get -u github.com/cshum/vipsgen/vips
All operations support parameters and optional arguments through structs, maintaining direct equivalence with the libvips API.
Pass nil to use default behavior for optional arguments.
See examples for common usage patterns.
package main
import (
"log"
"net/http"
"github.com/cshum/vipsgen/vips"
)
func main() {
// Fetch an image from http.Get
resp, err := http.Get("https://raw.githubusercontent.com/cshum/imagor/master/testdata/gopher.png")
if err != nil {
log.Fatalf("Failed to fetch image: %v", err)
}
defer resp.Body.Close()
// Create source from io.ReadCloser
source := vips.NewSource(resp.Body)
defer source.Close() // source needs to remain available during image lifetime
// Shrink-on-load via creating image from thumbnail source with options
image, err := vips.NewThumbnailSource(source, 800, &vips.ThumbnailSourceOptions{
Height: 1000,
FailOn: vips.FailOnError, // Fail on first error
})
if err != nil {
log.Fatalf("Failed to load image: %v", err)
}
defer image.Close() // always close images to free memory
// Add a yellow border using vips_embed
border := 10
if err := image.Embed(
border, border,
image.Width()+border*2,
image.Height()+border*2,
&vips.EmbedOptions{
Extend: vips.ExtendBackground, // extend with colour from the background property
Background: []float64{255, 255, 0, 255}, // Yellow border
},
); err != nil {
log.Fatalf("Failed to add border: %v", err)
}
log.Printf("Processed image: %dx%d\n", image.Width(), image.Height())
// Save the result as WebP file with options
err = image.Webpsave("resized-gopher.webp", &vips.WebpsaveOptions{
Q: 85, // Quality factor (0-100)
Effort: 4, // Compression effort (0-6)
SmartSubsample: true, // Better chroma subsampling
})
if err != nil {
log.Fatalf("Failed to save image as WebP: %v", err)
}
log.Println("Successfully saved processed images")
}
Pre-generated Packages
vipsgen provides pre-generated bindings for the following libvips versions. All packages use the same vips package name and API - only the import path differs.
| Import Path | libvips Version | Use When |
|-------------|----------------|----------|
| github.com/cshum/vipsgen/vips | 8.18.0 | Latest version (recommended) |
| github.com/cshum/vipsgen/vips817 | 8.17.3 | You have libvips 8.17.x installed |
| github.com/cshum/vipsgen/vips816 | 8.16.1 | You have libvips 8.16.x installed |
Important: Only import ONE of these packages in your project. Choose based on your installed libvips version.
Check your libvips version with vips --version, then use the corresponding import:
// For libvips 8.18.x (latest - recommended)
import "github.com/cshum/vipsgen/vips"
// For libvips 8.17.x
import "github.com/cshum/vipsgen/vips817"
// For libvips 8.16.x
import "github.com/cshum/vipsgen/vips816"
func main() {
// API is identical across all versions
img, err := vips.NewImageFromFile("input.jpg", nil)
if err != nil {
log.Fatal(err)
}
defer img.Close()
err = img.Resize(0.5, nil)
// ...
}
Image Loaders
Generic loaders — NewImageFromFile, NewImageFromBuffer, NewImageFromSource — automatically detect the image format and accept LoadOptions, a generic options struct covering common options across formats. Since not every format supports every option, use the format-specific loaders — NewGifload, NewJpegloadBuffer, NewPngloadSource, etc. — for precise, type-safe control. A few common examples:
Animated GIF — N: -1 loads all frames (full example):
image, err := vips.NewGifload("animation.gif", &vips.GifloadOptions{
N: -1, // -1 = load all frames
})
JPEG auto-rotation — rotate by EXIF orientation on load:
source := vips.NewSource(reader)
defer source.Close()
image, err := vips.NewJpegloadSource(source, &vips.JpegloadSourceOptions{
Autorotate: true,
})
Working with Animated Images
libvips represents multi-frame images (animated GIF, WebP) as a single vertically stacked image where each frame occupies one page of height PageHeight. vipsgen exposes the page metadata and provides dedicated helpers for operations that must process each frame individually.
Metadata
img.Pages() // number of frames
img.PageHeight() // height of a single frame in pixels
delays, _ := img.PageDelay() // per-frame delay in milliseconds
img.Loop() // loop count (0 = infinite)
Multi-page Helpers
Some operations — rotate, crop, embed — cannot be expressed as a single libvips pipeline call across a stacked image. vipsgen ships hand-written C helpers that loop over frames internally, so there is no per-frame CGo overhead from Go:
// Rotate all frames
err = img.RotMultiPage(vips.AngleD90)
// Crop all frames to the same region
err = img.ExtractAreaMultiPage(left, top, width, height)
// Embed (pad/extend) all frames to a new canvas
err = img.EmbedMultiPage(left, top, newWidth, newHeight, &vips.EmbedMultiPageOptions{
Extend: vips.ExtendBackground,
Background: []float64{0, 0, 0, 0},
})
These methods automatically fall through to the equivalent single-frame operation when the image has only one page.
Code Generation
Code generation requires libvips to be built with GObject introspection support.
go install github.com/cshum/vipsgen/cmd/vipsgen@latest
Generate the bindings:
vipsgen -out ./vips
Use your custom-generated code:
package main
import (
"yourproject/vips"
)
Command Line Options
Usage of vipsgen:
-debug
Enable debug json output
-extract
Extract embedded templates to a directory
-extract-dir string
Directory to extract templates to (default "./templates")
-include-test
Include test files in generated output
-out string
Output directory (default "./vips")
-templates string
Template directory (uses embedded templates if not specified)
How Code Generation Works
The generation process involves multiple layers to provide a type-safe, idiomatic Go API:
-
Introspection Analysis: vipsgen uses GObject introspection to analyze the libvips API, extracting operation metadata, argument types, and enum definitions.
-
Multi-Layer Generation: To create type-safe, idiomatic Go APIs from libvips dynamic parameter system, vipsgen creates a layered approach that handles both required and optional parameters.
-
Type-Safe Bindings: The generated code is fully type-safe with proper Go types, structs, and enums based on centralized introspection data.
┌─────────────────────────────────────────────────────────────┐
│ Go Method Layer │
│ • Methods on *Image struct │
│ • Go enums and structs │
│ • Options structs for optional parameters │
│ • Type conversions (Go <-> C) │
└─────────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────────┐
│ Go Binding Layer │
│ • vipsgenAbc() - required parameters only │
│ • vipsgen
