vips 8.8.0.3 → 8.10.5

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