Skip to content

govips hand-written API, generated API, and idiomatic patterns

Copy page

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.

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()

cmd/vipsgen/ reads libvips GObject introspection data at build time and generates generated.go, generated.c, and generated.h. 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, resample

Most users never need to run the generator — it runs during govips development. The generated functions are compiled into the vips package you import. If you are adding support for new libvips operations, regenerate with go generate ./vips/.

govips v2.19.0 introduces full io.Reader/io.Writer streaming:

  • LoadImageFromReader(r io.Reader, params *ImportParams): Load from any Reader (HTTP body, S3 stream, file handle) without buffering the full compressed input in Go memory.
  • SaveToWriter(w io.Writer, format ImageType, params *ExportParams): Encode directly to a Writer. Format-specific variants exist (SaveToWriterJpeg, SaveToWriterWebp, etc.).
  • TranscodeStream(r io.Reader, w io.Writer, opts *TranscodeOptions): All-in-one Reader → decode → transform → encode → Writer pipeline.

Two decode strategies:

  • Sequential fast path: When no random-access transform is needed, pixels flow from Reader to Writer. Peak RAM is bound by libvips line caches, independent of file and pixel count.
  • Materialized path: When random access is required (e.g., EXIF rotation), the decoded frame is rendered in one streaming pass to memory or a scratch disk file.
out, _ := os.Create("output.jpg")
defer out.Close()
image, _ := vips.LoadImageFromReader(os.Stdin, nil)
defer image.Close()
image.AutoRotate()
image.SaveToWriter(out, vips.ImageTypeJPEG, &vips.ExportParams{Quality: 85})
  1. Startup once per process, always check the error. It initialises libvips internal state. As of v2.18.0, Startup may return an error.
  2. Shutdown once, always deferred. It frees global libvips resources. Missing it may cause memory leaks.
  3. Close every ImageRef. Each load allocates libvips memory. Defer Close() or explicitly close when done.
  4. OpenImageRefs()/AssertNoLeaks(t) available since v2.18.0. Track unclosed ImageRef instances during development and testing.
  5. Programming error: using an image after close. libvips may crash or return corrupted data. In Go, this surfaces as a panic or silent garbage output.
func process(inputPath string) error {
image, err := vips.NewImageFromFile(inputPath)
if err != nil {
return err
}
defer image.Close()
// Operations here
return nil
}
  • pipeline package removed. It was a thin wrapper over ~40 ImageRef methods. Use ImageRef methods directly.
  • Minimum libvips raised from 8.10 to 8.14.
  • ImageRef split into 8 focused files by concern. Zero public API changes.
  • startupIfNeeded no longer panics, returns errors instead.

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.

  • vipsgen is not a separate binding or a fifth tab. It is govips’ internal code generator. External projects with similar names are not supported by this handbook unless separately evaluated.
  • You import github.com/davidbyttow/govips/v2/vips. The generated code is in the same package.
  • Hand-written and generated operations share the same *vips.ImageRef type and lifecycle — there is no semantic split at the call site.

govips v2.19.0, libvips 8.17.3 (reference). Reviewed 2026-10-11.