govips

davidbyttowMIT活跃维护

Go 语言的高性能图像处理与缩放库,基于 libvips,支持 JPEG、PNG、WebP、HEIC、GIF、SVG、PDF 等格式,适合需要快速批量处理图片的服务端场景。

A lightning fast image processing and resizing library for Go

v2.20.0发布于 2026-10-16 15:51 UTC1,683star220fork同步于 2026-11-10 17:49 UTC

怎么上手

由 README 提炼,执行前请确认
brew install vips pkg-config
go get -u github.com/davidbyttow/govips/v2/vips
硬件要求按 README 说明

README 未说明显存或 GPU 要求;需 libvips 8.14+、C 兼容编译器(gcc 4.6+ 或 clang 3.0+)及 Go 1.23+。

支持 Apple Silicon
下载:源码 zip·GitHub Releases(安装包)本站不镜像安装包

项目说明

由 README 自动翻译提炼

Go 语言封装 libvips 的高性能图像处理与缩放库,适合并发请求场景

Go 语言的高性能图像处理与缩放库,基于 libvips,支持 JPEG、PNG、WebP、HEIC、GIF、SVG、PDF 等格式,适合需要快速批量处理图片的服务端场景。

核心能力

  • 封装 libvips 全部图像操作到 Go 原生类型
  • 内置 vipsgen 代码生成器覆盖 193+ 操作
  • 用 NewThumbnailFromFile 只解码所需像素生成缩略图
  • 支持 JPEG/PNG/WebP/AVIF/TIFF 等格式互转
  • 提供 io.Reader/Writer 流式加载与保存

容易踩的坑

需先在本机安装 libvips 8.14+ 并配置 pkg-config,否则无法编译;MacOS 上需先 export CGO_CFLAGS_ALLOW="-Xpreprocessor";Windows 原生支持未测试,推荐通过 WSL 使用。

内容由模型根据 README 生成,可能不完整或不准确,以官方文档为准。看原文 README

最近发版

5 个版本v2.20.0
  1. v2.20.0最新正式版2026-10-16 · 2026-10-16 15:51 UTC

    Highlights

    • Keep export option: every format-specific *ExportParams struct gains a Keep ForeignKeep field wired to libvips's keep save option (libvips 8.15+). Where StripMetadata is all-or-nothing, Keep is a bitmask: ForeignKeepExif | ForeignKeepIcc retains just those, ForeignKeepNone strips everything, ForeignKeepAll keeps whatever the running libvips supports. Unset means no change; set, it takes precedence over StripMetadata. On libvips older than 8.15 a set Keep returns a clear error (#551)

    Behavior changes

    • WebP exports now keep the source ICC profile when StripMetadata is false, matching JPEG, PNG and TIFF. Previously webpsave was always given profile="none", so WebP output silently lost the profile. Files from sources with an embedded profile grow by roughly the profile's size (about 3 KB for sRGB). To get the old output back, set StripMetadata: true or a Keep without ForeignKeepIcc (#552, #556)

    Fixes

    Animated and multi-page images had several transforms that treated the stacked frames as one tall image:

    • Rotate(Angle90/Angle270) failed with "bad grid geometry" unless every page was loaded. Pages() is the page count of the file, not the loaded count (#553, #555)
    • Rotate(Angle180) and Flip(DirectionVertical) reversed the frame order. Both now operate per frame (#554, #558)
    • Zoom left the page height stale, so a 2× zoom read as twice as many half-height frames (#554, #558)
    • Resize collapsed frames into one tall image whenever pageHeight × scale wasn't a whole number, the #350 "toilet roll" again. The vertical scale is now chosen so the strip is exactly frames × newPageHeight, as vips_thumbnail does. Output is unchanged when the rounding already agreed (#554, #558)

    Housekeeping

    • CI actions bumped to actions/checkout@v7 and actions/setup-go@v7 (#550)

    Thanks to @diego-choi for Keep and the WebP fix, and to @ailintom for the Rotate fix and the thorough #554 report.

  2. v2.19.02026-09-20 · 2026-09-20 17:41 UTC
    查看更新说明

    Highlights

    • Streaming I/O: new LoadImageFromReader, SaveToWriter, and TranscodeStream for working with io.Reader/io.Writer instead of whole buffers (#539). Stream loads sniff the file signature, so sub-formats like AVIF vs HEIF are still reported correctly (#540)
    • NewImageFromMemory: build an ImageRef from a raw pixel buffer (#528)
    • WebP TargetSize: new option on WebpExportParams, requires libvips 8.17.4+ (#535)
    • Kill flag: SetKill exposes libvips' image evaluation kill flag, for cancelling long-running work (#537)
    • BigTIFF image type detection (#527)

    Fixes

    Several of these are memory-safety bugs that could crash a process. Upgrading is recommended.

    • Fix SIGSEGV after a failed DrawRect: the error path unref'd the caller's image, so the later Close() or GC finalizer was a double-unref. Reachable from truncated JPEGs (#547, #549)
    • Fix input double-unref in Join, which caused intermittent use-after-free crashes at unrelated call sites (#531)
    • Fix SetBlob: it passed the slice header to C instead of the backing array and panicked under cgocheck on any non-empty input (#545, #549)
    • Fix a C string leak on every ExportMagick call (#546, #549)
    • Keep ImageRef arguments alive across cgo calls in two-image ops (Composite, Insert, Join, ArrayJoin, BandJoin, Mapim, Maplut, Add, Subtract, Multiply, Divide), closing a GC finalization hazard (#543)
    • Fix background colors on 1 and 2-band greyscale images for Embed and friends (#534, #538)

    Housekeeping

    • Add AGENTS.md with contributor and agent guidance: cgo/memory rules, testing conventions, known local quirks (#541, #542)
    • CI installs the libheif HEVC plugin so HEIC fixtures run (#529)
    • Bump golang.org/x/image to 0.41.0 and golang.org/x/net to 0.55.0 (#533, #532)
    • Bump sharp in examples/tiff (#536, #548)

    Thanks to @antst, @alon-ne, @goodmartian, and @joecorall for patches, and to @svkoskin and @OvOhao for detailed bug reports.

  3. v2.18.02026-04-01 · 2026-04-01 16:53 UTC
    查看更新说明

    Highlights

    • Leak detector: new OpenImageRefs() and AssertNoLeaks(t) API for tracking unclosed ImageRef instances (#525)
    • Split ImageRef: decomposed the 2607-line god object into 8 focused files by concern — zero API changes, same public surface (#525)
    • WebP shrink-on-load support via scale parameter (#516)
    • Animated AVIF (avis) detection support (#513)
    • Fix memory leaks in vipsGetPoint and vipsImageGetAsString (#510)
    • Fix segfault during animated WebP export in test suite
    • Replace panics with errors in startupIfNeeded and test helpers (#522, #523)
    • Update minimum libvips from 8.10 to 8.14 (#518)
    • Fix C code bugs in set_image_delay and label (#512)
    • Remove incorrect defers that would free internal vips pointers (#511)
    • Update dependencies to fix known vulnerabilities
    • Simplify CI workflow, align Go version with go.mod (#519)

    Breaking

    • Removed vips/pipeline package — it was a thin wrapper over ImageRef methods covering ~40 of 139 methods, creating a dual-surface problem. Use ImageRef methods directly.
    • Minimum libvips version bumped from 8.10 to 8.14
  4. v2.17.02026-03-01 · 2026-03-01 23:52 UTC
    查看更新说明

    What's Changed

    New Features

    • Add built-in vipsgen code generator for auto-generating C bridge wrappers
    • Add NewTransparentCanvas helper for creating transparent RGBA images
    • Add Grey() constructor for creating gradient images
    • Add fast Go image.Image interop: ToGoImage and NewImageFromGoImage
    • Add Loop API and preserve loop/delay metadata in RemoveMetadata
    • Add gravity function
    • Add PSD support
    • Add Magick Save, support ICO load
    • Add access options while loading image
    • Add additional image operation functions

    Bug Fixes

    • Fix memory leak, panics, and race condition
    • Fix memory leak when using multi pages
    • Fix animated resize producing toilet-roll images
    • Fix CMYK ICC profile ignored when embedded profile exists
    • Fix TIFF tile dimensions zero-value crash
    • Fix JXL type detection for ISOBMFF containers with varying box sizes
    • Add runtime.KeepAlive to prevent GC finalization during CGo calls
    • Stop implicitly converting BMP files to PNG

    Internal Improvements

    • Consolidate generated C bridge files into generated.{c,h,go}
    • Consolidate hand-written C bridge files into operations.{c,h,go}
    • Reduce hand-written C bridge code by using generated wrappers
    • Remove dead code (INT_TO_GBOOLEAN, unused max_alpha())
    • Split golden tests by format for better organization

    Security

    • Update gopkg.in/yaml.v3 v3.0.0 to v3.0.1 (security fix)
    • Bump golang.org/x/net from 0.25.0 to 0.38.0

    Other

    • Add new HEIC magic numbers
    • Document GIF quality param limitation with native gifsave
    • Add side effects import for golang.org/x/image/webp
  5. v2.16.02025-01-16 · 2025-01-16 06:41 UTC
    查看更新说明

    What's Changed

    New Contributors

    Full Changelog: https://github.com/davidbyttow/govips/compare/v2.15.0...v2.16.0

用户点评

登录用户的真实使用记录,可按版本和硬件筛选
共 0 条

    还没有人点评。第一个说出真实体验的人最有价值。

    README 原文

    未翻译

    govips

    GoDoc Go Report Card GitHub release (latest SemVer) License Build Status Coverage Status

    A lightning fast image processing and resizing library for Go

    This package wraps the core functionality of libvips image processing library by exposing all image operations on first-class types in Go.

    Libvips is generally 4-8x faster than other graphics processors such as GraphicsMagick and ImageMagick. Check the benchmark: Speed and Memory Use

    The intent for this is to enable developers to build extremely fast image processors in Go, which is suited well for concurrent requests.

    Project Status

    govips now includes a built-in code generator (cmd/vipsgen/) that uses libvips GObject introspection to auto-generate type-safe Go bindings. This covers 193+ operations across 9 categories (arithmetic, colour, conversion, convolution, create, freqfilt, histogram, morphology, resample), while complex operations like image I/O remain as hand-written bindings for full control.

    Requirements

    • libvips 8.14+
    • C compatible compiler such as gcc 4.6+ or clang 3.0+
    • Go 1.23+

    Dependencies

    MacOS

    Use homebrew to install vips and pkg-config:

    brew install vips pkg-config
    

    Windows

    The recommended approach on Windows is to use Govips via WSL and Ubuntu.

    If you need to run Govips natively on Windows, it's not difficult but will require some effort. We don't have a recommended environment or setup at the moment. Windows is also not in our list of CI/CD targets so Govips is not regularly tested for compatibility. If you would be willing to setup and maintain a robust CI/CD Windows environment, please open a PR, we would be pleased to accept your contribution and support Windows as a platform.

    Installation

    go get -u github.com/davidbyttow/govips/v2/vips
    

    MacOS note

    On MacOS, govips may not compile without first setting an environment variable:

    export CGO_CFLAGS_ALLOW="-Xpreprocessor"
    

    Examples

    Every example below assumes this setup:

    package main
    
    import (
    	"fmt"
    	"os"
    
    	"github.com/davidbyttow/govips/v2/vips"
    )
    
    func main() {
    	vips.Startup(nil)
    	defer vips.Shutdown()
    
    	// ... example code goes here
    }
    

    1. Load an image and export as JPEG

    The basics: load from a file, auto-rotate based on EXIF data, and write it back out.

    image, err := vips.NewImageFromFile("input.jpg")
    if err != nil {
    	log.Fatal(err)
    }
    
    // Fix orientation from EXIF metadata
    if err := image.AutoRotate(); err != nil {
    	log.Fatal(err)
    }
    
    buf, _, err := image.ExportJpeg(vips.NewJpegExportParams())
    if err != nil {
    	log.Fatal(err)
    }
    os.WriteFile("output.jpg", buf, 0644)
    

    2. Resize an image

    Scale an image down by 50% using the Lanczos3 kernel (the sharpest option).

    image, err := vips.NewImageFromFile("photo.jpg")
    if err != nil {
    	log.Fatal(err)
    }
    
    // Scale to 50%
    if err := image.Resize(0.5, vips.KernelLanczos3); err != nil {
    	log.Fatal(err)
    }
    
    buf, _, err := image.ExportJpeg(&vips.JpegExportParams{Quality: 85})
    if err != nil {
    	log.Fatal(err)
    }
    os.WriteFile("resized.jpg", buf, 0644)
    

    3. Create a thumbnail with smart crop

    NewThumbnailFromFile is the fastest way to generate thumbnails. It decodes only the pixels it needs.

    // Load and shrink to fit within 200x200, cropping to the most interesting region
    image, err := vips.NewThumbnailFromFile("photo.jpg", 200, 200, vips.InterestingAttention)
    if err != nil {
    	log.Fatal(err)
    }
    
    buf, _, err := image.ExportJpeg(&vips.JpegExportParams{Quality: 80})
    if err != nil {
    	log.Fatal(err)
    }
    os.WriteFile("thumb.jpg", buf, 0644)
    

    4. Convert between formats

    Load a JPEG and export it as WebP and PNG.

    image, err := vips.NewImageFromFile("photo.jpg")
    if err != nil {
    	log.Fatal(err)
    }
    
    // Export as WebP (lossy)
    webpBuf, _, err := image.ExportWebp(&vips.WebpExportParams{Quality: 75})
    if err != nil {
    	log.Fatal(err)
    }
    os.WriteFile("photo.webp", webpBuf, 0644)
    
    // Export as PNG
    pngBuf, _, err := image.ExportPng(&vips.PngExportParams{Compression: 6})
    if err != nil {
    	log.Fatal(err)
    }
    os.WriteFile("photo.png", pngBuf, 0644)
    

    5. Crop and extract a region

    Pull out a specific rectangle from an image.

    image, err := vips.NewImageFromFile("photo.jpg")
    if err != nil {
    	log.Fatal(err)
    }
    
    // Extract a 300x300 region starting at (50, 100)
    if err := image.ExtractArea(50, 100, 300, 300); err != nil {
    	log.Fatal(err)
    }
    
    buf, _, err := image.ExportPng(vips.NewPngExportParams())
    if err != nil {
    	log.Fatal(err)
    }
    os.WriteFile("cropped.png", buf, 0644)
    

    6. Blur and sharpen

    Apply a Gaussian blur or sharpen an image.

    image, err := vips.NewImageFromFile("photo.jpg")
    if err != nil {
    	log.Fatal(err)
    }
    
    // Gaussian blur with sigma=3.0
    if err := image.GaussianBlur(3.0); err != nil {
    	log.Fatal(err)
    }
    
    buf, _, err := image.ExportJpeg(vips.NewJpegExportParams())
    if err != nil {
    	log.Fatal(err)
    }
    os.WriteFile("blurred.jpg", buf, 0644)
    
    // Or sharpen instead: sigma=1.0, x1=2.0, m2=3.0
    image2, _ := vips.NewImageFromFile("photo.jpg")
    if err := image2.Sharpen(1.0, 2.0, 3.0); err != nil {
    	log.Fatal(err)
    }
    
    buf2, _, _ := image2.ExportJpeg(vips.NewJpegExportParams())
    os.WriteFile("sharpened.jpg", buf2, 0644)
    

    7. Rotate and flip

    Rotate by fixed angles and flip along an axis.

    image, err := vips.NewImageFromFile("photo.jpg")
    if err != nil {
    	log.Fatal(err)
    }
    
    // Rotate 90 degrees clockwise
    if err := image.Rotate(vips.Angle90); err != nil {
    	log.Fatal(err)
    }
    
    // Flip horizontally
    if err := image.Flip(vips.DirectionHorizontal); err != nil {
    	log.Fatal(err)
    }
    
    buf, _, err := image.ExportJpeg(vips.NewJpegExportParams())
    if err != nil {
    	log.Fatal(err)
    }
    os.WriteFile("rotated.jpg", buf, 0644)
    

    8. Adjust brightness, saturation, and hue

    Modulate works in the LCH color space. Brightness and saturation are multipliers (1.0 = no change), hue is an angle shift in degrees.

    image, err := vips.NewImageFromFile("photo.jpg")
    if err != nil {
    	log.Fatal(err)
    }
    
    // Bump brightness by 20%, desaturate by 30%, shift hue by 45 degrees
    if err := image.Modulate(1.2, 0.7, 45); err != nil {
    	log.Fatal(err)
    }
    
    buf, _, err := image.ExportJpeg(&vips.JpegExportParams{Quality: 90})
    if err != nil {
    	log.Fatal(err)
    }
    os.WriteFile("adjusted.jpg", buf, 0644)
    

    9. Composite two images (watermark overlay)

    Layer one image on top of another using Porter-Duff blending.

    base, err := vips.NewImageFromFile("photo.jpg")
    if err != nil {
    	log.Fatal(err)
    }
    
    overlay, err := vips.NewImageFromFile("watermark.png")
    if err != nil {
    	log.Fatal(err)
    }
    
    // Place the watermark at position (20, 20) using "over" blending
    if err := base.Composite(overlay, vips.BlendModeOver, 20, 20); err != nil {
    	log.Fatal(err)
    }
    
    buf, _, err := base.ExportJpeg(&vips.JpegExportParams{Quality: 90})
    if err != nil {
    	log.Fatal(err)
    }
    os.WriteFile("watermarked.jpg", buf, 0644)
    

    10. Add a text label

    Overlay text directly onto an image.

    image, err := vips.NewImageFromFile("photo.jpg")
    if err != nil {
    	log.Fatal(err)
    }
    
    err = image.Label(&vips.LabelParams{
    	Text:      "govips",
    	Font:      "sans bold 16",
    	OffsetX:   vips.ValueOf(20),
    	OffsetY:   vips.ValueOf(20),
    	Opacity:   0.8,
    	Color:     vips.Color{R: 255, G: 255, B: 255},
    	Alignment: vips.AlignLow,
    	Width:     vips.ValueOf(200),
    	Height:    vips.ValueOf(40),
    })
    if err != nil {
    	log.Fatal(err)
    }
    
    buf, _, err := image.ExportPng(vips.NewPngExportParams())
    if err != nil {
    	log.Fatal(err)
    }
    os.WriteFile("labeled.png", buf, 0644)
    

    11. Flatten transparency onto a background color

    Remove the alpha channel by compositing onto a solid color.

    image, err := vips.NewImageFromFile("logo.png")
    if err != nil {
    	log.Fatal(err)
    }
    
    // Flatten alpha onto white
    if err := image.Flatten(&vips.Color{R: 255, G: 255, B: 255}); err != nil {
    	log.Fatal(err)
    }
    
    buf, _, err := image.ExportJpeg(&vips.JpegExportParams{Quality: 90})
    if err != nil {
    	log.Fatal(err)
    }
    os.WriteFile("flattened.jpg", buf, 0644)
    

    12. Embed an image in a larger canvas

    Center an image inside a larger canvas with a colored background.

    image, err := vips.NewImageFromFile("icon.png")
    if err != nil {
    	log.Fatal(err)
    }
    
    w, h := image.Width(), image.Height()
    
    // Center the image inside a 800x600 canvas with a dark background
    if err := image.EmbedBackgroundRGBA(
    	(800-w)/2, (600-h)/2, 800, 600,
    	&vips.ColorRGBA{R: 30, G: 30, B: 30, A: 255},
    ); err != nil {
    	log.Fatal(err)
    }
    
    buf, _, err := image.ExportPng(vips.NewPngExportParams())
    if err != nil {
    	log.Fatal(err)
    }
    os.WriteFile("embedded.png", buf, 0644)
    

    13. Load from a byte buffer and strip metadata

    Useful when you're reading images from HTTP requests or databases.

    inputBytes, err := os.ReadFile("photo.jpg")
    if err != nil {
    	log.Fatal(err)
    }
    
    image, err := vips.NewImageFromBuffer(inputBytes)
    if err != nil {
    	log.Fatal(err)
    }
    
    // Strip all EXIF/metadata for privacy
    if err := image.RemoveMetadata(); err != nil {
    	log.Fatal(err)
    }
    
    buf, _, err := image.ExportJpeg(&vips.JpegExportParams{
    	Quality:       80,
    	StripMetadata: true,
    })
    if err != nil {
    	log.Fatal(err)
    }
    os.WriteFile("clean.jpg", buf, 0644)
    

    14. Build a pipeline: thumbnail, sharpen, and export as AVIF

    Chain multiple operations together. Each method mutates the image in place, so you can pipeline them naturally.

    image, err := vips.NewThumbnailFromFile("photo.jpg", 800, 600, vips.InterestingCentre)
    if err != nil {
    	log.Fatal(err)
    }
    
    if err := image.Sharpen(0.7, 1.0, 2.0); err != nil {
    	log.Fatal(err)
    }
    
    buf, _, err := image.ExportAvif(&vips.AvifExportParams{
    	Quality: 50,
    	Effort:  4,
    })
    if err != nil {
    	log.Fatal(err)
    }
    os.WriteFile("output.avif", buf, 0644)
    

    15. Stream images with io.Reader and io.Writer

    Load directly from any io.Reader (HTTP body, S3 stream, file handle) and save directly to any io.Writer — without buffering the full compressed input or output in Go memory. If the reader also implements io.Seeker (like os.File), libvips uses random access for efficient loading of formats like HEIF. One exception on the save side: TIFF requires seekable output, so it is encoded in memory and written to w in a single chunk (bytes identical to ExportTiff).

    // Stream-load: no full-file buffer in Go memory
    f, err := os.Open("input.heic")
    if err != nil {
    	log.Fatal(err)
    }
    defer f.Close()
    
    image, err := vips.LoadImageFromReader(f, nil)
    if err != nil {
    	log.Fatal(err)
    }
    defer image.Close()
    
    // Process as usual
    if err := image.AutoRotate(); err != nil {
    	log.Fatal(err)
    }
    
    // Stream-save: encoded chunks written directly to the output
    out, err := os.Create("output.jpg")
    if err != nil {
    	log.Fatal(err)
    }
    defer out.Close()
    
    err = image.SaveToWriter(out, vips.ImageTypeJPEG, &vips.ExportParams{
    	Quality: 85,
    })
    if err != nil {
    	log.Fatal(err)
    }
    

    For the full set of format-specific export options (PNG palette, WebP near-lossless/target size, TIFF compression, HEIF bit depth, ...), use the typed variants: SaveToWriterJpeg, SaveToWriterPng, SaveToWriterWebp, SaveToWriterTiff, SaveToWriterHeif, SaveToWriterGif.

    For non-seekable readers (e.g. http.Request.Body), libvips buffers header data up to ~1 GB by default. Lower the limit to bound memory usage:

    vips.Startup(nil)
    vips.SetPipeReadLimit(100 * 1024 * 1024) // 100 MB
    

    16. End-to-end streaming transcode

    TranscodeStream runs reader → decode → transform → encode → writer as one pipeline, picking the cheapest decode strategy automatically:

    // Upload handler: stream the request body through a JPEG transcode into
    // content-addressed storage, hashing the output while writing.
    hasher := sha256.New()
    err := vips.TranscodeStream(req.Body, io.MultiWriter(hasher, storage), &vips.TranscodeOptions{
    	Format:       vips.ImageTypeJPEG,
    	AutoRotate:   true,
    	ExportParams: &vips.ExportParams{Quality: 85, Interlaced: false},
    })
    

    Two decode strategies:

    • Sequential fast path — when no random-access transform is needed, pixels flow from reader to writer in one pass. Peak RAM is bounded by libvips line caches, independent of file size and pixel count. Available directly via LoadImageFromReader with params.Access.Set(vips.AccessSequential); the source then stays connected (keep the reader open) until Close.
    • Materialized path — when random access is required (e.g. EXIF rotation), the decoded frame is rendered in one streaming pass to memory or, above a threshold, to an unlinked scratch file on disc. RAM stays bounded either way; the source is released as soon as materialization finishes.
    vips.SetStreamDiscThreshold(64 << 20) // decoded frames >64 MB go to scratch disc (default 100 MB, or VIPS_DISC_THRESHOLD)
    vips.SetStreamScratchDir("/var/scratch") // default os.TempDir()
    

    Which operations keep the sequential fast path? Sequential images may only be read top-to-bottom, once. Safe: resize/thumbnail (shrink), crop, flatten, colorspace conversion, sharpen/blur (line kernels), horizontal flip, format conversion. Forcing materialization: rotation (90°/180°/270°), vertical flip, AutoRotate for EXIF orientations 3–8 (TranscodeStream detects this from the header automatically), FindTrim, SmartCrop, and anything else that reads pixels out of order. Attempting a random-access operation on a sequential image fails with an "out of order read" error from libvips.

    Codec caveats. True end-to-end streaming also depends on the codec: progressive (interlaced) JPEG and interlaced PNG cannot stream — on decode the codec buffers all input before emitting rows, and on encode (govips' default JPEG params set Interlace: true) it buffers the whole image before writing the first byte. Pass Interlaced: false for streaming output. HEIF/HEIC decodes whole-frame inside libheif regardless of access mode, and TIFF output is encoded in memory (seekable-output requirement). Non-seekable inputs additionally accumulate compressed bytes read so far (bounded by SetPipeReadLimit).

    Where errors surface. On the default (materialized) load, truncated or erroring streams fail inside LoadImageFromReader/TranscodeStream during materialization. On the sequential path the load only reads the header, so the same failures surface from the operation that first consumes pixels — typically SaveToWriter — wrapped with the original reader error (errors.Is works).

    See the examples/ folder for more.

    Running tests

    $ make test
    

    Code Generation

    The built-in generator lives in cmd/vipsgen/ and uses libvips GObject introspection to discover operations and their arguments at build time. To regenerate the bindings:

    go generate ./vips/
    

    This produces the generated files in vips/gen_*.{c,h,go}. You should not need to regenerate unless you are adding support for new libvips operations.

    Memory usage note

    MALLOC_ARENA_MAX

    libvips uses GLib for memory management, and it brings GLib memory fragmentation issues to heavily multi-threaded programs. First thing you can try if you noticed constantly growing RSS usage without Go's sys memory growth is set MALLOC_ARENA_MAX:

    MALLOC_ARENA_MAX=2 application
    

    This will reduce GLib memory appetites by reducing the number of malloc arenas that it can create. By default GLib creates one are per thread, and this would follow to memory fragmentation.

    Jemalloc

    If the arena option doesn't help, you can try replacing the standard allocator with jemalloc, which emphasizes fragmentation avoidance and scalable concurrency support.

    To do this, you need to install the libjemalloc-dev package. And pass the following flags for build command:

    CGO_CFLAGS="-fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-free" CGO_LDFLAGS="-ljemalloc" go build
    

    Contributing

    Feel free to file issues or create pull requests. See this guide on contributing for more information.

    Credits

    Thanks to:

    License

    MIT