pyvips Documentation

repository·master·Indexed 21 days ago

https://github.com/libvips/pyvips

Python bindings for the libvips image processing library. pyvips provides a demand-driven, streamed pipeline approach for high-speed, low-memory image processing. It includes support for NumPy and PIL integration, color space transformations, affine transformations, and custom I/O via Source and Target classes.

Tokens
41.9K
Snippets
215
Records
240
Agent score
73%

What's inside pyvips

  1. How pyvips processes images

    master

    Unlike many image libraries, pyvips does not manipulate images directly in memory. Instead, it builds a pipeline of operations.

    When the end of the pipeline is connected to a destination (like a file write), the entire pipeline executes at once. The image is streamed in parallel from source to destination one section at a time. This approach makes pyvips extremely fast and memory-efficient, as it avoids loading entire large images into memory.

  2. Use libvips enums in pyvips

    master

    The pyvips.enums module provides Python classes representing various libvips enumerations.

    In pyvips, enum values are passed to API methods as strings. The enum classes serve as a source of truth for these valid string values, helping to prevent typos and providing discoverability via IDE autocompletion.

    Instead of manually typing strings like 'bilinear' or 'lanczos3', you should use the corresponding attribute from the enum classes in pyvips.enums.

  3. Understand the behavior of Draw operations

    master

    Paint operations such as Image.draw_circle and Image.draw_line modify their input image in-place. Because libvips is typically lazy and functional, these operations can cause crashes if not handled carefully.

    To prevent crashes, the pyvips wrapper automatically creates a private in-memory copy of the image before executing a drawing operation.

    Performance Note: This automatic copying makes drawing operations inefficient. If you perform many drawing operations (e.g., drawing 100 lines), the wrapper will perform 100 copies. While the wrapper attempts to recycle memory, this is still significantly slower than standard libvips operations. To avoid this overhead, you must call the underlying drawing operations yourself via the C API or equivalent low-level methods.

  4. Understand the VipsObject class

    master
    In pyvips, VipsObject is the base class for all objects that interact with the underlying libvips C library. Most high-level objects you use, such as images (VipsImage) or operations, inherit from VipsObject. It provides the fundamental interface for managing the lifecycle and properties of libvips objects within Python.
  5. Automatic expansion of enum-based operators

    master

    Some libvips operators use enums to select an action (e.g., vips_math with a 'sin' argument). pyvips automatically expands these enums into dedicated method names for convenience.

    Instead of: image.math('sin')

    You can use: image.sin()

  6. How pyvips handles image metadata and attributes

    master

    pyvips uses __getattr__ to allow accessing libvips properties and operations directly as attributes.

    Reading Metadata

    Use image.get(key) to retrieve metadata. You can use image.get_fields() to see all available field names.

    Modifying Metadata

    Because libvips caches and shares images, you cannot modify an image in place. To change metadata, you must first create a private copy using .copy().

    # Get metadata
    exif_date = image.get('exif-ifd0-DateTime')
    
    # Set metadata (must copy first)
    new_image = image.copy().set('icc-profile-data', new_profile)
  7. Configure libvips DLL path on Windows

    master

    On Windows, if you do not want to add the libvips bin directory to your system PATH, you can configure it programmatically at the start of your application. This is necessary for pyvips to find the required DLLs.

    For Python 3.8 and later, use os.add_dll_directory.

    import os
    vipsbin = r'c:\vips-dev-8.16\bin'
    add_dll_dir = getattr(os, 'add_dll_directory', None)
    if callable(add_dll_dir):
        add_dll_dir(vipsbin)
    else:
        os.environ['PATH'] = os.pathsep.join((vipsbin, os.environ['PATH']))
    
    import pyvips
  8. Install pyvips via binary package

    master

    The quickest way to start is by installing the self-contained binary package. This includes the most commonly needed libraries and works on most platforms (Linux, Windows, macOS) across 64/32-bit x64 and ARM CPUs.

    Note: The binary version is missing certain features like PDF loading and OpenSlide support.

    $ pip install "pyvips[binary]"
  9. Enable type checking for pyvips

    master

    pyvips provides type hints via PEP 561 type stub files (pyvips/__init__.pyi). To use them, install mypy and pyvips, then run mypy on your script.

    Note: pyvips methods accept arbitrary keyword arguments for libvips options which may not be fully covered by the type hints.

    $ pip install mypy pyvips
    $ mypy your_script.py
  10. Implement custom Sources and Targets

    master

    You can define custom I/O behavior by using pyvips.SourceCustom and pyvips.TargetCustom. This is useful for reading from or writing to non-standard streams (e.g., custom memory buffers or network sockets).

    • For a SourceCustom, use source.on_read(read_handler) where read_handler accepts a size and returns the data read.
    • For a TargetCustom, use target.on_write(write_handler) where write_handler accepts a chunk and returns the number of bytes written.
    • You can also define seek and finish handlers for more complex requirements.
    import sys
    
    # Custom Source example
    input_file = open(sys.argv[1], "rb")
    def read_handler(size):
        return input_file.read(size)
    
    source = pyvips.SourceCustom()
    source.on_read(read_handler)
    
    # Custom Target example
    output_file = open(sys.argv[2], "wb")
    def write_handler(chunk):
        return output_file.write(chunk)
    
    target = pyvips.TargetCustom()
    target.on_write(write_handler)
    
    image = pyvips.Image.new_from_source(source, '', access='sequential')
    image.write_to_target(target, '.png')
  11. Convert between pyvips, NumPy, and PIL

    master

    pyvips integrates easily with NumPy and PIL for data exchange.

    pyvips to NumPy/PIL

    • Use image.numpy() or numpy.asarray(image) to convert a pyvips image to a NumPy array.
    • Use image.pil() to convert a pyvips image to a PIL image.

    NumPy/PIL to pyvips

    • Use pyvips.Image.new_from_array(array) to create an image from a NumPy array or a PIL image.
    import pyvips
    import numpy as np
    import PIL.Image
    
    # NumPy to pyvips
    a = (np.random.random((100, 100, 3)) * 255).astype(np.uint8)
    image = pyvips.Image.new_from_array(a)
    
    # PIL to pyvips
    pil_image = PIL.Image.new('RGB', (60, 30), color='red')
    image = pyvips.Image.new_from_array(pil_image)
    
    # pyvips to NumPy
    array = image.numpy()
    
    # pyvips to PIL
    pil_img = image.pil()
  12. Use Sources and Targets for I/O

    master

    Instead of loading directly from files, you can use pyvips.Source and pyvips.Target to manage image input and output. This allows you to work with files, descriptors (like pipes), or memory areas.

    • Use pyvips.Source.new_from_file(path) to create a source.
    • Use pyvips.Target.new_to_file(path) to create a target.
    • Use pyvips.Image.new_from_source(source, name, access=...) to create an image from a source.
    • Use image.write_to_target(target, extension) to write an image to a target.
    source = pyvips.Source.new_from_file("some/file/name")
    image = pyvips.Image.new_from_source(source, "", access="sequential")
    target = pyvips.Target.new_to_file("some/file/name")
    image.write_to_target(target, ".png")