NetVips Documentation

repository·master·Indexed 19 days ago

https://github.com/kleisauke/net-vips

A .NET binding for the libvips image processing library, designed for high-performance, low-memory image manipulation using asynchronous pipelines. NetVips supports approximately 300 operations, a wide range of numeric formats, and broad format support including JPEG, PNG, WebP, AVIF, and TIFF. It utilizes a pipeline approach to stream images in parallel, avoiding the need to keep entire large images in RAM.

Tokens
5.1K
Snippets
14
Records
24
Agent score
68%

What's inside NetVips

  1. Overview of NetVips

    master

    NetVips is a .NET binding for the libvips image processing library. It is designed for high performance and low memory usage.

    Key features include:

    • High Performance: Benchmarks indicate it is significantly faster than Magick.NET and ImageSharp.
    • Extensive Operations: Supports approximately 300 operations including arithmetic, histograms, convolution, morphological operations, frequency filtering, colour, resampling, and statistics.
    • Flexible Data Types: Supports a wide range of numeric formats from 8-bit integer to 128-bit complex, and handles images with any number of bands.
    • Broad Format Support: Supports standard formats (JPEG, PNG, WebP, HEIC, AVIF, etc.) as well as scientific/technical formats (RAW, OpenEXR, FITS, etc.). It can also leverage ImageMagick or GraphicsMagick to support additional formats like DICOM.
  2. Perform draw operations safely using Mutate

    master

    Paint operations like DrawCircle and DrawLine are destructive; they modify the input image directly. Using them on shared images can lead to crashes or unpredictable behavior due to the way libvips manages memory and concurrency.

    To use these operations safely, use the image.Mutate method. This creates a MutableImage that is unshared and only accessible within the scope of the provided delegate. Once the delegate finishes, the changes are applied back to the original image.

    Workflow:

    1. Call image.Mutate(mutable => { ... }).
    2. Inside the delegate, use mutable (which is a MutableImage) to call draw operations.
    3. The MutableImage is only valid inside the delegate.
    using var mutated = image.Mutate(mutable =>
    {
        for (var i = 0; i <= 100; i++)
        {
            var j = i / 100.0;
            mutable.DrawLine(new[] { 255.0 }, (int)(mutable.Width * j), 0, 0, (int)(mutable.Height * (1 - j)));
        }
    });
  3. How NetVips works

    master
    NetVips does not manipulate images directly in memory. Instead, it builds a pipeline of image processing operations starting from a source image. The entire pipeline executes only when the end of the pipe is connected to a destination (e.g., writing to a file). This allows the library to stream the image in parallel, processing it section by section. This approach makes NetVips highly efficient, fast, and light on memory, as it avoids keeping entire large images in RAM.
  4. Call libvips operations and handle chaining

    master

    Most libvips operations are exposed as PascalCase methods on the Image class (e.g., vips_add becomes Add).

    Chaining and Memory Management

    Operations return a new Image and can be chained. Warning: Chaining does not automatically dispose of temporary intermediate images. This can lead to high memory usage until the next GC cycle.

    To manage memory correctly, use one of two patterns:

    1. Explicit using statements: Wrap every intermediate image in a using block.
    2. VipsArena: Wrap a sequence of operations in a VipsArena block to handle disposal automatically.

    Argument Expansion

    • Optional Arguments: NetVips uses nullable types to allow omitting optional libvips parameters.
    • Constant Expansion: If an operation expects an image but you provide a constant (like an array or a single value), the wrapper automatically expands it to match the required shape (e.g., in Ifthenelse or Bandjoin).
    // Pattern 1: Explicit using for memory safety
    using var real = image.Real();
    using var resultImage = real.Cos();
    
    // Pattern 2: VipsArena for automatic disposal of intermediates
    using (var arena = new VipsArena())
    {
        var img = Image.NewFromFile("input.jpg");
        img = img.Real().Cos(); // Intermediates are cleaned up by the arena
    }
    
    // Constant expansion example: adding an alpha channel
    using var rgba = rgb.Bandjoin(255);
  5. Install NetVips and native binaries

    master

    To use NetVips, you must install the NetVips NuGet package and ensure the libvips shared library (version 8.2 or later) is available on your library search path.

    Instead of manually managing the shared library, it is recommended to install the corresponding NetVips.Native.* NuGet package for your specific platform. These packages contain the pre-compiled binaries for common platforms including:

    • Windows: NetVips.Native.win-x64, NetVips.Native.win-x86, NetVips.Native.win-arm64
    • Linux: NetVips.Native.linux-x64 (glibc), NetVips.Native.linux-musl-x64 (musl), NetVips.Native.linux-arm64 (glibc), NetVips.Native.linux-musl-arm64 (musl), NetVips.Native.linux-arm (ARMv7)
    • macOS: NetVips.Native.osx-x64, NetVips.Native.osx-arm64

    Supported input formats include JPEG, PNG, Ultra HDR, WebP, AVIF, TIFF, GIF, and SVG.

    Install-Package NetVips
  6. How to load images from different sources

    master

    NetVips provides several ways to initialize an Image object:

    • From File: Image.NewFromFile(path, access: Enums.Access.Sequential)
    • From Buffer: Image.NewFromBuffer(buffer) (for formatted images in memory).
    • From C# Memory: Image.NewFromMemory(array) (wraps C-style memory arrays held as C# arrays).
    • From Constants: Image.NewFromArray(array, scale: double) (creates an image from an array constant).
    • Custom Sources/Targets: Link processing pipelines to your own code via custom sources and targets.
  7. Install NetVips.Native via NuGet

    master

    To use NetVips, you need the native binaries. You can install the NetVips.Native package, which acts as a meta-package depending on the specific platform-based NetVips.Native.* packages.

    Available platform-specific packages include:

    • NetVips.Native.linux-x64: Linux x64 glibc (Ubuntu, Debian, etc.)
    • NetVips.Native.linux-musl-x64: Linux x64 musl (Alpine, Gentoo Linux, etc.)
    • NetVips.Native.osx-x64: macOS x64
    • NetVips.Native.win-x64: Windows 64-bit
    • NetVips.Native.win-x86: Windows 32-bit
    dotnet add package NetVips.Native
  8. Track and interrupt image computation progress

    master

    You can monitor the progress of image operations by attaching progress handlers to an Image. This is useful for long-running computations where you want to report progress to a UI or cancel the operation if it takes too long.

    Using IProgress<int>

    You can pass an IProgress<int> to image.SetProgress(progress, cancellationToken). The progress handler will receive the completion percentage.

    Using Signals

    Alternatively, you can enable progress tracking with image.SetProgress(true) and connect to specific signals using image.SignalConnect. Supported signals include:

    • Enums.Signals.PreEval: Before evaluation starts.
    • Enums.Signals.Eval: During evaluation.
    • Enums.Signals.PostEval: After evaluation completes.

    Handlers receive a VipsProgress struct containing fields like Run (run time), Eta (estimated time of arrival), TPels (total pixels), NPels (pixels processed), and Percent (percent complete).

    Interrupting Computation

    To stop a computation early based on progress, use image.SetKill(true) inside a signal handler.

    // Example: Using IProgress and CancellationToken
    using var image = Image.Black(1, 500);
    var progress = new Progress<int>(percent =>
    {
        Console.Write($"\r{percent}% complete");
    });
    
    var cts = new CancellationTokenSource();
    cts.CancelAfter(5000);
    
    image.SetProgress(progress, cts.Token);
    var avg = image.Avg();
    
    // Example: Using Signals and SetKill
    image.SetProgress(true);
    image.SignalConnect(Enums.Signals.Eval, (img, progress) => 
    {
        if (progress.Percent > 50) 
        {
            img.SetKill(true);
        }
    });
    var avg = image.Avg();
  9. Configure logging and warnings

    master

    You can capture warnings and debug messages from the underlying libvips library by setting a log handler. This is useful for detecting issues like truncated files.

    Use Log.SetLogHandler to define a callback. Remember to call Log.RemoveLogHandler when you no longer need it to prevent leaks.

    // Set up a handler for VIPS warnings
    var _handlerId = Log.SetLogHandler("VIPS", Enums.LogLevelFlags.Warning, (domain, level, message) =>
    {
        Console.WriteLine($"Domain: '{domain}' Level: {level}");
        Console.WriteLine($"Message: {message}");
    });
    
    // Later, remove it
    Log.RemoveLogHandler("VIPS", _handlerId);
  10. Manage image metadata and attributes

    master

    Images in NetVips are immutable. To modify metadata, you must use the Mutate method.

    Reading Metadata

    • Use image.Get("field-name") to retrieve specific metadata (e.g., iptc-data, exif-ifd0-DateTime).
    • Use image.GetFields() to list all available field names.
    • Common properties like .Width are available as direct C# properties.

    Writing/Modifying Metadata

    • Use image.Mutate(mutable => { ... }) to perform changes. Inside the delegate, use mutable.Set(key, value) or mutable.Remove(key).

    Cloning Images

    Because libvips shares images between parts of your program, you cannot modify an image unless you own the only reference. Use image.Copy(xres, yres) to create a private clone.

    // Reading metadata
    var iptcString = image.Get("iptc-data");
    
    // Creating a private clone with new resolution
    using var newImage = image.Copy(xres: 12, yres: 13);
    
    // Modifying metadata (removing all except icc-profile-data)
    using var mutated = image.Mutate(mutable =>
    {
        foreach (var field in image.GetFields())
        {
            if (field == "icc-profile-data") continue;
            mutable.Remove(field);
        }
    });
  11. Troubleshoot NetVips initialization errors

    master

    If NetVips fails to initialize, check the following common error scenarios:

    Inner exceptionHRESULTSolution
    DllNotFoundException0x8007007EEnsure the bin folder of the libvips Windows build is in your PATH environment variable (if not using the native NuGet packages).
    BadImageFormatException0x8007000BIf targeting AnyCPU, ensure Prefer 32-bit is unchecked. Alternatively, target x64 explicitly.