module Vips

we can sometimes get dependent libraries from libvips – either the platform will open dependencies for us automatically, or the libvips binary has been built to includes all main dependencies (common on windows, can happen elsewhere)

we must get glib functions from libvips if we can, since it will be the one that libvips itself is using, and they will share runtime types

This module provides a binding for the [libvips image processing library](libvips.github.io/libvips/).

# Example

“‘ruby require ’vips’

if ARGV.length < 2

raise "usage: #{$PROGRAM_NAME}: input-file output-file"

end

im = Vips::Image.new_from_file ARGV, access: :sequential

im *= [1, 2, 1]

mask = Vips::Image.new_from_array [

 [-1, -1, -1],
 [-1, 16, -1],
 [-1, -1, -1]
], 8

im = im.conv mask, precision: :integer

im.write_to_file ARGV “‘

This example loads a file, boosts the green channel (I’m not sure why), sharpens the image, and saves it back to disc again.

Reading this example line by line, we have:

“‘ruby im = Vips::Image.new_from_file ARGV, access: :sequential “`

{Image.new_from_file} can load any image file supported by vips. In this example, we will be accessing pixels top-to-bottom as we sweep through the image reading and writing, so ‘:sequential` access mode is best for us. The default mode is `:random`: this allows for full random access to image pixels, but is slower and needs more memory. See {Access} for full details on the various modes available.

You can also load formatted images from memory buffers, create images that wrap C-style memory arrays, or make images from constants. Use {Source} and {Image.new_from_source} to load images from any data source, for example URIs.

The next line:

“‘ruby im *= [1, 2, 1] “`

Multiplying the image by an array constant uses one array element for each image band. This line assumes that the input image has three bands and will double the middle band. For RGB images, that’s doubling green.

Next we have:

“‘ruby mask = Vips::Image.new_from_array [

 [-1, -1, -1],
 [-1, 16, -1],
 [-1, -1, -1]
], 8

im = im.conv mask, precision: :integer “‘

{Image.new_from_array} creates an image from an array constant. The 8 at the end sets the scale: the amount to divide the image by after integer convolution.

See the libvips API docs for ‘vips_conv()` (the operation invoked by {Image#conv}) for details on the convolution operator. By default, it computes with a float mask, but `:integer` is fine for this case, and is much faster.

Finally:

“‘ruby im.write_to_file ARGV “`

{Image#write_to_file} writes an image back to the filesystem. It can write any format supported by vips: the file type is set from the filename suffix. You can also write formatted images to memory buffers, or dump image data to a raw memory array.

Use {Target} and {Image#write_to_target} to write formatted images to any data sink, for example URIs.

# How it works

The binding uses [ruby-ffi](github.com/ffi/ffi) to open the libvips shared library. When you call a method on the image class, it uses libvips introspection system (based on GObject) to search the library for an operation of that name, transforms the arguments to a form libvips can digest, and runs the operation.

This means ruby-vips always presents the API implemented by the libvips shared library. It should update itself as new features are added.

# Automatic wrapping

‘ruby-vips` adds a {Image.method_missing} handler to {Image} and uses it to look up vips operations. For example, the libvips operation `add`, which appears in C as `vips_add()`, appears in Ruby as {Image#add}.

The operation’s list of required arguments is searched and the first input image is set to the value of ‘self`. Operations which do not take an input image, such as {Image.black}, appear as class methods. The remainder of the arguments you supply in the function call are used to set the other required input arguments. Any trailing keyword arguments are used to set options on the operation.

The result is the required output argument if there is only one result, or an array of values if the operation produces several results. If the operation has optional output objects, they are returned as a final hash.

For example, {Image#min}, the vips operation that searches an image for the minimum value, has a large number of optional arguments. You can use it to find the minimum value like this:

“‘ruby min_value = image.min “`

You can ask it to return the position of the minimum with ‘:x` and `:y`.

“‘ruby min_value, opts = min x: true, y: true x_pos = opts y_pos = opts “`

Now ‘x_pos` and `y_pos` will have the coordinates of the minimum value. There’s actually a convenience method for this, {Image#minpos}.

You can also ask for the top n minimum, for example:

“‘ruby min_value, opts = min size: 10, x_array: true, y_array: true x_pos = opts y_pos = opts “`

Now ‘x_pos` and `y_pos` will be 10-element arrays.

Because operations are member functions and return the result image, you can chain them. For example, you can write:

“‘ruby result_image = image.real.cos “`

to calculate the cosine of the real part of a complex image. There are also a full set of arithmetic operator overloads, see below.

libvips types are also automatically wrapped. The override looks at the type of argument required by the operation and converts the value you supply, when it can. For example, {Image#linear} takes a ‘VipsArrayDouble` as an argument for the set of constants to use for multiplication. You can supply this value as an integer, a float, or some kind of compound object and it will be converted for you. You can write:

“‘ruby result_image = image.linear 1, 3 result_image = image.linear 12.4, 13.9 result_image = image.linear [1, 2, 3], [4, 5, 6] result_image = image.linear 1, [4, 5, 6] “`

And so on. A set of overloads are defined for {Image#linear}, see below.

It does a couple of more ambitious conversions. It will automatically convert to and from the various vips types, like ‘VipsBlob` and `VipsArrayImage`. For example, you can read the ICC profile out of an image like this:

“‘ruby profile = im.get_value “icc-profile-data” “`

and profile will be a byte array.

If an operation takes several input images, you can use a constant for all but one of them and the wrapper will expand the constant to an image for you. For example, {Image#ifthenelse} uses a condition image to pick pixels between a then and an else image:

“‘ruby result_image = condition_image.ifthenelse then_image, else_image “`

You can use a constant instead of either the then or the else parts and it will be expanded to an image for you. If you use a constant for both then and else, it will be expanded to match the condition image. For example:

“‘ruby result_image = condition_image.ifthenelse [0, 255, 0], [255, 0, 0] “`

Will make an image where true pixels are green and false pixels are red.

This is useful for {Image#bandjoin}, the thing to join two or more images up bandwise. You can write:

“‘ruby rgba = rgb.bandjoin 255 “`

to append a constant 255 band to an image, perhaps to add an alpha channel. Of course you can also write:

“‘ruby result_image = image1.bandjoin image2 result_image = image1.bandjoin [image2, image3] result_image = Vips::Image.bandjoin [image1, image2, image3] result_image = image1.bandjoin [image2, 255] “`

and so on.

# Logging

Libvips uses g_log() to log warning, debug, info and (some) error messages.

developer.gnome.org/glib/stable/glib-Message-Logging.html

You can disable warnings by defining the ‘VIPS_WARNING` environment variable. You can enable info output by defining `VIPS_INFO`.

# Exceptions

The wrapper spots errors from vips operations and raises the {Vips::Error} exception. You can catch it in the usual way.

# Automatic YARD documentation

The bulk of these API docs are generated automatically by {Yard#generate}. It examines libvips and writes a summary of each operation and the arguments and options that that operation expects.

Use the [C API # docs](libvips.github.io/libvips/API/current) for more detail.

# Enums

The libvips enums, such as ‘VipsBandFormat` appear in ruby-vips as Symbols like `:uchar`. They are documented as a set of classes for convenience, see {Vips::BandFormat}, for example.

# Draw operations

There are two ways of calling the libvips draw operations, like {Image#draw_circle} and {Image#draw_line}.

First, you can use them like functions. For example:

“‘ruby y = x.draw_line 255, 0, 0, x.width, x.height “`

This will make a new image, ‘y`, which is a copy of `x` but with a line drawn across it. `x` is unchanged.

This is simple, but will be slow if you want to draw many lines, since ruby-vips will make a copy of the whole image each time.

You can use {Image#mutate} to make a {MutableImage}. This is an image which is unshared and is only available inside the {Image#mutate} block. Within this block, you can use ‘!` versions of the draw operations to modify images and avoid the copy. For example:

“‘ruby image = image.mutate do |mutable|

(0 ... 1).step(0.01) do |i|
  mutable.draw_line! 255, mutable.width * i, 0, 0, mutable.height * (1 - i)
end

end “‘

Now each {Image#draw_line} will directly modify the mutable image, saving the copy. This is much faster and needs much less memory.

# Metadata read

Use {Image#get_fields} to get a list of the metadata fields that an image supports. ICC profiles, for example, are in a field called ‘icc-profile-data`. Use `vipsheader -a something.jpg` at the command-line to see all the fields on an image.

Use {Image#get_typeof} to get the type of a field. Types are integers, with 0 meaning “no such field”. Constants like {GObject::GINT_TYPE} are useful for testing field types.

You can read image metadata using {Image#get}. The field value is converted to a Ruby value in the obvious way.

# Metadata write

You can also set and remove image metadata fields. Images are immutable, so you must make any changes inside a {Image#mutate} block. For example:

“‘ruby image = image.mutate do |mutable|

image.get_fields.each do |field|
  mutable.remove! field unless field == "icc-profile-data"
end

end “‘

To remove all metadata except the icc profile.

You can use {MutableImage#set!} to change the value of an existing field, and {MutableImage#set_type!} to create a new field with a specified type.

# Progress

You can attach signal handlers to images to watch computation progress. For example:

“‘ruby image = Vips::Image.black 1, 100000 image.set_progress true

def progress_to_s(name, progress)

puts "#{name}:"
puts "    run = #{progress[:run]}"
puts "    eta = #{progress[:eta]}"
puts "    tpels = #{progress[:tpels]}"
puts "    npels = #{progress[:npels]}"
puts "    percent = #{progress[:percent]}"

end

image.signal_connect :preeval do |progress|

progress_to_s("preeval", progress)

end

image.signal_connect :eval do |progress|

progress_to_s("eval", progress)
image.set_kill(true) if progress[:percent] > 50

end

image.signal_connect :posteval do |progress|

progress_to_s("posteval", progress)

end

image.avg “‘

The ‘:eval` signal will fire for every tile that is processed. You can stop progress with {Image#set_kill} and processing will end with an exception.

User streams

You can make your own input and output stream objects with {SourceCustom} and {TargetCustom}. For example:

“‘ruby file = File.open “some/file”, “rb” source = Vips::SourceCustom.new source.on_read { |length| file.read length } image = Vips::Image.new_from_source source, “”, access: “sequential” “`

# Overloads

The wrapper defines the usual set of arithmetic, boolean and relational overloads on image. You can mix images, constants and lists of constants (almost) freely. For example, you can write:

“‘ruby result_image = ((image * [1, 2, 3]).abs < 128) | 4 “`

# Expansions

Some vips operators take an enum to select an action, for example {Image#math} can be used to calculate sine of every pixel like this:

“‘ruby result_image = image.math :sin “`

This is annoying, so the wrapper expands all these enums into separate members named after the enum. So you can write:

“‘ruby result_image = image.sin “`

# Convenience functions

The wrapper defines a few extra useful utility functions: {Image#get_value}, {Image#set_value}, {Image#bandsplit}, {Image#maxpos}, {Image#minpos}, {Image#median}.

Constants

ARGUMENT_CONSTRUCT
ARGUMENT_DEPRECATED
ARGUMENT_FLAGS
ARGUMENT_INPUT
ARGUMENT_MODIFY
ARGUMENT_OUTPUT
ARGUMENT_REQUIRED

enum VipsArgumentFlags

ARGUMENT_SET_ALWAYS
ARGUMENT_SET_ONCE
ARRAY_DOUBLE_TYPE
ARRAY_IMAGE_TYPE
ARRAY_INT_TYPE
BAND_FORMAT_TYPE
BLEND_MODE_TYPE
BLOB_TYPE
CODING_TYPE
DEFAULT_CONCURRENCY

Track the original default concurrency so we can reset to it.

IMAGE_TYPE

some handy gtypes

INTERPRETATION_TYPE
LIBRARY_VERSION
LOG_DOMAIN

we’ve already opened the libvips library

MARSHAL_ALL

map signal name to marshal proc

MARSHAL_FINISH
MARSHAL_PROGRESS

Our signal marshalers.

These are functions which take the handler as a param and return a closure with the right FFI signature for g_signal_connect for this specific signal.

ruby-ffi makes it hard to use the g_signal_connect user data param to pass the function pointer through, unfortunately.

We can’t throw exceptions across C, so we must catch everything.

MARSHAL_READ
MARSHAL_SEEK
MARSHAL_WRITE
MAX_COORD

libvips has this arbitrary number as a sanity-check upper bound on image size. It’s sometimes useful to know when calculating scale factors.

OPERATION_DEPRECATED
OPERATION_FLAGS
OPERATION_NOCACHE
OPERATION_SEQUENTIAL
REFSTR_TYPE
VERSION

Public Class Methods

at_least_libvips?(x, y) click to toggle source

True if this is at least libvips x.y

# File lib/vips.rb, line 805
def self.at_least_libvips?(x, y)
  major = version(0)
  minor = version(1)

  major > x || (major == x && minor >= y)
end
block(operation_name, enabled) click to toggle source

Block/unblock all operations in the libvips class hierarchy at specified operation_name and below.

For example this will block all loaders except JPEG

Vips.block("VipsForeignLoad", true);
Vips.block("VipsForeignLoadJpeg", false)

Use ‘vips -l` at the command-line to see the class hierarchy. This call does nothing if the named operation is not found.

# File lib/vips.rb, line 832
def self.block(operation_name, enabled)
  vips_operation_block_set(operation_name, enabled)
end
block_untrusted(enabled) click to toggle source

Block/unblock all untrusted operations from running. Use ‘vips -l` at the command-line to see the class hierarchy and which operations are marked as untrusted.

# File lib/vips.rb, line 818
def self.block_untrusted(enabled)
  vips_block_untrusted_set(enabled)
end
cache_max() click to toggle source

Get the maximum number of operations that libvips should cache.

# File lib/vips.rb, line 712
def self.cache_max
  vips_cache_get_max
end
cache_max_files() click to toggle source

Get the maximum number of files libvips keeps open in the operation cache.

# File lib/vips.rb, line 722
def self.cache_max_files
  vips_cache_get_max_files
end
cache_max_mem() click to toggle source

Get the maximum amount of memory that libvips uses for the operation cache.

# File lib/vips.rb, line 717
def self.cache_max_mem
  vips_cache_get_max_mem
end
cache_set_max(size) click to toggle source

Set the maximum number of operations that libvips should cache. Set 0 to disable the operation cache. The default is 1000.

# File lib/vips.rb, line 728
def self.cache_set_max size
  vips_cache_set_max size
  cache_max
end
cache_set_max_files(size) click to toggle source

Set the maximum number of files libvips should keep open in the operation cache. Set 0 to disable the operation cache. The default is 100.

# File lib/vips.rb, line 743
def self.cache_set_max_files size
  vips_cache_set_max_files size
  cache_max_files
end
cache_set_max_mem(size) click to toggle source

Set the maximum amount of memory that libvips should use for the operation cache. Set 0 to disable the operation cache. The default is 100mb.

# File lib/vips.rb, line 735
def self.cache_set_max_mem size
  vips_cache_set_max_mem size
  cache_max_mem
end
concurrency() click to toggle source

Get the size of libvips worker pools. Defaults to the VIPS_CONCURRENCY env var or the number of hardware threads on your computer.

# File lib/vips.rb, line 760
def self.concurrency
  vips_concurrency_get
end
concurrency_default() click to toggle source

Get the default size of libvips worker pools.

# File lib/vips.rb, line 765
def self.concurrency_default
  DEFAULT_CONCURRENCY
end
concurrency_set(n) click to toggle source

Set the size of each libvips worker pool. Max 1024 threads. Set to 1 to disable threading. Set to 0 or nil to reset to default.

# File lib/vips.rb, line 771
def self.concurrency_set n
  n = DEFAULT_CONCURRENCY if n.to_i == 0
  vips_concurrency_set n
  concurrency
end
get_suffixes() click to toggle source

Get a list of all supported file suffixes.

@return [[String]] array of supported suffixes

# File lib/vips.rb, line 840
def self.get_suffixes
  # vips_foreign_get_suffixes() was added in libvips 8.8
  return [] unless Vips.respond_to? :vips_foreign_get_suffixes

  array = Vips.vips_foreign_get_suffixes

  names = []
  p = array
  until (q = p.read_pointer).null?
    suff = q.read_string
    GLib.g_free q
    names << suff unless names.include? suff
    p += FFI::Type::POINTER.size
  end
  GLib.g_free array

  names
end
leak_set(leak) click to toggle source

Turn libvips leak testing on and off. Handy for debugging ruby-vips, not very useful for user code.

# File lib/vips.rb, line 674
def self.leak_set leak
  vips_leak_set((leak ? 1 : 0))
end
p2str(pointer) click to toggle source

turn a raw pointer that must be freed into a self-freeing Ruby string

# File lib/vips/image.rb, line 68
def self.p2str(pointer)
  pointer = FFI::AutoPointer.new(pointer, GLib::G_FREE)
  pointer.read_string
end
set_debug(debug) click to toggle source

Deprecated compatibility function.

Don’t use this, instead change GLib::logger.level.

# File lib/vips.rb, line 795
def self.set_debug debug
  if debug
    GLib.logger.level = Logger::DEBUG
  end
end
tracked_allocs() click to toggle source

Get the number of active allocations.

# File lib/vips.rb, line 702
def self.tracked_allocs
  vips_tracked_get_allocs
end
tracked_files() click to toggle source

Get the number of open files.

# File lib/vips.rb, line 707
def self.tracked_files
  vips_tracked_get_files
end
tracked_mem() click to toggle source

Get the number of bytes currently allocated via vips_malloc.

# File lib/vips.rb, line 692
def self.tracked_mem
  vips_tracked_get_mem
end
tracked_mem_highwater() click to toggle source

Get the greatest number of bytes ever actively allocated via vips_malloc.

# File lib/vips.rb, line 697
def self.tracked_mem_highwater
  vips_tracked_get_mem_highwater
end
unified?() click to toggle source
# File lib/vips.rb, line 55
def self.unified?
  @@is_unified
end
vector?() click to toggle source

Whether SIMD and the run-time compiler are enabled. This can give a nice speed-up, but can also be unstable on some systems or with some versions of the run-time compiler.

# File lib/vips.rb, line 780
def self.vector?
  vips_vector_isenabled == 1
end
vector_set(enabled) click to toggle source

Enable or disable SIMD and the run-time compiler. This can give a nice speed-up, but can also be unstable on some systems or with some versions of the run-time compiler.

# File lib/vips.rb, line 787
def self.vector_set enabled
  vips_vector_set_enabled(enabled ? 1 : 0)
  vector?
end