vips 8.8.0.3 → 8.10.5

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 (51) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +5 -2
  3. data/README.md +3 -1
  4. data/example/connection.rb +17 -0
  5. data/example/daltonize8.rb +13 -15
  6. data/example/example1.rb +1 -2
  7. data/example/example4.rb +2 -2
  8. data/example/example5.rb +4 -5
  9. data/example/inheritance_with_refcount.rb +2 -19
  10. data/example/progress.rb +30 -0
  11. data/example/thumb.rb +2 -4
  12. data/example/trim8.rb +4 -4
  13. data/ext/Rakefile +2 -2
  14. data/lib/vips.rb +101 -35
  15. data/lib/vips/align.rb +0 -1
  16. data/lib/vips/angle.rb +0 -1
  17. data/lib/vips/angle45.rb +0 -1
  18. data/lib/vips/bandformat.rb +0 -2
  19. data/lib/vips/blend_mode.rb +0 -2
  20. data/lib/vips/coding.rb +0 -1
  21. data/lib/vips/compass_direction.rb +0 -1
  22. data/lib/vips/connection.rb +46 -0
  23. data/lib/vips/direction.rb +0 -1
  24. data/lib/vips/extend.rb +0 -1
  25. data/lib/vips/gobject.rb +8 -4
  26. data/lib/vips/gvalue.rb +15 -9
  27. data/lib/vips/image.rb +269 -204
  28. data/lib/vips/interesting.rb +0 -1
  29. data/lib/vips/interpolate.rb +0 -5
  30. data/lib/vips/interpretation.rb +0 -1
  31. data/lib/vips/kernel.rb +0 -1
  32. data/lib/vips/methods.rb +150 -59
  33. data/lib/vips/object.rb +126 -18
  34. data/lib/vips/operation.rb +169 -101
  35. data/lib/vips/operationboolean.rb +0 -1
  36. data/lib/vips/operationcomplex.rb +0 -1
  37. data/lib/vips/operationcomplex2.rb +0 -1
  38. data/lib/vips/operationcomplexget.rb +0 -1
  39. data/lib/vips/operationmath.rb +0 -1
  40. data/lib/vips/operationmath2.rb +0 -1
  41. data/lib/vips/operationrelational.rb +0 -1
  42. data/lib/vips/operationround.rb +0 -1
  43. data/lib/vips/region.rb +73 -0
  44. data/lib/vips/size.rb +0 -1
  45. data/lib/vips/source.rb +89 -0
  46. data/lib/vips/sourcecustom.rb +90 -0
  47. data/lib/vips/target.rb +87 -0
  48. data/lib/vips/targetcustom.rb +78 -0
  49. data/lib/vips/version.rb +1 -1
  50. metadata +14 -7
  51. data/CHANGELOG.md +0 -266
@@ -41,6 +41,97 @@ module Vips
41
41
 
42
42
  private
43
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
+
44
135
  attach_function :vips_enum_from_nick, [:string, :GType, :string], :int
45
136
  attach_function :vips_enum_nick, [:GType, :int], :string
46
137
 
@@ -78,7 +169,6 @@ module Vips
78
169
  attach_function :type_find, :vips_type_find, [:string, :string], :GType
79
170
 
80
171
  class Object < GObject::GObject
81
-
82
172
  # print all active VipsObjects, with their reference counts. Handy for
83
173
  # debugging ruby-vips.
84
174
  def self.print_all
@@ -107,26 +197,24 @@ module Vips
107
197
 
108
198
  class Struct < GObject::GObject::Struct
109
199
  include ObjectLayout
110
-
111
200
  end
112
201
 
113
202
  class ManagedStruct < GObject::GObject::ManagedStruct
114
203
  include ObjectLayout
115
-
116
204
  end
117
205
 
118
206
  # return a pspec, or nil ... nil wil leave a message in the error log
119
207
  # which you must clear
120
208
  def get_pspec name
121
- pspec = GObject::GParamSpecPtr.new
209
+ ppspec = GObject::GParamSpecPtr.new
122
210
  argument_class = Vips::ArgumentClassPtr.new
123
211
  argument_instance = Vips::ArgumentInstancePtr.new
124
212
 
125
213
  result = Vips::vips_object_get_argument self, name,
126
- pspec, argument_class, argument_instance
214
+ ppspec, argument_class, argument_instance
127
215
  return nil if result != 0
128
216
 
129
- pspec
217
+ ppspec[:value]
130
218
  end
131
219
 
132
220
  # return a gtype, raise an error on not found
@@ -134,7 +222,7 @@ module Vips
134
222
  pspec = get_pspec name
135
223
  raise Vips::Error unless pspec
136
224
 
137
- pspec[:value][:value_type]
225
+ pspec[:value_type]
138
226
  end
139
227
 
140
228
  # return a gtype, 0 on not found
@@ -145,7 +233,7 @@ module Vips
145
233
  return 0
146
234
  end
147
235
 
148
- pspec[:value][:value_type]
236
+ pspec[:value_type]
149
237
  end
150
238
 
151
239
  def get name
@@ -154,20 +242,40 @@ module Vips
154
242
  gvalue.init gtype
155
243
  GObject::g_object_get_property self, name, gvalue
156
244
  result = gvalue.get
245
+ gvalue.unset
157
246
 
158
- GLib::logger.debug("Vips::Object.get") {"#{name} == #{result}"}
247
+ GLib::logger.debug("Vips::Object.get") { "#{name} == #{result}" }
159
248
 
160
249
  return result
161
250
  end
162
251
 
163
252
  def set name, value
164
- GLib::logger.debug("Vips::Object.set") {"#{name} = #{value}"}
253
+ GLib::logger.debug("Vips::Object.set") { "#{name} = #{value}" }
165
254
 
166
255
  gtype = get_typeof_error name
167
256
  gvalue = GObject::GValue.alloc
168
257
  gvalue.init gtype
169
258
  gvalue.set value
170
259
  GObject::g_object_set_property self, name, gvalue
260
+ gvalue.unset
261
+ end
262
+
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
266
+
267
+ unless handler ||= block
268
+ raise Vips::Error, "must supply either block or handler"
269
+ end
270
+
271
+ # The marshal function will make a closure with the right type signature
272
+ # for the selected signal
273
+ callback = marshal.(handler)
274
+
275
+ # we need to make sure this is not GCd while self is alive
276
+ @references << callback
277
+
278
+ GObject::g_signal_connect_data(self, name.to_s, callback, nil, nil, 0)
171
279
  end
172
280
 
173
281
  end
@@ -196,14 +304,14 @@ module Vips
196
304
  ARGUMENT_MODIFY = 128
197
305
 
198
306
  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
307
+ required: ARGUMENT_REQUIRED,
308
+ construct: ARGUMENT_CONSTRUCT,
309
+ set_once: ARGUMENT_SET_ONCE,
310
+ set_always: ARGUMENT_SET_ALWAYS,
311
+ input: ARGUMENT_INPUT,
312
+ output: ARGUMENT_OUTPUT,
313
+ deprecated: ARGUMENT_DEPRECATED,
314
+ modify: ARGUMENT_MODIFY
207
315
  }
208
316
 
209
317
  class ArgumentClass < Argument
@@ -11,7 +11,13 @@ module Vips
11
11
 
12
12
  attach_function :vips_operation_new, [:string], :pointer
13
13
 
14
- attach_function :vips_cache_operation_build, [:pointer], :pointer
14
+ # We may well block during this (eg. if it's avg, or perhaps jpegsave), and
15
+ # libvips might trigger some signals which ruby has handles for.
16
+ #
17
+ # We need FFI to drop the GIL lock during this call and reacquire it when
18
+ # the call ends, or we'll deadlock.
19
+ attach_function :vips_cache_operation_build, [:pointer], :pointer,
20
+ blocking: true
15
21
  attach_function :vips_object_unref_outputs, [:pointer], :void
16
22
 
17
23
  callback :argument_map_fn, [:pointer,
@@ -28,15 +34,126 @@ module Vips
28
34
  OPERATION_DEPRECATED = 8
29
35
 
30
36
  OPERATION_FLAGS = {
31
- :sequential => OPERATION_SEQUENTIAL,
32
- :nocache => OPERATION_NOCACHE,
33
- :deprecated => OPERATION_DEPRECATED
37
+ sequential: OPERATION_SEQUENTIAL,
38
+ nocache: OPERATION_NOCACHE,
39
+ deprecated: OPERATION_DEPRECATED
34
40
  }
35
41
 
36
42
  attach_function :vips_operation_get_flags, [:pointer], :int
37
43
 
38
- class Operation < Object
44
+ # Introspect a vips operation and return a large structure containing
45
+ # everything we know about it. This is used for doc generation as well as
46
+ # call.
47
+ class Introspect
48
+ attr_reader :name, :description, :flags, :args, :required_input,
49
+ :optional_input, :required_output, :optional_output, :member_x,
50
+ :method_args
51
+
52
+ @@introspect_cache = {}
53
+
54
+ def initialize name
55
+ @op = Operation.new name
56
+ @args = []
57
+ @required_input = []
58
+ @optional_input = {}
59
+ @required_output = []
60
+ @optional_output = {}
61
+
62
+ # find all the arguments the operator can take
63
+ @op.argument_map do |pspec, argument_class, _argument_instance|
64
+ flags = argument_class[:flags]
65
+ if (flags & ARGUMENT_CONSTRUCT) != 0
66
+ # names can include - as punctuation, but we always use _ in
67
+ # Ruby
68
+ arg_name = pspec[:name].tr("-", "_")
69
+ args << {
70
+ :arg_name => arg_name,
71
+ :flags => flags,
72
+ :gtype => pspec[:value_type]
73
+ }
74
+ end
75
+ end
76
+
77
+ @args.each do |details|
78
+ arg_name = details[:arg_name]
79
+ flags = details[:flags]
80
+
81
+ if (flags & ARGUMENT_INPUT) != 0
82
+ if (flags & ARGUMENT_REQUIRED) != 0 &&
83
+ (flags & ARGUMENT_DEPRECATED) == 0
84
+ @required_input << details
85
+ else
86
+ # we allow deprecated optional args
87
+ @optional_input[arg_name] = details
88
+ end
89
+
90
+ # MODIFY INPUT args count as OUTPUT as well
91
+ if (flags & ARGUMENT_MODIFY) != 0
92
+ if (flags & ARGUMENT_REQUIRED) != 0 &&
93
+ (flags & ARGUMENT_DEPRECATED) == 0
94
+ @required_output << details
95
+ else
96
+ @optional_output[arg_name] = details
97
+ end
98
+ end
99
+ elsif (flags & ARGUMENT_OUTPUT) != 0
100
+ if (flags & ARGUMENT_REQUIRED) != 0 &&
101
+ (flags & ARGUMENT_DEPRECATED) == 0
102
+ @required_output << details
103
+ else
104
+ # again, allow deprecated optional args
105
+ @optional_output[arg_name] = details
106
+ end
107
+ end
108
+ end
109
+ end
110
+
111
+ # Yard comment generation needs a little more introspection. We add this
112
+ # extra metadata in a separate method to keep the main path as fast as
113
+ # we can.
114
+ def add_yard_introspection name
115
+ @name = name
116
+ @description = Vips::vips_object_get_description @op
117
+ @flags = Vips::vips_operation_get_flags @op
118
+ @member_x = nil
119
+ @method_args = []
120
+
121
+ @args.each do |details|
122
+ arg_name = details[:arg_name]
123
+ flags = details[:flags]
124
+ gtype = details[:gtype]
125
+
126
+ details[:yard_name] = arg_name == "in" ? "im" : arg_name
127
+ pspec = @op.get_pspec arg_name
128
+ details[:blurb] = GObject::g_param_spec_get_blurb pspec
129
+
130
+ if (flags & ARGUMENT_INPUT) != 0 &&
131
+ (flags & ARGUMENT_REQUIRED) != 0 &&
132
+ (flags & ARGUMENT_DEPRECATED) == 0
133
+ # the first required input image is the thing we will be a method
134
+ # of
135
+ if @member_x == nil && gtype == IMAGE_TYPE
136
+ @member_x = details
137
+ else
138
+ @method_args << details
139
+ end
140
+ end
141
+ end
142
+ end
143
+
144
+ def self.get name
145
+ @@introspect_cache[name] ||= Introspect.new name
146
+ end
39
147
 
148
+ def self.get_yard name
149
+ introspect = Introspect.get name
150
+ introspect.add_yard_introspection name
151
+ introspect
152
+ end
153
+
154
+ end
155
+
156
+ class Operation < Object
40
157
  # the layout of the VipsOperation struct
41
158
  module OperationLayout
42
159
  def self.included base
@@ -49,12 +166,10 @@ module Vips
49
166
 
50
167
  class Struct < Object::Struct
51
168
  include OperationLayout
52
-
53
169
  end
54
170
 
55
171
  class ManagedStruct < Object::ManagedStruct
56
172
  include OperationLayout
57
-
58
173
  end
59
174
 
60
175
  def initialize value
@@ -62,7 +177,7 @@ module Vips
62
177
  # things like _build
63
178
  if value.is_a? String
64
179
  value = Vips::vips_operation_new value
65
- raise Vips::Error if value == nil
180
+ raise Vips::Error if value.null?
66
181
  end
67
182
 
68
183
  super value
@@ -70,7 +185,8 @@ module Vips
70
185
 
71
186
  def build
72
187
  op = Vips::vips_cache_operation_build self
73
- if op == nil
188
+ if op.null?
189
+ Vips::vips_object_unref_outputs self
74
190
  raise Vips::Error
75
191
  end
76
192
 
@@ -78,42 +194,23 @@ module Vips
78
194
  end
79
195
 
80
196
  def argument_map &block
81
- fn = Proc.new do |op, pspec, argument_class, argument_instance, a, b|
197
+ fn = Proc.new do |_op, pspec, argument_class, argument_instance, _a, _b|
82
198
  block.call pspec, argument_class, argument_instance
83
199
  end
84
200
 
85
201
  Vips::vips_argument_map self, fn, nil, nil
86
202
  end
87
203
 
88
- def get_flags
89
- Vips::vips_operation_get_flags self
90
- end
91
-
92
- # not quick! try to call this infrequently
93
- def get_construct_args
94
- args = []
95
-
96
- argument_map do |pspec, argument_class, argument_instance|
97
- flags = argument_class[:flags]
98
- if (flags & ARGUMENT_CONSTRUCT) != 0
99
- # names can include - as punctuation, but we always use _ in
100
- # Ruby
101
- name = pspec[:name].tr("-", "_")
102
-
103
- args << [name, flags]
204
+ # Search an object for the first element to match a predicate. Search
205
+ # inside subarrays and sub-hashes. Equlvalent to x.flatten.find{}.
206
+ def self.flat_find object, &block
207
+ if object.respond_to? :each
208
+ object.each do |x|
209
+ result = flat_find x, &block
210
+ return result if result != nil
104
211
  end
105
- end
106
-
107
- return args
108
- end
109
-
110
- # search array for the first element to match a predicate ...
111
- # search inside subarrays and sub-hashes
112
- def self.find_inside object, &block
113
- return object if block.call object
114
-
115
- if object.is_a? Enumerable
116
- object.find {|value| block.call value, block}
212
+ else
213
+ return object if yield object
117
214
  end
118
215
 
119
216
  return nil
@@ -125,8 +222,8 @@ module Vips
125
222
 
126
223
  # 2D array values become tiny 2D images
127
224
  # if there's nothing to match to, we also make a 2D image
128
- if (value.is_a?(Array) && value[0].is_a?(Array)) ||
129
- match_image == nil
225
+ if (value.is_a?(Array) && value[0].is_a?(Array)) ||
226
+ match_image == nil
130
227
  return Image.new_from_array value
131
228
  else
132
229
  # we have a 1D array ... use that as a pixel constant and
@@ -137,9 +234,7 @@ module Vips
137
234
 
138
235
  # set an operation argument, expanding constants and copying images as
139
236
  # required
140
- def set name, value, match_image = nil, flags = 0
141
- gtype = get_typeof name
142
-
237
+ def set name, value, match_image, flags, gtype
143
238
  if gtype == IMAGE_TYPE
144
239
  value = Operation::imageize match_image, value
145
240
 
@@ -148,7 +243,7 @@ module Vips
148
243
  value = value.copy.copy_memory
149
244
  end
150
245
  elsif gtype == ARRAY_IMAGE_TYPE
151
- value = value.map {|x| Operation::imageize match_image, x}
246
+ value = value.map { |x| Operation::imageize match_image, x }
152
247
  end
153
248
 
154
249
  super name, value
@@ -226,66 +321,39 @@ module Vips
226
321
  def self.call name, supplied, optional = {}, option_string = ""
227
322
  GLib::logger.debug("Vips::VipsOperation.call") {
228
323
  "name = #{name}, supplied = #{supplied}, " +
229
- "optional = #{optional}, option_string = #{option_string}"
324
+ "optional = #{optional}, option_string = #{option_string}"
230
325
  }
231
326
 
232
- op = Operation.new name
327
+ introspect = Introspect.get name
328
+ required_input = introspect.required_input
329
+ required_output = introspect.required_output
330
+ optional_input = introspect.optional_input
331
+ optional_output = introspect.optional_output
233
332
 
234
- # find and classify all the arguments the operator can take
235
- args = op.get_construct_args
236
- required_input = []
237
- optional_input = {}
238
- required_output = []
239
- optional_output = {}
240
- args.each do |name, flags|
241
- next if (flags & ARGUMENT_DEPRECATED) != 0
242
-
243
- if (flags & ARGUMENT_INPUT) != 0
244
- if (flags & ARGUMENT_REQUIRED) != 0
245
- required_input << [name, flags]
246
- else
247
- optional_input[name] = flags
248
- end
249
- end
250
-
251
- # MODIFY INPUT args count as OUTPUT as well
252
- if (flags & ARGUMENT_OUTPUT) != 0 ||
253
- ((flags & ARGUMENT_INPUT) != 0 &&
254
- (flags & ARGUMENT_MODIFY) != 0)
255
- if (flags & ARGUMENT_REQUIRED) != 0
256
- required_output << [name, flags]
257
- else
258
- optional_output[name] = flags
259
- end
260
- end
261
-
262
- end
263
-
264
- # so we should have been supplied with n_required_input values, or
265
- # n_required_input + 1 if there's a hash of options at the end
266
333
  unless supplied.is_a? Array
267
334
  raise Vips::Error, "unable to call #{name}: " +
268
- "argument array is not an array"
335
+ "argument array is not an array"
269
336
  end
270
337
  unless optional.is_a? Hash
271
338
  raise Vips::Error, "unable to call #{name}: " +
272
- "optional arguments are not a hash"
339
+ "optional arguments are not a hash"
273
340
  end
341
+
274
342
  if supplied.length != required_input.length
275
343
  raise Vips::Error, "unable to call #{name}: " +
276
- "you supplied #{supplied.length} arguments, " +
277
- "but operation needs #{required_input.length}."
344
+ "you supplied #{supplied.length} arguments, " +
345
+ "but operation needs " + "#{required_input.length}."
278
346
  end
279
347
 
280
- # very that all supplied_optional keys are in optional_input or
348
+ # all supplied_optional keys should be in optional_input or
281
349
  # optional_output
282
- optional.each do |key, value|
350
+ optional.each do |key, _value|
283
351
  arg_name = key.to_s
284
352
 
285
353
  unless optional_input.has_key?(arg_name) ||
286
354
  optional_output.has_key?(arg_name)
287
355
  raise Vips::Error, "unable to call #{name}: " +
288
- "unknown option #{arg_name}"
356
+ "unknown option #{arg_name}"
289
357
  end
290
358
  end
291
359
 
@@ -294,9 +362,9 @@ module Vips
294
362
  #
295
363
  # look inside array and hash arguments, since we may be passing an
296
364
  # array of images
297
- match_image = find_inside(supplied) do |value|
298
- value.is_a? Image
299
- end
365
+ match_image = flat_find(supplied) { |value| value.is_a? Image }
366
+
367
+ op = Operation.new name
300
368
 
301
369
  # set any string args first so they can't be overridden
302
370
  if option_string != nil
@@ -307,11 +375,13 @@ module Vips
307
375
 
308
376
  # set all required inputs
309
377
  required_input.each_index do |i|
310
- arg_name = required_input[i][0]
311
- flags = required_input[i][1]
378
+ details = required_input[i]
379
+ arg_name = details[:arg_name]
380
+ flags = details[:flags]
381
+ gtype = details[:gtype]
312
382
  value = supplied[i]
313
383
 
314
- op.set arg_name, value, match_image, flags
384
+ op.set arg_name, value, match_image, flags, gtype
315
385
  end
316
386
 
317
387
  # set all optional inputs
@@ -321,9 +391,11 @@ module Vips
321
391
  arg_name = key.to_s
322
392
 
323
393
  if optional_input.has_key? arg_name
324
- flags = optional_input[arg_name]
394
+ details = optional_input[arg_name]
395
+ flags = details[:flags]
396
+ gtype = details[:gtype]
325
397
 
326
- op.set arg_name, value, match_image, flags
398
+ op.set arg_name, value, match_image, flags, gtype
327
399
  end
328
400
  end
329
401
 
@@ -331,18 +403,16 @@ module Vips
331
403
 
332
404
  # get all required results
333
405
  result = []
334
- required_output.each do |arg_name, flags|
335
- result << op.get(arg_name)
406
+ required_output.each do |details|
407
+ result << op.get(details[:arg_name])
336
408
  end
337
409
 
338
410
  # fetch all optional ones
339
411
  optional_results = {}
340
- optional.each do |key, value|
412
+ optional.each do |key, _value|
341
413
  arg_name = key.to_s
342
414
 
343
415
  if optional_output.has_key? arg_name
344
- flags = optional_output[arg_name]
345
-
346
416
  optional_results[arg_name] = op.get arg_name
347
417
  end
348
418
  end
@@ -355,13 +425,11 @@ module Vips
355
425
  result = nil
356
426
  end
357
427
 
358
- GLib::logger.debug("Vips::Operation.call") {"result = #{result}"}
428
+ GLib::logger.debug("Vips::Operation.call") { "result = #{result}" }
359
429
 
360
430
  Vips::vips_object_unref_outputs op
361
431
 
362
432
  return result
363
433
  end
364
-
365
434
  end
366
-
367
435
  end