ruby-vips 1.0.6 → 2.0.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.
- checksums.yaml +4 -4
- data/.travis.yml +9 -12
- data/CHANGELOG.md +5 -1
- data/README.md +32 -115
- data/TODO +4 -6
- data/VERSION +1 -1
- data/example/inheritance_with_refcount.rb +286 -0
- data/lib/ruby-vips.rb +1 -0
- data/lib/vips.rb +425 -93
- data/lib/vips/access.rb +1 -4
- data/lib/vips/align.rb +2 -2
- data/lib/vips/angle.rb +2 -2
- data/lib/vips/angle45.rb +2 -2
- data/lib/vips/bandformat.rb +1 -1
- data/lib/vips/coding.rb +1 -1
- data/lib/vips/direction.rb +2 -2
- data/lib/vips/extend.rb +8 -13
- data/lib/vips/gobject.rb +121 -0
- data/lib/vips/gvalue.rb +251 -0
- data/lib/vips/image.rb +487 -585
- data/lib/vips/interesting.rb +1 -1
- data/lib/vips/interpolate.rb +31 -6
- data/lib/vips/interpretation.rb +1 -1
- data/lib/vips/kernel.rb +1 -1
- data/lib/vips/methods.rb +339 -334
- data/lib/vips/object.rb +204 -0
- data/lib/vips/operation.rb +358 -14
- data/lib/vips/operationboolean.rb +14 -0
- data/lib/vips/operationcomplex.rb +12 -0
- data/lib/vips/operationcomplex2.rb +10 -0
- data/lib/vips/operationcomplexget.rb +11 -0
- data/lib/vips/operationmath.rb +18 -0
- data/lib/vips/operationmath2.rb +10 -0
- data/lib/vips/operationrelational.rb +15 -0
- data/lib/vips/operationround.rb +11 -0
- data/lib/vips/size.rb +2 -1
- data/lib/vips/version.rb +1 -1
- data/ruby-vips.gemspec +2 -6
- metadata +19 -11
- data/lib/vips/argument.rb +0 -159
- data/lib/vips/call.rb +0 -370
- data/lib/vips/demandstyle.rb +0 -35
- data/lib/vips/error.rb +0 -30
- data/lib/vips/foreignflags.rb +0 -20
data/lib/vips/object.rb
ADDED
@@ -0,0 +1,204 @@
|
|
1
|
+
# This module provides an interface to the top level bits of libvips
|
2
|
+
# via ruby-ffi.
|
3
|
+
#
|
4
|
+
# Author:: John Cupitt (mailto:jcupitt@gmail.com)
|
5
|
+
# License:: MIT
|
6
|
+
|
7
|
+
require 'ffi'
|
8
|
+
|
9
|
+
module Vips
|
10
|
+
private
|
11
|
+
|
12
|
+
# we must init these by hand, since they are usually made on first image
|
13
|
+
# create
|
14
|
+
attach_function :vips_band_format_get_type, [], :GType
|
15
|
+
attach_function :vips_interpretation_get_type, [], :GType
|
16
|
+
attach_function :vips_coding_get_type, [], :GType
|
17
|
+
|
18
|
+
public
|
19
|
+
|
20
|
+
# some handy gtypes
|
21
|
+
IMAGE_TYPE = GObject::g_type_from_name "VipsImage"
|
22
|
+
ARRAY_INT_TYPE = GObject::g_type_from_name "VipsArrayInt"
|
23
|
+
ARRAY_DOUBLE_TYPE = GObject::g_type_from_name "VipsArrayDouble"
|
24
|
+
ARRAY_IMAGE_TYPE = GObject::g_type_from_name "VipsArrayImage"
|
25
|
+
REFSTR_TYPE = GObject::g_type_from_name "VipsRefString"
|
26
|
+
BLOB_TYPE = GObject::g_type_from_name "VipsBlob"
|
27
|
+
|
28
|
+
BAND_FORMAT_TYPE = Vips::vips_band_format_get_type
|
29
|
+
INTERPRETATION_TYPE = Vips::vips_interpretation_get_type
|
30
|
+
CODING_TYPE = Vips::vips_coding_get_type
|
31
|
+
|
32
|
+
private
|
33
|
+
|
34
|
+
attach_function :vips_enum_from_nick, [:string, :GType, :string], :int
|
35
|
+
attach_function :vips_enum_nick, [:GType, :int], :string
|
36
|
+
|
37
|
+
attach_function :vips_value_set_array_double,
|
38
|
+
[GObject::GValue.ptr, :pointer, :int], :void
|
39
|
+
attach_function :vips_value_set_array_int,
|
40
|
+
[GObject::GValue.ptr, :pointer, :int], :void
|
41
|
+
attach_function :vips_value_set_array_image,
|
42
|
+
[GObject::GValue.ptr, :int], :void
|
43
|
+
callback :free_fn, [:pointer], :void
|
44
|
+
attach_function :vips_value_set_blob,
|
45
|
+
[GObject::GValue.ptr, :free_fn, :pointer, :size_t], :void
|
46
|
+
|
47
|
+
class SizeStruct < FFI::Struct
|
48
|
+
layout :value, :size_t
|
49
|
+
end
|
50
|
+
|
51
|
+
class IntStruct < FFI::Struct
|
52
|
+
layout :value, :int
|
53
|
+
end
|
54
|
+
|
55
|
+
attach_function :vips_value_get_ref_string,
|
56
|
+
[GObject::GValue.ptr, SizeStruct.ptr], :string
|
57
|
+
attach_function :vips_value_get_array_double,
|
58
|
+
[GObject::GValue.ptr, IntStruct.ptr], :pointer
|
59
|
+
attach_function :vips_value_get_array_int,
|
60
|
+
[GObject::GValue.ptr, IntStruct.ptr], :pointer
|
61
|
+
attach_function :vips_value_get_array_image,
|
62
|
+
[GObject::GValue.ptr, IntStruct.ptr], :pointer
|
63
|
+
attach_function :vips_value_get_blob,
|
64
|
+
[GObject::GValue.ptr, SizeStruct.ptr], :pointer
|
65
|
+
|
66
|
+
attach_function :type_find, :vips_type_find, [:string, :string], :GType
|
67
|
+
|
68
|
+
class Object < GObject::GObject
|
69
|
+
|
70
|
+
# the layout of the VipsObject struct
|
71
|
+
module ObjectLayout
|
72
|
+
def self.included base
|
73
|
+
base.class_eval do
|
74
|
+
# don't actually need most of these
|
75
|
+
layout :parent, GObject::GObject::Struct,
|
76
|
+
:constructed, :int,
|
77
|
+
:static_object, :int,
|
78
|
+
:argument_table, :pointer,
|
79
|
+
:nickname, :string,
|
80
|
+
:description, :string,
|
81
|
+
:preclose, :int,
|
82
|
+
:close, :int,
|
83
|
+
:postclose, :int,
|
84
|
+
:local_memory, :size_t
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
class Struct < GObject::GObject::Struct
|
90
|
+
include ObjectLayout
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
class ManagedStruct < GObject::GObject::ManagedStruct
|
95
|
+
include ObjectLayout
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
def get_typeof name
|
100
|
+
pspec = GObject::GParamSpecPtr.new
|
101
|
+
argument_class = Vips::ArgumentClassPtr.new
|
102
|
+
argument_instance = Vips::ArgumentInstancePtr.new
|
103
|
+
|
104
|
+
result = Vips::vips_object_get_argument self, name,
|
105
|
+
pspec, argument_class, argument_instance
|
106
|
+
raise Vips::Error if result != 0
|
107
|
+
|
108
|
+
pspec[:value][:value_type]
|
109
|
+
end
|
110
|
+
|
111
|
+
def get name
|
112
|
+
gtype = get_typeof name
|
113
|
+
gvalue = GObject::GValue.alloc
|
114
|
+
gvalue.init gtype
|
115
|
+
GObject::g_object_get_property self, name, gvalue
|
116
|
+
result = gvalue.get
|
117
|
+
|
118
|
+
# Vips::log "Vips::Object.get(\"#{name}\"): result = #{result}"
|
119
|
+
|
120
|
+
return result
|
121
|
+
end
|
122
|
+
|
123
|
+
def set name, value
|
124
|
+
# Vips::log "Vips::Object.set: #{name} = #{value}"
|
125
|
+
|
126
|
+
gtype = get_typeof name
|
127
|
+
gvalue = GObject::GValue.alloc
|
128
|
+
gvalue.init gtype
|
129
|
+
gvalue.set value
|
130
|
+
GObject::g_object_set_property self, name, gvalue
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
class ObjectClass < FFI::Struct
|
136
|
+
# opaque
|
137
|
+
end
|
138
|
+
|
139
|
+
class Argument < FFI::Struct
|
140
|
+
layout :pspec, GObject::GParamSpec.ptr
|
141
|
+
end
|
142
|
+
|
143
|
+
class ArgumentInstance < Argument
|
144
|
+
layout :parent, Argument
|
145
|
+
# rest opaque
|
146
|
+
end
|
147
|
+
|
148
|
+
# enum VipsArgumentFlags
|
149
|
+
ARGUMENT_REQUIRED = 1
|
150
|
+
ARGUMENT_CONSTRUCT = 2
|
151
|
+
ARGUMENT_SET_ONCE = 4
|
152
|
+
ARGUMENT_SET_ALWAYS = 8
|
153
|
+
ARGUMENT_INPUT = 16
|
154
|
+
ARGUMENT_OUTPUT = 32
|
155
|
+
ARGUMENT_DEPRECATED = 64
|
156
|
+
ARGUMENT_MODIFY = 128
|
157
|
+
|
158
|
+
ARGUMENT_FLAGS = {
|
159
|
+
:required => ARGUMENT_REQUIRED,
|
160
|
+
:construct => ARGUMENT_CONSTRUCT,
|
161
|
+
:set_once => ARGUMENT_SET_ONCE,
|
162
|
+
:set_always => ARGUMENT_SET_ALWAYS,
|
163
|
+
:input => ARGUMENT_INPUT,
|
164
|
+
:output => ARGUMENT_OUTPUT,
|
165
|
+
:deprecated => ARGUMENT_DEPRECATED,
|
166
|
+
:modify => ARGUMENT_MODIFY
|
167
|
+
}
|
168
|
+
|
169
|
+
class ArgumentClass < Argument
|
170
|
+
layout :parent, Argument,
|
171
|
+
:object_class, ObjectClass.ptr,
|
172
|
+
:flags, :uint,
|
173
|
+
:priority, :int,
|
174
|
+
:offset, :ulong_long
|
175
|
+
end
|
176
|
+
|
177
|
+
class ArgumentClassPtr < FFI::Struct
|
178
|
+
layout :value, ArgumentClass.ptr
|
179
|
+
end
|
180
|
+
|
181
|
+
class ArgumentInstancePtr < FFI::Struct
|
182
|
+
layout :value, ArgumentInstance.ptr
|
183
|
+
end
|
184
|
+
|
185
|
+
# just use :pointer, not VipsObject.ptr, to avoid casting gobject
|
186
|
+
# subclasses
|
187
|
+
attach_function :vips_object_get_argument,
|
188
|
+
[:pointer, :string,
|
189
|
+
GObject::GParamSpecPtr.ptr,
|
190
|
+
ArgumentClassPtr.ptr, ArgumentInstancePtr.ptr],
|
191
|
+
:int
|
192
|
+
|
193
|
+
attach_function :vips_object_print_all, [], :void
|
194
|
+
|
195
|
+
attach_function :vips_object_set_from_string, [:pointer, :string], :int
|
196
|
+
|
197
|
+
callback :type_map_fn, [:GType, :pointer], :pointer
|
198
|
+
attach_function :vips_type_map, [:GType, :type_map_fn, :pointer], :pointer
|
199
|
+
|
200
|
+
attach_function :vips_object_get_description, [:pointer], :string
|
201
|
+
|
202
|
+
end
|
203
|
+
|
204
|
+
|
data/lib/vips/operation.rb
CHANGED
@@ -1,19 +1,363 @@
|
|
1
|
+
# This module provides an interface to the top level bits of libvips
|
2
|
+
# via ruby-ffi.
|
3
|
+
#
|
4
|
+
# Author:: John Cupitt (mailto:jcupitt@gmail.com)
|
5
|
+
# License:: MIT
|
6
|
+
|
7
|
+
require 'ffi'
|
8
|
+
|
1
9
|
module Vips
|
10
|
+
private
|
11
|
+
|
12
|
+
attach_function :vips_operation_new, [:string], :pointer
|
13
|
+
|
14
|
+
attach_function :vips_cache_operation_build, [:pointer], :pointer
|
15
|
+
attach_function :vips_object_unref_outputs, [:pointer], :void
|
16
|
+
|
17
|
+
callback :argument_map_fn, [:pointer,
|
18
|
+
GObject::GParamSpec.ptr,
|
19
|
+
ArgumentClass.ptr,
|
20
|
+
ArgumentInstance.ptr,
|
21
|
+
:pointer, :pointer], :pointer
|
22
|
+
attach_function :vips_argument_map, [:pointer,
|
23
|
+
:argument_map_fn,
|
24
|
+
:pointer, :pointer], :pointer
|
25
|
+
|
26
|
+
OPERATION_SEQUENTIAL = 1
|
27
|
+
OPERATION_NOCACHE = 4
|
28
|
+
OPERATION_DEPRECATED = 8
|
29
|
+
|
30
|
+
OPERATION_FLAGS = {
|
31
|
+
:sequential => OPERATION_SEQUENTIAL,
|
32
|
+
:nocache => OPERATION_NOCACHE,
|
33
|
+
:deprecated => OPERATION_DEPRECATED
|
34
|
+
}
|
35
|
+
|
36
|
+
attach_function :vips_operation_get_flags, [:pointer], :int
|
37
|
+
|
38
|
+
class Operation < Object
|
39
|
+
|
40
|
+
# the layout of the VipsOperation struct
|
41
|
+
module OperationLayout
|
42
|
+
def self.included base
|
43
|
+
base.class_eval do
|
44
|
+
layout :parent, Object::Struct
|
45
|
+
# rest opaque
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class Struct < Object::Struct
|
51
|
+
include OperationLayout
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
class ManagedStruct < Object::ManagedStruct
|
56
|
+
include OperationLayout
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
def initialize value
|
61
|
+
# allow init with a pointer so we can wrap the return values from
|
62
|
+
# things like _build
|
63
|
+
if value.is_a? String
|
64
|
+
value = Vips::vips_operation_new value
|
65
|
+
raise Vips::Error if value == nil
|
66
|
+
end
|
67
|
+
|
68
|
+
super value
|
69
|
+
end
|
70
|
+
|
71
|
+
def build
|
72
|
+
op = Vips::vips_cache_operation_build self
|
73
|
+
if op == nil
|
74
|
+
raise Vips::Error
|
75
|
+
end
|
76
|
+
|
77
|
+
return Operation.new op
|
78
|
+
end
|
79
|
+
|
80
|
+
def argument_map &block
|
81
|
+
fn = Proc.new do |op, pspec, argument_class, argument_instance, a, b|
|
82
|
+
block.call pspec, argument_class, argument_instance
|
83
|
+
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
|
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].gsub("-", "_")
|
102
|
+
|
103
|
+
args << [name, flags]
|
104
|
+
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}
|
117
|
+
end
|
118
|
+
|
119
|
+
return nil
|
120
|
+
end
|
121
|
+
|
122
|
+
# expand a constant into an image
|
123
|
+
def self.imageize match_image, value
|
124
|
+
return value if value.is_a? Image
|
125
|
+
|
126
|
+
# 2D array values become tiny 2D images
|
127
|
+
# if there's nothing to match to, we also make a 2D image
|
128
|
+
if (value.is_a? Array and value[0].is_a? Array) or match_image == nil
|
129
|
+
return Image.new_from_array value
|
130
|
+
else
|
131
|
+
# we have a 1D array ... use that as a pixel constant and
|
132
|
+
# expand to match match_image
|
133
|
+
return match_image.new_from_image value
|
134
|
+
end
|
135
|
+
end
|
2
136
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
137
|
+
# set an operation argument, expanding constants and copying images as
|
138
|
+
# required
|
139
|
+
def set name, value, match_image = nil, flags = 0
|
140
|
+
gtype = get_typeof name
|
141
|
+
|
142
|
+
if gtype == IMAGE_TYPE
|
143
|
+
value = Operation::imageize match_image, value
|
144
|
+
|
145
|
+
if (flags & ARGUMENT_MODIFY) != 0
|
146
|
+
# make sure we have a unique copy
|
147
|
+
value = value.copy.copy_memory
|
148
|
+
end
|
149
|
+
elsif gtype == ARRAY_IMAGE_TYPE
|
150
|
+
value = value.map {|x| Operation::imageize match_image, x}
|
151
|
+
end
|
152
|
+
|
153
|
+
super name, value
|
17
154
|
end
|
155
|
+
|
156
|
+
public
|
157
|
+
|
158
|
+
# This is the public entry point for the vips binding. {call} will run
|
159
|
+
# any vips operation, for example:
|
160
|
+
#
|
161
|
+
# ```ruby
|
162
|
+
# out = Vips::Operation.call "black", [100, 100], {:bands => 12}
|
163
|
+
# ```
|
164
|
+
#
|
165
|
+
# will call the C function
|
166
|
+
#
|
167
|
+
# ```C
|
168
|
+
# vips_black( &out, 100, 100, "bands", 12, NULL );
|
169
|
+
# ```
|
170
|
+
#
|
171
|
+
# There are {Image#method_missing} hooks which will run {call} for you
|
172
|
+
# on {Image} for undefined instance or class methods. So you can also
|
173
|
+
# write:
|
174
|
+
#
|
175
|
+
# ```ruby
|
176
|
+
# out = Vips::Image.black 100, 100, bands: 12
|
177
|
+
# ```
|
178
|
+
#
|
179
|
+
# Or perhaps:
|
180
|
+
#
|
181
|
+
# ```ruby
|
182
|
+
# x = Vips::Image.black 100, 100
|
183
|
+
# y = x.invert
|
184
|
+
# ```
|
185
|
+
#
|
186
|
+
# to run the `vips_invert()` operator.
|
187
|
+
#
|
188
|
+
# There are also a set of operator overloads and some convenience
|
189
|
+
# functions, see {Image}.
|
190
|
+
#
|
191
|
+
# If the operator needs a vector constant, {call} will turn a scalar
|
192
|
+
# into a
|
193
|
+
# vector for you. So for `x.linear a, b`, which calculates
|
194
|
+
# `x * a + b` where `a` and `b` are vector constants, you can write:
|
195
|
+
#
|
196
|
+
# ```ruby
|
197
|
+
# x = Vips::Image.black 100, 100, bands: 3
|
198
|
+
# y = x.linear 1, 2
|
199
|
+
# y = x.linear [1], 4
|
200
|
+
# y = x.linear [1, 2, 3], 4
|
201
|
+
# ```
|
202
|
+
#
|
203
|
+
# or any other combination. The operator overloads use this facility to
|
204
|
+
# support all the variations on:
|
205
|
+
#
|
206
|
+
# ```ruby
|
207
|
+
# x = Vips::Image.black 100, 100, bands: 3
|
208
|
+
# y = x * 2
|
209
|
+
# y = x + [1,2,3]
|
210
|
+
# y = x % [1]
|
211
|
+
# ```
|
212
|
+
#
|
213
|
+
# Similarly, wherever an image is required, you can use a constant. The
|
214
|
+
# constant will be expanded to an image matching the first input image
|
215
|
+
# argument. For example, you can write:
|
216
|
+
#
|
217
|
+
# ```
|
218
|
+
# x = Vips::Image.black 100, 100, bands: 3
|
219
|
+
# y = x.bandjoin 255
|
220
|
+
# ```
|
221
|
+
#
|
222
|
+
# to add an extra band to the image where each pixel in the new band has
|
223
|
+
# the constant value 255.
|
224
|
+
|
225
|
+
def self.call name, supplied, optional = {}, option_string = ""
|
226
|
+
#Vips::log "Vips::VipsOperation.call: name = #{name}, " +
|
227
|
+
# "supplied = #{supplied} optional = #{optional} " +
|
228
|
+
# "option_string = #{option_string}"
|
229
|
+
|
230
|
+
op = Operation.new name
|
231
|
+
|
232
|
+
# find and classify all the arguments the operator can take
|
233
|
+
args = op.get_construct_args
|
234
|
+
required_input = []
|
235
|
+
optional_input = {}
|
236
|
+
required_output = []
|
237
|
+
optional_output = {}
|
238
|
+
args.each do |name, flags|
|
239
|
+
next if (flags & ARGUMENT_DEPRECATED) != 0
|
240
|
+
|
241
|
+
if (flags & ARGUMENT_INPUT) != 0
|
242
|
+
if (flags & ARGUMENT_REQUIRED) != 0 and
|
243
|
+
required_input << [name, flags]
|
244
|
+
else
|
245
|
+
optional_input[name] = flags
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
# MODIFY INPUT args count as OUTPUT as well
|
250
|
+
if (flags & ARGUMENT_OUTPUT) != 0 or
|
251
|
+
((flags & ARGUMENT_INPUT) != 0 and
|
252
|
+
(flags & ARGUMENT_MODIFY) != 0)
|
253
|
+
if (flags & ARGUMENT_REQUIRED) != 0 and
|
254
|
+
required_output << [name, flags]
|
255
|
+
else
|
256
|
+
optional_output[name] = flags
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
end
|
261
|
+
|
262
|
+
# so we should have been supplied with n_required_input values, or
|
263
|
+
# n_required_input + 1 if there's a hash of options at the end
|
264
|
+
if not supplied.is_a? Array
|
265
|
+
raise Vips::Error, "unable to call #{name}: " +
|
266
|
+
"argument array is not an array"
|
267
|
+
end
|
268
|
+
if not optional.is_a? Hash
|
269
|
+
raise Vips::Error, "unable to call #{name}: " +
|
270
|
+
"optional arguments are not a hash"
|
271
|
+
end
|
272
|
+
if supplied.length != required_input.length
|
273
|
+
raise Vips::Error, "unable to call #{name}: " +
|
274
|
+
"you supplied #{supplied.length} arguments, " +
|
275
|
+
"but operation needs #{required_input.length}."
|
276
|
+
end
|
277
|
+
|
278
|
+
# very that all supplied_optional keys are in optional_input or
|
279
|
+
# optional_output
|
280
|
+
optional.each do |key, value|
|
281
|
+
arg_name = key.to_s
|
282
|
+
|
283
|
+
if not optional_input.has_key? arg_name and
|
284
|
+
not optional_output.has_key? arg_name
|
285
|
+
raise Vips::Error, "unable to call #{name}: " +
|
286
|
+
"unknown option #{arg_name}"
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
# the first image arg is the thing we expand constants to match ...
|
291
|
+
# we need to find it
|
292
|
+
#
|
293
|
+
# look inside array and hash arguments, since we may be passing an
|
294
|
+
# array of images
|
295
|
+
match_image = find_inside(supplied) do |value|
|
296
|
+
value.is_a? Image
|
297
|
+
end
|
298
|
+
|
299
|
+
# set any string args first so they can't be overridden
|
300
|
+
if option_string != nil
|
301
|
+
if Vips::vips_object_set_from_string(op, option_string) != 0
|
302
|
+
raise Vips::Error
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
# set all required inputs
|
307
|
+
required_input.each_index do |i|
|
308
|
+
arg_name = required_input[i][0]
|
309
|
+
flags = required_input[i][1]
|
310
|
+
value = supplied[i]
|
311
|
+
|
312
|
+
op.set arg_name, value, match_image, flags
|
313
|
+
end
|
314
|
+
|
315
|
+
# set all optional inputs
|
316
|
+
optional.each do |key, value|
|
317
|
+
arg_name = key.to_s
|
318
|
+
|
319
|
+
if optional_input.has_key? arg_name
|
320
|
+
flags = optional_input[arg_name]
|
321
|
+
|
322
|
+
op.set arg_name, value, match_image, flags
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
op = op.build
|
327
|
+
|
328
|
+
# get all required results
|
329
|
+
result = []
|
330
|
+
required_output.each do |arg_name, flags|
|
331
|
+
result << op.get(arg_name)
|
332
|
+
end
|
333
|
+
|
334
|
+
# fetch all optional ones
|
335
|
+
optional_results = {}
|
336
|
+
optional.each do |key, value|
|
337
|
+
arg_name = key.to_s
|
338
|
+
|
339
|
+
if optional_output.has_key? arg_name
|
340
|
+
flags = optional_output[arg_name]
|
341
|
+
|
342
|
+
optional_results[arg_name] = op.get arg_name
|
343
|
+
end
|
344
|
+
end
|
345
|
+
|
346
|
+
result << optional_results if optional_results != {}
|
347
|
+
|
348
|
+
if result.length == 1
|
349
|
+
result = result.first
|
350
|
+
elsif result.length == 0
|
351
|
+
result = nil
|
352
|
+
end
|
353
|
+
|
354
|
+
# Vips::log "Vips::Operation.call: result = #{result}"
|
355
|
+
|
356
|
+
Vips::vips_object_unref_outputs op
|
357
|
+
|
358
|
+
return result
|
359
|
+
end
|
360
|
+
|
18
361
|
end
|
362
|
+
|
19
363
|
end
|