Vips::Native
NAME
Vips::Native - Raku FFI wrapper for libvips with bundled prebuilts
SYNOPSIS
use Vips::Native;
# 1. Smart-crop + resize to fixed output dimensions, saved as PNG.
smart-resize("input.png", "thumb.png", 128, 128);
# 2. Letterbox-resize to a fixed square + return raw 8-bit RGB pixels.
# Aspect ratio preserved; gap filled with the chosen background.
# Output is suitable to feed to ML inference engines.
my Buf[uint8] $bytes = letterbox-to-buffer(
'photo.png'.IO,
:size(448),
:bg(255, 255, 255),
);
say $bytes.bytes; # 448 Ć 448 Ć 3 = 602112DESCRIPTION
Vips::Native is a Raku NativeCall wrapper around libvips, shipped with prebuilt platform bundles so the common case (install, import, run) doesn't require a working libvips toolchain on the host.
The module exposes two high-level helpers:
smart-resize ā thumbnail-style: smart-crop to the requested aspect ratio (using libvips's saliency / entropy / attention model), then Lanczos3-resize, then save as PNG.
letterbox-to-buffer ā ML-preprocess: scale-to-fit inside a square canvas (no crop), pad the gap with a chosen colour, composite RGBA over that colour, and return the raw RGB pixel buffer in NHWC byte order. The preprocess pipeline image classifiers want.
The full (variadic) libvips C API is available via direct is native bindings under Vips::Native::FFI ā see the module's SYNOPSIS for the bindings exported. Most of those go through a tiny non-variadic C shim (src/vips_native_shim.c) for ABI safety on Apple arm64 / Linux aarch64, where Raku's NativeCall can't marshal C variadics correctly.
INSTALLATION
Vips::Native tries three lookup paths at install + load time, in order:
Prebuilt bundle (default) ā fetched from the project's GitHub Releases at install time, sha256-pinned against
resources/checksums.txt, staged under$XDG_DATA_HOME/Vips-Native/<binary-tag>/lib/. Bundles include libvips, libglib, libgio, libgobject, the format loaders (jpeg/png/webp/tiff/heif/avif/jxl/openslide/poppler/magick) and all their transitive deps with@loader_path(macOS) /$ORIGIN(Linux) / sibling-DLL (Windows) relocations baked in, so the bundle is self-contained.System libvips ā fallback when the prebuilt download fails or no prebuilt exists for your platform. The OS dynamic loader resolves
is native('vips')against your installed libvips.On macOS:
brew install vipsOn Debian/Ubuntu:
sudo apt install libvips-devCustom install ā set
VIPS_NATIVE_LIB_DIR=/path/to/dirto point at a directory containinglibvips.{dylib,so,dll}andlibgobject-2.0.{dylib,so,dll}. Caller takes responsibility for ABI compatibility.
Supported platforms
macOS arm64
Linux x86_64 + aarch64 (glibc 2.35+)
Windows x86_64 + arm64
Every supported platform ships a working bundle with the varargs shim included.
Build-time environment
VIPS_NATIVE_PREFER_SYSTEM=1ā skip prebuilt download, force system libvips at runtime.VIPS_NATIVE_BINARY_ONLY=1ā refuse to fall back to system libvips; fail loudly if the prebuilt can't be installed (CI / pinned deployments).VIPS_NATIVE_DATA_DIR=/pathā override staged-libs root (default$XDG_DATA_HOMEor~/.local/share).VIPS_NATIVE_CACHE_DIR=/pathā override prebuilt-archive download cache (default$XDG_CACHE_HOMEor~/.cache).VIPS_NATIVE_BINARY_URL=https://ā¦ā override the GitHub Release base URL (custom mirror).VIPS_NATIVE_KEEP_OLD_STAGES=1ā opt out of the orphaned-stage GC that runs after every install. Use when intentionally pinning multiple versions side-by-side.
EXTERNAL API
smart-resize
sub smart-resize(
Str $in-path,
Str $out-path,
Int $out-width,
Int $out-height,
--> Bool
) is exportSmart-crop the source image to match the output aspect ratio (using libvips's VIPS_INTERESTING_ATTENTION saliency model ā picks the visually-important rectangle, not just the centre), then Lanczos3- resize the cropped image to $out-width Ć $out-height and save as PNG to $out-path.
Returns True on success; fails with the underlying error if libvips errors out.
A vips_smart_resize shell binary is also installed:
vips_smart_resize --in=/path/to/image.png --out=/path/to/save.png \
--width=180 --height=180letterbox-to-buffer
sub letterbox-to-buffer(
IO::Path() $path,
UInt :$size = 448,
:@bg = (255, 255, 255),
--> Buf[uint8]
) is exportResize $path to fit inside a $size Ć $size square while preserving aspect ratio, pad the unfilled region with the @bg colour, composite alpha over that colour for RGBA inputs, and return the raw 8-bit RGB pixel buffer in NHWC byte order. Length is always exactly $size Ć $size Ć 3.
The preprocess pipeline image classifiers want: deterministic gap fill, fixed input dimensions, no GC entanglement with libvips's heap. Pair with ONNX::Native or your inference engine of choice to feed RGB pixels directly.
The buffer is owned by the caller ā internally we copy from the vips_image_write_to_memory result into a Raku-owned buf8 and release the source via vips_shim_free, so there's no lifetime trap.
Inputs may be 3-band RGB or 4-band RGBA (UCHAR pixels only ā 16-bit PNG / HDR / float images are out of scope for v1). Greyscale and CMYK fail loudly with details.
Vips::Native::FFI
The complete (variadic + non-variadic) libvips C bindings are exported from Vips::Native::FFI:
vips_init,vips_image_new_from_filevips_image_get_width/get_height/get_bands/get_formatvips_smartcrop,vips_resize,vips_flatten,vips_embedvips_pngsave,vips_image_write_to_memoryvips_shim_free(libglib heap free for write-to-memory output)g_object_unref(release VipsImage handles)VIPS_KERNEL_*,VIPS_INTERESTING_*,VIPS_EXTEND_*,VIPS_FORMAT_*constants
vips_flatten and vips_embed require the libvips_shim (their options take a VipsArrayDouble * that's awkward to construct directly from Raku). Every prebuilt bundle includes it; if you're running against system libvips, the shim is compiled at install time via the platform's C toolchain and falls back gracefully if no toolchain is available.
AUTHOR
Matt Doughty [email protected]
COPYRIGHT AND LICENSE
Copyright 2025-2026 Matt Doughty.
This library is free software; you can redistribute it and/or modify it under the Artistic License 2.0.