ruby-vips 1.0.2 → 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -1
- data/VERSION +1 -1
- data/lib/vips/call.rb +234 -170
- data/lib/vips/image.rb +48 -18
- data/lib/vips/interpolate.rb +2 -2
- data/lib/vips/kernel.rb +22 -0
- data/lib/vips/methods.rb +269 -119
- data/lib/vips/version.rb +1 -1
- data/ruby-vips.gemspec +6 -3
- metadata +9 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f9821647ddcaaa31442cb2f6ce3b488004bfecd1
|
4
|
+
data.tar.gz: 77f02bd4c937b0b08d78419878728a2d62e47293
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a7e07153fe581bb27cb56533e3274abdb3dca1bcc95e33e964606c35ed8aa3ad1007131fee4d2d5543bc704dc52ec52ff90f160ee71da996d2f59fc74b90a3e0
|
7
|
+
data.tar.gz: 865c2cc4d66b7ea6359225f36f9ae6c17274e1c4e0c34f54efc0a6cdce457cbe72fdb7388692b6c5836ef4c24ee243d26b9d1b9383078d0d2d38b2e65a441384
|
data/CHANGELOG.md
CHANGED
@@ -1,6 +1,15 @@
|
|
1
1
|
# master
|
2
2
|
|
3
|
-
# Version 1.0.
|
3
|
+
# Version 1.0.3
|
4
|
+
|
5
|
+
* doc improvements [John Cupitt]
|
6
|
+
* add #size to get [width, height] [John Cupitt]
|
7
|
+
* only ask for ruby 2.0 to help OS X [John Cupitt]
|
8
|
+
* break up Image.call to make it easier to understand [John Cupitt]
|
9
|
+
* detect operation build fail correctly [John Cupitt]
|
10
|
+
* lock gobject-introspection at 3.0.8 to avoid breakage [John Cupitt]
|
11
|
+
|
12
|
+
# Version 1.0.2
|
4
13
|
|
5
14
|
* add .yardopts to fix ruby-gems docs [John Cupitt]
|
6
15
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0.
|
1
|
+
1.0.3
|
data/lib/vips/call.rb
CHANGED
@@ -1,225 +1,281 @@
|
|
1
1
|
module Vips
|
2
2
|
|
3
|
-
#
|
4
|
-
# I've really no idea why :-(
|
3
|
+
# Call a vips operation.
|
5
4
|
#
|
6
|
-
#
|
7
|
-
#
|
5
|
+
# This will crash if there's a GC during the call, only use
|
6
|
+
# this via {Vips.call}.
|
7
|
+
private
|
8
|
+
class Call
|
9
|
+
attr_writer :instance, :option_string
|
10
|
+
|
11
|
+
def initialize(name, supplied_values)
|
12
|
+
@name = name
|
13
|
+
@supplied_values = supplied_values
|
14
|
+
@instance = nil
|
15
|
+
@option_string = nil
|
16
|
+
|
17
|
+
if @supplied_values.last.is_a? Hash
|
18
|
+
@optional_values = @supplied_values.last
|
19
|
+
@supplied_values.delete_at -1
|
20
|
+
else
|
21
|
+
@optional_values = {}
|
22
|
+
end
|
8
23
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
log "option_string = #{option_string}"
|
15
|
-
log "supplied_values are:"
|
16
|
-
supplied_values.each {|x| log " #{x}"}
|
17
|
-
|
18
|
-
if supplied_values.last.is_a? Hash
|
19
|
-
optional_values = supplied_values.last
|
20
|
-
supplied_values.delete_at -1
|
21
|
-
else
|
22
|
-
optional_values = {}
|
23
|
-
end
|
24
|
+
begin
|
25
|
+
@op = Vips::Operation.new @name
|
26
|
+
rescue
|
27
|
+
raise Vips::Error, "no operator '#{@name}'"
|
28
|
+
end
|
24
29
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
30
|
+
log "Vips::Call.init"
|
31
|
+
log "name = #{@name}"
|
32
|
+
log "supplied_values are:"
|
33
|
+
@supplied_values.each {|x| log " #{x}"}
|
34
|
+
log "optional_values are:"
|
35
|
+
@optional_values.each {|x| log " #{x}"}
|
29
36
|
end
|
30
37
|
|
31
|
-
# set string options
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
38
|
+
# set any string options on the operation
|
39
|
+
def set_string_args
|
40
|
+
if @option_string
|
41
|
+
log "setting string options #{@option_string} ..."
|
42
|
+
|
43
|
+
if @op.set_from_string(@option_string) != 0
|
44
|
+
raise Error
|
45
|
+
end
|
36
46
|
end
|
37
47
|
end
|
38
48
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
49
|
+
# set @match_image to be the image we build constants to match
|
50
|
+
def find_match_image
|
51
|
+
# the instance, if supplied, must be a vips image ... we use it for
|
52
|
+
# match_image, below
|
53
|
+
if @instance and not @instance.is_a? Vips::Image
|
54
|
+
raise Vips::Error, "@instance is not a Vips::Image."
|
55
|
+
end
|
46
56
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
end
|
55
|
-
if match_image == nil
|
56
|
-
match = optional_values.find do |name, value|
|
57
|
-
value.is_a? Vips::Image
|
57
|
+
# if the op needs images but the user supplies constants, we expand
|
58
|
+
# them to match the first input image argument ... find the first
|
59
|
+
# image
|
60
|
+
log "searching for first image argument ..."
|
61
|
+
match_image = @instance
|
62
|
+
if match_image == nil
|
63
|
+
match_image = @supplied_values.find {|x| x.is_a? Vips::Image}
|
58
64
|
end
|
59
|
-
|
60
|
-
|
61
|
-
|
65
|
+
if match_image == nil
|
66
|
+
match = @optional_values.find do |name, value|
|
67
|
+
value.is_a? Vips::Image
|
68
|
+
end
|
69
|
+
# if we found a match, it'll be [name, value]
|
70
|
+
if match
|
71
|
+
match_image = match[1]
|
72
|
+
end
|
62
73
|
end
|
63
|
-
end
|
64
74
|
|
65
|
-
|
66
|
-
log "finding unassigned required input arguments ..."
|
67
|
-
required_input = all_args.select do |arg|
|
68
|
-
not arg.isset and
|
69
|
-
(arg.flags & :input) != 0 and
|
70
|
-
(arg.flags & :required) != 0
|
75
|
+
return match_image
|
71
76
|
end
|
72
77
|
|
73
|
-
#
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
gtype = GLib::Type["VipsImage"]
|
78
|
-
vtype = arg.prop.value_type
|
78
|
+
# look through the operation args and find required and optional
|
79
|
+
# input args
|
80
|
+
def find_input
|
81
|
+
all_args = @op.get_args
|
79
82
|
|
80
|
-
|
83
|
+
# find unassigned required input args
|
84
|
+
log "finding unassigned required input arguments ..."
|
85
|
+
required_input = all_args.select do |arg|
|
86
|
+
not arg.isset and
|
87
|
+
(arg.flags & :input) != 0 and
|
88
|
+
(arg.flags & :required) != 0
|
81
89
|
end
|
82
|
-
|
83
|
-
|
84
|
-
|
90
|
+
|
91
|
+
# find optional unassigned input args
|
92
|
+
log "finding optional unassigned input arguments ..."
|
93
|
+
optional_input = all_args.select do |arg|
|
94
|
+
not arg.isset and
|
95
|
+
(arg.flags & :input) != 0 and
|
96
|
+
(arg.flags & :required) == 0
|
85
97
|
end
|
86
|
-
x.set_value match_image, instance
|
87
|
-
required_input.delete x
|
88
|
-
end
|
89
98
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
"#{required_input.length} arguments, you supplied " +
|
94
|
-
"#{supplied_values.length}."
|
95
|
-
end
|
99
|
+
# make a hash from name to arg for the options
|
100
|
+
optional_input = Hash[
|
101
|
+
optional_input.map(&:name).zip(optional_input)]
|
96
102
|
|
97
|
-
|
98
|
-
required_input.zip(supplied_values).each do |arg, value|
|
99
|
-
arg.set_value match_image, value
|
103
|
+
return required_input, optional_input
|
100
104
|
end
|
101
105
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
106
|
+
def find_optional_output
|
107
|
+
all_args = @op.get_args
|
108
|
+
|
109
|
+
log "finding optional output arguments ..."
|
110
|
+
optional_output = all_args.select do |arg|
|
111
|
+
(arg.flags & :output) != 0 and
|
112
|
+
(arg.flags & :required) == 0
|
113
|
+
end
|
114
|
+
optional_output = Hash[
|
115
|
+
optional_output.map(&:name).zip(optional_output)]
|
109
116
|
|
110
|
-
|
111
|
-
optional_input = Hash[
|
112
|
-
optional_input.map(&:name).zip(optional_input)]
|
117
|
+
return optional_output
|
113
118
|
|
114
|
-
# find optional unassigned output args
|
115
|
-
log "finding optional unassigned output arguments ..."
|
116
|
-
optional_output = all_args.select do |arg|
|
117
|
-
not arg.isset and
|
118
|
-
(arg.flags & :output) != 0 and
|
119
|
-
(arg.flags & :required) == 0
|
120
119
|
end
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
120
|
+
|
121
|
+
def set_required_input(match_image, required_input)
|
122
|
+
# do we have a non-nil instance? set the first image arg with this
|
123
|
+
if @instance != nil
|
124
|
+
log "setting first image arg with instance ..."
|
125
|
+
x = required_input.find do |arg|
|
126
|
+
gtype = GLib::Type["VipsImage"]
|
127
|
+
vtype = arg.prop.value_type
|
128
|
+
|
129
|
+
vtype.type_is_a? gtype
|
130
|
+
end
|
131
|
+
if x == nil
|
132
|
+
raise Vips::Error,
|
133
|
+
"No #{@instance.class} argument to #{@name}."
|
134
|
+
end
|
135
|
+
x.set_value match_image, @instance
|
136
|
+
required_input.delete x
|
137
|
+
end
|
138
|
+
|
139
|
+
if required_input.length != @supplied_values.length
|
133
140
|
raise Vips::Error,
|
134
|
-
"
|
135
|
-
|
136
|
-
|
141
|
+
"Wrong number of arguments. '#{@name}' requires " +
|
142
|
+
"#{required_input.length} arguments, you supplied " +
|
143
|
+
"#{@supplied_values.length}."
|
144
|
+
end
|
145
|
+
|
146
|
+
log "setting required input arguments ..."
|
147
|
+
required_input.zip(@supplied_values).each do |arg, value|
|
148
|
+
arg.set_value match_image, value
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
def set_optional_input(match_image, optional_input, optional_output)
|
154
|
+
log "setting optional input args ..."
|
155
|
+
@optional_values.each do |name, value|
|
156
|
+
# we are passed symbols as keys
|
157
|
+
name = name.to_s
|
158
|
+
if optional_input.has_key? name
|
159
|
+
log "setting #{name} to #{value}"
|
160
|
+
optional_input[name].set_value match_image, value
|
161
|
+
elsif optional_output.has_key? name and value != true
|
162
|
+
raise Vips::Error,
|
163
|
+
"Optional output argument #{name} must be true."
|
164
|
+
elsif not optional_output.has_key? name
|
165
|
+
raise Vips::Error, "No such option '#{name}',"
|
166
|
+
end
|
137
167
|
end
|
138
168
|
end
|
139
169
|
|
140
|
-
|
170
|
+
def build
|
171
|
+
log "building ..."
|
141
172
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
op = op2
|
173
|
+
op2 = Vips::cache_operation_lookup @op
|
174
|
+
if op2
|
175
|
+
log "cache hit"
|
146
176
|
|
147
|
-
|
177
|
+
hit = true
|
178
|
+
@op = op2
|
179
|
+
else
|
180
|
+
log "cache miss ... building"
|
148
181
|
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
log "cache miss ... building"
|
158
|
-
if not op.build
|
159
|
-
raise Vips::Error
|
182
|
+
hit = false
|
183
|
+
if @op.build() != 0
|
184
|
+
raise Vips::Error
|
185
|
+
end
|
186
|
+
# showall
|
187
|
+
|
188
|
+
log "adding to cache ... "
|
189
|
+
Vips::cache_operation_add @op
|
160
190
|
end
|
161
|
-
showall
|
162
191
|
|
163
|
-
|
164
|
-
Vips::cache_operation_add op
|
192
|
+
return hit
|
165
193
|
end
|
166
194
|
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
195
|
+
def fetch_output(optional_output)
|
196
|
+
log "fetching outputs ..."
|
197
|
+
|
198
|
+
# gather output args
|
199
|
+
out = []
|
200
|
+
|
201
|
+
all_args = @op.get_args
|
202
|
+
all_args.each do |arg|
|
203
|
+
# required output
|
204
|
+
if (arg.flags & :output) != 0 and
|
205
|
+
(arg.flags & :required) != 0
|
206
|
+
log "fetching required output #{arg.name}"
|
207
|
+
out << arg.get_value
|
208
|
+
end
|
209
|
+
|
210
|
+
# modified input arg ... this will get the result of the
|
211
|
+
# copy() we did in Argument.set_value
|
212
|
+
if (arg.flags & :input) != 0 and
|
213
|
+
(arg.flags & :modify) != 0
|
214
|
+
log "fetching modified input arg ..."
|
215
|
+
out << arg.get_value
|
216
|
+
end
|
217
|
+
end
|
171
218
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
219
|
+
opts = {}
|
220
|
+
@optional_values.each do |name, value|
|
221
|
+
# we are passed symbols as keys
|
222
|
+
name = name.to_s
|
223
|
+
if optional_output.has_key? name
|
224
|
+
log "fetching optional output arg ..."
|
225
|
+
opts[name] = optional_output[name].get_value
|
226
|
+
end
|
178
227
|
end
|
228
|
+
out << opts if opts != {}
|
179
229
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
log "fetching modified input arg ..."
|
185
|
-
out << arg.get_value
|
230
|
+
if out.length == 1
|
231
|
+
out = out[0]
|
232
|
+
elsif out.length == 0
|
233
|
+
out = nil
|
186
234
|
end
|
235
|
+
|
236
|
+
return out
|
237
|
+
|
187
238
|
end
|
188
239
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
240
|
+
def invoke
|
241
|
+
set_string_args()
|
242
|
+
match_image = find_match_image()
|
243
|
+
required_input, optional_input = find_input()
|
244
|
+
optional_output = find_optional_output()
|
245
|
+
|
246
|
+
set_required_input(match_image, required_input)
|
247
|
+
set_optional_input(match_image, optional_input, optional_output)
|
248
|
+
|
249
|
+
hit = build()
|
250
|
+
|
251
|
+
# if there was a cache hit, we need to refind this since all the arg
|
252
|
+
# pointers will have changed
|
253
|
+
if hit
|
254
|
+
optional_output = find_optional_output()
|
196
255
|
end
|
197
|
-
|
198
|
-
out << opts if opts != {}
|
256
|
+
out = fetch_output(optional_output)
|
199
257
|
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
end
|
258
|
+
log "unreffing outputs ..."
|
259
|
+
@op.unref_outputs()
|
260
|
+
@op = nil
|
261
|
+
# showall
|
205
262
|
|
206
|
-
|
207
|
-
op.unref_outputs
|
208
|
-
op = nil
|
209
|
-
# showall
|
263
|
+
log "success! #{@name}.out = #{out}"
|
210
264
|
|
211
|
-
|
265
|
+
return out
|
266
|
+
end
|
212
267
|
|
213
|
-
return out
|
214
268
|
end
|
215
269
|
|
216
|
-
#
|
270
|
+
# full-fat call, with the GC disabled
|
217
271
|
private
|
218
272
|
def self.call_base(name, instance, option_string, supplied_values)
|
219
273
|
gc_was_enabled = GC.disable
|
220
274
|
begin
|
221
|
-
|
222
|
-
|
275
|
+
call = Call.new(name, supplied_values)
|
276
|
+
call.instance = instance
|
277
|
+
call.option_string = option_string
|
278
|
+
result = call.invoke
|
223
279
|
ensure
|
224
280
|
GC.enable if gc_was_enabled
|
225
281
|
end
|
@@ -283,7 +339,7 @@ module Vips
|
|
283
339
|
# y = x % [1]
|
284
340
|
# ```
|
285
341
|
#
|
286
|
-
# Similarly,
|
342
|
+
# Similarly, wherever an image is required, you can use a constant. The
|
287
343
|
# constant will be expanded to an image matching the first input image
|
288
344
|
# argument. For example, you can write:
|
289
345
|
#
|
@@ -296,7 +352,15 @@ module Vips
|
|
296
352
|
# the constant value 255.
|
297
353
|
|
298
354
|
def self.call(name, *args)
|
299
|
-
|
355
|
+
gc_was_enabled = GC.disable
|
356
|
+
begin
|
357
|
+
call = Call.new(name, args)
|
358
|
+
result = call.invoke
|
359
|
+
ensure
|
360
|
+
GC.enable if gc_was_enabled
|
361
|
+
end
|
362
|
+
|
363
|
+
return result
|
300
364
|
end
|
301
365
|
|
302
366
|
end
|