PageRenderTime 44ms CodeModel.GetById 23ms app.highlight 19ms RepoModel.GetById 0ms app.codeStats 0ms

/vendor/cache/ruby/2.7.0/gems/ruby-vips-2.0.17/lib/vips/object.rb

https://gitlab.com/gitnyasha/zimcreative
Ruby | 355 lines | 256 code | 61 blank | 38 comment | 4 complexity | b6122f246e493603a85aa02352f7bdae MD5 | raw file
  1# This module provides an interface to the top level bits of libvips
  2# via ruby-ffi.
  3#
  4# Author::    John Cupitt  (mailto:jcupitt@gmail.com)
  5# License::   MIT
  6
  7require 'ffi'
  8
  9module Vips
 10  private
 11
 12  # debugging support
 13  attach_function :vips_object_print_all, [], :void
 14
 15  # we must init these by hand, since they are usually made on first image
 16  # create
 17  attach_function :vips_band_format_get_type, [], :GType
 18  attach_function :vips_interpretation_get_type, [], :GType
 19  attach_function :vips_coding_get_type, [], :GType
 20
 21  public
 22
 23  # some handy gtypes
 24  IMAGE_TYPE = GObject::g_type_from_name "VipsImage"
 25  ARRAY_INT_TYPE = GObject::g_type_from_name "VipsArrayInt"
 26  ARRAY_DOUBLE_TYPE = GObject::g_type_from_name "VipsArrayDouble"
 27  ARRAY_IMAGE_TYPE = GObject::g_type_from_name "VipsArrayImage"
 28  REFSTR_TYPE = GObject::g_type_from_name "VipsRefString"
 29  BLOB_TYPE = GObject::g_type_from_name "VipsBlob"
 30
 31  BAND_FORMAT_TYPE = Vips::vips_band_format_get_type
 32  INTERPRETATION_TYPE = Vips::vips_interpretation_get_type
 33  CODING_TYPE = Vips::vips_coding_get_type
 34
 35  if Vips::at_least_libvips?(8, 6)
 36    attach_function :vips_blend_mode_get_type, [], :GType
 37    BLEND_MODE_TYPE = Vips::vips_blend_mode_get_type
 38  else
 39    BLEND_MODE_TYPE = nil
 40  end
 41
 42  private
 43
 44  class Progress < FFI::Struct
 45    layout :im, :pointer,
 46      :run, :int,
 47      :eta, :int,
 48      :tpels, :int64_t, 
 49      :npels, :int64_t, 
 50      :percent, :int, 
 51      :start, :pointer 
 52  end
 53
 54  # Our signal marshalers. 
 55  #
 56  # These are functions which take the handler as a param and return a 
 57  # closure with the right FFI signature for g_signal_connect for this
 58  # specific signal. 
 59  #
 60  # ruby-ffi makes it hard to use the g_signal_connect user data param 
 61  # to pass the function pointer through, unfortunately.
 62  #
 63  # We can't throw exceptions across C, so we must catch everything.
 64
 65  MARSHAL_PROGRESS = Proc.new do |handler|
 66    FFI::Function.new(:void, [:pointer, :pointer, :pointer]) do |vi, prog, cb|
 67      begin
 68        handler.(Progress.new(prog))
 69      rescue Exception => e
 70        puts "progress: #{e}"
 71      end
 72    end
 73  end
 74
 75  MARSHAL_READ = Proc.new do |handler|
 76    FFI::Function.new(:int64_t, [:pointer, :pointer, :int64_t]) do |i, p, len|
 77      begin
 78        result = handler.(p, len)
 79      rescue Exception => e
 80        puts "read: #{e}"
 81        result = 0
 82      end
 83
 84      result
 85    end
 86  end
 87
 88  MARSHAL_SEEK = Proc.new do |handler|
 89    FFI::Function.new(:int64_t, [:pointer, :int64_t, :int]) do |i, off, whence|
 90      begin
 91        result = handler.(off, whence)
 92      rescue Exception => e
 93        puts "seek: #{e}"
 94        result = -1
 95      end
 96
 97      result
 98    end
 99  end
100
101  MARSHAL_WRITE = Proc.new do |handler|
102    FFI::Function.new(:int64_t, [:pointer, :pointer, :int64_t]) do |i, p, len|
103      begin
104        result = handler.(p, len)
105      rescue Exception => e
106        puts "write: #{e}"
107        result = 0
108      end
109
110      result
111    end
112  end
113
114  MARSHAL_FINISH = Proc.new do |handler|
115    FFI::Function.new(:void, [:pointer, :pointer]) do |i, cb|
116      begin
117        handler.()
118      rescue Exception => e
119        puts "finish: #{e}"
120      end
121    end
122  end
123
124  # map signal name to marshal proc
125  MARSHAL_ALL = {
126    :preeval => MARSHAL_PROGRESS,
127    :eval => MARSHAL_PROGRESS,
128    :posteval => MARSHAL_PROGRESS,
129    :read => MARSHAL_READ,
130    :seek => MARSHAL_SEEK,
131    :write => MARSHAL_WRITE,
132    :finish => MARSHAL_FINISH,
133  }
134
135  attach_function :vips_enum_from_nick, [:string, :GType, :string], :int
136  attach_function :vips_enum_nick, [:GType, :int], :string
137
138  attach_function :vips_value_set_ref_string,
139      [GObject::GValue.ptr, :string], :void
140  attach_function :vips_value_set_array_double,
141      [GObject::GValue.ptr, :pointer, :int], :void
142  attach_function :vips_value_set_array_int,
143      [GObject::GValue.ptr, :pointer, :int], :void
144  attach_function :vips_value_set_array_image,
145      [GObject::GValue.ptr, :int], :void
146  callback :free_fn, [:pointer], :void
147  attach_function :vips_value_set_blob,
148      [GObject::GValue.ptr, :free_fn, :pointer, :size_t], :void
149
150  class SizeStruct < FFI::Struct
151    layout :value, :size_t
152  end
153
154  class IntStruct < FFI::Struct
155    layout :value, :int
156  end
157
158  attach_function :vips_value_get_ref_string,
159      [GObject::GValue.ptr, SizeStruct.ptr], :string
160  attach_function :vips_value_get_array_double,
161      [GObject::GValue.ptr, IntStruct.ptr], :pointer
162  attach_function :vips_value_get_array_int,
163      [GObject::GValue.ptr, IntStruct.ptr], :pointer
164  attach_function :vips_value_get_array_image,
165      [GObject::GValue.ptr, IntStruct.ptr], :pointer
166  attach_function :vips_value_get_blob,
167      [GObject::GValue.ptr, SizeStruct.ptr], :pointer
168
169  attach_function :type_find, :vips_type_find, [:string, :string], :GType
170
171  class Object < GObject::GObject
172    # print all active VipsObjects, with their reference counts. Handy for
173    # debugging ruby-vips.
174    def self.print_all
175      GC.start
176      Vips::vips_object_print_all
177    end
178
179    # the layout of the VipsObject struct
180    module ObjectLayout
181      def self.included base
182        base.class_eval do
183          # don't actually need most of these
184          layout :parent, GObject::GObject::Struct,
185             :constructed, :int,
186             :static_object, :int,
187             :argument_table, :pointer,
188             :nickname, :string,
189             :description, :string,
190             :preclose, :int,
191             :close, :int,
192             :postclose, :int,
193             :local_memory, :size_t
194        end
195      end
196    end
197
198    class Struct < GObject::GObject::Struct
199      include ObjectLayout
200    end
201
202    class ManagedStruct < GObject::GObject::ManagedStruct
203      include ObjectLayout
204    end
205
206    # return a pspec, or nil ... nil wil leave a message in the error log
207    # which you must clear
208    def get_pspec name
209      ppspec = GObject::GParamSpecPtr.new
210      argument_class = Vips::ArgumentClassPtr.new
211      argument_instance = Vips::ArgumentInstancePtr.new
212
213      result = Vips::vips_object_get_argument self, name,
214          ppspec, argument_class, argument_instance
215      return nil if result != 0
216
217      ppspec[:value]
218    end
219
220    # return a gtype, raise an error on not found
221    def get_typeof_error name
222      pspec = get_pspec name
223      raise Vips::Error unless pspec
224
225      pspec[:value_type]
226    end
227
228    # return a gtype, 0 on not found
229    def get_typeof name
230      pspec = get_pspec name
231      unless pspec
232        Vips::vips_error_clear
233        return 0
234      end
235
236      pspec[:value_type]
237    end
238
239    def get name
240      gtype = get_typeof_error name
241      gvalue = GObject::GValue.alloc
242      gvalue.init gtype
243      GObject::g_object_get_property self, name, gvalue
244      result = gvalue.get
245      gvalue.unset
246
247      GLib::logger.debug("Vips::Object.get") { "#{name} == #{result}" }
248
249      return result
250    end
251
252    def set name, value
253      GLib::logger.debug("Vips::Object.set") { "#{name} = #{value}" }
254
255      gtype = get_typeof_error name
256      gvalue = GObject::GValue.alloc
257      gvalue.init gtype
258      gvalue.set value
259      GObject::g_object_set_property self, name, gvalue
260      gvalue.unset
261    end
262
263    def signal_connect name, handler=nil
264      marshal = MARSHAL_ALL[name.to_sym]
265      raise Vips::Error, "unsupported signal #{name}" if marshal == nil
266
267      if block_given? 
268        # This will grab any block given to us and make it into a proc
269        prc = Proc.new
270      elsif handler
271        # We assume the hander is a proc (perhaps we should test)
272        prc = handler
273      else
274        raise Vips::Error, "must supply either block or handler"
275      end
276
277      # The marshal function will make a closure with the right type signature 
278      # for the selected signal
279      callback = marshal.(prc)
280
281      # we need to make sure this is not GCd while self is alive
282      @references << callback
283
284      GObject::g_signal_connect_data(self, name.to_s, callback, nil, nil, 0)
285    end
286
287  end
288
289  class ObjectClass < FFI::Struct
290    # opaque
291  end
292
293  class Argument < FFI::Struct
294    layout :pspec, GObject::GParamSpec.ptr
295  end
296
297  class ArgumentInstance < Argument
298    layout :parent, Argument
299    # rest opaque
300  end
301
302  # enum VipsArgumentFlags
303  ARGUMENT_REQUIRED = 1
304  ARGUMENT_CONSTRUCT = 2
305  ARGUMENT_SET_ONCE = 4
306  ARGUMENT_SET_ALWAYS = 8
307  ARGUMENT_INPUT = 16
308  ARGUMENT_OUTPUT = 32
309  ARGUMENT_DEPRECATED = 64
310  ARGUMENT_MODIFY = 128
311
312  ARGUMENT_FLAGS = {
313    required: ARGUMENT_REQUIRED,
314    construct: ARGUMENT_CONSTRUCT,
315    set_once: ARGUMENT_SET_ONCE,
316    set_always: ARGUMENT_SET_ALWAYS,
317    input: ARGUMENT_INPUT,
318    output: ARGUMENT_OUTPUT,
319    deprecated: ARGUMENT_DEPRECATED,
320    modify: ARGUMENT_MODIFY
321  }
322
323  class ArgumentClass < Argument
324    layout :parent, Argument,
325           :object_class, ObjectClass.ptr,
326           :flags, :uint,
327           :priority, :int,
328           :offset, :ulong_long
329  end
330
331  class ArgumentClassPtr < FFI::Struct
332    layout :value, ArgumentClass.ptr
333  end
334
335  class ArgumentInstancePtr < FFI::Struct
336    layout :value, ArgumentInstance.ptr
337  end
338
339  # just use :pointer, not VipsObject.ptr, to avoid casting gobject
340  # subclasses
341  attach_function :vips_object_get_argument,
342      [:pointer, :string,
343       GObject::GParamSpecPtr.ptr,
344       ArgumentClassPtr.ptr, ArgumentInstancePtr.ptr],
345      :int
346
347  attach_function :vips_object_print_all, [], :void
348
349  attach_function :vips_object_set_from_string, [:pointer, :string], :int
350
351  callback :type_map_fn, [:GType, :pointer], :pointer
352  attach_function :vips_type_map, [:GType, :type_map_fn, :pointer], :pointer
353
354  attach_function :vips_object_get_description, [:pointer], :string
355end