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"