govips hand-written API, generated API, and idiomatic patterns
govips v2.19.0 wraps libvips with two API layers: carefully maintained hand-written functions for I/O, export, streaming, and complex workflows, and auto-generated type-safe bindings for 193+ pixel-level operations. This page explains how they fit together, covers the major changes since v2.18.0 (pipeline package removal, minimum libvips raised to 8.14, OpenImageRefs leak detection), and covers v2.19.0’s new streaming I/O (LoadImageFromReader/SaveToWriter/TranscodeStream), and what you need to know to use govips safely in production.
The two API layers
Section titled “The two API layers”Hand-written functions
Section titled “Hand-written functions”These are maintained in the main package and provide lifecycle management, file/buffer/stream I/O, encoding/decoding, and convenience helpers that cannot be covered by the GObject introspection code generator:
| Category | Key functions |
|---|---|
| Lifecycle | Startup(nil) (must check error), Shutdown(), OpenImageRefs(), AssertNoLeaks() |
| Input | NewImageFromFile, NewImageFromBuffer, NewThumbnailFromFile, LoadImageFromReader, NewImageFromMemory |
| Geometry | Resize, ExtractArea, Similarity, Flip, Rotate |
| Colour | Modulate (LCH colourspace) |
| Alpha | Flatten, HasAlpha, Bands |
| Export | ExportWebp, ExportPng, ExportJpeg, SaveToWriter (and format-specific variants) |
| Streaming | TranscodeStream, SetPipeReadLimit, SetStreamDiscThreshold |
| Cancellation | SetKill |
Every program must call vips.Startup(nil), check the error, and defer vips.Shutdown(). Every *vips.ImageRef must be closed when done:
if err := vips.Startup(nil); err != nil { return fmt.Errorf("start libvips: %w", err)}defer vips.Shutdown()
image, err := vips.NewImageFromFile("input.jpg")if err != nil { return err}defer image.Close()Generated operations
Section titled “Generated operations”govips’ code generator reads libvips GObject introspection data at build time and generates the low-level wrapper code. The vipsGen* functions are internal implementations; user-facing ImageRef methods and selected exported helpers provide the type-safe API around them. As of v2.19.0 this covers 193+ operations across nine categories:
arithmetic, colour, conversion, convolution, create,freqfilt, histogram, morphology, resampleApplication code calls the public ImageRef methods. vipsGen* stays inside govips and is not a second API for application code to call. The generator runs only when govips itself is built.
Streaming I/O (new in v2.19.0)
Section titled “Streaming I/O (new in v2.19.0)”govips v2.19.0 introduces full io.Reader / io.Writer streaming:
LoadImageFromReader(r io.Reader, params *ImportParams): creates anImageReffrom a Reader. WithoutAccessSequential, the decoded image is materialised (fully decoded and buffered into memory or a temporary file) before the call returns. Only an explicit sequential access defers pixel reads until something consumes them.SaveToWriter(w io.Writer, format ImageType, params *ExportParams): writes encoded bytes to a Writer. Format-specific variants includeSaveToWriterJpegandSaveToWriterWebp.TranscodeStream(r io.Reader, w io.Writer, opts *TranscodeOptions): wraps read, optional auto-rotate, and write in one call. It does not take acontext.Context.SetKill(true): asks the current evaluation to stop, typically from another goroutine. Set the flag back tofalseafterwards. On v2.19.0, setting kill before export made that export return an error.
Two decode strategies:
- Sequential fast path: with explicit
AccessSequentialand no later random-access operation, pixels are read from the Reader when something consumes them. Memory still depends on the codec and the line cache. It is not a constant ceiling independent of image width. - Materialised path: the default import, or any later random-access operation, places the decoded image in memory or a temporary file.
out, err := os.Create("output.jpg")if err != nil { return err}defer out.Close()
image, err := vips.LoadImageFromReader(os.Stdin, nil)if err != nil { return err}defer image.Close()
if err := image.AutoRotate(); err != nil { return err}return image.SaveToWriter(out, vips.ImageTypeJPEG, &vips.ExportParams{Quality: 85})Lifecycle rules for production
Section titled “Lifecycle rules for production”Startuponce per process, always check the error. It initialises libvips internal state. As of v2.18.0,Startupmay return an error.Shutdownonce, always deferred. It frees global libvips resources. Missing it may leave native resources unreleased.CloseeveryImageRef. Each load allocates libvips native memory. DeferClose()or explicitly close when done.OpenImageRefs()/AssertNoLeaks(t)available since v2.18.0. Track unclosedImageRefinstances during development and testing.- Never use an image after close. libvips may crash or return corrupted data. In Go, this surfaces as a panic or silent error.
func process(inputPath string) error { image, err := vips.NewImageFromFile(inputPath) if err != nil { return err } defer image.Close()
// Operations here return nil}v2.18.0 breaking changes
Section titled “v2.18.0 breaking changes”pipelinepackage removed. It was a thin wrapper over ~40ImageRefmethods. UseImageRefmethods directly.- Minimum libvips raised from 8.10 to 8.14.
ImageRefsplit into 8 focused files by concern. Zero public API changes.startupIfNeededno longer panics, returns errors instead.
Memory and performance notes
Section titled “Memory and performance notes”libvips uses GLib for memory allocation, which can cause fragmentation under heavy concurrency. Two approaches help:
MALLOC_ARENA_MAX=2: Reduces GLib malloc arena count. Try this first.- Jemalloc: Replaces the system allocator. Build with
CGO_LDFLAGS="-ljemalloc".
Neither is a silver bullet — measure your own workload before adopting either.
Internal details you do not need to call
Section titled “Internal details you do not need to call”vipsgenis not a fifth interface and not its own binding. It is the code generator inside govips.vipsGen*is not an API for application code. The public entry is anImageRefmethod; the generated functions implement those methods.- Import
github.com/davidbyttow/govips/v2/vips. Handwritten wrappers and generated operations share*vips.ImageRef, and application code stops at the public method.
Verified version
Section titled “Verified version”govips v2.19.0 and libvips 8.17.3. Reviewed 2026-10-12. The SetKill failure path was executed on that version.