Name

viprs — generate tile pyramids from images and PDFs for web-based viewers

Synopsis

viprs pyramid [OPTIONS] <INPUT> [<OUTPUT>]
viprs info <INPUT>
viprs plan [OPTIONS] <WIDTH_OR_INPUT>
viprs test-image [OPTIONS] <OUTPUT>

# Phase 3 hardening flags (subset)
viprs pyramid input.pdf tiles/ --blank-tolerance 2
viprs pyramid input.pdf --sink s3://bucket/prefix
viprs pyramid input.pdf out/ --resume --retry-max 3 --retry-backoff 200
viprs pyramid input.pdf out/ --manifest-emit-checksums --checksum-algo blake3
viprs pyramid input.pdf out/ --dedupe-blanks
viprs pyramid input.pdf --sink packfile://out.tar.gz
viprs pyramid input.pdf out/ --trace-level info

Description

viprs converts large raster images and multi-page PDF documents — high-resolution scans, gigapixel photographs, aerial and satellite imagery, historical maps, and digitised archives — into multi-resolution tile pyramids suitable for Deep Zoom viewers, slippy-map UIs, and GIS applications. It supports three tile layouts (DeepZoom, XYZ, Google Maps), three image formats (PNG, JPEG, raw), and three engine modes (monolithic, streaming, parallel MapReduce) to balance throughput and memory usage for images of any size.

The XYZ and Deep Zoom tile pyramids it emits are served directly to and rendered by MapLibre GL — the open-source WebGL map and tile engine — so a gigapixel source can be panned and zoomed at interactive speed in the browser.

Commands

pyramid

Generate a tile pyramid from a PDF or image file. This is the primary command — it loads the source, plans the pyramid grid, and writes tiles to disk.

The Rust program below is what viprs pyramid input.pdf tiles/ runs internally with no flags. Click any flag below to see how it slots into this template, or check flags to assemble a complete program in the generator panel at the bottom.

// Pre-generated; the live version reflects flag selections.

Reference test: builder_sink_fs.rs · two_arg_new_defaults_to_png — the canonical minimal builder call.

Arguments

<INPUT>

Path to a PDF, PNG, JPEG, or TIFF file. Use "-" for stdin (pipe a file directly into viprs). PDF inputs are either raster-extracted (default) or vector-rendered (with --render).

<OUTPUT>

Directory where tiles are written. Created automatically. DeepZoom also writes a .dzi manifest alongside.

Tile options

--tile-size <PIXELS>

Width and height of each tile in pixels. Viewers fetch tiles on demand — smaller tiles mean finer-grained loading but more HTTP requests. 256 is the web standard; use 512 for high-DPI displays or when serving from fast storage. Default: 256

--overlap <PIXELS>

Pixel overlap between adjacent tiles (DeepZoom only). Overlap lets viewers blend tile edges for seamless rendering. OpenSeadragon typically uses overlap=1. Not applicable to Google or XYZ layouts. Default: 0

--layout <FORMAT>

Tile naming and directory convention. Different viewers expect different conventions — OpenSeadragon uses DeepZoom, Leaflet uses XYZ, Google Maps uses its own grid. Default: deep-zoom

Values: deep-zoom ({level}/{col}_{row}.ext + .dzi), xyz ({z}/{x}/{y}.ext), google ({z}/{y}/{x}.ext, power-of-2 grids).

--format <TYPE>

Tile image encoding. PNG preserves quality for line art and text; JPEG saves disk for photographs; raw is useful when a downstream pipeline handles encoding. Default: png

Values: png (lossless), jpeg (lossy, smaller), raw (unencoded pixels, fastest).

--quality <1-100>

JPEG quality factor. Only used with --format jpeg. Default: 85

--centre

Centre the image within the tile grid, adding even background padding on all sides. Google Maps layout requires power-of-2 tile grids — without centring, the image sits at (0,0) and padding fills the right/bottom. With centring, padding is distributed evenly so the image appears centred in the viewer.

--skip-blank

Replace blank (uniform-color) tiles with a 1-byte placeholder instead of encoding the full image. Scanned documents have large white margins that produce many identical tiles — placeholder files reduce output size dramatically. Consumers detect them by file size and render a solid color.

--blank-tolerance <N>

Treat a tile as blank when every channel in every pixel varies by at most N from the first pixel's value. Extends --skip-blank to near-uniform tiles; useful for slightly noisy scanner output where pure-white detection misses off-white margins. Requires --skip-blank or --dedupe-blanks. Default: 0 (exact match only)

PDF options

--dpi <N>

Resolution for PDF rendering and page-size scaling. Higher DPI produces more pixels (and more tiles). 72 matches libvips' default; use 150–300 for print-quality scans. Default: 72

--page <N>

PDF page to extract (1-based). Default: 1

--render

Use PDFium for vector PDF rendering instead of extracting embedded raster images. Scanned documents embed a raster image inside the PDF — extraction is fast and lossless. Vector-authored PDFs and text-heavy documents contain vector paths that must be rendered to pixels. Use --render when the PDF is not a simple raster scan.

--match-page-size

After extracting a raster from a PDF, resize it to match the PDF page dimensions at the specified --dpi. Has no effect with --render. Embedded rasters may have a different resolution than the page's declared dimensions — this flag produces output consistent with libvips' default PDF handling.

Engine options

--concurrency <N>

Number of worker threads for tile extraction. Tile extraction is embarrassingly parallel — each tile reads from the source independently. Set to the number of CPU cores for maximum throughput. With --parallel, this controls per-strip tile workers. Default: 0 (single-threaded)

--buffer-size <N>

Maximum tiles buffered between producer threads and the sink. A large buffer smooths out slow disk writes at the cost of higher memory; a small buffer limits peak memory but may cause producers to block. Default: 64

--memory-limit <MB>

Hard memory limit in MB. If the estimated peak memory exceeds this, the command exits before rendering. Acts as a safety net for containerised deployments — prevents the engine from attempting a pyramid that would OOM-kill the process. Combine with --memory-budget to both limit and control memory. Default: 0 (disabled)

--memory-budget <MB>

Soft memory budget for strip-based processing. Switches from the monolithic engine to the streaming engine, which processes the image in horizontal bands. A 16820×11888 scan at 300 DPI needs ~5 GB as a monolithic canvas — the streaming engine reduces this to ~50 MB by processing strips. The strip height is maximised within the budget to balance memory and speed.

When set to 0: auto-selects a budget (1/4 of estimated monolithic peak). When omitted: uses the monolithic engine (original behavior).

--parallel

Use the parallel MapReduce engine instead of the sequential streaming engine. Requires --memory-budget. On multi-core systems, the MapReduce engine overlaps strip rendering for higher throughput — the sequential streaming engine processes one strip at a time. Both produce byte-identical output.

Renders multiple strips concurrently (bounded by the budget), then propagates downscale results sequentially. The --concurrency flag controls per-strip tile worker threads.

Output sink options

--sink <URI>

Output sink URI. The default filesystem sink is used when this flag is omitted (the <OUTPUT> positional argument sets the directory). Two additional sink types are available with optional features:

s3://bucket/prefix — write tiles to an S3-compatible object store. Requires --features s3 at compile time and standard AWS credentials in the environment.

packfile://out.tar, packfile://out.tar.gz, packfile://out.zip — archive the pyramid into a single file. Requires --features packfile.

Resumable job options

--resume

Resume an interrupted run. Reads the checkpoint file (.libviprs-job.json) at the output root and skips tiles that were already written. The run completes from the last safe checkpoint. Cannot be combined with --overwrite or --verify.

--overwrite

Start fresh even if a previous run's output or checkpoint exists. All existing tiles and the checkpoint file are removed before the job begins. Default behaviour when none of --resume / --overwrite / --verify is given

--verify

Re-read every tile produced by a previous run and verify its checksum against the checkpoint. Exits with a non-zero status if any tile is missing or corrupt. Does not write new tiles. Requires checksums to have been emitted during the original run (--manifest-emit-checksums).

Retry and failure policy options

--retry-max <N>

Maximum number of attempts for a single tile write before the failure policy is applied. Default: 0 (no retry)

--retry-backoff <MS>

Initial back-off delay in milliseconds between retry attempts. Each subsequent attempt doubles the delay (exponential back-off). Default: 100

--failure-policy <POLICY>

What to do when a tile write exhausts its retries. Default: fail-fast

Values: fail-fast (abort immediately), retry-then-fail (retry up to --retry-max times then abort), retry-then-skip (retry then record the tile as missing in the manifest and continue).

Checksum options

--manifest-emit-checksums

Compute a digest for each tile and embed it in the manifest JSON. Does not verify existing tiles; use --verify for that. Requires --features checksum.

--checksum-algo <ALGO>

Hash algorithm for tile digests. Only used with --manifest-emit-checksums or --verify. Default: blake3

Values: blake3 (faster, 256-bit), sha256 (wider tooling support).

Deduplication options

--dedupe-blanks

Store only one copy of the blank placeholder tile and point all other blank positions at it via a symlink or hardlink. Significantly reduces inode count on images with large uniform margins. Requires --features dedupe.

--dedupe-all

Extend deduplication to every tile, not just blanks. The engine hashes each encoded tile; duplicate content is stored once and the rest are links or manifest references. Implies --manifest-emit-checksums. Requires --features dedupe. Slower than --dedupe-blanks due to per-tile hashing.

Tracing options

--trace-level <LEVEL>

Emit structured tracing spans at the given verbosity level. Spans are named libviprs::pipeline, libviprs::level, and libviprs::tile. Attach any tracing-compatible subscriber (e.g. tracing-opentelemetry) to export spans to Jaeger, Tempo, or another collector. Requires --features tracing at compile time. Default: off

Values: error, warn, info, debug, trace.

Geo-reference options

--geo-origin <LON,LAT>

Geographic coordinate of the top-left pixel as "longitude,latitude".

--geo-scale <SX,SY>

Degrees per pixel as "scale_x,scale_y". Typically positive X (east) and negative Y (south). Together with --geo-origin, defines an affine transform that lets tile viewers overlay the pyramid on a world map.

Generated CLI & Rust code

No flags selected. Check boxes above to assemble a CLI command and a complete Rust program.

CLI command

Equivalent Rust program

Each flag links to a representative integration test in libviprs-tests that exercises the underlying Rust API. Edit the input/output paths in the generated program before running.

info

Show metadata about a PDF or image file without generating tiles. For PDFs, displays page count, dimensions, and embedded image details. For images, displays pixel dimensions and format.

use libviprs::{pdf_info, decode_file};
use std::path::Path;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let path = Path::new("/path/to/your/input.pdf");

    if path.extension().and_then(|e| e.to_str()) == Some("pdf") {
        let info = pdf_info(path)?;
        println!("PDF: {} pages", info.page_count);
        for page in &info.pages {
            println!(
                "  Page {}: {:.1} x {:.1} pts",
                page.page_number, page.width_pts, page.height_pts,
            );
        }
    } else {
        let raster = decode_file(path)?;
        println!(
            "{}x{} {:?}",
            raster.width(), raster.height(), raster.format(),
        );
    }
    Ok(())
}

Reference tests: pdf_ops.rs · pdf_info_reads_page_count · libviprs/src/source.rs · generate_test_raster_dimensions (decode flow).

<INPUT>

Path to the PDF or image file to inspect. Useful before running pyramid to understand source dimensions, plan memory usage, and decide on DPI settings.

plan

Show the tile pyramid plan without generating any tiles. Displays the number of levels, total tiles, and per-level grid dimensions. Useful for capacity planning and understanding how tile parameters affect output.

use libviprs::{Layout, PyramidPlanner};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Plan from explicit dimensions — no source file needed.
    let planner = PyramidPlanner::new(
        16820, 11888,        // width, height
        256,                 // --tile-size
        0,                   // --overlap
        Layout::Google,      // --layout
    )?
    .with_centre(true);      // --centre

    let plan = planner.plan();
    let (canvas_w, canvas_h) = planner.canvas_dimensions();

    println!("Canvas: {}x{}", canvas_w, canvas_h);
    println!("Levels: {}, total tiles: {}",
        plan.level_count(),
        plan.total_tile_count(),
    );
    println!("Estimated peak memory: {:.1} MB",
        planner.estimate_peak_memory() as f64 / (1024.0 * 1024.0));
    Ok(())
}

Reference tests: libviprs/src/planner.rs · total_tile_count_sums_all_levels · streaming_engine.rs · estimate_streaming_memory_reasonable (peak-memory estimation).

<WIDTH_OR_INPUT>

Either a pixel width (when paired with --height) or a path to an image/PDF file to read dimensions from.

--height <PIXELS>

Image height in pixels. Required when the first argument is a number.

--tile-size, --overlap, --layout, --centre

Same as in pyramid. Control how the plan is computed.

--dpi, --page

Used when the input is a PDF to resolve page dimensions to pixels.

test-image

Generate a synthetic RGB8 gradient test image. Useful for benchmarking, testing, and verifying the tile pipeline without needing real image data.

use libviprs::{generate_test_raster, sink::encode_png};
use std::fs;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let raster = generate_test_raster(1024, 1024)?;
    let bytes  = encode_png(&raster)?;
    fs::write("/path/to/output.png", bytes)?;
    Ok(())
}

Reference tests: libviprs/src/source.rs · generate_test_raster_dimensions · libviprs/src/sink.rs · encode_png_gray8.

<OUTPUT>

Output file path (PNG).

--width <PIXELS>

Image width. Default: 1024

--height <PIXELS>

Image height. Default: 1024

abs

Absolute value of every sample.

arithmetic · image->image · EXACT

viprs abs in.png out.v --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_abs(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<IN>

Input image Required.

<OUT>

Output image Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

add

Add two images pixel-by-pixel (8-bit widens to 16-bit to avoid wrap).

core · n-image->image · EXACT-AFTER-CAST

viprs add left.png right.png out.v --max-width PX --max-height PX
    let left = io::load(&left_path, &limits)?;
    let right = io::load(&right_path, &limits)?;
    // Guard the three conditions core's `add` asserts on, so a bad input is exit
    // 1 (a clear message) and NEVER a process abort (exit 101).
    if left.format().is_float() || right.format().is_float() {
        bail!(
            "add: float inputs are not supported yet (a later arithmetic batch adds float \
             addition); cast to an unsigned 8-bit format first"
        );
    }
    // Reject 16-bit (and any non-uchar) inputs: vips `add` promotes ushort→uint
    // and returns the true sum, but core keeps 16-bit at 16-bit and SATURATES at
    // 65535 (raster_ops.rs). Accepting them would emit a silently-wrong result,
    // so the accepted surface is restricted to 8-bit (uchar), where core == vips.
    // Wide-input addition lands with a later arithmetic batch (see the module
    // docs / OP_MAP `add` note).
    if left.format().bytes_per_channel() != 1 || right.format().bytes_per_channel() != 1 {
        bail!(
            "add: 16-bit inputs are not supported yet (a later arithmetic batch adds \
             ushort→uint promotion; core would saturate the sum at 65535 instead of \
             promoting like vips); cast to an unsigned 8-bit format first"
        );
    }
    if (left.width(), left.height()) != (right.width(), right.height()) {
        bail!(
            "add: dimension mismatch — LEFT is {}x{} but RIGHT is {}x{}",
            left.width(),
            left.height(),
            right.width(),
            right.height()
        );
    }
    if left.format().channels() != right.format().channels() {
        bail!(
            "add: channel-count mismatch — LEFT has {} band(s) but RIGHT has {}",
            left.format().channels(),
            right.format().channels()
        );
    }
    let out = left.add(&right);
    io::save(&out, &out_path)?;
<LEFT>

Left-hand input image Required.

<RIGHT>

Right-hand input image Required.

<OUT>

Output image Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

addalpha

Append a fully-opaque alpha channel to an image.

conversion · image->image · EXACT

viprs addalpha in.png out.v --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_addalpha()?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image with an added alpha band Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

affine

Apply a 2x2 affine matrix transform to an image.

resample · image->image · BOUNDED-TOL

viprs affine in.png out.v matrix.png --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_affine(matrix, interpolate)?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<MATRIX>

2x2 transform matrix as one space-separated string, e.g. "1.5 0 0 1.5" Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

--interpolate <I>

Point interpolator (nearest|bilinear|bicubic|nohalo|lbb) One of: nearest, bilinear, bicubic, nohalo, lbb. Default: bilinear

arrayjoin

Tile an array of images into a grid.

conversion · n-image->image · EXACT

viprs arrayjoin inputs.png --across N --shim 0
    let rasters: Vec<Raster> = inputs
        .iter()
        .map(|p| io::load(p, &limits))
        .collect::<Result<_>>()?;
    let refs: Vec<&Raster> = rasters.iter().collect();
    let out = Raster::try_arrayjoin(&refs, across, shim)?;
    io::save(&out, &out_path)?;
<INPUTS>

Two or more input images followed by the output path Required.

--across <N>

Number of images across the grid (>= 1; default all in one row)

--shim <PX>

Pixels of black gap between cells (default 0) Default: 0

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

autorot

Auto-rotate an image by its EXIF orientation tag.

conversion · image->image · EXACT

viprs autorot in.png out.v --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_autorot()?;
    io::save(&out, &out_path)?;
<IN>

Input image (orientation from TIFF/.v metadata) Required.

<OUT>

Output image Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

avg

Find the mean of every sample in an image and print it.

arithmetic · image->stdout-scalar · EXACT

viprs avg in.png --max-width PX --max-height PX
let raster = decode_file(&input)?;
let value = raster.try_avg(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
println!("{value}");
<IN>

Input image Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

bandbool

Fold an image's bands with a bitwise boolean operation.

bands · image->image · EXACT

viprs bandbool in.png out.v op.png --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let out = match op {
        "and" => raster.try_bandand()?,
        "or" => raster.try_bandor()?,
        "eor" => raster.try_bandeor()?,
        other => bail!("unknown bandbool operation {other:?} (expected and|or|eor)"),
    };
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<OP>

Bitwise operation to fold the bands with (and|or|eor; vips's lshift/rshift are intentionally excluded — not core-backed) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

bandfold

Fold the x axis into bands.

bands · image->image · EXACT

viprs bandfold in.png out.v --factor 0 --max-width PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_bandfold(factor)?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

--factor <N>

Fold by this factor (0 = fold the whole width into bands) Default: 0

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

bandjoin

Join the bands of two or more images into one image.

bands · n-image->image · EXACT

viprs bandjoin inputs.png --max-width PX --max-height PX
    let mut acc = io::load(&inputs[0], &limits)?;
    for path in &inputs[1..] {
        let next = io::load(path, &limits)?;
        acc = acc.try_bandjoin(&next)?;
    }
    io::save(&acc, &out_path)?;
<INPUTS>

Two or more input images followed by the output path Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

bandjoin_const

Append one constant band per element of a vector to an image.

bands · image->image · EXACT

viprs bandjoin_const in.png out.v c.png --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_bandjoin_vec(&consts)?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<C>

Space-separated constants, one appended band each (e.g. "10 20") Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

bandmean

Average an image's bands into a single-band image.

bands · image->image · EXACT

viprs bandmean in.png out.v --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_bandmean()?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

bandrank

Select a per-sample rank statistic across a set of images.

bands · n-image->image · EXACT

viprs bandrank inputs.png --index -1 --max-width PX
    let rasters: Vec<Raster> = inputs
        .iter()
        .map(|p| io::load(p, &limits))
        .collect::<Result<_>>()?;
    let (first, rest) = rasters
        .split_first()
        .expect("inputs_and_out guarantees at least one input");
    let others: Vec<&Raster> = rest.iter().collect();
    let out = first.try_bandrank(&others, index)?;
    io::save(&out, &out_path)?;
<INPUTS>

Two or more input images followed by the output path Required.

--index <I>

Sorted-list index to select (>= -1: 0 = min, count-1 = max, -1 = median, the default) Default: -1

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

bandunfold

Unfold image bands into the x axis.

bands · image->image · EXACT

viprs bandunfold in.png out.v --factor 0 --max-width PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_bandunfold(factor)?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

--factor <N>

Unfold by this factor (0 = unfold every band into the width) Default: 0

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

black

Make an all-zero uchar image.

create · creator · EXACT

viprs black out.v width.png height.png --bands 1
    let out_raster = Raster::try_black_bands(dim(m, "WIDTH"), dim(m, "HEIGHT"), bands)?;
    io::save(&out_raster, &out_path(m))?;
<OUT>

Output image path Required.

<WIDTH>

Image width in pixels (>= 1) Required.

<HEIGHT>

Image height in pixels (>= 1) Required.

--bands <N>

Number of bands (vips --bands, default 1) Default: 1

boolean

Samplewise bitwise boolean operation on two images.

arithmetic · n-image->image · EXACT

viprs boolean left.png right.png out.v op.png --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_boolean(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<LEFT>

Left-hand input image Required.

<RIGHT>

Right-hand input image Required.

<OUT>

Output image Required.

<OP>

Boolean operator (and|or|eor). vips's lshift|rshift are 2-image in vips but core-only as boolean_const constants, so they are NOT accepted here — use boolean_const. Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

boolean_const

Samplewise bitwise boolean operation against a constant.

arithmetic · image->image · EXACT

viprs boolean_const in.png out.v op.png c.png --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_boolean_const(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<OP>

Boolean operator to apply against the constant Required.

<C>

Integer constant (bit-mask for and|or|eor, shift count for lshift|rshift; a shift must be >= 0). NOTE: vips takes a per-band constant vector; core applies ONE constant to all bands, so a single scalar is accepted here. Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

buildlut

Build a look-up table from a control-point matrix file.

create · image->image · BOUNDED-TOL

viprs buildlut in.png out.v
let raster = decode_file(&input)?;
let result = raster.try_buildlut()?;
save_file(&result, &output)?;
<IN>

Control-point matrix as a vips text matrix file Required.

<OUT>

Output image path Required.

byteswap

Swap the byte order within every sample.

conversion · image->image · EXACT

viprs byteswap in.png out.v --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    // `byteswap` is infallible (it can never fail on any input): a straight
    // per-sample byte reversal, so there is no `try_byteswap` to call.
    let out = raster.byteswap();
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

cast

Cast an image to a new pixel format (uchar, ushort, or float).

conversion · image->image · EXACT

viprs cast in.png out.v format.png --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    // The target keeps the input's band count (try_cast rejects a band-count
    // change); only the per-channel byte width changes.
    let channels = raster.format().channels();
    let bytes = match fmt_name {
        "uchar" => 1,
        "ushort" => 2,
        "float" => 4,
        other => bail!("unsupported cast format {other:?} (expected uchar|ushort|float)"),
    };
    let target = PixelFormat::with_channels(channels, bytes)
        .ok_or_else(|| anyhow!("no {fmt_name} format exists for a {channels}-band image"))?;
    let out = raster.try_cast(target)?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<FORMAT>

Target format: uchar (8-bit), ushort (16-bit), or float (f32). char/short/int/uint/complex/double/dpcomplex are not core-backed (#283/#285). Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

clamp

Clip every sample into [min, max] (vips defaults 0 and 1).

arithmetic · image->image · EXACT

viprs clamp in.png out.v --min V --max V
let raster = decode_file(&input)?;
let result = raster.try_clamp(min, max, max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<IN>

Input image Required.

<OUT>

Output image Required.

--min <V>

Lower bound (default 0)

--max <V>

Upper bound (default 1)

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

colourspace

Convert an image to a new colour space.

colour · image->image · BOUNDED-TOL

viprs colourspace in.png out.v space.png --source-space multiband --max-width PX
    let raster = io::load(&in_path, &limits)?;
    // `--source-space` re-tags the input's interpretation (the core reads the
    // source space from the raster's tag) before the conversion; absent, the
    // input's own interpretation is used, mirroring vips.
    let input = match source {
        Some(space) => raster.copy().interpretation(space).build(),
        None => raster,
    };
    let out = input.try_colourspace(target)?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<SPACE>

Destination colour space (vips VipsInterpretation nickname) Required.

--source-space <space>

Source colour space; overrides the input's own interpretation tag (default: the input's interpretation) One of: multiband, b-w, histogram, xyz, lab, cmyk, labq, rgb, cmc, lch, labs, srgb, yxy, fourier, rgb16, grey16, matrix, scrgb, hsv, oklab, oklch.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

compass

Convolve with a rotating compass mask and combine the results.

convolution · image->image · BOUNDED-TOL

viprs compass in.png out.v mask.png --times 2 --angle d0
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_compass(&kernel, times, angle, combine, precision)?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<MASK>

Odd-sided square mask as a vips text matrix Required.

--times <N>

Rotate and convolve this many times (1..=1000) Default: 2

--angle <d0|d45|…|d315>

Rotate the mask by this much between convolutions One of: d0, d45, d90, d135, d180, d225, d270, d315. Default: d90

--combine <max|sum>

Combine the results (max|sum; vips's min is not core-backed) One of: max, sum. Default: max

--precision <integer|float>

Calculation precision (integer|float; vips's approximate is not core-backed) One of: integer, float. Default: float

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

complex

Apply a complex operation to a complex (re,im band-pair) image.

arithmetic · image->image · FOURIER

viprs complex in.png out.v op.png --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_complex(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<IN>

Input complex image ((re,im) band pairs, use .v) Required.

<OUT>

Output complex image (use .v) Required.

<OP>

Complex operation (polar/rect angles in DEGREES) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

complexform

Form a complex image from two real images (left=real, right=imag).

arithmetic · n-image->image · FOURIER

viprs complexform left.png right.png out.v --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_complexform(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<LEFT>

Real-part input image Required.

<RIGHT>

Imaginary-part input image Required.

<OUT>

Output complex image as (re,im) band pairs (use .v) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

complexget

Extract the real or imaginary component from a complex image.

arithmetic · image->image · FOURIER

viprs complexget in.png out.v op.png --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_complexget(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<IN>

Input complex image ((re,im) band pairs, use .v) Required.

<OUT>

Output real image (float; use .v) Required.

<OP>

Component to extract Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

composite

Blend two images with a blend mode (vips array form, two inputs).

composite · n-image->image · BOUNDED-TOL

viprs composite base.png overlay.png out.v mode.png --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_composite(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<BASE>

Base image (the backdrop) Required.

<OVERLAY>

Overlay image (the source), same size as BASE Required.

<OUT>

Output image Required.

<MODE>

Blend mode: one of the 25 vips VipsBlendMode names (clear|source|over|in|out|atop|dest|dest-over|dest-in|dest-out|dest-atop|xor|add|saturate|multiply|screen|overlay|darken|lighten|colour-dodge|colour-burn|hard-light|soft-light|difference|exclusion) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

composite2

Blend a base and an overlay image with a blend mode.

composite · n-image->image · BOUNDED-TOL

viprs composite2 base.png overlay.png out.v mode.png --max-width PX --max-height PX
    let base = io::load(&base_path, &limits)?;
    let overlay = io::load(&overlay_path, &limits)?;
    let out = base.try_composite2(&overlay, mode)?;
    io::save(&out, &out_path)?;
<BASE>

Base image (the backdrop) Required.

<OVERLAY>

Overlay image (the source), same size as BASE Required.

<OUT>

Output image Required.

<MODE>

Blend mode: one of the 25 vips VipsBlendMode names (clear|source|over|in|out|atop|dest|dest-over|dest-in|dest-out|dest-atop|xor|add|saturate|multiply|screen|overlay|darken|lighten|colour-dodge|colour-burn|hard-light|soft-light|difference|exclusion) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

conv

Convolve an image with a mask matrix.

convolution · image->image · EXACT

viprs conv in.png out.v mask.png --precision integer --max-width PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_conv(&kernel, precision)?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<MASK>

Convolution mask as a vips text matrix (with an optional scale) Required.

--precision <integer|float>

Calculation precision (integer|float; vips's approximate is not core-backed) One of: integer, float. Default: float

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

convsep

Separably convolve an image with a 1xN or Nx1 mask.

convolution · image->image · EXACT

viprs convsep in.png out.v mask.png --precision integer --max-width PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_convsep(&kernel, precision)?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<MASK>

Separable (1xN or Nx1) mask as a vips text matrix Required.

--precision <integer|float>

Calculation precision (integer|float; vips's approximate is not core-backed) One of: integer, float. Default: float

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

copy

Copy an image, tweaking header fields (interpretation, resolution, offset).

conversion · image->image · EXACT

viprs copy in.png out.v --interpretation multiband --xres PPMM
    let raster = io::load(&in_path, &limits)?;
    let mut builder = raster.copy();
    if let Some(s) = m.get_one::<String>("interpretation") {
        builder = builder.interpretation(interpretation_from_str(s)?);
    }
    if let Some(&v) = m.get_one::<f64>("xres") {
        builder = builder.xres(v);
    }
    if let Some(&v) = m.get_one::<f64>("yres") {
        builder = builder.yres(v);
    }
    if let Some(&v) = m.get_one::<i32>("xoffset") {
        builder = builder.xoffset(v);
    }
    if let Some(&v) = m.get_one::<i32>("yoffset") {
        builder = builder.yoffset(v);
    }
    if let Some(&v) = m.get_one::<u8>("orientation") {
        builder = builder.orientation(v);
    }
    let out = builder.build();
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

--interpretation <SPACE>

Set the colour interpretation tag One of: multiband, b-w, histogram, xyz, lab, cmyk, labq, rgb, cmc, lch, labs, srgb, yxy, fourier, rgb16, grey16, matrix, scrgb, hsv, oklab, oklch.

--xres <PPMM>

Horizontal resolution in pixels/mm

--yres <PPMM>

Vertical resolution in pixels/mm

--xoffset <PX>

Horizontal offset of the image origin

--yoffset <PX>

Vertical offset of the image origin

--orientation <N>

viprs-only (hidden, non-vips): set the EXIF-style orientation tag (1..=8)

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

countlines

Count the average number of lines in a one-band image and print it.

morphology · image->stdout-scalar · EXACT

viprs countlines in.png direction.png --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let nolines = raster.try_countlines(direction)?;
<IN>

Input image (one band, unsigned 8/16-bit) Required.

<DIRECTION>

Line direction to count Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

crop

Crop a rectangle out of an image (alias of extract_area).

extract · image->image · EXACT

viprs crop in.png out.v left.png top.png width.png height.png --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_crop(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<LEFT>

Left edge of the extract area Required.

<TOP>

Top edge of the extract area Required.

<WIDTH>

Width of the extract area Required.

<HEIGHT>

Height of the extract area Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

dE00

CIEDE2000 colour difference between two images.

colour · n-image->image · BOUNDED-TOL

viprs dE00 left.png right.png out.v --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_dE00(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<LEFT>

Left-hand input image Required.

<RIGHT>

Right-hand input image Required.

<OUT>

Output difference image Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

dE76

CIE76 colour difference between two images.

colour · n-image->image · BOUNDED-TOL

viprs dE76 left.png right.png out.v --max-width PX --max-height PX
    let left = io::load(&left_path, &limits)?;
    let right = io::load(&right_path, &limits)?;
    let out = match kind {
        DeKind::E76 => left.try_de76(&right)?,
        DeKind::E00 => left.try_de00(&right)?,
        DeKind::Cmc => left.try_de_cmc(&right)?,
    };
    io::save(&out, &out_path)?;
<LEFT>

Left-hand input image Required.

<RIGHT>

Right-hand input image Required.

<OUT>

Output difference image Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

dECMC

CMC colour difference between two images.

colour · n-image->image · BOUNDED-TOL

viprs dECMC left.png right.png out.v --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_dECMC(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<LEFT>

Left-hand input image Required.

<RIGHT>

Right-hand input image Required.

<OUT>

Output difference image Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

deviate

Find the sample standard deviation of an image and print it.

arithmetic · image->stdout-scalar · BOUNDED-TOL

viprs deviate in.png --max-width PX --max-height PX
let raster = decode_file(&input)?;
let value = raster.try_deviate(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
println!("{value}");
<IN>

Input image Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

divide

Divide the left image by the right (left / right).

arithmetic · n-image->image · EXACT-AFTER-CAST

viprs divide left.png right.png out.v --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_divide(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<LEFT>

Left-hand input image Required.

<RIGHT>

Right-hand input image Required.

<OUT>

Output image Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

draw_circle

Draw a circle outline (or a filled disc with --fill) on an image.

draw · draw · GOLDEN-ONLY

viprs draw_circle in.png out.v cx.png cy.png radius.png --ink "r g b" --fill
    let mut raster = io::load(&in_path, &limits)?;
    if fill {
        raster.try_draw_circle_filled(&ink, cx, cy, radius)?;
    } else {
        raster.try_draw_circle(&ink, cx, cy, radius)?;
    }
    io::save(&raster, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<CX>

Centre x coordinate Required.

<CY>

Centre y coordinate Required.

<RADIUS>

Radius in pixels (>= 0) Required.

--ink <"r g b">

Colour to paint, space-separated, one value per band of IN (e.g. "255 0 0") Required.

--fill

Fill the disc instead of drawing only the outline

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

draw_flood

Flood-fill a region of an image from a seed point.

draw · draw · GOLDEN-ONLY

viprs draw_flood in.png out.v x.png y.png --ink "r g b" --equal
    let mut raster = io::load(&in_path, &limits)?;
    // The flood wrappers are inherently fallible (ink width + off-canvas seed);
    // `--equal` selects the "flood while equal to the seed value" blob variant.
    if equal {
        raster.draw_flood_blob(&ink, x, y)?;
    } else {
        raster.draw_flood(&ink, x, y)?;
    }
    io::save(&raster, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<X>

Seed x coordinate (>= 0) Required.

<Y>

Seed y coordinate (>= 0) Required.

--ink <"r g b">

Colour to paint, space-separated, one value per band of IN (e.g. "255 0 0") Required.

--equal

Flood the region of pixels EQUAL to the seed value (vips draw_flood_blob) instead of flooding until the ink-coloured boundary

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

draw_image

Paste a sub-image into an image at a given offset.

draw · draw · GOLDEN-ONLY

viprs draw_image in.png out.v sub.png x.png y.png --max-width PX --max-height PX
    let mut raster = io::load(&in_path, &limits)?;
    let sub = io::load(&sub_path, &limits)?;
    raster.draw_image(&sub, x, y);
    io::save(&raster, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<SUB>

Sub-image to paste (must share IN's pixel format) Required.

<X>

Target x of the sub-image's left edge Required.

<Y>

Target y of the sub-image's top edge Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

draw_line

Draw a 1px line between two points on an image.

draw · draw · GOLDEN-ONLY

viprs draw_line in.png out.v x1.png y1.png x2.png y2.png --ink "r g b" --max-width PX
    let mut raster = io::load(&in_path, &limits)?;
    raster.try_draw_line(&ink, x1, y1, x2, y2)?;
    io::save(&raster, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<X1>

Start x coordinate Required.

<Y1>

Start y coordinate Required.

<X2>

End x coordinate Required.

<Y2>

End y coordinate Required.

--ink <"r g b">

Colour to paint, space-separated, one value per band of IN (e.g. "255 0 0") Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

draw_mask

Paint ink through a single-band 8-bit stencil onto an image.

draw · draw · GOLDEN-ONLY

viprs draw_mask in.png out.v mask.png x.png y.png --ink "r g b" --max-width PX
    let mut raster = io::load(&in_path, &limits)?;
    let mask = io::load(&mask_path, &limits)?;
    // `try_draw_mask` rejects a float target with a typed error (the blend
    // decodes unsigned 8/16-bit samples); the single-band 8-bit stencil is
    // validated above (a non-conforming mask is a documented core no-op).
    raster.try_draw_mask(&ink, &mask, x, y)?;
    io::save(&raster, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<MASK>

Single-band 8-bit stencil image (each pixel is the ink opacity 0..=255) Required.

<X>

Target x of the mask's left edge Required.

<Y>

Target y of the mask's top edge Required.

--ink <"r g b">

Colour to paint, space-separated, one value per band of IN (e.g. "255 0 0") Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

draw_rect

Draw a rectangle outline (or a filled rectangle with --fill) on an image.

draw · draw · GOLDEN-ONLY

viprs draw_rect in.png out.v left.png top.png width.png height.png --ink "r g b" --fill
    let mut raster = io::load(&in_path, &limits)?;
    if fill {
        raster.try_draw_rect_filled(&ink, left, top, width, height)?;
    } else {
        raster.try_draw_rect(&ink, left, top, width, height)?;
    }
    io::save(&raster, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<LEFT>

Left edge x coordinate Required.

<TOP>

Top edge y coordinate Required.

<WIDTH>

Rectangle width in pixels Required.

<HEIGHT>

Rectangle height in pixels Required.

--ink <"r g b">

Colour to paint, space-separated, one value per band of IN (e.g. "255 0 0") Required.

--fill

Fill the rectangle instead of drawing only the outline

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

draw_smudge

Box-blur a rectangular region of an image in place.

draw · draw · GOLDEN-ONLY

viprs draw_smudge in.png out.v left.png top.png width.png height.png --max-width PX --max-height PX
    let mut raster = io::load(&in_path, &limits)?;
    raster.draw_smudge(left, top, width, height);
    io::save(&raster, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<LEFT>

Left edge x coordinate Required.

<TOP>

Top edge y coordinate Required.

<WIDTH>

Rectangle width in pixels Required.

<HEIGHT>

Rectangle height in pixels Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

embed

Embed an image in a larger canvas at a given position.

extract · image->image · EXACT

viprs embed in.png out.v x.png y.png width.png height.png --extend black --background "r g b"
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_embed(x, y, width, height, extend, background.as_deref())?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<X>

Left edge of the input in the output Required.

<Y>

Top edge of the input in the output Required.

<WIDTH>

Canvas width in pixels Required.

<HEIGHT>

Canvas height in pixels Required.

--extend <black|copy|repeat|mirror|white|background>

How to fill the pixels around the input One of: black, copy, repeat, mirror, white, background. Default: black

--background <"r g b">

Background colour for --extend background (space-separated, one value or one per band)

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

extract_area

Extract a rectangular region from an image.

extract · image->image · EXACT

viprs extract_area in.png out.v left.png top.png width.png height.png --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_extract_area(left, top, width, height)?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<LEFT>

Left edge of the extract area Required.

<TOP>

Top edge of the extract area Required.

<WIDTH>

Width of the extract area Required.

<HEIGHT>

Height of the extract area Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

extract_band

Extract one band, or --n consecutive bands, from an image.

bands · image->image · EXACT

viprs extract_band in.png out.v band.png --n 1 --max-width PX
    let raster = io::load(&in_path, &limits)?;
    // A single `extract_band BAND` is `--n 1`; both go through the range API so
    // the `--n` case is one code path (mirrors vips's single `extract_band` op).
    let out = raster.try_extract_bands(band, n)?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<BAND>

First band to extract (>= 0) Required.

--n <N>

Number of consecutive bands to extract Default: 1

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

eye

Make an image of the eye's spatial-frequency response.

create · creator · BOUNDED-TOL

viprs eye out.v width.png height.png --uchar
let raster = decode_file(&input)?;
let result = raster.try_eye()?;
save_file(&result, &output)?;
<OUT>

Output image path Required.

<WIDTH>

Image width in pixels (>= 1) Required.

<HEIGHT>

Image height in pixels (>= 1) Required.

--uchar

Output an unsigned char image (vips --uchar)

falsecolour

Map an image through the libvips PET false-colour scale.

conversion · image->image · EXACT

viprs falsecolour in.png out.v --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_falsecolour()?;
    io::save(&out, &out_path)?;
<IN>

Input image (band 0 is used) Required.

<OUT>

Output sRGB image Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

fastcor

Fast (sum-of-squared-differences) correlation of an image against a template.

convolution · n-image->image · EXACT

viprs fastcor in.png ref.png out.v --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let template = io::load(&ref_path, &limits)?;
    let out = raster.try_fastcor(&template)?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<REF>

Template / reference image Required.

<OUT>

Output correlation surface (.v) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

find_trim

Find the bounding box of non-background content and print left/top/width/height.

arithmetic · image->stdout-scalar · EXACT

viprs find_trim in.png --background c… --max-width PX
let raster = decode_file(&input)?;
let value = raster.try_find_trim(background, max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
println!("{value}");
<IN>

Input image Required.

--background <c…>

Background colour as a space-separated vector (default 255 per band); vips's --threshold (default 10) and --line-art are not core-exposed

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

flatten

Flatten an alpha channel out against a background.

conversion · image->image · BOUNDED-TOL

viprs flatten in.png out.v --background c… --max-width PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_flatten(background.as_deref())?;
    io::save(&out, &out_path)?;
<IN>

Input image with an alpha band Required.

<OUT>

Output image Required.

--background <c…>

Background value: a single constant for every band, or one space-separated value per output band (e.g. "255 0 0"). Default black.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

flip

Flip an image horizontally or vertically.

conversion · image->image · EXACT

viprs flip in.png out.v direction.png --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let out = match dir {
        "horizontal" => raster.try_fliphor()?,
        "vertical" => raster.try_flipver()?,
        other => bail!("unknown flip direction {other:?} (expected horizontal|vertical)"),
    };
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<DIRECTION>

Direction to flip the image Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

fractsurf

Make a fractal surface.

create · creator · GOLDEN-ONLY

viprs fractsurf out.v width.png height.png fractal_dimension.png
let raster = decode_file(&input)?;
let result = raster.try_fractsurf()?;
save_file(&result, &output)?;
<OUT>

Output image path Required.

<WIDTH>

Image width in pixels (>= 1) Required.

<HEIGHT>

Image height in pixels (>= 1) Required.

<FRACTAL_DIMENSION>

Fractal dimension (vips 2..3) Required.

freqmult

Multiply an image by a mask in Fourier space.

freqfilt · n-image->image · FOURIER

viprs freqmult in.png mask.png out.v --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let mask = io::load(&mask_path, &limits)?;
    let out = raster.try_freqmult(&mask)?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<MASK>

Input mask image (a real float mask, same size as IN) Required.

<OUT>

Output image Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

fwfft

Forward 2D fast Fourier transform (real or complex input → complex spectrum).

freqfilt · image->image · FOURIER

viprs fwfft in.png out.v --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_fwfft()?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output spectrum (write to .v — a complex float-pair raster) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

gamma

Apply a gamma curve to an image.

conversion · image->image · EXACT

viprs gamma in.png out.v --exponent E --max-width PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_gamma(exponent)?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

--exponent <E>

Gamma factor (finite, in 1e-6..=1000; vips default 0.416667 = 1/2.4)

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

gaussblur

Gaussian-blur an image.

convolution · image->image · EXACT

viprs gaussblur in.png out.v sigma.png --min-ampl 0.2 --precision integer
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_gaussblur(sigma, min_ampl, precision)?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<SIGMA>

Sigma of the Gaussian (0..=1000) Required.

--min-ampl <A>

Minimum amplitude of the Gaussian (0.001..=1) Default: 0.2

--precision <integer|float>

Calculation precision (integer|float; vips's approximate is not core-backed) One of: integer, float. Default: integer

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

gaussmat

Make a Gaussian mask matrix.

convolution · creator · BOUNDED-TOL

viprs gaussmat out.v sigma.png min-ampl.png --separable --precision integer
    let kernel = Kernel::try_gaussmat(sigma, min_ampl, separable, precision)?;
    save_matrix(&kernel, &out)?;
<OUT>

Output matrix (.v) Required.

<SIGMA>

Sigma of the Gaussian (1e-06..=10000) Required.

<MIN-AMPL>

Minimum amplitude of the Gaussian (1e-06..=10000) Required.

--separable

Generate the separable (1xN centre row) form

--precision <integer|float>

Calculation precision (integer|float; vips's approximate is not core-backed) One of: integer, float. Default: integer

gaussnoise

Make a Gaussian-noise image (seeded PRNG).

create · creator · GOLDEN-ONLY

viprs gaussnoise out.v width.png height.png --sigma 30 --mean 128
let raster = decode_file(&input)?;
let result = raster.try_gaussnoise(sigma, mean, seed)?;
save_file(&result, &output)?;
<OUT>

Output image path Required.

<WIDTH>

Image width in pixels (>= 1) Required.

<HEIGHT>

Image height in pixels (>= 1) Required.

--sigma <S>

Standard deviation of the noise (vips --sigma, default 30, >= 0) Default: 30

--mean <M>

Mean of the noise (vips --mean, default 128) Default: 128

--seed <N>

PRNG seed (vips --seed gint, default 0; negatives honored) Default: 0

getpoint

Read one pixel and print its per-band values in vips numeric format.

core · image->stdout-scalar · EXACT

viprs getpoint in.png x.png y.png --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    // Bounds-check before the call: core's getpoint asserts `x < width` /
    // `y < height`, so an out-of-range coordinate must become exit 1, not abort.
    if x >= raster.width() || y >= raster.height() {
        bail!(
            "getpoint: coordinate ({x}, {y}) is out of bounds for a {}x{} image",
            raster.width(),
            raster.height()
        );
    }
    let pixel = raster.getpoint(x, y);
<IN>

Input image Required.

<X>

Column to read (>= 0) Required.

<Y>

Row to read (>= 0) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

globalbalance

Balance the brightness of an assembled viprs mosaic.

mosaicing · image->image · GOLDEN-ONLY

viprs globalbalance in.png out.v --max-width PX --max-height PX
    let mosaic = io::load(&in_path, &limits)?;
    // Errors (no / corrupt join-tree metadata, unsolvable factor system) become
    // exit 1; the output is always float, so callers write a `.v` sink.
    let out = mosaic.try_global_balance()?;
    io::save(&out, &out_path)?;
<IN>

A mosaic built by `viprs merge`/`viprs mosaic` (carries join-tree metadata) Required.

<OUT>

Output image (always float — write .v) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

gravity

Place an image within a larger canvas at a compass position.

extract · image->image · EXACT

viprs gravity in.png out.v direction.png width.png height.png --extend black --background "r g b"
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_gravity(direction, width, height, extend, background.as_deref())?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<DIRECTION>

Compass position to place the image at Required.

<WIDTH>

Canvas width in pixels Required.

<HEIGHT>

Canvas height in pixels Required.

--extend <black|copy|repeat|mirror|white|background>

How to fill the pixels around the input One of: black, copy, repeat, mirror, white, background. Default: black

--background <"r g b">

Background colour for --extend background (space-separated, one value or one per band)

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

grey

Create a horizontal grey ramp image.

conversion · creator · BOUNDED-TOL

viprs grey out.v width.png height.png --uchar
    let out = Raster::try_grey(width, height, uchar)?;
    io::save(&out, &out_path)?;
<OUT>

Output image Required.

<WIDTH>

Image width in pixels (>= 1) Required.

<HEIGHT>

Image height in pixels (>= 1) Required.

--uchar

Output an 8-bit Gray8 ramp instead of the default float ramp

grid

Re-tile a tall stack of tiles into a grid.

conversion · image->image · EXACT

viprs grid in.png out.v tile-height.png across.png down.png --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_grid(tile_height, across, down)?;
    io::save(&out, &out_path)?;
<IN>

Input image (a vertical tile stack) Required.

<OUT>

Output image Required.

<TILE-HEIGHT>

Height of each tile in pixels (>= 1) Required.

<ACROSS>

Number of tiles across the output grid (>= 1) Required.

<DOWN>

Number of tiles down the output grid (>= 1) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

hist_cum

Form the cumulative histogram (running sum).

histogram · image->image · EXACT

viprs hist_cum in.png out.v --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_hist_cum()?;
    io::save(&out, &out_path)?;
<IN>

Input histogram Required.

<OUT>

Output cumulative histogram Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

hist_entropy

Print the Shannon entropy (bits) of a histogram.

histogram · image->stdout-scalar · BOUNDED-TOL

viprs hist_entropy in.png --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let entropy = raster.try_hist_entropy()?;
<IN>

Input histogram image Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

hist_equal

Histogram-equalise an image (each band independently).

histogram · image->image · BOUNDED-TOL

viprs hist_equal in.png out.v --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.hist_equal();
    io::save(&out, &out_path)?;
<IN>

Input image (unsigned 8/16-bit) Required.

<OUT>

Output equalised image Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

hist_find

Find the per-band value histogram of an image.

histogram · image->image · EXACT

viprs hist_find in.png out.v --band -1 --max-width PX
    let raster = io::load(&in_path, &limits)?;
    let out = match band {
        None => raster.try_hist_find()?,
        Some(b) => raster.try_hist_find_band(b)?,
    };
    io::save(&out, &out_path)?;
<IN>

Input image (unsigned 8/16-bit) Required.

<OUT>

Output histogram Required.

--band <N>

Find the histogram of this band only (-1..=100000; -1 = all bands, the default) Default: -1

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

hist_find_indexed

Sum image samples into bins selected by an index image. Bins combine by SUM only (vips's max/min combine modes are not supported by the core).

histogram · n-image->image · EXACT

viprs hist_find_indexed in.png index.png out.v --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let index = io::load(&index_path, &limits)?;
    let out = raster.try_hist_find_indexed(&index)?;
    io::save(&out, &out_path)?;
<IN>

Input image (unsigned 8/16-bit) Required.

<INDEX>

One-band index image selecting the output bin per pixel Required.

<OUT>

Output histogram Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

hist_find_ndim

Find an up-to-3-dimensional histogram of an image.

histogram · image->image · EXACT

viprs hist_find_ndim in.png out.v --bins 10 --max-width PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_hist_find_ndim(Some(bins))?;
    io::save(&out, &out_path)?;
<IN>

Input image (unsigned 8/16-bit, 1-3 bands) Required.

<OUT>

Output histogram cube Required.

--bins <N>

Number of bins in each dimension (1..=65536; default 10) Default: 10

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

hist_ismonotonic

Print whether a histogram is monotonically non-decreasing.

histogram · image->stdout-scalar · EXACT

viprs hist_ismonotonic in.png --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let monotonic = raster.try_hist_ismonotonic()?;
<IN>

Input histogram image Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

hist_local

Local (CLAHE) histogram equalisation over a sliding window.

histogram · image->image · GOLDEN-ONLY

viprs hist_local in.png out.v width.png height.png --max-slope 0 --max-width PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_hist_local(width, height, max_slope)?;
    io::save(&out, &out_path)?;
<IN>

Input image (unsigned 8/16-bit) Required.

<OUT>

Output image Required.

<WIDTH>

Window width in pixels (1..=100000000) Required.

<HEIGHT>

Window height in pixels (1..=100000000) Required.

--max-slope <N>

CLAHE contrast limit (0..=100; 0 = unlimited, the default) Default: 0

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

hist_match

Build a LUT matching one histogram to a reference histogram.

histogram · n-image->image · GOLDEN-ONLY

viprs hist_match in.png ref.png out.v --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let reference = io::load(&ref_path, &limits)?;
    let out = raster.try_hist_match(&reference)?;
    io::save(&out, &out_path)?;
<IN>

Input histogram Required.

<REF>

Reference histogram Required.

<OUT>

Output matching LUT Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

hist_norm

Normalise a histogram so each band's maximum equals the max index.

histogram · image->image · BOUNDED-TOL

viprs hist_norm in.png out.v --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_hist_norm()?;
    io::save(&out, &out_path)?;
<IN>

Input histogram Required.

<OUT>

Output normalised histogram Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

hist_plot

Plot a one-band histogram as a bar-graph image.

histogram · image->image · GOLDEN-ONLY

viprs hist_plot in.png out.v --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_hist_plot()?;
    io::save(&out, &out_path)?;
<IN>

Input one-band histogram Required.

<OUT>

Output plot image Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

hough_circle

Hough circle transform (scale 1), one band per radius in MIN..=MAX.

arithmetic · image->image · GOLDEN-ONLY

viprs hough_circle in.png out.v min_radius.png max_radius.png --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_hough_circle(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<IN>

Input image Required.

<OUT>

Output accumulator image (.v) Required.

<MIN_RADIUS>

Smallest radius to search for (>= 1) Required.

<MAX_RADIUS>

Largest radius to search for (>= 1) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

hough_line

Hough line transform into the fixed 256×256 accumulator.

arithmetic · image->image · GOLDEN-ONLY

viprs hough_line in.png out.v --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_hough_line(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<IN>

Input image Required.

<OUT>

Output accumulator image (.v) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

icc_export

Export a PCS image to a device colour space with an ICC profile.

colour · image->image · BOUNDED-TOL

viprs icc_export in.png out.v --output-profile PROFILE --intent perceptual
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_icc_export_with(depth, intent, output_profile.as_deref())?;
    io::save(&out, &out_path)?;
<IN>

Input PCS (Lab) image Required.

<OUT>

Output device image Required.

--output-profile <PROFILE>

ICC profile file to export to (default: the image's embedded icc-profile-data)

--intent <INTENT>

Rendering intent (perceptual|relative|saturation|absolute; vips's `auto` is not core-backed) One of: perceptual, relative, saturation, absolute. Default: relative

--depth <BITS>

Output device-space depth in bits (8 or 16) Default: 8

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

icc_import

Import a device image to the profile connection space with an ICC profile.

colour · image->image · BOUNDED-TOL

viprs icc_import in.png out.v --input-profile PROFILE --intent perceptual
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_icc_import_with(intent, input_profile.as_deref(), Some(pcs))?;
    io::save(&out, &out_path)?;
<IN>

Input device image Required.

<OUT>

Output PCS image Required.

--input-profile <PROFILE>

ICC profile file to import from (default: the image's embedded icc-profile-data)

--intent <INTENT>

Rendering intent (perceptual|relative|saturation|absolute; vips's `auto` is not core-backed) One of: perceptual, relative, saturation, absolute. Default: relative

--pcs <PCS>

Profile connection space of the output (lab|xyz) One of: lab, xyz. Default: lab

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

icc_transform

Transform a device image to another device profile in one step.

colour · image->image · BOUNDED-TOL

viprs icc_transform in.png out.v output_profile.v --input-profile PROFILE --intent perceptual
    let raster = io::load(&in_path, &limits)?;
    // Compose import→export uniformly so `--intent`/`--depth` are honoured on
    // both the `--input-profile` and the embedded-profile (input_profile=None)
    // paths — the core `try_icc_transform` wrapper would silently substitute
    // perceptual intent and the input's own depth.
    let out = raster
        .try_icc_import_with(intent, input_profile.as_deref(), None)?
        .try_icc_export_with(depth, intent, Some(&output_profile))?;
    io::save(&out, &out_path)?;
<IN>

Input device image Required.

<OUT>

Output device image Required.

<OUTPUT_PROFILE>

ICC profile file to export to (positional, as in vips) Required.

--input-profile <PROFILE>

ICC profile file to import from (default: the image's embedded icc-profile-data)

--intent <INTENT>

Rendering intent (perceptual|relative|saturation|absolute; vips's `auto` is not core-backed) One of: perceptual, relative, saturation, absolute. Default: relative

--depth <BITS>

Output device-space depth in bits (8 or 16) Default: 8

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

identity

Create a 1-D identity look-up table image.

conversion · creator · EXACT

viprs identity out.v --ushort
    // Both constructors are infallible (fixed-size LUTs), so there is no
    // `try_identity` to call.
    let out = if ushort {
        Raster::identity_ushort()
    } else {
        Raster::identity()
    };
    io::save(&out, &out_path)?;
<OUT>

Output image Required.

--ushort

Create a 16-bit (65536×1 Gray16) LUT instead of the 8-bit (256×1) LUT

ifthenelse

Select pixels from two images under a condition image.

conversion · n-image->image · EXACT

viprs ifthenelse cond.png in1.png in2.png out.v --max-width PX --max-height PX
    let cond = io::load(&cond_path, &limits)?;
    let then = io::load(&in1_path, &limits)?;
    let otherwise = io::load(&in2_path, &limits)?;
    let out = cond.try_ifthenelse(&then, &otherwise)?;
    io::save(&out, &out_path)?;
<COND>

Condition image (non-zero = pick IN1) Required.

<IN1>

Source for TRUE (non-zero) pixels Required.

<IN2>

Source for FALSE (zero) pixels Required.

<OUT>

Output image Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

insert

Insert one image onto another at a position.

extract · n-image->image · EXACT

viprs insert main.png sub.png out.v x.png y.png --expand --background "r g b"
    let main = io::load(&main_path, &limits)?;
    let sub = io::load(&sub_path, &limits)?;
    let out = main.try_insert(&sub, x, y, expand, background.as_deref())?;
    io::save(&out, &out_path)?;
<MAIN>

Main (background) image Required.

<SUB>

Sub-image to insert Required.

<OUT>

Output image Required.

<X>

Left edge of the sub-image in the main image Required.

<Y>

Top edge of the sub-image in the main image Required.

--expand

Expand the output to hold all of both inputs (new pixels use --background, default black)

--background <"r g b">

Background colour for --extend background (space-separated, one value or one per band)

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

invertlut

Build an inverse look-up table from a matrix of measured (x, f(x)) rows.

matrix · image->image · BOUNDED-TOL

viprs invertlut in.png out.v --size 256
    let matrix = load_matrix(&in_path)?;
    let out = matrix.try_invertlut_size(size)?;
    io::save(&out, &out_path)?;
<IN>

Input matrix of measured points (column 0 = input level, each further column = one band's response, all in 0..=1), as a vips text-matrix file Required.

<OUT>

Output LUT path (use .v: a float matrix carrier) Required.

--size <N>

LUT size to generate (vips range 1..=1000000, default 256) Default: 256

invfft

Inverse 2D fast Fourier transform; --real keeps only the real part.

freqfilt · image->image · FOURIER

viprs invfft in.png out.v --real --max-width PX
    let raster = io::load(&in_path, &limits)?;
    let out = if real {
        raster.try_invfft_real()?
    } else {
        raster.try_invfft()?
    };
    io::save(&out, &out_path)?;
<IN>

Input image / spectrum Required.

<OUT>

Output image (write to .v — complex, or real with --real) Required.

--real

Output only the real part of the transform (vips `invfft --real`, the folded `invfft_real` op)

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

labelregions

Label 4-connected regions; write the label mask and print the segment count.

morphology · image->two-outputs · EXACT

viprs labelregions in.png mask_out.v --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let (mask, segments) = raster.try_label_regions()?;
    io::save(&mask, &mask_out)?;
<IN>

Input image Required.

<MASK_OUT>

Output path for the Gray16 label mask Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

linear

Compute a·in + b (scalar, broadcast across bands); float out, or uchar with --uchar.

arithmetic · image->image · EXACT-AFTER-CAST

viprs linear in.png out.v a.png b.png --uchar --max-width PX
let raster = decode_file(&input)?;
let result = raster.try_linear(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<A>

Multiplier as a space-separated vector (a single scalar is broadcast) Required.

<B>

Addend as a space-separated vector (a single scalar is broadcast) Required.

--uchar

Clip and truncate the result into an 8-bit image (vips --uchar)

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

logmat

Make a Laplacian-of-Gaussian mask matrix.

convolution · creator · BOUNDED-TOL

viprs logmat out.v sigma.png min-ampl.png --separable --precision integer
    let kernel = Kernel::try_logmat(sigma, min_ampl, separable, precision)?;
    save_matrix(&kernel, &out)?;
<OUT>

Output matrix (.v) Required.

<SIGMA>

Radius of the Gaussian (1e-06..=10000) Required.

<MIN-AMPL>

Minimum amplitude of the Gaussian (1e-06..=10000) Required.

--separable

Generate the separable (1xN centre row) form

--precision <integer|float>

Calculation precision (integer|float; vips's approximate is not core-backed) One of: integer, float. Default: integer

mapim

Resample an image through a two-band coordinate index image.

resample · n-image->image · BOUNDED-TOL

viprs mapim in.png out.v index.png --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let index = io::load(&index_path, &limits)?;
    let out = raster.try_mapim(&index, interpolate)?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<INDEX>

Two-band coordinate index image (band 0 = source x, band 1 = source y) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

--interpolate <I>

Point interpolator (nearest|bilinear|bicubic|nohalo|lbb) One of: nearest, bilinear, bicubic, nohalo, lbb. Default: bilinear

maplut

Map every sample of an image through a look-up table. The LUT applies to ALL bands (vips's per-band `--band` selection is not supported by the core).

histogram · n-image->image · EXACT

viprs maplut in.png out.v lut.png --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let lut = io::load(&lut_path, &limits)?;
    let out = raster.try_maplut(&lut)?;
    io::save(&out, &out_path)?;
<IN>

Input image (unsigned 8/16-bit) Required.

<OUT>

Output mapped image Required.

<LUT>

Look-up table image (histogram-shaped: Nx1 or 1xN) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

mask_butterworth

Make a Butterworth frequency-domain filter mask.

create · creator · BOUNDED-TOL

viprs mask_butterworth out.v width.png height.png order.png frequency_cutoff.png amplitude_cutoff.png --nodc --optical
let raster = decode_file(&input)?;
let result = raster.try_mask_butterworth()?;
save_file(&result, &output)?;
<OUT>

Output image path Required.

<WIDTH>

Image width in pixels (>= 1) Required.

<HEIGHT>

Image height in pixels (>= 1) Required.

<ORDER>

Filter order (vips >= 1) Required.

<FREQUENCY_CUTOFF>

Frequency cutoff (vips >= 0) Required.

<AMPLITUDE_CUTOFF>

Amplitude cutoff (vips 0..1) Required.

--nodc

Remove the DC component (vips --nodc)

--optical

Rotate quadrants to optical space (vips --optical)

--uchar

Output an unsigned char image (vips --uchar)

mask_butterworth_band

Make a Butterworth band filter mask.

create · creator · BOUNDED-TOL

viprs mask_butterworth_band out.v width.png height.png order.png frequency_cutoff_x.png frequency_cutoff_y.png radius.png amplitude_cutoff.png --uchar --optical
let raster = decode_file(&input)?;
let result = raster.try_mask_butterworth_band()?;
save_file(&result, &output)?;
<OUT>

Output image path Required.

<WIDTH>

Image width in pixels (>= 1) Required.

<HEIGHT>

Image height in pixels (>= 1) Required.

<ORDER>

Filter order (vips >= 1) Required.

<FREQUENCY_CUTOFF_X>

Frequency cutoff x (vips >= 0) Required.

<FREQUENCY_CUTOFF_Y>

Frequency cutoff y (vips >= 0) Required.

<RADIUS>

Radius of the circle (vips >= 0) Required.

<AMPLITUDE_CUTOFF>

Amplitude cutoff (vips 0..1) Required.

--uchar

Output an unsigned char image (vips --uchar)

--optical

Rotate quadrants to optical space (vips --optical)

--nodc

Remove the DC component (vips --nodc)

mask_butterworth_ring

Make a Butterworth ring filter mask.

create · creator · BOUNDED-TOL

viprs mask_butterworth_ring out.v width.png height.png order.png frequency_cutoff.png amplitude_cutoff.png ringwidth.png --nodc
let raster = decode_file(&input)?;
let result = raster.try_mask_butterworth_ring()?;
save_file(&result, &output)?;
<OUT>

Output image path Required.

<WIDTH>

Image width in pixels (>= 1) Required.

<HEIGHT>

Image height in pixels (>= 1) Required.

<ORDER>

Filter order (vips >= 1) Required.

<FREQUENCY_CUTOFF>

Frequency cutoff (vips >= 0) Required.

<AMPLITUDE_CUTOFF>

Amplitude cutoff (vips 0..1) Required.

<RINGWIDTH>

Ring width (vips >= 0) Required.

--nodc

Remove the DC component (vips --nodc)

mask_fractal

Make a fractal power-spectrum filter mask.

create · creator · BOUNDED-TOL

viprs mask_fractal out.v width.png height.png fractal_dimension.png
let raster = decode_file(&input)?;
let result = raster.try_mask_fractal()?;
save_file(&result, &output)?;
<OUT>

Output image path Required.

<WIDTH>

Image width in pixels (>= 1) Required.

<HEIGHT>

Image height in pixels (>= 1) Required.

<FRACTAL_DIMENSION>

Fractal dimension (vips 2..3) Required.

mask_gaussian

Make a Gaussian frequency-domain filter mask.

create · creator · BOUNDED-TOL

viprs mask_gaussian out.v width.png height.png frequency_cutoff.png amplitude_cutoff.png --nodc
let raster = decode_file(&input)?;
let result = raster.try_mask_gaussian()?;
save_file(&result, &output)?;
<OUT>

Output image path Required.

<WIDTH>

Image width in pixels (>= 1) Required.

<HEIGHT>

Image height in pixels (>= 1) Required.

<FREQUENCY_CUTOFF>

Frequency cutoff (vips >= 0) Required.

<AMPLITUDE_CUTOFF>

Amplitude cutoff (vips 0..1) Required.

--nodc

Remove the DC component (vips --nodc)

mask_gaussian_band

Make a Gaussian band filter mask.

create · creator · BOUNDED-TOL

viprs mask_gaussian_band out.v width.png height.png frequency_cutoff_x.png frequency_cutoff_y.png radius.png amplitude_cutoff.png
let raster = decode_file(&input)?;
let result = raster.try_mask_gaussian_band()?;
save_file(&result, &output)?;
<OUT>

Output image path Required.

<WIDTH>

Image width in pixels (>= 1) Required.

<HEIGHT>

Image height in pixels (>= 1) Required.

<FREQUENCY_CUTOFF_X>

Frequency cutoff x (vips >= 0) Required.

<FREQUENCY_CUTOFF_Y>

Frequency cutoff y (vips >= 0) Required.

<RADIUS>

Radius of the circle (vips >= 0) Required.

<AMPLITUDE_CUTOFF>

Amplitude cutoff (vips 0..1) Required.

mask_gaussian_ring

Make a Gaussian ring filter mask.

create · creator · BOUNDED-TOL

viprs mask_gaussian_ring out.v width.png height.png frequency_cutoff.png amplitude_cutoff.png ringwidth.png --nodc
let raster = decode_file(&input)?;
let result = raster.try_mask_gaussian_ring()?;
save_file(&result, &output)?;
<OUT>

Output image path Required.

<WIDTH>

Image width in pixels (>= 1) Required.

<HEIGHT>

Image height in pixels (>= 1) Required.

<FREQUENCY_CUTOFF>

Frequency cutoff (vips >= 0) Required.

<AMPLITUDE_CUTOFF>

Amplitude cutoff (vips 0..1) Required.

<RINGWIDTH>

Ring width (vips >= 0) Required.

--nodc

Remove the DC component (vips --nodc)

mask_ideal

Make an ideal frequency-domain filter mask.

create · creator · BOUNDED-TOL

viprs mask_ideal out.v width.png height.png frequency_cutoff.png --nodc
let raster = decode_file(&input)?;
let result = raster.try_mask_ideal()?;
save_file(&result, &output)?;
<OUT>

Output image path Required.

<WIDTH>

Image width in pixels (>= 1) Required.

<HEIGHT>

Image height in pixels (>= 1) Required.

<FREQUENCY_CUTOFF>

Frequency cutoff (vips >= 0) Required.

--nodc

Remove the DC component (vips --nodc)

mask_ideal_band

Make an ideal band filter mask.

create · creator · BOUNDED-TOL

viprs mask_ideal_band out.v width.png height.png frequency_cutoff_x.png frequency_cutoff_y.png radius.png
let raster = decode_file(&input)?;
let result = raster.try_mask_ideal_band()?;
save_file(&result, &output)?;
<OUT>

Output image path Required.

<WIDTH>

Image width in pixels (>= 1) Required.

<HEIGHT>

Image height in pixels (>= 1) Required.

<FREQUENCY_CUTOFF_X>

Frequency cutoff x (vips >= 0) Required.

<FREQUENCY_CUTOFF_Y>

Frequency cutoff y (vips >= 0) Required.

<RADIUS>

Radius of the circle (vips >= 0) Required.

mask_ideal_ring

Make an ideal ring filter mask.

create · creator · BOUNDED-TOL

viprs mask_ideal_ring out.v width.png height.png frequency_cutoff.png ringwidth.png --nodc
let raster = decode_file(&input)?;
let result = raster.try_mask_ideal_ring()?;
save_file(&result, &output)?;
<OUT>

Output image path Required.

<WIDTH>

Image width in pixels (>= 1) Required.

<HEIGHT>

Image height in pixels (>= 1) Required.

<FREQUENCY_CUTOFF>

Frequency cutoff (vips >= 0) Required.

<RINGWIDTH>

Ring width (vips >= 0) Required.

--nodc

Remove the DC component (vips --nodc)

math

Apply a unary math (trig / log / exp) operation; float output.

arithmetic · image->image · FOURIER

viprs math in.png out.v op.png --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_math(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<IN>

Input image Required.

<OUT>

Output image (float; use .v) Required.

<OP>

Math operation (trig args/results are in DEGREES; asin/acos need inputs in [-1,1], log/exp domains apply) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

math2

Apply a binary math (atan2 / pow / wop) operation; float output.

arithmetic · n-image->image · FOURIER

viprs math2 left.png right.png out.v op.png --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_math2(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<LEFT>

Left-hand input image Required.

<RIGHT>

Right-hand input image Required.

<OUT>

Output image (float; use .v) Required.

<OP>

Binary math operation (pow = left^right, wop = right^left) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

math2_const

Binary math with a constant; only the power operation (pow) is core-backed.

arithmetic · image->image · EXACT-AFTER-CAST

viprs math2_const in.png out.v math2.png c.png --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_math2_const(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<MATH2>

Math operation (only pow is core-backed) Required.

<C>

Exponent constant (a single scalar; per-band vectors are not core-backed) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

matrixinvert

Invert a square matrix read from a vips text-matrix file.

matrix · image->image · EXACT-AFTER-CAST

viprs matrixinvert in.png out.v
    let matrix = load_matrix(&in_path)?;
    let out = matrix.try_matrixinvert()?;
    io::save(&out, &out_path)?;
<IN>

Input square matrix as a vips text-matrix file Required.

<OUT>

Output matrix path (use .v: a float matrix carrier) Required.

max

Find the maximum sample of an image and print it (with --x/--y, its position).

arithmetic · image->stdout-scalar · EXACT

viprs max in.png --x --y
let raster = decode_file(&input)?;
let value = raster.try_max(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
println!("{value}");
<IN>

Input image Required.

--x

Also print the horizontal position of the first maximum

--y

Also print the vertical position of the first maximum

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

maxpair

Samplewise maximum of a pair of images.

arithmetic · n-image->image · EXACT

viprs maxpair left.png right.png out.v --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_maxpair(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<LEFT>

Left-hand input image Required.

<RIGHT>

Right-hand input image Required.

<OUT>

Output image Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

measure

Measure the mean of each patch in an H×V grid and write the matrix to a .v image.

arithmetic · image->image · BOUNDED-TOL

viprs measure in.png out.v h.png v.png --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_measure(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<IN>

Input image Required.

<OUT>

Output patch-means matrix (.v) Required.

<H>

Number of patches across (>= 1) Required.

<V>

Number of patches down (>= 1) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

merge

Merge two overlapping images with a feathered seam.

mosaicing · n-image->image · EXACT

viprs merge ref.png sec.png out.v direction.png dx.png dy.png --mblend 10 --max-width PX
    let reference = io::load(&ref_path, &limits)?;
    let secondary = io::load(&sec_path, &limits)?;
    let out = reference.try_merge(&secondary, dir, dx, dy)?;
    io::save(&out, &out_path)?;
<REF>

Reference image (placed at the origin) Required.

<SEC>

Secondary image (displaced by DX/DY) Required.

<OUT>

Output image Required.

<DIRECTION>

Join direction (REF on the left/top respectively) Required.

<DX>

Horizontal displacement from SEC to REF Required.

<DY>

Vertical displacement from SEC to REF Required.

--mblend <N>

Maximum blend width (vips default 10; the core fixes this at 10, so any other value is rejected) Default: 10

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

min

Find the minimum sample of an image and print it (with --x/--y, its position).

arithmetic · image->stdout-scalar · EXACT

viprs min in.png --x --y
let raster = decode_file(&input)?;
let value = raster.try_min(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
println!("{value}");
<IN>

Input image Required.

--x

Also print the horizontal position of the first minimum

--y

Also print the vertical position of the first minimum

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

minpair

Samplewise minimum of a pair of images.

arithmetic · n-image->image · EXACT

viprs minpair left.png right.png out.v --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_minpair(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<LEFT>

Left-hand input image Required.

<RIGHT>

Right-hand input image Required.

<OUT>

Output image Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

morph

Erode or dilate a binary image with a morphological mask.

morphology · image->image · EXACT

viprs morph in.png out.v mask.png op.png --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let out = match op {
        "erode" => raster.try_erode(&mask_refs)?,
        "dilate" => raster.try_dilate(&mask_refs)?,
        other => bail!("unknown morph operation {other:?} (expected erode|dilate)"),
    };
    io::save(&out, &out_path)?;
<IN>

Input image (8-bit) Required.

<OUT>

Output image Required.

<MASK>

Structuring element as a vips text matrix (values 0/128/255) Required.

<OP>

Morphological operation Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

mosaic

Join two images by refining an approximate tie-point.

mosaicing · n-image->image · EXACT

viprs mosaic ref.png sec.png out.v direction.png xref.png yref.png xsec.png ysec.png --max-width PX --max-height PX
    let reference = io::load(&ref_path, &limits)?;
    let secondary = io::load(&sec_path, &limits)?;
    // The discrete tie-point search runs entirely inside try_mosaic (the search
    // failure modes surface as typed errors → exit 1, never a panic).
    let out = reference.try_mosaic(&secondary, dir, xref, yref, xsec, ysec)?;
    io::save(&out, &out_path)?;
<REF>

Reference image (placed at the origin) Required.

<SEC>

Secondary image Required.

<OUT>

Output image Required.

<DIRECTION>

Join direction (REF on the left/top respectively) Required.

<XREF>

Reference tie-point x (in REF) Required.

<YREF>

Reference tie-point y (in REF) Required.

<XSEC>

Secondary tie-point x (in SEC) Required.

<YSEC>

Secondary tie-point y (in SEC) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

msb

Pick the most-significant byte of each sample.

conversion · image->image · EXACT

viprs msb in.png out.v --band -1 --max-width PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_msb(band)?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

--band <N>

Band to take the MSB of (>= -1; -1 = all bands, the default) Default: -1

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

multiply

Multiply two images samplewise.

arithmetic · n-image->image · EXACT-AFTER-CAST

viprs multiply left.png right.png out.v --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_multiply(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<LEFT>

Left-hand input image Required.

<RIGHT>

Right-hand input image Required.

<OUT>

Output image Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

percent

Print the threshold below which a given percent of pixels lie.

histogram · image->stdout-scalar · GOLDEN-ONLY

viprs percent in.png percent.png --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let threshold = raster.try_percent(percent)?;
<IN>

Input image (unsigned 8/16-bit) Required.

<PERCENT>

Percent of pixels (0..=100) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

perlin

Make a Perlin-noise image (seeded PRNG).

create · creator · GOLDEN-ONLY

viprs perlin out.v width.png height.png --seed 0
let raster = decode_file(&input)?;
let result = raster.try_perlin(seed)?;
save_file(&result, &output)?;
<OUT>

Output image path Required.

<WIDTH>

Image width in pixels (>= 1) Required.

<HEIGHT>

Image height in pixels (>= 1) Required.

--seed <N>

PRNG seed (vips --seed gint, default 0; negatives honored) Default: 0

phasecor

Phase correlation of two images (the peak is their translation).

freqfilt · n-image->image · FOURIER

viprs phasecor in.png in2.png out.v --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let other = io::load(&in2_path, &limits)?;
    let out = raster.try_phasecor(&other)?;
    io::save(&out, &out_path)?;
<IN>

First input image Required.

<IN2>

Second input image (same size as IN) Required.

<OUT>

Output correlation surface (write to .v — a real float raster) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

premultiply

Premultiply the colour bands by the alpha band.

arithmetic · image->image · BOUNDED-TOL

viprs premultiply in.png out.v --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_premultiply(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<IN>

Input image Required.

<OUT>

Output image Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

profile

Find, per column and per row, the first non-zero sample position.

arithmetic · image->two-outputs · EXACT

viprs profile in.png cols.png rows.png --max-width PX --max-height PX
let raster = decode_file(&input)?;
let value = raster.try_profile(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
println!("{value}");
<IN>

Input image Required.

<COLS>

Output columns image (.v) Required.

<ROWS>

Output rows image (.v) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

project

Sum every column and every row; write the two projection images.

arithmetic · image->two-outputs · EXACT

viprs project in.png cols.png rows.png --max-width PX --max-height PX
let raster = decode_file(&input)?;
let value = raster.try_project(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
println!("{value}");
<IN>

Input image Required.

<COLS>

Output column-sums image (.v) Required.

<ROWS>

Output row-sums image (.v) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

rank

Rank (order-statistic) filter over a sliding window.

morphology · image->image · EXACT

viprs rank in.png out.v width.png height.png index.png --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_rank(width, height, index)?;
    io::save(&out, &out_path)?;
<IN>

Input image (unsigned 8/16-bit) Required.

<OUT>

Output image Required.

<WIDTH>

Window width in pixels Required.

<HEIGHT>

Window height in pixels Required.

<INDEX>

Sorted-window index (0 = min, width*height-1 = max, middle = median) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

recomb

Recombine bands with a coefficient matrix (one output band per row).

arithmetic · image->image · EXACT

viprs recomb in.png out.v m.png --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_recomb(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<M>

Coefficient matrix as a vips text matrix file (one row per output band, one column per input band) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

reduce

Downsample an image with an anti-aliasing kernel.

resample · image->image · BOUNDED-TOL

viprs reduce in.png out.v hshrink.png vshrink.png --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_reduce(hshrink, vshrink, kernel)?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<HSHRINK>

Horizontal shrink factor (>= 1) Required.

<VSHRINK>

Vertical shrink factor (>= 1) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

--kernel <K>

Resampling kernel (nearest|linear|cubic|mitchell|lanczos2|lanczos3) One of: nearest, linear, cubic, mitchell, lanczos2, lanczos3. Default: lanczos3

reduceh

Downsample an image horizontally with a kernel.

resample · image->image · BOUNDED-TOL

viprs reduceh in.png out.v hshrink.png --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_reduceh(max_width, max_height, max_coord, max_pixels, max_alloc_bytes, kernel)?;
save_file(&result, &output)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<HSHRINK>

Horizontal shrink factor (>= 1) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

--kernel <K>

Resampling kernel (nearest|linear|cubic|mitchell|lanczos2|lanczos3) One of: nearest, linear, cubic, mitchell, lanczos2, lanczos3. Default: lanczos3

reducev

Downsample an image vertically with a kernel.

resample · image->image · BOUNDED-TOL

viprs reducev in.png out.v vshrink.png --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_reducev(max_width, max_height, max_coord, max_pixels, max_alloc_bytes, kernel)?;
save_file(&result, &output)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<VSHRINK>

Vertical shrink factor (>= 1) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

--kernel <K>

Resampling kernel (nearest|linear|cubic|mitchell|lanczos2|lanczos3) One of: nearest, linear, cubic, mitchell, lanczos2, lanczos3. Default: lanczos3

relational

Samplewise relational comparison of two images (0/255 mask out).

arithmetic · n-image->image · EXACT

viprs relational left.png right.png out.v op.png --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_relational(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<LEFT>

Left-hand input image Required.

<RIGHT>

Right-hand input image Required.

<OUT>

Output image Required.

<OP>

Relational operator to apply (left OP right) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

relational_const

Samplewise relational comparison against a constant (0/255 mask out).

arithmetic · image->image · EXACT

viprs relational_const in.png out.v op.png c.png --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_relational_const(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<OP>

Relational operator to apply (in OP c) Required.

<C>

Constant compared against every sample. NOTE: vips takes a per-band constant vector; core applies ONE constant to all bands, so a single scalar is accepted here. Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

remainder_const

Remainder of every sample divided by a constant (format-preserving integer op).

arithmetic · image->image · EXACT

viprs remainder_const in.png out.v c.png --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_remainder_const(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<C>

Divisor constant (a single scalar; per-band vectors are not core-backed) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

replicate

Tile an image across and down.

extract · image->image · EXACT

viprs replicate in.png out.v across.png down.png --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_replicate(across, down)?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<ACROSS>

Repeat this many times horizontally Required.

<DOWN>

Repeat this many times vertically Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

resize

Resize an image by a scale factor.

resample · image->image · BOUNDED-TOL

viprs resize in.png out.v scale.png --vscale S --max-width PX
    let raster = io::load(&in_path, &limits)?;
    let options = ResizeOptions {
        vscale,
        kernel,
        ..ResizeOptions::default()
    };
    let out = raster.try_resize_with(scale, options)?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<SCALE>

Scale factor (> 0) Required.

--vscale <S>

Vertical scale factor (> 0); defaults to SCALE when omitted

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

--kernel <K>

Resampling kernel (nearest|linear|cubic|mitchell|lanczos2|lanczos3) One of: nearest, linear, cubic, mitchell, lanczos2, lanczos3. Default: lanczos3

rot

Rotate an image by a multiple of 90 degrees.

conversion · image->image · EXACT

viprs rot in.png out.v angle.png --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_rot(angle)?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<ANGLE>

Angle to rotate clockwise Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

rot45

Rotate an odd-sided square image by a multiple of 45 degrees.

conversion · image->image · EXACT

viprs rot45 in.png out.v --angle d0 --max-width PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_rot45(angle)?;
    io::save(&out, &out_path)?;
<IN>

Input image (odd-sided square) Required.

<OUT>

Output image Required.

--angle <d0|d45|…|d315>

Angle to rotate clockwise (vips default d45) One of: d0, d45, d90, d135, d180, d225, d270, d315. Default: d45

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

rotate

Rotate an image by an arbitrary angle in degrees.

resample · image->image · BOUNDED-TOL

viprs rotate in.png out.v angle.png --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_rotate(max_width, max_height, max_coord, max_pixels, max_alloc_bytes, interpolate)?;
save_file(&result, &output)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<ANGLE>

Rotate clockwise by this many degrees Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

--interpolate <I>

Point interpolator (nearest|bilinear|bicubic|nohalo|lbb) One of: nearest, bilinear, bicubic, nohalo, lbb. Default: bilinear

round

Round every sample with the chosen rounding mode.

arithmetic · image->image · EXACT

viprs round in.png out.v round.png --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_round(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<ROUND>

Rounding operation Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

scale

Scale an image linearly (or with a log curve) to fill 0..=255 uchar.

arithmetic · image->image · BOUNDED-TOL

viprs scale in.png out.v --log --max-width PX
let raster = decode_file(&input)?;
let result = raster.try_scale(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<IN>

Input image Required.

<OUT>

Output image Required.

--log

Use the log-scaling curve instead of a linear stretch. (vips's --exp log-curve exponent is fixed at 0.25 in core and not configurable.)

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

sdf

Make a signed distance field for a shape.

create · creator · BOUNDED-TOL

viprs sdf out.v width.png height.png shape.png --a 0 0 --b "x y"
let raster = decode_file(&input)?;
let result = raster.try_sdf(a, b, r, corners)?;
save_file(&result, &output)?;
<OUT>

Output image path Required.

<WIDTH>

Image width in pixels (>= 1) Required.

<HEIGHT>

Image height in pixels (>= 1) Required.

<SHAPE>

Shape to render (vips VipsSdfShape) Required.

--a <"x y">

Point a: circle centre / box corner / line start, INTEGER "x y" (vips --a; core SdfParams is integer-only — a §9 subset of vips's gdouble VipsArrayDouble, so "10.5 10.5" is rejected where vips would accept it) Default: 0 0

--b <"x y">

Point b: opposite box corner / line end, INTEGER "x y" (vips --b; integer-only, §9 subset of vips's gdouble)

--r <R>

Circle radius, INTEGER (vips --r, default 50, >= 0; integer-only, §9 subset of vips's gdouble — "16.5" is rejected where vips would accept it) Default: 50

--corners <"c0 c1 c2 c3">

rounded-box corner radii, clockwise from top-right, INTEGER (vips --corners; integer-only, §9 subset of vips's gdouble)

sharpen

Unsharp-mask an image for print.

convolution · image->image · BOUNDED-TOL

viprs sharpen in.png out.v --sigma 0.5 --m1 0
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_sharpen(sigma, m1, m2)?;
    io::save(&out, &out_path)?;
<IN>

Input image (sRGB / mono) Required.

<OUT>

Output image Required.

--sigma <S>

Sigma of the blur Gaussian (1e-06..=10) Default: 0.5

--m1 <M>

Slope for flat areas (vips default 0) Default: 0

--m2 <M>

Slope for jaggy areas (vips default 3) Default: 3

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

shrink

Shrink an image by integer or fractional factors with a box filter.

resample · image->image · BOUNDED-TOL

viprs shrink in.png out.v hshrink.png vshrink.png --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_shrink(hshrink, vshrink)?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<HSHRINK>

Horizontal shrink factor (>= 1) Required.

<VSHRINK>

Vertical shrink factor (>= 1) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

shrinkh

Shrink an image horizontally by an integer factor.

resample · image->image · BOUNDED-TOL

viprs shrinkh in.png out.v hshrink.png --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_shrinkh(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<HSHRINK>

Horizontal shrink factor (>= 1) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

shrinkv

Shrink an image vertically by an integer factor.

resample · image->image · BOUNDED-TOL

viprs shrinkv in.png out.v vshrink.png --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_shrinkv(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<VSHRINK>

Vertical shrink factor (>= 1) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

sign

Unit sign of every sample (−1 / 0 / 1; unsigned input yields 0/1).

arithmetic · image->image · EXACT-AFTER-CAST

viprs sign in.png out.v --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_sign(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<IN>

Input image Required.

<OUT>

Output image Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

similarity

Rotate and scale an image (similarity transform).

resample · image->image · BOUNDED-TOL

viprs similarity in.png out.v --scale 1 --angle 0
let raster = decode_file(&input)?;
let result = raster.try_similarity(scale, angle, max_width, max_height, max_coord, max_pixels, max_alloc_bytes, interpolate)?;
save_file(&result, &output)?;
<IN>

Input image Required.

<OUT>

Output image Required.

--scale <S>

Scale by this factor (> 0) Default: 1

--angle <DEG>

Rotate clockwise by this many degrees Default: 0

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

--interpolate <I>

Point interpolator (nearest|bilinear|bicubic|nohalo|lbb) One of: nearest, bilinear, bicubic, nohalo, lbb. Default: bilinear

sines

Make a 2D sine grating.

create · creator · BOUNDED-TOL

viprs sines out.v width.png height.png
let raster = decode_file(&input)?;
let result = raster.try_sines()?;
save_file(&result, &output)?;
<OUT>

Output image path Required.

<WIDTH>

Image width in pixels (>= 1) Required.

<HEIGHT>

Image height in pixels (>= 1) Required.

smartcrop

Crop to the most interesting area of an image.

extract · image->image · EXACT

viprs smartcrop in.png out.v width.png height.png --interesting centre --premultiplied
    let raster = io::load(&in_path, &limits)?;
    let (out, ax, ay) = raster.try_smartcrop(width, height, interesting, premultiplied)?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<WIDTH>

Width of the crop area Required.

<HEIGHT>

Height of the crop area Required.

--interesting <centre|entropy|attention|low|high|all>

How to measure interestingness (vips's `none` is excluded — not core-backed); prints the attention centre `x y` to stdout One of: centre, entropy, attention, low, high, all. Default: attention

--premultiplied

The input's alpha is already premultiplied (skip the internal premultiply)

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

spcor

Normalised spatial cross-correlation of an image against a template.

convolution · n-image->image · BOUNDED-TOL

viprs spcor in.png ref.png out.v --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let template = io::load(&ref_path, &limits)?;
    let out = raster.try_spcor(&template)?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<REF>

Template / reference image Required.

<OUT>

Output correlation surface (.v) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

spectrum

Make a displayable log-scaled power spectrum.

freqfilt · image->image · FOURIER

viprs spectrum in.png out.v --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_spectrum()?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output spectrum (a uchar image; DC is moved to the centre) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

stats

Compute a per-band statistics matrix and write it to a .v image.

arithmetic · image->image · BOUNDED-TOL

viprs stats in.png out.v --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_stats(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<IN>

Input image Required.

<OUT>

Output statistics matrix (.v; 6 columns min/max/sum/sum2/mean/sd) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

stdif

Statistical differencing over a sliding window.

arithmetic · image->image · EXACT

viprs stdif in.png out.v width.png height.png --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_stdif(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<WIDTH>

Window width in pixels (1..=256) Required.

<HEIGHT>

Window height in pixels (1..=256). (vips's --a --m0 --b --s0 tuning knobs are fixed at core defaults 0.5/128/0.5/50.) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

subsample

Subsample (point-decimate) an image by integer factors.

extract · image->image · EXACT

viprs subsample in.png out.v xfac.png yfac.png --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_subsample(xfac, yfac)?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<XFAC>

Horizontal subsample factor (top-left of each cell; vips's --point averaging mode is not core-backed) Required.

<YFAC>

Vertical subsample factor Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

subtract

Subtract the right image from the left (left - right).

arithmetic · n-image->image · EXACT-AFTER-CAST

viprs subtract left.png right.png out.v --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_subtract(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<LEFT>

Left-hand input image Required.

<RIGHT>

Right-hand input image Required.

<OUT>

Output image Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

sum

Sum an array of two or more images into one image.

arithmetic · n-image->image · EXACT-AFTER-CAST

viprs sum inputs.png --max-width PX --max-height PX
let raster = decode_file(&input)?;
let value = raster.try_sum(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
println!("{value}");
<INPUTS>

Two or more input images followed by the output path Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

switch

Find the index of the first non-zero condition image at each pixel.

conversion · n-image->image · EXACT

viprs switch inputs.png --max-width PX --max-height PX
    let rasters: Vec<Raster> = inputs
        .iter()
        .map(|p| io::load(p, &limits))
        .collect::<Result<_>>()?;
    let refs: Vec<&Raster> = rasters.iter().collect();
    let out = Raster::try_switch(&refs)?;
    io::save(&out, &out_path)?;
<INPUTS>

Two or more single-band condition images followed by the output path Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

text

Render text to a coverage image.

create · creator · GOLDEN-ONLY

viprs text out.v text.png --dpi DPI --width PX
let raster = decode_file(&input)?;
let result = raster.try_text(dpi, width, height, wrap)?;
save_file(&result, &output)?;
<OUT>

Output image path Required.

<TEXT>

Text to render Required.

--dpi <DPI>

Render resolution (vips --dpi, default 72)

--width <PX>

Maximum image width in pixels; wraps lines (vips --width)

--height <PX>

Maximum image height in pixels; enables dpi auto-fit (vips --height)

--wrap <word|char|word-char|none>

Line-wrap mode (vips --wrap, default word) One of: word, char, word-char, none.

thumbnail

Make a thumbnail from an image file, fitting a box.

resample · image->image · BOUNDED-TOL

viprs thumbnail filename.png out.v width.png --height PX --crop INTERESTING
let raster = decode_file(&input)?;
let result = raster.try_thumbnail(height, crop, export_profile, max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<FILENAME>

Source image file to read from Required.

<OUT>

Output image Required.

<WIDTH>

Fit within this width (>= 1) Required.

--height <PX>

Fit within this height (>= 1); a square WIDTH box when omitted

--crop <INTERESTING>

Fill the box and centre-crop (vips --crop; core supports none|centre only — `--crop` == `--crop centre`)

--linear

Reduce in linear light (square WIDTH box; not combinable with --height/--crop)

--export-profile <NAME>

Export through the embedded ICC profile to this output profile (only "srgb"; square WIDTH box; not combinable with the others)

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

thumbnail_image

Make a thumbnail from an already-loaded image.

resample · image->image · BOUNDED-TOL

viprs thumbnail_image in.png out.v width.png --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_thumbnail_image(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<WIDTH>

Fit within a square WIDTH box (>= 1) Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

tonelut

Build a print tone-mapping look-up table.

create · creator · BOUNDED-TOL

viprs tonelut out.v
let raster = decode_file(&input)?;
let result = raster.try_tonelut()?;
save_file(&result, &output)?;
<OUT>

Output image path Required.

unpremultiply

Unpremultiply (divide) the colour bands by the alpha band.

arithmetic · image->image · BOUNDED-TOL

viprs unpremultiply in.png out.v --max-width PX --max-height PX
let raster = decode_file(&input)?;
let result = raster.try_unpremultiply(max_width, max_height, max_coord, max_pixels, max_alloc_bytes)?;
save_file(&result, &output)?;
<IN>

Input image Required.

<OUT>

Output image Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

worley

Make a Worley-noise image (seeded PRNG).

create · creator · GOLDEN-ONLY

viprs worley out.v width.png height.png --seed 0
let raster = decode_file(&input)?;
let result = raster.try_worley(seed)?;
save_file(&result, &output)?;
<OUT>

Output image path Required.

<WIDTH>

Image width in pixels (>= 1) Required.

<HEIGHT>

Image height in pixels (>= 1) Required.

--seed <N>

PRNG seed (vips --seed gint, default 0; negatives honored) Default: 0

wrap

Wrap the image origin to its centre, swapping quadrants.

conversion · image->image · EXACT

viprs wrap in.png out.v --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_wrap()?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

xyz

Make an image whose pixels are their own coordinates.

create · creator · EXACT

viprs xyz out.v width.png height.png
let raster = decode_file(&input)?;
let result = raster.try_xyz()?;
save_file(&result, &output)?;
<OUT>

Output image path Required.

<WIDTH>

Image width in pixels (>= 1) Required.

<HEIGHT>

Image height in pixels (>= 1) Required.

zone

Make a zone-plate test pattern.

create · creator · BOUNDED-TOL

viprs zone out.v width.png height.png
let raster = decode_file(&input)?;
let result = raster.try_zone()?;
save_file(&result, &output)?;
<OUT>

Output image path Required.

<WIDTH>

Image width in pixels (>= 1) Required.

<HEIGHT>

Image height in pixels (>= 1) Required.

zoom

Zoom in by integer pixel replication.

extract · image->image · EXACT

viprs zoom in.png out.v xfac.png yfac.png --max-width PX --max-height PX
    let raster = io::load(&in_path, &limits)?;
    let out = raster.try_zoom(xfac, yfac)?;
    io::save(&out, &out_path)?;
<IN>

Input image Required.

<OUT>

Output image Required.

<XFAC>

Horizontal zoom factor Required.

<YFAC>

Vertical zoom factor Required.

--max-width <PX>

Reject inputs wider than PX pixels (DecodeLimits::max_width)

--max-height <PX>

Reject inputs taller than PX pixels (DecodeLimits::max_height)

--max-coord <PX>

Reject a single axis larger than PX pixels (DecodeLimits::max_coord)

--max-pixels <N>

Reject inputs with more than N total pixels (DecodeLimits::max_pixels)

--max-alloc-bytes <BYTES>

Reject a decode allocation larger than BYTES (DecodeLimits::max_alloc_bytes)

Examples

Basic pyramid generation

DeepZoom from an image (default settings)

$ viprs pyramid photo.jpg tiles/

Produces a DeepZoom pyramid at tiles/ with a companion tiles.dzi manifest. Tiles are 256×256 PNG with no overlap. The monolithic engine holds the entire image in memory.

XYZ layout with JPEG tiles

$ viprs pyramid aerial.tiff map_tiles/ \
    --layout xyz --format jpeg --quality 90

Outputs {z}/{x}/{y}.jpeg tiles ready to serve to MapLibre GL, Leaflet, or any XYZ tile client. JPEG reduces tile size ~5× vs PNG for photographic content.

Google Maps layout with centring

$ viprs pyramid gigapixel.png google_tiles/ \
    --layout google --centre

Google layout uses power-of-2 tile grids. --centre places the image in the middle of the canvas with even padding.

DeepZoom with overlap for OpenSeadragon

$ viprs pyramid scan.png viewer_tiles/ \
    --tile-size 512 --overlap 1

512px tiles with 1px overlap. OpenSeadragon uses the overlap to blend adjacent tiles for seamless rendering at high zoom.

PDF inputs

Scanned document (raster extraction)

$ viprs pyramid scan.pdf tiles/ --page 2

Extracts the embedded raster image from page 2 of the PDF. Fast and lossless — no rendering needed for scanned documents.

Vector PDF rendering with PDFium

$ viprs pyramid document.pdf tiles/ \
    --render --dpi 300

Renders the vector PDF at 300 DPI using PDFium. Required for vector-authored PDF exports, text-heavy documents, and PDFs with paths/shapes instead of embedded images.

Match page dimensions after extraction

$ viprs pyramid scan.pdf tiles/ \
    --match-page-size --dpi 150

Extracts the embedded raster, then resizes it to match the PDF page dimensions at 150 DPI. Produces output consistent with libvips' default PDF handling.

Blank tile optimization

Skip blank tiles on sparse images

$ viprs pyramid whiteboard.png tiles/ --skip-blank

Done: 341 tiles, 11 levels, peak memory 12.5 MB, 2.31s (287 blank tiles skipped)

Replaces 287 uniform-color tiles with 1-byte placeholders. Total output drops from ~45 MB to ~8 MB on a typical whiteboard scan.

Multi-threaded execution

Parallel tile extraction (monolithic engine)

$ viprs pyramid large.png tiles/ \
    --concurrency 8 --buffer-size 128

8 worker threads extract tiles in parallel from the full-resolution canvas. Buffer of 128 tiles smooths out disk I/O variance. Best when the image fits comfortably in RAM.

Memory-constrained processing

Streaming engine with explicit budget

$ viprs pyramid huge_scan.png tiles/ \
    --memory-budget 128

Streaming: budget 128.0 MB, strip_height=2048, estimated peak 98.4 MB
Done: 4521 tiles, 15 levels, peak memory 97.2 MB, 14.8s

Processes the image in 2048px-tall horizontal strips, keeping peak memory under 128 MB. The monolithic engine would need ~2 GB for this image.

Auto-select streaming budget

$ viprs pyramid huge_scan.png tiles/ --memory-budget 0

Budget is set to 1/4 of the estimated monolithic peak. The engine auto-selects: monolithic if the image is small, streaming otherwise. Best default for unknown image sizes.

Hard memory limit (safety net)

$ viprs pyramid huge.pdf tiles/ \
    --memory-limit 512 --memory-budget 128 --render --dpi 300

Exits with an error if the estimated monolithic peak exceeds 512 MB, then uses streaming with a 128 MB budget. Double protection for containers with hard memory limits.

Parallel MapReduce engine

MapReduce with concurrent strip rendering

$ viprs pyramid huge_scan.png tiles/ \
    --memory-budget 256 --parallel

MapReduce: budget 256.0 MB, strip_height=2048, 4 in-flight strips, estimated peak 198.7 MB
Done: 4521 tiles, 15 levels, peak memory 195.3 MB, 9.2s

Renders 4 strips concurrently within the 256 MB budget. ~35% faster than sequential streaming on a 4-core machine. Output is byte-identical.

MapReduce with per-strip tile workers

$ viprs pyramid huge_scan.png tiles/ \
    --memory-budget 256 --parallel --concurrency 4

Each strip also uses 4 tile-extraction workers for an additional level of parallelism. Best on systems with 8+ cores and fast storage.

MapReduce with auto budget and blank skipping

$ viprs pyramid document.pdf tiles/ \
    --memory-budget 0 --parallel --skip-blank \
    --layout google --centre

Full-featured pipeline: auto budget, parallel processing, blank tile optimization, Google layout with centring. The engine chooses the optimal strip height and in-flight count.

Geo-referenced tiles

Geo-referenced DeepZoom pyramid

$ viprs pyramid aerial.png tiles/ \
    --geo-origin "-73.9857,40.7484" --geo-scale "0.00001,-0.00001"

Maps the top-left pixel to (73.9857°W, 40.7484°N) with ~1.1m per pixel. Enables map viewers to overlay the pyramid on a world map.

Inspection and planning

Inspect a PDF file

$ viprs info document.pdf

PDF: document.pdf
Pages: 3
  Page 1: 841.89 x 595.28 pt (A4 landscape)
    Image: 3508 x 2480 px (JPEG, 1234567 bytes)
  Page 2: 841.89 x 595.28 pt
    Image: 3508 x 2480 px (JPEG, 987654 bytes)
  Page 3: 841.89 x 595.28 pt
    (no embedded raster — use --render)

Shows page dimensions, embedded raster details, and whether PDFium rendering is needed.

Preview the pyramid plan

$ viprs plan document.pdf --tile-size 256 --layout google --centre

Shows levels, tile counts, and canvas dimensions without generating any tiles. Use this to estimate output size and pick the right tile parameters.

Plan from explicit dimensions

$ viprs plan 16820 --height 11888 --layout google --centre

Plan using raw pixel dimensions instead of reading from a file.

Test images

Generate a test image for benchmarking

$ viprs test-image gradient.png --width 4096 --height 4096

Creates a 4096×4096 RGB8 gradient image. Useful for benchmarking the tile engine without needing real production images.

Full pipeline test (generate + tile)

$ viprs test-image /tmp/test.png --width 2048 --height 2048
$ viprs pyramid /tmp/test.png /tmp/tiles/ \
    --memory-budget 8 --parallel --concurrency 4 --skip-blank

End-to-end smoke test: create a synthetic image, then tile it with every engine feature enabled.

Stdin input

Pipe an image from another command

$ curl -s https://example.com/scan.png | viprs pyramid - tiles/

Use - as the input to read from stdin. Works with any command that outputs image data.

Object-storage sink

Write pyramid directly to S3

$ viprs pyramid document.pdf --sink s3://my-bucket/tiles/set-a/ \
    --format png --manifest-emit-checksums

Tiles are streamed to S3 without a local temp directory. Credentials are read from the standard AWS credential chain (AWS_ACCESS_KEY_ID, instance role, etc.). Requires compile-time --features s3.

Packfile archive

Archive a pyramid into a single .tar.gz

$ viprs pyramid scan.tiff --sink packfile://scan_tiles.tar.gz \
    --layout deep-zoom --format png

Outputs a single scan_tiles.tar.gz containing the full tile tree and the .dzi manifest. Requires compile-time --features packfile.

Resumable job

Resume an interrupted run

# First run (interrupted)
$ viprs pyramid huge.pdf tiles/ --manifest-emit-checksums
^C  # killed after 3200/4521 tiles

# Resume from checkpoint
$ viprs pyramid huge.pdf tiles/ --resume --manifest-emit-checksums
Resuming: 3200 tiles already written, 1321 remaining
Done: 4521 tiles, 15 levels, 1321 new tiles written, 6.3s

The checkpoint file tiles/.libviprs-job.json records each completed tile. On resume, only missing tiles are re-rendered.

Verify a completed run

$ viprs pyramid huge.pdf tiles/ --verify
Verified 4521 tiles. All checksums match.

Reads every tile and confirms it matches the stored digest. Non-zero exit if any tile is missing or corrupt.

Retry and failure policy

Retry transient errors, skip permanently failing tiles

$ viprs pyramid document.pdf --sink s3://my-bucket/out/ \
    --retry-max 5 --retry-backoff 500 \
    --failure-policy retry-then-skip

Each failing tile is retried up to 5 times with 500 ms initial back-off. If still failing, the tile is recorded as missing in the manifest and the job continues. Useful for long-running S3 uploads over unreliable links.

Blank-tile tolerance

Collapse near-white tiles on a noisy scan

$ viprs pyramid noisy_scan.pdf tiles/ --skip-blank --blank-tolerance 2

Done: 341 tiles, 11 levels, peak memory 12.1 MB, 2.18s (312 blank tiles skipped)

Tiles where every pixel channel is within ±2 of the background value are treated as blank. Without --blank-tolerance, scanner noise would prevent most margin tiles from matching the exact background colour.

Checksums and deduplication

Emit Blake3 checksums and deduplicate blank tiles

$ viprs pyramid document.pdf tiles/ \
    --manifest-emit-checksums --checksum-algo blake3 \
    --dedupe-blanks

The manifest records a Blake3 digest for each tile. A single copy of the blank placeholder is stored; all other blank tile paths are symlinks to it.

Full deduplication with content hashing

$ viprs pyramid document.pdf tiles/ --dedupe-all

Every tile is hashed after encoding. Duplicate content (common in tiled vector artwork) is stored once. Inode count can drop by 40–60% on typical document pyramids.

Tracing

Emit info-level spans

$ viprs pyramid document.pdf tiles/ --trace-level info

Emits libviprs::pipeline, libviprs::level, and libviprs::tile spans. Wire up a tracing-opentelemetry subscriber before calling viprs from a Rust driver, or export via the OTEL_EXPORTER_OTLP_ENDPOINT environment variable. Requires compile-time --features tracing.

Engine Comparison

Scenario Flags Engine Best for
Small image, fast disk (none) Monolithic Images that fit in RAM
Small image, multi-core --concurrency 8 Monolithic (parallel tiles) Throughput on multi-core
Large image, limited RAM --memory-budget 128 Streaming Memory-constrained containers
Large image, multi-core --memory-budget 256 --parallel MapReduce Fast + memory-bounded
Large image, max throughput --memory-budget 256 --parallel --concurrency 8 MapReduce (full parallel) Dedicated build servers

All engines produce byte-identical output. Choose based on available memory and CPU cores.

Cargo Features

Optional capabilities are gated behind Cargo features. Pass them at build time:

$ cargo install --path . --features s3,tracing,checksum,dedupe
FeatureDefaultEnables
pdfiumno--render flag (dynamic libpdfium)
pdfium-staticno--render flag (static libpdfium, larger binary)
s3no--sink s3://…
tracingno--trace-level
packfileno--sink packfile://…
checksumno--manifest-emit-checksums, --checksum-algo, --verify
dedupeno--dedupe-blanks, --dedupe-all

Exit Status

CodeMeaning
0Success
1Error (invalid args, file not found, memory limit exceeded, engine failure)

See Also

libviprs homeAPI documentationGitHub repositorylibvips (the project that inspired libviprs)