ruby-vips 2.0.14 → 2.1.1
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.
- checksums.yaml +4 -4
- data/.github/ISSUE_TEMPLATE/bug_report.md +42 -0
- data/.github/workflows/test.yml +80 -0
- data/.standard.yml +17 -0
- data/.yardopts +0 -1
- data/CHANGELOG.md +41 -0
- data/Gemfile +3 -1
- data/README.md +42 -41
- data/Rakefile +13 -21
- data/TODO +18 -10
- data/VERSION +1 -1
- data/example/annotate.rb +6 -6
- data/example/connection.rb +26 -0
- data/example/daltonize8.rb +16 -18
- data/example/draw_lines.rb +30 -0
- data/example/example1.rb +5 -6
- data/example/example2.rb +6 -6
- data/example/example3.rb +5 -5
- data/example/example4.rb +4 -4
- data/example/example5.rb +6 -7
- data/example/inheritance_with_refcount.rb +36 -54
- data/example/progress.rb +30 -0
- data/example/thumb.rb +8 -10
- data/example/trim8.rb +5 -5
- data/example/watermark.rb +2 -2
- data/example/wobble.rb +1 -1
- data/lib/ruby-vips.rb +1 -1
- data/lib/vips.rb +199 -93
- data/lib/vips/align.rb +0 -1
- data/lib/vips/angle.rb +0 -1
- data/lib/vips/angle45.rb +0 -1
- data/lib/vips/bandformat.rb +0 -2
- data/lib/vips/blend_mode.rb +29 -27
- data/lib/vips/coding.rb +0 -1
- data/lib/vips/compass_direction.rb +0 -1
- data/lib/vips/connection.rb +46 -0
- data/lib/vips/direction.rb +0 -1
- data/lib/vips/extend.rb +0 -1
- data/lib/vips/gobject.rb +26 -15
- data/lib/vips/gvalue.rb +61 -55
- data/lib/vips/image.rb +455 -282
- data/lib/vips/interesting.rb +0 -1
- data/lib/vips/interpolate.rb +3 -7
- data/lib/vips/interpretation.rb +0 -1
- data/lib/vips/kernel.rb +0 -1
- data/lib/vips/methods.rb +791 -124
- data/lib/vips/mutableimage.rb +173 -0
- data/lib/vips/object.rb +178 -68
- data/lib/vips/operation.rb +277 -130
- data/lib/vips/operationboolean.rb +0 -1
- data/lib/vips/operationcomplex.rb +0 -1
- data/lib/vips/operationcomplex2.rb +0 -1
- data/lib/vips/operationcomplexget.rb +0 -1
- data/lib/vips/operationmath.rb +0 -1
- data/lib/vips/operationmath2.rb +0 -1
- data/lib/vips/operationrelational.rb +0 -1
- data/lib/vips/operationround.rb +0 -1
- data/lib/vips/region.rb +73 -0
- data/lib/vips/size.rb +0 -1
- data/lib/vips/source.rb +88 -0
- data/lib/vips/sourcecustom.rb +89 -0
- data/lib/vips/target.rb +86 -0
- data/lib/vips/targetcustom.rb +77 -0
- data/lib/vips/version.rb +1 -2
- data/ruby-vips.gemspec +26 -21
- metadata +39 -51
- data/.rubocop.yml +0 -10
- data/.rubocop_todo.yml +0 -730
- data/.travis.yml +0 -62
- data/install-vips.sh +0 -26
data/lib/vips/operation.rb
CHANGED
@@ -4,39 +4,180 @@
|
|
4
4
|
# Author:: John Cupitt (mailto:jcupitt@gmail.com)
|
5
5
|
# License:: MIT
|
6
6
|
|
7
|
-
require
|
7
|
+
require "ffi"
|
8
|
+
require "set"
|
8
9
|
|
9
10
|
module Vips
|
10
11
|
private
|
11
12
|
|
12
13
|
attach_function :vips_operation_new, [:string], :pointer
|
13
14
|
|
14
|
-
|
15
|
+
# We may well block during this (eg. if it's avg, or perhaps jpegsave), and
|
16
|
+
# libvips might trigger some signals which ruby has handles for.
|
17
|
+
#
|
18
|
+
# We need FFI to drop the GIL lock during this call and reacquire it when
|
19
|
+
# the call ends, or we'll deadlock.
|
20
|
+
attach_function :vips_cache_operation_build, [:pointer], :pointer,
|
21
|
+
blocking: true
|
15
22
|
attach_function :vips_object_unref_outputs, [:pointer], :void
|
16
23
|
|
17
24
|
callback :argument_map_fn, [:pointer,
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
25
|
+
GObject::GParamSpec.ptr,
|
26
|
+
ArgumentClass.ptr,
|
27
|
+
ArgumentInstance.ptr,
|
28
|
+
:pointer, :pointer], :pointer
|
22
29
|
attach_function :vips_argument_map, [:pointer,
|
23
|
-
|
24
|
-
|
30
|
+
:argument_map_fn,
|
31
|
+
:pointer, :pointer], :pointer
|
25
32
|
|
26
33
|
OPERATION_SEQUENTIAL = 1
|
27
34
|
OPERATION_NOCACHE = 4
|
28
35
|
OPERATION_DEPRECATED = 8
|
29
36
|
|
30
37
|
OPERATION_FLAGS = {
|
31
|
-
|
32
|
-
|
33
|
-
|
38
|
+
sequential: OPERATION_SEQUENTIAL,
|
39
|
+
nocache: OPERATION_NOCACHE,
|
40
|
+
deprecated: OPERATION_DEPRECATED
|
34
41
|
}
|
35
42
|
|
36
43
|
attach_function :vips_operation_get_flags, [:pointer], :int
|
37
44
|
|
38
|
-
|
45
|
+
# Introspect a vips operation and return a large structure containing
|
46
|
+
# everything we know about it. This is used for doc generation as well as
|
47
|
+
# call.
|
48
|
+
class Introspect
|
49
|
+
attr_reader :name, :description, :flags, :args, :required_input,
|
50
|
+
:optional_input, :required_output, :optional_output, :member_x,
|
51
|
+
:method_args, :vips_name, :destructive
|
52
|
+
|
53
|
+
@@introspect_cache = {}
|
54
|
+
|
55
|
+
def initialize name
|
56
|
+
# if there's a trailing "!", this is a destructive version of an
|
57
|
+
# operation
|
58
|
+
if name[-1] == "!"
|
59
|
+
@destructive = true
|
60
|
+
# strip the trailing "!"
|
61
|
+
@vips_name = name[0...-1]
|
62
|
+
else
|
63
|
+
@destructive = false
|
64
|
+
@vips_name = name
|
65
|
+
end
|
66
|
+
|
67
|
+
@op = Operation.new @vips_name
|
68
|
+
@args = []
|
69
|
+
@required_input = []
|
70
|
+
@optional_input = {}
|
71
|
+
@required_output = []
|
72
|
+
@optional_output = {}
|
73
|
+
|
74
|
+
# find all the arguments the operator can take
|
75
|
+
@op.argument_map do |pspec, argument_class, _argument_instance|
|
76
|
+
flags = argument_class[:flags]
|
77
|
+
if (flags & ARGUMENT_CONSTRUCT) != 0
|
78
|
+
# names can include - as punctuation, but we always use _ in
|
79
|
+
# Ruby
|
80
|
+
arg_name = pspec[:name].tr("-", "_")
|
81
|
+
@args << {
|
82
|
+
arg_name: arg_name,
|
83
|
+
flags: flags,
|
84
|
+
gtype: pspec[:value_type]
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
nil
|
89
|
+
end
|
90
|
+
|
91
|
+
@args.each do |details|
|
92
|
+
arg_name = details[:arg_name]
|
93
|
+
flags = details[:flags]
|
94
|
+
|
95
|
+
if (flags & ARGUMENT_INPUT) != 0
|
96
|
+
if (flags & ARGUMENT_REQUIRED) != 0 &&
|
97
|
+
(flags & ARGUMENT_DEPRECATED) == 0
|
98
|
+
@required_input << details
|
99
|
+
else
|
100
|
+
# we allow deprecated optional args
|
101
|
+
@optional_input[arg_name] = details
|
102
|
+
end
|
103
|
+
|
104
|
+
# MODIFY INPUT args count as OUTPUT as well in non-destructive mode
|
105
|
+
if (flags & ARGUMENT_MODIFY) != 0 &&
|
106
|
+
!@destructive
|
107
|
+
if (flags & ARGUMENT_REQUIRED) != 0 &&
|
108
|
+
(flags & ARGUMENT_DEPRECATED) == 0
|
109
|
+
@required_output << details
|
110
|
+
else
|
111
|
+
@optional_output[arg_name] = details
|
112
|
+
end
|
113
|
+
end
|
114
|
+
elsif (flags & ARGUMENT_OUTPUT) != 0
|
115
|
+
if (flags & ARGUMENT_REQUIRED) != 0 &&
|
116
|
+
(flags & ARGUMENT_DEPRECATED) == 0
|
117
|
+
@required_output << details
|
118
|
+
else
|
119
|
+
# again, allow deprecated optional args
|
120
|
+
@optional_output[arg_name] = details
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# in destructive mode, the first required input arg must be MODIFY and
|
126
|
+
# must be an image
|
127
|
+
if @destructive
|
128
|
+
if @required_input.length < 1 ||
|
129
|
+
@required_input[0][:flags] & ARGUMENT_MODIFY == 0 ||
|
130
|
+
@required_input[0][:gtype] != IMAGE_TYPE
|
131
|
+
raise Vips::Error, "operation #{@vips_name} is not destructive"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
# Yard comment generation needs a little more introspection. We add this
|
137
|
+
# extra metadata in a separate method to keep the main path as fast as
|
138
|
+
# we can.
|
139
|
+
def add_yard_introspection name
|
140
|
+
@name = name
|
141
|
+
@description = Vips.vips_object_get_description @op
|
142
|
+
@flags = Vips.vips_operation_get_flags @op
|
143
|
+
@member_x = nil
|
144
|
+
@method_args = []
|
145
|
+
|
146
|
+
@args.each do |details|
|
147
|
+
arg_name = details[:arg_name]
|
148
|
+
flags = details[:flags]
|
149
|
+
gtype = details[:gtype]
|
150
|
+
|
151
|
+
details[:yard_name] = arg_name == "in" ? "im" : arg_name
|
152
|
+
pspec = @op.get_pspec arg_name
|
153
|
+
details[:blurb] = GObject.g_param_spec_get_blurb pspec
|
154
|
+
|
155
|
+
if (flags & ARGUMENT_INPUT) != 0 &&
|
156
|
+
(flags & ARGUMENT_REQUIRED) != 0 &&
|
157
|
+
(flags & ARGUMENT_DEPRECATED) == 0
|
158
|
+
# the first required input image is the thing we will be a method
|
159
|
+
# of
|
160
|
+
if @member_x.nil? && gtype == IMAGE_TYPE
|
161
|
+
@member_x = details
|
162
|
+
else
|
163
|
+
@method_args << details
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
39
168
|
|
169
|
+
def self.get name
|
170
|
+
@@introspect_cache[name] ||= Introspect.new name
|
171
|
+
end
|
172
|
+
|
173
|
+
def self.get_yard name
|
174
|
+
introspect = Introspect.get name
|
175
|
+
introspect.add_yard_introspection name
|
176
|
+
introspect
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
class Operation < Object
|
40
181
|
# the layout of the VipsOperation struct
|
41
182
|
module OperationLayout
|
42
183
|
def self.included base
|
@@ -49,106 +190,83 @@ module Vips
|
|
49
190
|
|
50
191
|
class Struct < Object::Struct
|
51
192
|
include OperationLayout
|
52
|
-
|
53
193
|
end
|
54
194
|
|
55
195
|
class ManagedStruct < Object::ManagedStruct
|
56
196
|
include OperationLayout
|
57
|
-
|
58
197
|
end
|
59
198
|
|
60
199
|
def initialize value
|
61
200
|
# allow init with a pointer so we can wrap the return values from
|
62
201
|
# things like _build
|
63
202
|
if value.is_a? String
|
64
|
-
value = Vips
|
65
|
-
raise Vips::Error if value
|
203
|
+
value = Vips.vips_operation_new value
|
204
|
+
raise Vips::Error if value.null?
|
66
205
|
end
|
67
206
|
|
68
207
|
super value
|
69
208
|
end
|
70
209
|
|
71
210
|
def build
|
72
|
-
op = Vips
|
73
|
-
if op
|
211
|
+
op = Vips.vips_cache_operation_build self
|
212
|
+
if op.null?
|
213
|
+
Vips.vips_object_unref_outputs self
|
74
214
|
raise Vips::Error
|
75
215
|
end
|
76
216
|
|
77
|
-
|
217
|
+
Operation.new op
|
78
218
|
end
|
79
219
|
|
80
220
|
def argument_map &block
|
81
|
-
fn =
|
221
|
+
fn = proc do |_op, pspec, argument_class, argument_instance, _a, _b|
|
82
222
|
block.call pspec, argument_class, argument_instance
|
83
223
|
end
|
84
|
-
|
85
|
-
Vips::vips_argument_map self, fn, nil, nil
|
86
|
-
end
|
87
|
-
|
88
|
-
def get_flags
|
89
|
-
Vips::vips_operation_get_flags self
|
224
|
+
Vips.vips_argument_map self, fn, nil, nil
|
90
225
|
end
|
91
226
|
|
92
|
-
#
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
# names can include - as punctuation, but we always use _ in
|
100
|
-
# Ruby
|
101
|
-
name = pspec[:name].tr("-", "_")
|
102
|
-
|
103
|
-
args << [name, flags]
|
227
|
+
# Search an object for the first element to match a predicate. Search
|
228
|
+
# inside subarrays and sub-hashes. Equlvalent to x.flatten.find{}.
|
229
|
+
def self.flat_find object, &block
|
230
|
+
if object.respond_to? :each
|
231
|
+
object.each do |x|
|
232
|
+
result = flat_find x, &block
|
233
|
+
return result unless result.nil?
|
104
234
|
end
|
235
|
+
elsif yield object
|
236
|
+
return object
|
105
237
|
end
|
106
238
|
|
107
|
-
|
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}
|
117
|
-
end
|
118
|
-
|
119
|
-
return nil
|
239
|
+
nil
|
120
240
|
end
|
121
241
|
|
122
242
|
# expand a constant into an image
|
123
243
|
def self.imageize match_image, value
|
124
|
-
return value if value.is_a?
|
244
|
+
return value if value.is_a?(Image) || value.is_a?(MutableImage)
|
125
245
|
|
126
246
|
# 2D array values become tiny 2D images
|
127
247
|
# 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
|
-
|
130
|
-
return Image.new_from_array value
|
248
|
+
if (value.is_a?(Array) && value[0].is_a?(Array)) || match_image.nil?
|
249
|
+
Image.new_from_array value
|
131
250
|
else
|
132
251
|
# we have a 1D array ... use that as a pixel constant and
|
133
252
|
# expand to match match_image
|
134
|
-
|
253
|
+
match_image.new_from_image value
|
135
254
|
end
|
136
255
|
end
|
137
256
|
|
138
257
|
# set an operation argument, expanding constants and copying images as
|
139
258
|
# required
|
140
|
-
def set name, value, match_image
|
141
|
-
gtype = get_typeof name
|
142
|
-
|
259
|
+
def set name, value, match_image, flags, gtype, destructive
|
143
260
|
if gtype == IMAGE_TYPE
|
144
|
-
value = Operation
|
261
|
+
value = Operation.imageize match_image, value
|
145
262
|
|
146
|
-
|
147
|
-
|
263
|
+
# in non-destructive mode, make sure we have a unique copy
|
264
|
+
if (flags & ARGUMENT_MODIFY) != 0 &&
|
265
|
+
!destructive
|
148
266
|
value = value.copy.copy_memory
|
149
267
|
end
|
150
268
|
elsif gtype == ARRAY_IMAGE_TYPE
|
151
|
-
value = value.map {|x| Operation
|
269
|
+
value = value.map { |x| Operation.imageize match_image, x }
|
152
270
|
end
|
153
271
|
|
154
272
|
super name, value
|
@@ -224,68 +342,42 @@ module Vips
|
|
224
342
|
# the constant value 255.
|
225
343
|
|
226
344
|
def self.call name, supplied, optional = {}, option_string = ""
|
227
|
-
GLib
|
228
|
-
"name = #{name}, supplied = #{supplied}, "
|
229
|
-
|
345
|
+
GLib.logger.debug("Vips::VipsOperation.call") {
|
346
|
+
"name = #{name}, supplied = #{supplied}, " \
|
347
|
+
"optional = #{optional}, option_string = #{option_string}"
|
230
348
|
}
|
231
349
|
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
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
|
350
|
+
introspect = Introspect.get name
|
351
|
+
required_input = introspect.required_input
|
352
|
+
required_output = introspect.required_output
|
353
|
+
optional_input = introspect.optional_input
|
354
|
+
optional_output = introspect.optional_output
|
355
|
+
destructive = introspect.destructive
|
263
356
|
|
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
357
|
unless supplied.is_a? Array
|
267
|
-
raise Vips::Error, "unable to call #{name}: "
|
268
|
-
|
358
|
+
raise Vips::Error, "unable to call #{name}: " \
|
359
|
+
"argument array is not an array"
|
269
360
|
end
|
270
361
|
unless optional.is_a? Hash
|
271
|
-
raise Vips::Error, "unable to call #{name}: "
|
272
|
-
|
362
|
+
raise Vips::Error, "unable to call #{name}: " \
|
363
|
+
"optional arguments are not a hash"
|
273
364
|
end
|
365
|
+
|
274
366
|
if supplied.length != required_input.length
|
275
|
-
raise Vips::Error, "unable to call #{name}: "
|
276
|
-
|
277
|
-
|
367
|
+
raise Vips::Error, "unable to call #{name}: " \
|
368
|
+
"you supplied #{supplied.length} arguments, " \
|
369
|
+
"but operation needs #{required_input.length}."
|
278
370
|
end
|
279
371
|
|
280
|
-
#
|
372
|
+
# all supplied_optional keys should be in optional_input or
|
281
373
|
# optional_output
|
282
|
-
optional.each do |key,
|
374
|
+
optional.each do |key, _value|
|
283
375
|
arg_name = key.to_s
|
284
376
|
|
285
377
|
unless optional_input.has_key?(arg_name) ||
|
286
378
|
optional_output.has_key?(arg_name)
|
287
|
-
raise Vips::Error, "unable to call #{name}: "
|
288
|
-
|
379
|
+
raise Vips::Error, "unable to call #{name}: " \
|
380
|
+
"unknown option #{arg_name}"
|
289
381
|
end
|
290
382
|
end
|
291
383
|
|
@@ -294,24 +386,68 @@ module Vips
|
|
294
386
|
#
|
295
387
|
# look inside array and hash arguments, since we may be passing an
|
296
388
|
# array of images
|
297
|
-
|
298
|
-
|
389
|
+
#
|
390
|
+
# also enforce the rules around mutable and non-mutable images
|
391
|
+
match_image = nil
|
392
|
+
flat_find(supplied) do |value|
|
393
|
+
if match_image
|
394
|
+
# no non-first image arg can ever be mutable
|
395
|
+
if value.is_a?(MutableImage)
|
396
|
+
raise Vips::Error, "unable to call #{name}: " \
|
397
|
+
"only the first image argument can be mutable"
|
398
|
+
end
|
399
|
+
elsif destructive
|
400
|
+
if value.is_a?(Image)
|
401
|
+
raise Vips::Error, "unable to call #{name}: " \
|
402
|
+
"first image argument to a destructive " \
|
403
|
+
"operation must be mutable"
|
404
|
+
elsif value.is_a?(MutableImage)
|
405
|
+
match_image = value
|
406
|
+
end
|
407
|
+
elsif value.is_a?(MutableImage)
|
408
|
+
# non destructive operation, so no mutable images
|
409
|
+
raise Vips::Error, "unable to call #{name}: " \
|
410
|
+
"must not pass mutable images to " \
|
411
|
+
"non-destructive operations"
|
412
|
+
elsif value.is_a?(Image)
|
413
|
+
match_image = value
|
414
|
+
end
|
415
|
+
|
416
|
+
# keep looping
|
417
|
+
false
|
299
418
|
end
|
300
419
|
|
420
|
+
op = Operation.new introspect.vips_name
|
421
|
+
|
301
422
|
# set any string args first so they can't be overridden
|
302
|
-
|
303
|
-
if Vips
|
423
|
+
unless option_string.nil?
|
424
|
+
if Vips.vips_object_set_from_string(op, option_string) != 0
|
304
425
|
raise Vips::Error
|
305
426
|
end
|
306
427
|
end
|
307
428
|
|
429
|
+
# collect a list of all input references here
|
430
|
+
references = Set.new
|
431
|
+
|
432
|
+
add_reference = lambda do |x|
|
433
|
+
if x.is_a?(Vips::Image)
|
434
|
+
x.references.each do |i|
|
435
|
+
references << i
|
436
|
+
end
|
437
|
+
end
|
438
|
+
false
|
439
|
+
end
|
440
|
+
|
308
441
|
# set all required inputs
|
309
442
|
required_input.each_index do |i|
|
310
|
-
|
311
|
-
|
443
|
+
details = required_input[i]
|
444
|
+
arg_name = details[:arg_name]
|
445
|
+
flags = details[:flags]
|
446
|
+
gtype = details[:gtype]
|
312
447
|
value = supplied[i]
|
313
448
|
|
314
|
-
|
449
|
+
flat_find value, &add_reference
|
450
|
+
op.set arg_name, value, match_image, flags, gtype, destructive
|
315
451
|
end
|
316
452
|
|
317
453
|
# set all optional inputs
|
@@ -321,29 +457,42 @@ module Vips
|
|
321
457
|
arg_name = key.to_s
|
322
458
|
|
323
459
|
if optional_input.has_key? arg_name
|
324
|
-
|
460
|
+
details = optional_input[arg_name]
|
461
|
+
flags = details[:flags]
|
462
|
+
gtype = details[:gtype]
|
325
463
|
|
326
|
-
|
464
|
+
flat_find value, &add_reference
|
465
|
+
op.set arg_name, value, match_image, flags, gtype, destructive
|
327
466
|
end
|
328
467
|
end
|
329
468
|
|
330
469
|
op = op.build
|
331
470
|
|
471
|
+
# attach all input refs to output x
|
472
|
+
set_reference = lambda do |x|
|
473
|
+
if x.is_a? Vips::Image
|
474
|
+
x.references += references
|
475
|
+
end
|
476
|
+
false
|
477
|
+
end
|
478
|
+
|
332
479
|
# get all required results
|
333
480
|
result = []
|
334
|
-
required_output.each do |
|
335
|
-
|
481
|
+
required_output.each do |details|
|
482
|
+
value = details[:arg_name]
|
483
|
+
flat_find value, &set_reference
|
484
|
+
result << op.get(value)
|
336
485
|
end
|
337
486
|
|
338
487
|
# fetch all optional ones
|
339
488
|
optional_results = {}
|
340
|
-
optional.each do |key,
|
489
|
+
optional.each do |key, _value|
|
341
490
|
arg_name = key.to_s
|
342
491
|
|
343
492
|
if optional_output.has_key? arg_name
|
344
|
-
|
345
|
-
|
346
|
-
optional_results[arg_name] =
|
493
|
+
value = op.get arg_name
|
494
|
+
flat_find value, &set_reference
|
495
|
+
optional_results[arg_name] = value
|
347
496
|
end
|
348
497
|
end
|
349
498
|
|
@@ -355,13 +504,11 @@ module Vips
|
|
355
504
|
result = nil
|
356
505
|
end
|
357
506
|
|
358
|
-
GLib
|
507
|
+
GLib.logger.debug("Vips::Operation.call") { "result = #{result}" }
|
359
508
|
|
360
|
-
Vips
|
509
|
+
Vips.vips_object_unref_outputs op
|
361
510
|
|
362
|
-
|
511
|
+
result
|
363
512
|
end
|
364
|
-
|
365
513
|
end
|
366
|
-
|
367
514
|
end
|