# This module provides an interface to the top level bits of libvips # via ruby-ffi. # # Author:: John Cupitt (mailto:jcupitt@gmail.com) # License:: MIT require 'ffi' module Vips private # debugging support attach_function :vips_object_print_all, [], :void # we must init these by hand, since they are usually made on first image # create attach_function :vips_band_format_get_type, [], :GType attach_function :vips_interpretation_get_type, [], :GType attach_function :vips_coding_get_type, [], :GType public # some handy gtypes IMAGE_TYPE = GObject::g_type_from_name "VipsImage" ARRAY_INT_TYPE = GObject::g_type_from_name "VipsArrayInt" ARRAY_DOUBLE_TYPE = GObject::g_type_from_name "VipsArrayDouble" ARRAY_IMAGE_TYPE = GObject::g_type_from_name "VipsArrayImage" REFSTR_TYPE = GObject::g_type_from_name "VipsRefString" BLOB_TYPE = GObject::g_type_from_name "VipsBlob" BAND_FORMAT_TYPE = Vips::vips_band_format_get_type INTERPRETATION_TYPE = Vips::vips_interpretation_get_type CODING_TYPE = Vips::vips_coding_get_type if Vips::at_least_libvips?(8, 6) attach_function :vips_blend_mode_get_type, [], :GType BLEND_MODE_TYPE = Vips::vips_blend_mode_get_type else BLEND_MODE_TYPE = nil end private attach_function :vips_enum_from_nick, [:string, :GType, :string], :int attach_function :vips_enum_nick, [:GType, :int], :string attach_function :vips_value_set_ref_string, [GObject::GValue.ptr, :string], :void attach_function :vips_value_set_array_double, [GObject::GValue.ptr, :pointer, :int], :void attach_function :vips_value_set_array_int, [GObject::GValue.ptr, :pointer, :int], :void attach_function :vips_value_set_array_image, [GObject::GValue.ptr, :int], :void callback :free_fn, [:pointer], :void attach_function :vips_value_set_blob, [GObject::GValue.ptr, :free_fn, :pointer, :size_t], :void class SizeStruct < FFI::Struct layout :value, :size_t end class IntStruct < FFI::Struct layout :value, :int end attach_function :vips_value_get_ref_string, [GObject::GValue.ptr, SizeStruct.ptr], :string attach_function :vips_value_get_array_double, [GObject::GValue.ptr, IntStruct.ptr], :pointer attach_function :vips_value_get_array_int, [GObject::GValue.ptr, IntStruct.ptr], :pointer attach_function :vips_value_get_array_image, [GObject::GValue.ptr, IntStruct.ptr], :pointer attach_function :vips_value_get_blob, [GObject::GValue.ptr, SizeStruct.ptr], :pointer attach_function :type_find, :vips_type_find, [:string, :string], :GType class Object < GObject::GObject # print all active VipsObjects, with their reference counts. Handy for # debugging ruby-vips. def self.print_all GC.start Vips::vips_object_print_all end # the layout of the VipsObject struct module ObjectLayout def self.included base base.class_eval do # don't actually need most of these layout :parent, GObject::GObject::Struct, :constructed, :int, :static_object, :int, :argument_table, :pointer, :nickname, :string, :description, :string, :preclose, :int, :close, :int, :postclose, :int, :local_memory, :size_t end end end class Struct < GObject::GObject::Struct include ObjectLayout end class ManagedStruct < GObject::GObject::ManagedStruct include ObjectLayout end # return a pspec, or nil ... nil wil leave a message in the error log # which you must clear def get_pspec name pspec = GObject::GParamSpecPtr.new argument_class = Vips::ArgumentClassPtr.new argument_instance = Vips::ArgumentInstancePtr.new result = Vips::vips_object_get_argument self, name, pspec, argument_class, argument_instance return nil if result != 0 pspec end # return a gtype, raise an error on not found def get_typeof_error name pspec = get_pspec name raise Vips::Error unless pspec pspec[:value][:value_type] end # return a gtype, 0 on not found def get_typeof name pspec = get_pspec name unless pspec Vips::vips_error_clear return 0 end pspec[:value][:value_type] end def get name gtype = get_typeof_error name gvalue = GObject::GValue.alloc gvalue.init gtype GObject::g_object_get_property self, name, gvalue result = gvalue.get GLib::logger.debug("Vips::Object.get") { "#{name} == #{result}" } return result end def set name, value GLib::logger.debug("Vips::Object.set") { "#{name} = #{value}" } gtype = get_typeof_error name gvalue = GObject::GValue.alloc gvalue.init gtype gvalue.set value GObject::g_object_set_property self, name, gvalue end end class ObjectClass < FFI::Struct # opaque end class Argument < FFI::Struct layout :pspec, GObject::GParamSpec.ptr end class ArgumentInstance < Argument layout :parent, Argument # rest opaque end # enum VipsArgumentFlags ARGUMENT_REQUIRED = 1 ARGUMENT_CONSTRUCT = 2 ARGUMENT_SET_ONCE = 4 ARGUMENT_SET_ALWAYS = 8 ARGUMENT_INPUT = 16 ARGUMENT_OUTPUT = 32 ARGUMENT_DEPRECATED = 64 ARGUMENT_MODIFY = 128 ARGUMENT_FLAGS = { required: ARGUMENT_REQUIRED, construct: ARGUMENT_CONSTRUCT, set_once: ARGUMENT_SET_ONCE, set_always: ARGUMENT_SET_ALWAYS, input: ARGUMENT_INPUT, output: ARGUMENT_OUTPUT, deprecated: ARGUMENT_DEPRECATED, modify: ARGUMENT_MODIFY } class ArgumentClass < Argument layout :parent, Argument, :object_class, ObjectClass.ptr, :flags, :uint, :priority, :int, :offset, :ulong_long end class ArgumentClassPtr < FFI::Struct layout :value, ArgumentClass.ptr end class ArgumentInstancePtr < FFI::Struct layout :value, ArgumentInstance.ptr end # just use :pointer, not VipsObject.ptr, to avoid casting gobject # subclasses attach_function :vips_object_get_argument, [:pointer, :string, GObject::GParamSpecPtr.ptr, ArgumentClassPtr.ptr, ArgumentInstancePtr.ptr], :int attach_function :vips_object_set_from_string, [:pointer, :string], :int callback :type_map_fn, [:GType, :pointer], :pointer attach_function :vips_type_map, [:GType, :type_map_fn, :pointer], :pointer attach_function :vips_object_get_description, [:pointer], :string end