Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork1
Go binding generator for libvips image processing library
License
cshum/vipsgen
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
vipsgen is a Go binding generator forlibvips - a fast and efficient image processing library.
libvips is generally 4-8xfaster than ImageMagick with low memory usage, thanks to itsdemand-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.
You can use vipsgen in two ways:
- Import directly: Use the pre-generated library
github.com/cshum/vipsgen/vips
for the default installation of libvips 8.17 - Generate custom bindings: Run the vipsgen command to create bindings for your specific libvips version and installation
- Comprehensive: Bindings for around300 libvips operations
- Type-Safe: Proper Go types for all libvips C enums and structs
- Idiomatic: Clean Go APIs that feel natural to use
- Streaming:
VipsSource
andVipsTarget
integration with Goio.Reader
andio.Writer
forstreaming
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 thelibvips API.Passnil
to use default behavior for optional arguments.Seeexamples for common usage patterns.
package mainimport ("log""net/http""github.com/cshum/vipsgen/vips")funcmain() {// Fetch an image from http.Getresp,err:=http.Get("https://raw.githubusercontent.com/cshum/imagor/master/testdata/gopher.png")iferr!=nil {log.Fatalf("Failed to fetch image: %v",err)}deferresp.Body.Close()// Create source from io.ReadClosersource:=vips.NewSource(resp.Body)defersource.Close()// source needs to remain available during image lifetime// Shrink-on-load via creating image from thumbnail source with optionsimage,err:=vips.NewThumbnailSource(source,800,&vips.ThumbnailSourceOptions{Height:1000,FailOn:vips.FailOnError,// Fail on first error})iferr!=nil {log.Fatalf("Failed to load image: %v",err)}deferimage.Close()// always close images to free memory// Add a yellow border using vips_embedborder:=10iferr:=image.Embed(border,border,image.Width()+border*2,image.Height()+border*2,&vips.EmbedOptions{Extend:vips.ExtendBackground,// extend with colour from the background propertyBackground: []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 optionserr=image.Webpsave("resized-gopher.webp",&vips.WebpsaveOptions{Q:85,// Quality factor (0-100)Effort:4,// Compression effort (0-6)SmartSubsample:true,// Better chroma subsampling})iferr!=nil {log.Fatalf("Failed to save image as WebP: %v",err)}log.Println("Successfully saved processed images")}
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 mainimport ("yourproject/vips")
Usage: vipsgen [options]Options:-out string Output directory (default "./out")-templates string Template directory (uses embedded templates if not specified)-extract Extract embedded templates and exit-extract-dir string Directory to extract templates to (default "./templates")-debug Enable debug json output
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 ││ • vipsgenAbcWithOptions() - with optional parameters ││ • C array handling and memory management ││ • String conversions and cleanup ││ • Error handling and resource management │└─────────────────────────────────────────────────────────────┘ │┌─────────────────────────────────────────────────────────────┐│ C Layer ││ • vipsgen_abc() - required args only ││ • vipsgen_abc_with_options() - all parameters ││ • VipsOperation dynamic dispatch ││ • Proper VipsArray creation and cleanup │└─────────────────────────────────────────────────────────────┘ │┌─────────────────────────────────────────────────────────────┐│ libvips ││ • vips_abc() - original variadic functions ││ • VipsOperation object system ││ • GObject introspection metadata │└─────────────────────────────────────────────────────────────┘
1. C Layer (vips.c/vips.h)
Problem: libvips dynamic parameter system with variadic functions likevips_resize(in, &out, scale, "kernel", kernel, ...)
does not translate well to type-safe, idiomatic Go APIs.
Solution: Generate two types of C wrapper functions:
// Basic function - required arguments only, calls vips_resize directlyintvipsgen_resize(VipsImage*in,VipsImage**out,doublescale) {returnvips_resize(in,out,scale,NULL);}// With options - uses VipsOperation for optional parametersintvipsgen_resize_with_options(VipsImage*in,VipsImage**out,doublescale,VipsKernelkernel,doublegap,doublevscale) {VipsOperation*operation=vips_operation_new("resize");if (!operation)return1;if (vips_object_set(VIPS_OBJECT(operation),"in",in,NULL)||vips_object_set(VIPS_OBJECT(operation),"scale",scale,NULL)||vipsgen_set_int(operation,"kernel",kernel)||vipsgen_set_double(operation,"gap",gap)||vipsgen_set_double(operation,"vscale",vscale) ) {g_object_unref(operation);return1; }intresult=vipsgen_operation_execute(operation,"out",out,NULL);returnresult;}
This layer handles VipsArray creation/cleanup, VipsOperation lifecycle management, type-specific setters.
2. Go Binding Layer (vips.go)
Problem: C arrays, string management, and complex type conversions.
Solution: Generate Go wrapper functions that handle CGO complexity:
// vipsgenResize vips_resize resize an imagefuncvipsgenResize(in*C.VipsImage,scalefloat64) (*C.VipsImage,error) {varout*C.VipsImageiferr:=C.vipsgen_resize(in,&out,C.double(scale));err!=0 {returnnil,handleImageError(out) }returnout,nil}// vipsgenResizeWithOptions vips_resize resize an image with optional argumentsfuncvipsgenResizeWithOptions(in*C.VipsImage,scalefloat64,kernelKernel,gapfloat64,vscalefloat64) (*C.VipsImage,error) {varout*C.VipsImageiferr:=C.vipsgen_resize_with_options(in,&out,C.double(scale),C.VipsKernel(kernel),C.double(gap),C.double(vscale));err!=0 {returnnil,handleImageError(out) }returnout,nil}
This layer handles C array conversion, string conversion with cleanup, memory management, error handling, and type conversion between Go and C.
3. Go Method Layer (image.go)
Problem: Provide idiomatic Go API with proper encapsulation.
Solution: Generate methods on*Image
struct that encapsulate the two-function approach with options pattern:
// ResizeOptions optional arguments for vips_resizetypeResizeOptionsstruct {// Kernel Resampling kernelKernelKernel// Gap Reducing gapGapfloat64// Vscale Vertical scale image by this factorVscalefloat64}// DefaultResizeOptions creates default value for vips_resize optional argumentsfuncDefaultResizeOptions()*ResizeOptions {return&ResizeOptions{Kernel:Kernel(5),Gap:2, }}// Resize vips_resize resize an imagefunc (r*Image)Resize(scalefloat64,options*ResizeOptions)error {ifoptions!=nil {// Use the WithOptions variant when options are providedout,err:=vipsgenResizeWithOptions(r.image,scale,options.Kernel,options.Gap,options.Vscale)iferr!=nil {returnerr }r.setImage(out)returnnil }// Use the basic variant for required parameters onlyout,err:=vipsgenResize(r.image,scale)iferr!=nil {returnerr }r.setImage(out)returnnil}
This layer provides idiomatic Go methods, options structs for optional parameters, Go type system integration.
Contributions are welcome! Please feel free to submit a Pull Request.
When contributing to vipsgen,do not commit the generated code in thevips/
directory (exceptvips/vips_test.go
). The development workflow is designed to keep generated code separate from source code. The repository uses GitHub Actions to automatically handle code generation when PRs are created.
We extend our heartfelt gratitude to thegovips project and its maintainers for pioneering Go bindings for libvips. govips demonstrated the potential of bringing libvips's powerful image processing capabilities to the Go ecosystem.
vipsgen draws significant inspiration from govips. Their early contributions to the Go + libvips ecosystem paved the way for projects like vipsgen to exist.
While vipsgen takes a different approach, it builds upon the foundation and lessons learned from govips. We're honored that the govips team has recommended vipsgen as the path forward for the Go community.
MIT
About
Go binding generator for libvips image processing library
Topics
Resources
License
Uh oh!
There was an error while loading.Please reload this page.
Stars
Watchers
Forks
Sponsor this project
Uh oh!
There was an error while loading.Please reload this page.
Packages0
Uh oh!
There was an error while loading.Please reload this page.