| English | Chinese Simplified |
Rust bindings for libvips: fast, low-memory image processing with a safe, ergonomic API.
Documentation: https://docs.rs/vips/
brew install vipsapt-get install -y pkg-config libvips-dev (or your distro equivalent)Add to your Cargo.toml:
[dependencies]
vips = "0.2"
use vips::*;
fn main() -> Result<()> {
// Initialize once per process. The boolean enables leak diagnostics.
let _instance = VipsInstance::new("app_example", true)?;
// Create a thumbnail with forced width and height (preferred for files)
let thumb = VipsImage::thumbnail_file("./examples/images/kodim01.png", 320, 240, VipsSize::VIPS_SIZE_FORCE)?;
// Save the result
thumb.write_to_file("kodim01_320x240.jpg")?;
Ok(())
}
This version uses the published vips-sys 0.3.0 dependency;
no sibling checkout is required.
write_to_memory_owned / write_to_buffer_owned return VipsOwnedBuffer,
which owns a GLib allocation and exposes immutable bytes without the extra
full-buffer copy into a Rust Vec. Existing Vec APIs remain available.from_file_with_access / from_buffer_with_access accept a VipsAccess hint.
Prefer sequential access for a one-pass pipeline and file/buffer thumbnail
constructors for shrink-on-load.--features v8_18 adds tile_size, gainmap, camera RAW file/buffer loaders,
UltraHDR file/buffer IO and scRGB conversion, Oklab/Oklch conversion helpers,
and interpretation_bands. Requires libvips 8.18+; RAW and HDR codecs remain
optional build-time dependencies of the system library.VipsRegion now has a buffer lifetime; lazy multi-image operations retain
every input buffer’s lifetime. Image handles may drop before their results,
but borrowed pixel buffers must remain alive.VipsInterpolateMethod::call is unsafe because output size/alignment and a
prepared interpolation window are native caller obligations.VipsInstance uses the same initialization state as init and no longer
shuts the process-wide library down when its handle is dropped.vips = { version = "0.2", features = ["v8_18"] }
Run cargo run --release --example buffer_bench for an alternating ABBA
comparison of copied and owned raw exports. See the review and roadmap.
let pixels = vec![0u8; 256 * 256 * 3]; // RGB
let img = VipsImage::from_memory(pixels, 256, 256, 3, VipsBandFormat::VIPS_FORMAT_UCHAR)?;
let thumb = img.thumbnail(200, 200, VipsSize::VIPS_SIZE_FORCE)?;
thumb.write_to_file("black_200x200.png")?;
let pixels = vec![0u8; 256 * 256 * 3];
let img = VipsImage::from_memory_reference(&pixels, 256, 256, 3, VipsBandFormat::VIPS_FORMAT_UCHAR)?;
let thumb = img.thumbnail(200, 200, VipsSize::VIPS_SIZE_FORCE)?;
thumb.write_to_file("black_ref_200x200.png")?;
from_file, from_memory) when possible.from_memory_reference) tie the image lifetime to the borrowed slice. Do not let the slice
drop before all derived images are fully used.| Area | APIs |
|---|---|
| IO | from_file, from_memory, from_memory_reference, from_buffer, write_to_file, write_to_memory, write_to_buffer, write_jpeg, find_load/find_save, black/xyz/grey/sines/zone/perlin/gaussnoise |
| Geometry | thumbnail_file, thumbnail_buffer, thumbnail (in-memory), resize, resize_reduce, reduce, shrink_box, crop, embed, flip/rot/rotate/autorot, zoom, insert, gravity, extract_band, bandjoin2/bandjoin_const, copy/copy_memory, smartcrop, ifthenelse |
| Arithmetic | add/subtract/multiply/divide, linear/linear1, invert, pow_const, abs/sign/clamp, floor/ceil/rint |
| Math | sin/cos/tan, ln/log10/exp/exp10 |
| Relational | less/lesseq/more/moreeq/equal_const/notequal_const, boolean/shift const, bandand/bandor/bando |
| Color | cast, colourspace, falsecolour, premultiply/unpremultiply |
| Filter | gaussblur, sharpen, conv, erode/dilate, median, sobel, canny, maplut |
| Hist | hist_find/hist_local/hist_equal/hist_entropy, labelregions |
| Stats | avg, min_value, max_value, deviate, percent, getpoint, find_trim |
| Properties | width, height, size, bands |
| Drawing | draw_rect, draw_line, draw_circle, draw_flood, … (in-place) |
| Stitching | merge, mosaic, match_, globalbalance, remosaic |
| Interpolation | VipsInterpolate nearest / bilinear / custom |
VipsImage::thumbnail_file / VipsImage::thumbnail_buffer over from_file/from_buffer + thumbnail for downscales. They call vips_thumbnail / vips_thumbnail_buffer, which combine load and resize so libvips can shrink-on-load (often ~3× faster and several times lower peak memory than thumbnail_image). Use the instance method thumbnail only for already-decoded raw pixels.write_to_file over write_to_memory when the destination is a path (avoids a full in-memory copy).resize_reduce against resize before choosing the extra box pre-shrink pass; it can be slower on small inputs.vips::set_concurrency, set_max_operations, and set_max_mem_bytes for your workload.init and VipsInstance share process-wide state. Native objects use RAII; global state remains available until process exit.self.vips-sys or use unsafe vips::vips_call(...)
to invoke libvips operations directly.Builds resolve vips-sys from crates.io. To develop both crates together, add this
optional override at the workspace/consumer root:
[patch.crates-io]
vips-sys = { path = "../vips-sys" }
Docker-based check (no local libvips required):
docker run --rm -v "$PWD/..":/workspace -w /workspace/vips-rs rust:1.88-bookworm \
bash -c 'apt-get update -qq && apt-get install -y -qq pkg-config libvips-dev && cargo test'
See CHANGELOG.md.