ruby-vips 2.0.13 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
-