ImageProcessing

repository·master·Indexed 21 days ago

https://github.com/janko/image_processing

A Ruby gem providing a high-level, chainable API for image manipulation. It serves as a unified interface for ImageMagick (via MiniMagick) and libvips (via ruby-vips), enabling consistent operations such as resizing, converting, cropping, and stripping metadata. It supports both basic and branching pipelines, custom instrumentation, and low-level configuration for its underlying processors.

Tokens
10.9K
Snippets
51
Records
62
Agent score
75%

What's inside image_processing

  1. Optimize resizing with Resize-on-load

    master

    To significantly speed up resizing and improve accuracy, you should place #resize_* operations as the first operation in your processing chain. This allows the processor to use vips_thumbnail(), which performs resize-on-load.

    Avoid this pattern (no resize-on-load):

    ImageProcessing::Vips
      .source(image)
      .colourspace(:grey16)
      .resize_to_limit(400, 400)

    Use this pattern (utilizes resize-on-load):

    ImageProcessing::Vips
      .source(image)
      .resize_to_limit(400, 400)
      .colourspace(:grey16)
    # GOOD: utilizes resize-on-load
    ImageProcessing::Vips
      .source(image)
      .resize_to_limit(400, 400)
      .colourspace(:grey16)
  2. Install ImageProcessing and its processors

    master

    To use ImageProcessing, you must first install the system-level libraries (ImageMagick or libvips) and then add the corresponding Ruby gems to your Gemfile.

    1. Install system libraries

    macOS (via Homebrew):

    $ brew install imagemagick # for ImageMagick
    $ brew install vips       # for libvips

    Debian/Ubuntu:

    $ sudo apt install imagemagick # for ImageMagick
    $ sudo apt install libvips     # for libvips

    2. Add gems to Gemfile

    Add the core gem and the processor of your choice:

    gem "image_processing", "~> 2.0"
    gem "mini_magick", "~> 5.0" # if using ImageMagick
    gem "ruby-vips", "~> 2.0"   # if using libvips
    $ brew install imagemagick
    $ brew install vips
  3. Use ImageProcessing::Vips for image processing

    master

    The ImageProcessing::Vips module provides a chainable API for image manipulation using the ruby-vips gem. You must require image_processing/vips to use it.

    Example usage:

    require "image_processing/vips"
    
    processed = ImageProcessing::Vips
      .source(image)
      .resize_to_limit(400, 400)
      .saver(strip: true)
      .call
    
    # processed is a Tempfile
    require "image_processing/vips"
    
    processed = ImageProcessing::Vips
      .source(image)
      .resize_to_limit(400, 400)
      .saver(strip: true)
      .call
  4. Use the chainable image processing API

    master

    Processing is performed through the ImageProcessing::Vips or ImageProcessing::MiniMagick modules. Both modules share a chainable API for defining a pipeline of operations.

    Basic Pipeline

    Define a source and chain operations like .resize_to_limit or .convert. The pipeline is executed when you call #call or use a bang method (e.g., .resize_to_limit!).

    require "image_processing/mini_magick"
    
    processed = ImageProcessing::MiniMagick
      .source(file)
      .resize_to_limit(400, 400)
      .convert("png")
      .call
    
    # processed is a Tempfile

    Branching Pipelines

    You can create a base pipeline and branch it into multiple derivatives using bang methods (!), which execute the processing immediately for that specific step.

    require "image_processing/vips"
    
    pipeline = ImageProcessing::Vips
      .source(file)
      .convert("png")
    
    large  = pipeline.resize_to_limit!(800, 800)
    medium = pipeline.resize_to_limit!(500, 500)
    small  = pipeline.resize_to_limit!(300, 300)
    require "image_processing/mini_magick"
    
    processed = ImageProcessing::MiniMagick
      .source(file)
      .resize_to_limit(400, 400)
      .convert("png")
      .call
  5. Install ImageMagick or GraphicsMagick

    master

    Before using the ImageProcessing::MiniMagick module, you must have either ImageMagick or GraphicsMagick installed on your system. If you are using Homebrew, you can install them using the following commands:

    $ brew install imagemagick
    # or
    $ brew install graphicsmagick
  6. Enable untrusted loaders in libvips

    master

    On libvips 8.13+, ImageProcessing::Vips automatically blocks untrusted operations to prevent security vulnerabilities. This prevents the processing of formats like SVGs and PDFs by default.

    To allow all available formats and disable this safeguard, call Vips.block_untrusted(false). This must be called after image_processing/vips has been required.

    require "image_processing/vips"
    # ...
    # must be called after `image_processing/vips` has been required
    Vips.block_untrusted(false)
  7. Use ImageProcessing with MiniMagick or Vips

    master

    The ImageProcessing module provides a unified interface for image manipulation using different backends. You can choose between ImageProcessing::MiniMagick and ImageProcessing::Vips as your processor. The library uses a builder pattern to construct image processing pipelines.

    # Example of selecting a processor (conceptual usage based on module structure)
    # The specific syntax for building a pipeline is handled by ImageProcessing::Builder
    ImageProcessing::MiniMagick.new(source_path).resize_to_limit(400, 400).call
  8. How the ImageProcessing::Processor works

    master

    The ImageProcessing::Processor is an abstract base class used to implement specific image processing backends (like MiniMagick or Vips). It manages the lifecycle of an image processing task through a standard pipeline: loading a source, applying a sequence of operations, and saving to a destination.

    The Processing Pipeline

    When Processor.call is invoked, it follows these steps:

    1. Loading: Loads the source (a file path or an accumulator object) using the provided loader options.
    2. Resizing Optimization: If the first operation is a resize_ operation, the loader is empty, and the processor supports it via supports_resize_on_load?, the processor may optimize by resizing during the load phase.
    3. Operations: Iterates through the operations array. Each operation is applied to the image accumulator.
    4. Saving: If a destination is provided, the image is saved using the saver options. Otherwise, the processed accumulator is returned.
    ImageProcessing::Processor.call(
      source: "/path/to/source.jpg",
      loader: { page: 1 },
      operations: [[:resize_to_limit, [400, 400]], [:strip, []]],
      saver: { format: "png" },
      destination: "/path/to/output.png"
    )
  9. How the Chainable interface handles unknown operations

    master

    The Chainable module uses method_missing to allow calling processor-specific operations directly as if they were methods on the builder.

    • Standard operations: Calling a method like .resize(400) adds it as an operation.
    • Bang (!) suffix: If you append a ! to a method name (e.g., .resize!(400)), it is treated as an operation that should be performed immediately by the processor.
    • Question (?) suffix: Methods ending in ? are ignored by the operation registration logic.

    Security Note: The implementation includes a check to prevent calling unsafe Ruby core methods (like Kernel#system) to avoid remote shell execution.