lib/vips.rb in vips-8.11.3 vs lib/vips.rb in vips-8.12.1
- old
+ new
@@ -2,12 +2,12 @@
# via ruby-ffi.
#
# Author:: John Cupitt (mailto:jcupitt@gmail.com)
# License:: MIT
-require 'ffi'
-require 'logger'
+require "ffi"
+require "logger"
# This module uses FFI to make a simple layer over the glib and gobject
# libraries.
# Generate a library name for ffi.
@@ -35,39 +35,39 @@
module GLib
class << self
attr_accessor :logger
end
- @logger = Logger.new(STDOUT)
+ @logger = Logger.new($stdout)
@logger.level = Logger::WARN
extend FFI::Library
- ffi_lib library_name('glib-2.0', 0)
+ ffi_lib library_name("glib-2.0", 0)
attach_function :g_malloc, [:size_t], :pointer
# save the FFI::Function that attach will return ... we can use it directly
# as a param for callbacks
G_FREE = attach_function :g_free, [:pointer], :void
callback :g_log_func, [:string, :int, :string, :pointer], :void
attach_function :g_log_set_handler,
- [:string, :int, :g_log_func, :pointer], :int
+ [:string, :int, :g_log_func, :pointer], :int
attach_function :g_log_remove_handler, [:string, :int], :void
# log flags
- LOG_FLAG_RECURSION = 1 << 0
- LOG_FLAG_FATAL = 1 << 1
+ LOG_FLAG_RECURSION = 1 << 0
+ LOG_FLAG_FATAL = 1 << 1
# GLib log levels
- LOG_LEVEL_ERROR = 1 << 2 # always fatal
- LOG_LEVEL_CRITICAL = 1 << 3
- LOG_LEVEL_WARNING = 1 << 4
- LOG_LEVEL_MESSAGE = 1 << 5
- LOG_LEVEL_INFO = 1 << 6
- LOG_LEVEL_DEBUG = 1 << 7
+ LOG_LEVEL_ERROR = 1 << 2 # always fatal
+ LOG_LEVEL_CRITICAL = 1 << 3
+ LOG_LEVEL_WARNING = 1 << 4
+ LOG_LEVEL_MESSAGE = 1 << 5
+ LOG_LEVEL_INFO = 1 << 6
+ LOG_LEVEL_DEBUG = 1 << 7
# map glib levels to Logger::Severity
GLIB_TO_SEVERITY = {
LOG_LEVEL_ERROR => Logger::ERROR,
LOG_LEVEL_CRITICAL => Logger::FATAL,
@@ -81,23 +81,23 @@
# nil being the default
@glib_log_domain = nil
@glib_log_handler_id = 0
# module-level, so it's not GCd away
- LOG_HANDLER = Proc.new do |domain, level, message, _user_data|
+ LOG_HANDLER = proc { |domain, level, message, _user_data|
@logger.log(GLIB_TO_SEVERITY[level], message, domain)
- end
+ }
def self.remove_log_handler
if @glib_log_handler_id != 0 && @glib_log_domain
g_log_remove_handler @glib_log_domain, @glib_log_handler_id
@glib_log_handler_id = nil
end
end
def self.set_log_domain domain
- GLib::remove_log_handler
+ GLib.remove_log_handler
@glib_log_domain = domain
# forward all glib logging output from this domain to a Ruby logger
if @glib_log_domain
@@ -123,20 +123,20 @@
# we must remove any handlers on exit, since libvips may log stuff
# on shutdown and we don't want LOG_HANDLER to be invoked
# after Ruby has gone
at_exit {
- GLib::remove_log_handler
+ GLib.remove_log_handler
}
end
end
end
module GObject
extend FFI::Library
- ffi_lib library_name('gobject-2.0', 0)
+ ffi_lib library_name("gobject-2.0", 0)
# we can't just use ulong, windows has different int sizing rules
if FFI::Platform::ADDRESS_SIZE == 64
typedef :uint64, :GType
else
@@ -160,12 +160,12 @@
GFLAGS_TYPE = g_type_from_name "GFlags"
GSTR_TYPE = g_type_from_name "gchararray"
GOBJECT_TYPE = g_type_from_name "GObject"
end
-require 'vips/gobject'
-require 'vips/gvalue'
+require "vips/gobject"
+require "vips/gvalue"
# This module provides a binding for the [libvips image processing
# library](https://libvips.github.io/libvips/).
#
# # Example
@@ -206,17 +206,15 @@
# 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.
+# 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.
#
-# 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]
# ```
@@ -254,11 +252,11 @@
# {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
+# 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](https://github.com/ffi/ffi) to open the libvips
@@ -407,75 +405,122 @@
# 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
-# {Vips::Yard::generate}. It examines
-# libvips and writes a summary of each operation and the arguments and options
-# that that operation expects.
+# 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](https://libvips.github.io/libvips/API/current)
+# Use the [C API # docs](https://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
-# the class list.
+# {Vips::BandFormat}, for example.
#
# # Draw operations
#
-# Paint operations like {Image#draw_circle} and {Image#draw_line}
-# modify their input image. This
-# makes them hard to use with the rest of libvips: you need to be very careful
-# about the order in which operations execute or you can get nasty crashes.
+# There are two ways of calling the libvips draw operations, like
+# {Image#draw_circle} and {Image#draw_line}.
#
-# The wrapper spots operations of this type and makes a private copy of the
-# image in memory before calling the operation. This stops crashes, but it does
-# make it inefficient. If you draw 100 lines on an image, for example, you'll
-# copy the image 100 times. The wrapper does make sure that memory is recycled
-# where possible, so you won't have 100 copies in memory.
+# First, you can use them like functions. For example:
#
-# If you want to avoid the copies, you'll need to call drawing operations
-# yourself.
+# ```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
#
@@ -523,57 +568,58 @@
# {Image#median}.
module Vips
extend FFI::Library
- if FFI::Platform.windows?
- vips_libname = 'libvips-42.dll'
- else
- vips_libname = File.expand_path(FFI.map_library_name('vips'), __dir__)
- end
+ ffi_lib library_name("vips", 42)
- ffi_lib vips_libname
-
LOG_DOMAIN = "VIPS"
- GLib::set_log_domain LOG_DOMAIN
+ GLib.set_log_domain LOG_DOMAIN
- typedef :ulong, :GType
+ # we can't just use ulong, windows has different int sizing rules
+ if FFI::Platform::ADDRESS_SIZE == 64
+ typedef :uint64, :GType
+ else
+ typedef :uint32, :GType
+ end
attach_function :vips_error_buffer, [], :string
attach_function :vips_error_clear, [], :void
+ attach_function :vips_error_freeze, [], :void
+ attach_function :vips_error_thaw, [], :void
# The ruby-vips error class.
class Error < RuntimeError
# @param msg [String] The error message. If this is not supplied, grab
# and clear the vips error buffer and use that.
def initialize msg = nil
if msg
@details = msg
- elsif Vips::vips_error_buffer != ""
- @details = Vips::vips_error_buffer
- Vips::vips_error_clear
+ elsif Vips.vips_error_buffer != ""
+ @details = Vips.vips_error_buffer
+ Vips.vips_error_clear
else
@details = nil
end
end
# Pretty-print a {Vips::Error}.
#
# @return [String] The error message
def to_s
- if @details != nil
+ if !@details.nil?
@details
else
super.to_s
end
end
end
attach_function :vips_init, [:string], :int
- if Vips::vips_init($0) != 0
- throw Vips::get_error
+ if Vips.vips_init($0) != 0
+ throw Vips.get_error
end
# don't use at_exit to call vips_shutdown, it causes problems with fork, and
# in any case libvips does this for us
@@ -633,11 +679,11 @@
# Deprecated compatibility function.
#
# Don't use this, instead change GLib::logger.level.
def self.set_debug debug
if debug
- GLib::logger.level = Logger::DEBUG
+ GLib.logger.level = Logger::DEBUG
end
end
attach_function :version, :vips_version, [:int], :int
attach_function :version_string, :vips_version_string, [], :string
@@ -655,38 +701,39 @@
# @return [[String]] array of supported suffixes
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
+ array = Vips.vips_foreign_get_suffixes
names = []
p = array
until (q = p.read_pointer).null?
suff = q.read_string
- GLib::g_free q
+ GLib.g_free q
names << suff unless names.include? suff
p += FFI::Type::POINTER.size
end
- GLib::g_free array
+ GLib.g_free array
names
end
- LIBRARY_VERSION = Vips::version_string
+ LIBRARY_VERSION = Vips.version_string
# libvips has this arbitrary number as a sanity-check upper bound on image
# size. It's sometimes useful to know when calculating scale factors.
MAX_COORD = 10000000
end
-require 'vips/object'
-require 'vips/operation'
-require 'vips/image'
-require 'vips/interpolate'
-require 'vips/region'
-require 'vips/version'
-require 'vips/connection'
-require 'vips/source'
-require 'vips/sourcecustom'
-require 'vips/target'
-require 'vips/targetcustom'
+require "vips/object"
+require "vips/operation"
+require "vips/image"
+require "vips/mutableimage"
+require "vips/interpolate"
+require "vips/region"
+require "vips/version"
+require "vips/connection"
+require "vips/source"
+require "vips/sourcecustom"
+require "vips/target"
+require "vips/targetcustom"