ruby-vips 2.0.13 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +42 -0
  3. data/.github/workflows/test.yml +80 -0
  4. data/.standard.yml +17 -0
  5. data/.yardopts +0 -1
  6. data/CHANGELOG.md +44 -0
  7. data/Gemfile +3 -1
  8. data/README.md +45 -47
  9. data/Rakefile +13 -15
  10. data/TODO +19 -10
  11. data/VERSION +1 -1
  12. data/example/annotate.rb +7 -7
  13. data/example/connection.rb +26 -0
  14. data/example/daltonize8.rb +27 -29
  15. data/example/draw_lines.rb +30 -0
  16. data/example/example1.rb +5 -6
  17. data/example/example2.rb +11 -11
  18. data/example/example3.rb +9 -9
  19. data/example/example4.rb +8 -8
  20. data/example/example5.rb +8 -9
  21. data/example/inheritance_with_refcount.rb +203 -221
  22. data/example/progress.rb +30 -0
  23. data/example/thumb.rb +12 -14
  24. data/example/trim8.rb +7 -7
  25. data/example/watermark.rb +15 -36
  26. data/example/wobble.rb +25 -25
  27. data/lib/ruby-vips.rb +1 -1
  28. data/lib/vips.rb +473 -338
  29. data/lib/vips/access.rb +9 -9
  30. data/lib/vips/align.rb +7 -8
  31. data/lib/vips/angle.rb +8 -9
  32. data/lib/vips/angle45.rb +12 -13
  33. data/lib/vips/bandformat.rb +16 -18
  34. data/lib/vips/blend_mode.rb +36 -0
  35. data/lib/vips/coding.rb +11 -12
  36. data/lib/vips/compass_direction.rb +13 -14
  37. data/lib/vips/connection.rb +46 -0
  38. data/lib/vips/direction.rb +7 -8
  39. data/lib/vips/extend.rb +13 -14
  40. data/lib/vips/gobject.rb +111 -100
  41. data/lib/vips/gvalue.rb +243 -237
  42. data/lib/vips/image.rb +1501 -1338
  43. data/lib/vips/interesting.rb +10 -11
  44. data/lib/vips/interpolate.rb +50 -54
  45. data/lib/vips/interpretation.rb +25 -26
  46. data/lib/vips/kernel.rb +18 -19
  47. data/lib/vips/methods.rb +929 -309
  48. data/lib/vips/mutableimage.rb +154 -0
  49. data/lib/vips/object.rb +318 -208
  50. data/lib/vips/operation.rb +467 -320
  51. data/lib/vips/operationboolean.rb +10 -11
  52. data/lib/vips/operationcomplex.rb +8 -9
  53. data/lib/vips/operationcomplex2.rb +6 -7
  54. data/lib/vips/operationcomplexget.rb +7 -8
  55. data/lib/vips/operationmath.rb +14 -15
  56. data/lib/vips/operationmath2.rb +6 -7
  57. data/lib/vips/operationrelational.rb +11 -12
  58. data/lib/vips/operationround.rb +7 -8
  59. data/lib/vips/region.rb +73 -0
  60. data/lib/vips/size.rb +9 -10
  61. data/lib/vips/source.rb +88 -0
  62. data/lib/vips/sourcecustom.rb +89 -0
  63. data/lib/vips/target.rb +86 -0
  64. data/lib/vips/targetcustom.rb +77 -0
  65. data/lib/vips/version.rb +1 -2
  66. data/ruby-vips.gemspec +29 -20
  67. metadata +51 -40
  68. data/.travis.yml +0 -55
  69. data/install-vips.sh +0 -26
@@ -0,0 +1,154 @@
1
+ # This module provides an interface to the vips image processing library
2
+ # via ruby-ffi.
3
+ #
4
+ # Author:: John Cupitt (mailto:jcupitt@gmail.com)
5
+ # License:: MIT
6
+
7
+ require "ffi"
8
+ require "forwardable"
9
+
10
+ module Vips
11
+ # This class represents a libvips image which can be modified. See
12
+ # {Vips::Image#mutate}.
13
+ class MutableImage < Vips::Object
14
+ extend Forwardable
15
+ alias_method :parent_get_typeof, :get_typeof
16
+ def_instance_delegators :@image, :width, :height, :bands, :format,
17
+ :interpretation, :filename, :xoffset, :yoffset, :xres, :yres, :size,
18
+ :get, :get_typeof, :get_fields
19
+
20
+ # layout is exactly as {Image} (since we are also wrapping a VipsImage
21
+ # object)
22
+ module MutableImageLayout
23
+ def self.included base
24
+ base.class_eval do
25
+ layout :parent, Vips::Object::Struct
26
+ # rest opaque
27
+ end
28
+ end
29
+ end
30
+
31
+ class Struct < Vips::Object::Struct
32
+ include MutableImageLayout
33
+ end
34
+
35
+ class ManagedStruct < Vips::Object::ManagedStruct
36
+ include MutableImageLayout
37
+ end
38
+
39
+ # Get the {Image} this {MutableImage} is modifying. Only use this once you
40
+ # have finished all modifications.
41
+ #
42
+ # This is for internal use only. See {Vips::Image#mutate} for the
43
+ # user-facing interface.
44
+ attr_reader :image
45
+
46
+ # Make a {MutableImage} from a regular {Image}.
47
+ #
48
+ # This is for internal use only. See {Vips::Image#mutate} for the
49
+ # user-facing interface.
50
+ def initialize(image)
51
+ # We take a copy of the regular Image to ensure we have an unshared
52
+ # (unique) object. We forward things like #width and #height to this, and
53
+ # it's the thing we return at the end of the mutate block.
54
+ copy_image = image.copy
55
+
56
+ # use ptr since we need the raw unwrapped pointer inside the image ...
57
+ # and make the ref that gobject will unref when it finishes
58
+ pointer = copy_image.ptr
59
+ ::GObject.g_object_ref pointer
60
+ super pointer
61
+
62
+ # and save the copy ready for when we finish mutating
63
+ @image = copy_image
64
+ end
65
+
66
+ def inspect
67
+ "#<MutableImage #{width}x#{height} #{format}, #{bands} bands, #{interpretation}>"
68
+ end
69
+
70
+ def respond_to? name, include_all = false
71
+ # To support keyword args, we need to tell Ruby that final image
72
+ # arguments cannot be hashes of keywords.
73
+ #
74
+ # https://makandracards.com/makandra/
75
+ # 36013-heads-up-ruby-implicitly-converts-a-hash-to-keyword-arguments
76
+ return false if name == :to_hash
77
+
78
+ super
79
+ end
80
+
81
+ def respond_to_missing? name, include_all = false
82
+ # respond to all vips operations by nickname
83
+ return true if Vips.type_find("VipsOperation", name.to_s) != 0
84
+
85
+ super
86
+ end
87
+
88
+ # Invoke a vips operation with {Vips::Operation#call}, using self as
89
+ # the first input argument. {Vips::Operation#call} will only allow
90
+ # operations that modify self when passed a {MutableImage}.
91
+ #
92
+ # @param name [String] vips operation to call
93
+ # @return result of vips operation
94
+ def method_missing name, *args, **options
95
+ Vips::Operation.call name.to_s, [self, *args], options
96
+ end
97
+
98
+ # Create a metadata item on an image of the specifed type. Ruby types
99
+ # are automatically transformed into the matching glib type (eg.
100
+ # {GObject::GINT_TYPE}), if possible.
101
+ #
102
+ # For example, you can use this to set an image's ICC profile:
103
+ #
104
+ # ```ruby
105
+ # x.set_type! Vips::BLOB_TYPE, "icc-profile-data", profile
106
+ # ```
107
+ #
108
+ # where `profile` is an ICC profile held as a binary string object.
109
+ #
110
+ # @see set!
111
+ # @param gtype [Integer] GType of item
112
+ # @param name [String] Metadata field to set
113
+ # @param value [Object] Value to set
114
+ def set_type! gtype, name, value
115
+ gvalue = GObject::GValue.alloc
116
+ gvalue.init gtype
117
+ gvalue.set value
118
+ Vips.vips_image_set self, name, gvalue
119
+ gvalue.unset
120
+ end
121
+
122
+ # Set the value of a metadata item on an image. The metadata item must
123
+ # already exist. Ruby types are automatically transformed into the
124
+ # matching {GObject::GValue}, if possible.
125
+ #
126
+ # For example, you can use this to set an image's ICC profile:
127
+ #
128
+ # ```
129
+ # x.set! "icc-profile-data", profile
130
+ # ```
131
+ #
132
+ # where `profile` is an ICC profile held as a binary string object.
133
+ #
134
+ # @see set_type!
135
+ # @param name [String] Metadata field to set
136
+ # @param value [Object] Value to set
137
+ def set! name, value
138
+ set_type! get_typeof(name), name, value
139
+ end
140
+
141
+ # Remove a metadata item from an image.
142
+ #
143
+ # For example:
144
+ #
145
+ # ```
146
+ # x.remove! "icc-profile-data"
147
+ # ```
148
+ #
149
+ # @param name [String] Metadata field to remove
150
+ def remove! name
151
+ Vips.vips_image_remove self, name
152
+ end
153
+ end
154
+ end
data/lib/vips/object.rb CHANGED
@@ -4,241 +4,351 @@
4
4
  # Author:: John Cupitt (mailto:jcupitt@gmail.com)
5
5
  # License:: MIT
6
6
 
7
- require 'ffi'
7
+ require "ffi"
8
8
 
9
9
  module 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
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 do |handler|
66
+ FFI::Function.new(:void, [:pointer, :pointer, :pointer]) do |vi, prog, cb|
67
+ begin
68
+ handler.call(Progress.new(prog))
69
+ rescue Exception => e
70
+ puts "progress: #{e}"
71
+ end
40
72
  end
41
-
42
- private
43
-
44
- attach_function :vips_enum_from_nick, [:string, :GType, :string], :int
45
- attach_function :vips_enum_nick, [:GType, :int], :string
46
-
47
- attach_function :vips_value_set_ref_string,
48
- [GObject::GValue.ptr, :string], :void
49
- attach_function :vips_value_set_array_double,
50
- [GObject::GValue.ptr, :pointer, :int], :void
51
- attach_function :vips_value_set_array_int,
52
- [GObject::GValue.ptr, :pointer, :int], :void
53
- attach_function :vips_value_set_array_image,
54
- [GObject::GValue.ptr, :int], :void
55
- callback :free_fn, [:pointer], :void
56
- attach_function :vips_value_set_blob,
57
- [GObject::GValue.ptr, :free_fn, :pointer, :size_t], :void
58
-
59
- class SizeStruct < FFI::Struct
60
- layout :value, :size_t
73
+ end
74
+
75
+ MARSHAL_READ = proc do |handler|
76
+ FFI::Function.new(:int64_t, [:pointer, :pointer, :int64_t]) do |i, p, len|
77
+ begin
78
+ result = handler.call(p, len)
79
+ rescue Exception => e
80
+ puts "read: #{e}"
81
+ result = 0
82
+ end
83
+
84
+ result
61
85
  end
62
-
63
- class IntStruct < FFI::Struct
64
- layout :value, :int
86
+ end
87
+
88
+ MARSHAL_SEEK = proc do |handler|
89
+ FFI::Function.new(:int64_t, [:pointer, :int64_t, :int]) do |i, off, whence|
90
+ begin
91
+ result = handler.call(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 do |handler|
102
+ FFI::Function.new(:int64_t, [:pointer, :pointer, :int64_t]) do |i, p, len|
103
+ begin
104
+ result = handler.call(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 do |handler|
115
+ FFI::Function.new(:void, [:pointer, :pointer]) do |i, cb|
116
+ begin
117
+ handler.call
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
65
177
  end
66
178
 
67
- attach_function :vips_value_get_ref_string,
68
- [GObject::GValue.ptr, SizeStruct.ptr], :string
69
- attach_function :vips_value_get_array_double,
70
- [GObject::GValue.ptr, IntStruct.ptr], :pointer
71
- attach_function :vips_value_get_array_int,
72
- [GObject::GValue.ptr, IntStruct.ptr], :pointer
73
- attach_function :vips_value_get_array_image,
74
- [GObject::GValue.ptr, IntStruct.ptr], :pointer
75
- attach_function :vips_value_get_blob,
76
- [GObject::GValue.ptr, SizeStruct.ptr], :pointer
77
-
78
- attach_function :type_find, :vips_type_find, [:string, :string], :GType
79
-
80
- class Object < GObject::GObject
81
-
82
- # print all active VipsObjects, with their reference counts. Handy for
83
- # debugging ruby-vips.
84
- def self.print_all
85
- GC.start
86
- Vips::vips_object_print_all
87
- end
88
-
89
- # the layout of the VipsObject struct
90
- module ObjectLayout
91
- def self.included base
92
- base.class_eval do
93
- # don't actually need most of these
94
- layout :parent, GObject::GObject::Struct,
95
- :constructed, :int,
96
- :static_object, :int,
97
- :argument_table, :pointer,
98
- :nickname, :string,
99
- :description, :string,
100
- :preclose, :int,
101
- :close, :int,
102
- :postclose, :int,
103
- :local_memory, :size_t
104
- end
105
- end
106
- end
107
-
108
- class Struct < GObject::GObject::Struct
109
- include ObjectLayout
110
-
111
- end
112
-
113
- class ManagedStruct < GObject::GObject::ManagedStruct
114
- include ObjectLayout
115
-
116
- end
117
-
118
- # return a pspec, or nil ... nil wil leave a message in the error log
119
- # which you must clear
120
- def get_pspec name
121
- pspec = GObject::GParamSpecPtr.new
122
- argument_class = Vips::ArgumentClassPtr.new
123
- argument_instance = Vips::ArgumentInstancePtr.new
124
-
125
- result = Vips::vips_object_get_argument self, name,
126
- pspec, argument_class, argument_instance
127
- return nil if result != 0
128
-
129
- pspec
130
- end
131
-
132
- # return a gtype, raise an error on not found
133
- def get_typeof_error name
134
- pspec = get_pspec name
135
- raise Vips::Error unless pspec
136
-
137
- pspec[:value][:value_type]
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
138
194
  end
195
+ end
196
+ end
139
197
 
140
- # return a gtype, 0 on not found
141
- def get_typeof name
142
- pspec = get_pspec name
143
- unless pspec
144
- Vips::vips_error_clear
145
- return 0
146
- end
147
-
148
- pspec[:value][:value_type]
149
- end
198
+ class Struct < GObject::GObject::Struct
199
+ include ObjectLayout
200
+ end
150
201
 
151
- def get name
152
- gtype = get_typeof_error name
153
- gvalue = GObject::GValue.alloc
154
- gvalue.init gtype
155
- GObject::g_object_get_property self, name, gvalue
156
- result = gvalue.get
202
+ class ManagedStruct < GObject::GObject::ManagedStruct
203
+ include ObjectLayout
204
+ end
157
205
 
158
- GLib::logger.debug("Vips::Object.get") {"#{name} == #{result}"}
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
159
212
 
160
- return result
161
- end
213
+ result = Vips.vips_object_get_argument self, name,
214
+ ppspec, argument_class, argument_instance
215
+ return nil if result != 0
162
216
 
163
- def set name, value
164
- GLib::logger.debug("Vips::Object.set") {"#{name} = #{value}"}
217
+ ppspec[:value]
218
+ end
165
219
 
166
- gtype = get_typeof_error name
167
- gvalue = GObject::GValue.alloc
168
- gvalue.init gtype
169
- gvalue.set value
170
- GObject::g_object_set_property self, name, gvalue
171
- end
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
172
224
 
225
+ pspec[:value_type]
173
226
  end
174
227
 
175
- class ObjectClass < FFI::Struct
176
- # opaque
177
- end
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
178
235
 
179
- class Argument < FFI::Struct
180
- layout :pspec, GObject::GParamSpec.ptr
236
+ pspec[:value_type]
181
237
  end
182
238
 
183
- class ArgumentInstance < Argument
184
- layout :parent, Argument
185
- # rest opaque
186
- end
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
187
246
 
188
- # enum VipsArgumentFlags
189
- ARGUMENT_REQUIRED = 1
190
- ARGUMENT_CONSTRUCT = 2
191
- ARGUMENT_SET_ONCE = 4
192
- ARGUMENT_SET_ALWAYS = 8
193
- ARGUMENT_INPUT = 16
194
- ARGUMENT_OUTPUT = 32
195
- ARGUMENT_DEPRECATED = 64
196
- ARGUMENT_MODIFY = 128
197
-
198
- ARGUMENT_FLAGS = {
199
- :required => ARGUMENT_REQUIRED,
200
- :construct => ARGUMENT_CONSTRUCT,
201
- :set_once => ARGUMENT_SET_ONCE,
202
- :set_always => ARGUMENT_SET_ALWAYS,
203
- :input => ARGUMENT_INPUT,
204
- :output => ARGUMENT_OUTPUT,
205
- :deprecated => ARGUMENT_DEPRECATED,
206
- :modify => ARGUMENT_MODIFY
207
- }
208
-
209
- class ArgumentClass < Argument
210
- layout :parent, Argument,
211
- :object_class, ObjectClass.ptr,
212
- :flags, :uint,
213
- :priority, :int,
214
- :offset, :ulong_long
215
- end
247
+ GLib.logger.debug("Vips::Object.get") { "#{name} == #{result}" }
216
248
 
217
- class ArgumentClassPtr < FFI::Struct
218
- layout :value, ArgumentClass.ptr
249
+ result
219
250
  end
220
251
 
221
- class ArgumentInstancePtr < FFI::Struct
222
- layout :value, ArgumentInstance.ptr
223
- end
252
+ def set name, value
253
+ GLib.logger.debug("Vips::Object.set") { "#{name} = #{value}" }
224
254
 
225
- # just use :pointer, not VipsObject.ptr, to avoid casting gobject
226
- # subclasses
227
- attach_function :vips_object_get_argument,
228
- [:pointer, :string,
229
- GObject::GParamSpecPtr.ptr,
230
- ArgumentClassPtr.ptr, ArgumentInstancePtr.ptr],
231
- :int
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
232
262
 
233
- attach_function :vips_object_print_all, [], :void
263
+ def signal_connect name, handler = nil, &block
264
+ marshal = MARSHAL_ALL[name.to_sym]
265
+ raise Vips::Error, "unsupported signal #{name}" if marshal.nil?
234
266
 
235
- attach_function :vips_object_set_from_string, [:pointer, :string], :int
267
+ if block
268
+ # our block as a Proc
269
+ prc = block
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
236
276
 
237
- callback :type_map_fn, [:GType, :pointer], :pointer
238
- attach_function :vips_type_map, [:GType, :type_map_fn, :pointer], :pointer
277
+ # The marshal function will make a closure with the right type signature
278
+ # for the selected signal
279
+ callback = marshal.call(prc)
239
280
 
240
- attach_function :vips_object_get_description, [:pointer], :string
281
+ # we need to make sure this is not GCd while self is alive
282
+ @references << callback
241
283
 
284
+ GObject.g_signal_connect_data(self, name.to_s, callback, nil, nil, 0)
285
+ end
286
+ end
287
+
288
+ class ObjectClass < FFI::Struct
289
+ # opaque
290
+ end
291
+
292
+ class Argument < FFI::Struct
293
+ layout :pspec, GObject::GParamSpec.ptr
294
+ end
295
+
296
+ class ArgumentInstance < Argument
297
+ layout :parent, Argument
298
+ # rest opaque
299
+ end
300
+
301
+ # enum VipsArgumentFlags
302
+ ARGUMENT_REQUIRED = 1
303
+ ARGUMENT_CONSTRUCT = 2
304
+ ARGUMENT_SET_ONCE = 4
305
+ ARGUMENT_SET_ALWAYS = 8
306
+ ARGUMENT_INPUT = 16
307
+ ARGUMENT_OUTPUT = 32
308
+ ARGUMENT_DEPRECATED = 64
309
+ ARGUMENT_MODIFY = 128
310
+
311
+ ARGUMENT_FLAGS = {
312
+ required: ARGUMENT_REQUIRED,
313
+ construct: ARGUMENT_CONSTRUCT,
314
+ set_once: ARGUMENT_SET_ONCE,
315
+ set_always: ARGUMENT_SET_ALWAYS,
316
+ input: ARGUMENT_INPUT,
317
+ output: ARGUMENT_OUTPUT,
318
+ deprecated: ARGUMENT_DEPRECATED,
319
+ modify: ARGUMENT_MODIFY
320
+ }
321
+
322
+ class ArgumentClass < Argument
323
+ layout :parent, Argument,
324
+ :object_class, ObjectClass.ptr,
325
+ :flags, :uint,
326
+ :priority, :int,
327
+ :offset, :ulong_long
328
+ end
329
+
330
+ class ArgumentClassPtr < FFI::Struct
331
+ layout :value, ArgumentClass.ptr
332
+ end
333
+
334
+ class ArgumentInstancePtr < FFI::Struct
335
+ layout :value, ArgumentInstance.ptr
336
+ end
337
+
338
+ # just use :pointer, not VipsObject.ptr, to avoid casting gobject
339
+ # subclasses
340
+ attach_function :vips_object_get_argument,
341
+ [:pointer, :string,
342
+ GObject::GParamSpecPtr.ptr,
343
+ ArgumentClassPtr.ptr, ArgumentInstancePtr.ptr],
344
+ :int
345
+
346
+ attach_function :vips_object_print_all, [], :void
347
+
348
+ attach_function :vips_object_set_from_string, [:pointer, :string], :int
349
+
350
+ callback :type_map_fn, [:GType, :pointer], :pointer
351
+ attach_function :vips_type_map, [:GType, :type_map_fn, :pointer], :pointer
352
+
353
+ attach_function :vips_object_get_description, [:pointer], :string
242
354
  end
243
-
244
-