vips 8.11.3 → 8.12.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/development.yml +54 -0
- data/.standard.yml +17 -0
- data/.yardopts +0 -1
- data/CHANGELOG.md +323 -0
- data/Gemfile +3 -1
- data/README.md +29 -15
- data/Rakefile +23 -18
- data/TODO +43 -0
- data/example/annotate.rb +6 -6
- data/example/connection.rb +18 -9
- data/example/daltonize8.rb +6 -6
- data/example/draw_lines.rb +30 -0
- data/example/example1.rb +4 -4
- data/example/example2.rb +6 -6
- data/example/example3.rb +5 -5
- data/example/example4.rb +2 -2
- data/example/example5.rb +4 -4
- data/example/inheritance_with_refcount.rb +46 -39
- data/example/progress.rb +3 -3
- data/example/thumb.rb +6 -6
- data/example/trim8.rb +1 -1
- data/example/watermark.rb +2 -2
- data/example/wobble.rb +1 -1
- data/lib/vips/blend_mode.rb +29 -25
- data/lib/vips/connection.rb +4 -4
- data/lib/vips/gobject.rb +18 -11
- data/lib/vips/gvalue.rb +54 -54
- data/lib/vips/image.rb +362 -169
- data/lib/vips/interpolate.rb +3 -2
- data/lib/vips/methods.rb +2877 -2319
- data/lib/vips/mutableimage.rb +173 -0
- data/lib/vips/object.rb +81 -88
- data/lib/vips/operation.rb +175 -82
- data/lib/vips/region.rb +6 -6
- data/lib/vips/source.rb +11 -12
- data/lib/vips/sourcecustom.rb +7 -8
- data/lib/vips/target.rb +12 -13
- data/lib/vips/targetcustom.rb +9 -10
- data/lib/vips/version.rb +1 -1
- data/lib/vips.rb +129 -82
- data/vips.gemspec +3 -3
- metadata +26 -19
data/lib/vips/operation.rb
CHANGED
@@ -4,7 +4,8 @@
|
|
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
|
@@ -12,22 +13,22 @@ module Vips
|
|
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
|
15
|
-
# libvips might trigger some signals which ruby has handles for.
|
16
|
+
# libvips might trigger some signals which ruby has handles for.
|
16
17
|
#
|
17
|
-
# We need FFI to drop the GIL lock during this call and reacquire it when
|
18
|
+
# We need FFI to drop the GIL lock during this call and reacquire it when
|
18
19
|
# the call ends, or we'll deadlock.
|
19
|
-
attach_function :vips_cache_operation_build, [:pointer], :pointer,
|
20
|
+
attach_function :vips_cache_operation_build, [:pointer], :pointer,
|
20
21
|
blocking: true
|
21
22
|
attach_function :vips_object_unref_outputs, [:pointer], :void
|
22
23
|
|
23
24
|
callback :argument_map_fn, [:pointer,
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
GObject::GParamSpec.ptr,
|
26
|
+
ArgumentClass.ptr,
|
27
|
+
ArgumentInstance.ptr,
|
28
|
+
:pointer, :pointer], :pointer
|
28
29
|
attach_function :vips_argument_map, [:pointer,
|
29
|
-
|
30
|
-
|
30
|
+
:argument_map_fn,
|
31
|
+
:pointer, :pointer], :pointer
|
31
32
|
|
32
33
|
OPERATION_SEQUENTIAL = 1
|
33
34
|
OPERATION_NOCACHE = 4
|
@@ -45,14 +46,26 @@ module Vips
|
|
45
46
|
# everything we know about it. This is used for doc generation as well as
|
46
47
|
# call.
|
47
48
|
class Introspect
|
48
|
-
attr_reader :name, :description, :flags, :args, :required_input,
|
49
|
-
:optional_input, :required_output, :optional_output, :member_x,
|
50
|
-
:method_args
|
49
|
+
attr_reader :name, :description, :flags, :args, :required_input,
|
50
|
+
:optional_input, :required_output, :optional_output, :member_x,
|
51
|
+
:method_args, :vips_name, :destructive, :doc_optional_input,
|
52
|
+
:doc_optional_output
|
51
53
|
|
52
54
|
@@introspect_cache = {}
|
53
55
|
|
54
56
|
def initialize name
|
55
|
-
|
57
|
+
# if there's a trailing "!", this is a destructive version of an
|
58
|
+
# operation
|
59
|
+
if name[-1] == "!"
|
60
|
+
@destructive = true
|
61
|
+
# strip the trailing "!"
|
62
|
+
@vips_name = name[0...-1]
|
63
|
+
else
|
64
|
+
@destructive = false
|
65
|
+
@vips_name = name
|
66
|
+
end
|
67
|
+
|
68
|
+
@op = Operation.new @vips_name
|
56
69
|
@args = []
|
57
70
|
@required_input = []
|
58
71
|
@optional_input = {}
|
@@ -66,12 +79,14 @@ module Vips
|
|
66
79
|
# names can include - as punctuation, but we always use _ in
|
67
80
|
# Ruby
|
68
81
|
arg_name = pspec[:name].tr("-", "_")
|
69
|
-
args << {
|
70
|
-
:
|
71
|
-
:
|
72
|
-
:
|
82
|
+
@args << {
|
83
|
+
arg_name: arg_name,
|
84
|
+
flags: flags,
|
85
|
+
gtype: pspec[:value_type]
|
73
86
|
}
|
74
87
|
end
|
88
|
+
|
89
|
+
nil
|
75
90
|
end
|
76
91
|
|
77
92
|
@args.each do |details|
|
@@ -79,26 +94,27 @@ module Vips
|
|
79
94
|
flags = details[:flags]
|
80
95
|
|
81
96
|
if (flags & ARGUMENT_INPUT) != 0
|
82
|
-
if (flags & ARGUMENT_REQUIRED) != 0 &&
|
83
|
-
|
97
|
+
if (flags & ARGUMENT_REQUIRED) != 0 &&
|
98
|
+
(flags & ARGUMENT_DEPRECATED) == 0
|
84
99
|
@required_input << details
|
85
100
|
else
|
86
101
|
# we allow deprecated optional args
|
87
102
|
@optional_input[arg_name] = details
|
88
103
|
end
|
89
104
|
|
90
|
-
# MODIFY INPUT args count as OUTPUT as well
|
91
|
-
if (flags & ARGUMENT_MODIFY) != 0
|
92
|
-
|
93
|
-
|
105
|
+
# MODIFY INPUT args count as OUTPUT as well in non-destructive mode
|
106
|
+
if (flags & ARGUMENT_MODIFY) != 0 &&
|
107
|
+
!@destructive
|
108
|
+
if (flags & ARGUMENT_REQUIRED) != 0 &&
|
109
|
+
(flags & ARGUMENT_DEPRECATED) == 0
|
94
110
|
@required_output << details
|
95
111
|
else
|
96
112
|
@optional_output[arg_name] = details
|
97
113
|
end
|
98
114
|
end
|
99
115
|
elsif (flags & ARGUMENT_OUTPUT) != 0
|
100
|
-
if (flags & ARGUMENT_REQUIRED) != 0 &&
|
101
|
-
|
116
|
+
if (flags & ARGUMENT_REQUIRED) != 0 &&
|
117
|
+
(flags & ARGUMENT_DEPRECATED) == 0
|
102
118
|
@required_output << details
|
103
119
|
else
|
104
120
|
# again, allow deprecated optional args
|
@@ -106,6 +122,16 @@ module Vips
|
|
106
122
|
end
|
107
123
|
end
|
108
124
|
end
|
125
|
+
|
126
|
+
# in destructive mode, the first required input arg must be MODIFY and
|
127
|
+
# must be an image
|
128
|
+
if @destructive
|
129
|
+
if @required_input.length < 1 ||
|
130
|
+
@required_input[0][:flags] & ARGUMENT_MODIFY == 0 ||
|
131
|
+
@required_input[0][:gtype] != IMAGE_TYPE
|
132
|
+
raise Vips::Error, "operation #{@vips_name} is not destructive"
|
133
|
+
end
|
134
|
+
end
|
109
135
|
end
|
110
136
|
|
111
137
|
# Yard comment generation needs a little more introspection. We add this
|
@@ -113,10 +139,12 @@ module Vips
|
|
113
139
|
# we can.
|
114
140
|
def add_yard_introspection name
|
115
141
|
@name = name
|
116
|
-
@description = Vips
|
117
|
-
@flags = Vips
|
142
|
+
@description = Vips.vips_object_get_description @op
|
143
|
+
@flags = Vips.vips_operation_get_flags @op
|
118
144
|
@member_x = nil
|
119
145
|
@method_args = []
|
146
|
+
@doc_optional_input = {}
|
147
|
+
@doc_optional_output = {}
|
120
148
|
|
121
149
|
@args.each do |details|
|
122
150
|
arg_name = details[:arg_name]
|
@@ -125,20 +153,31 @@ module Vips
|
|
125
153
|
|
126
154
|
details[:yard_name] = arg_name == "in" ? "im" : arg_name
|
127
155
|
pspec = @op.get_pspec arg_name
|
128
|
-
details[:blurb] = GObject
|
156
|
+
details[:blurb] = GObject.g_param_spec_get_blurb pspec
|
129
157
|
|
130
|
-
if (flags & ARGUMENT_INPUT) != 0 &&
|
131
|
-
|
132
|
-
|
133
|
-
# the first required input image is the thing we will be a method
|
158
|
+
if (flags & ARGUMENT_INPUT) != 0 &&
|
159
|
+
(flags & ARGUMENT_REQUIRED) != 0 &&
|
160
|
+
(flags & ARGUMENT_DEPRECATED) == 0
|
161
|
+
# the first required input image is the thing we will be a method
|
134
162
|
# of
|
135
|
-
if @member_x
|
136
|
-
@member_x = details
|
163
|
+
if @member_x.nil? && gtype == IMAGE_TYPE
|
164
|
+
@member_x = details
|
137
165
|
else
|
138
166
|
@method_args << details
|
139
167
|
end
|
140
168
|
end
|
141
169
|
end
|
170
|
+
|
171
|
+
# and make the arg sets to document by filtering out deprecated args
|
172
|
+
@optional_input.each do |arg_name, details|
|
173
|
+
next if (details[:flags] & ARGUMENT_DEPRECATED) != 0
|
174
|
+
@doc_optional_input[details[:arg_name]] = details
|
175
|
+
end
|
176
|
+
|
177
|
+
@optional_output.each do |arg_name, details|
|
178
|
+
next if (details[:flags] & ARGUMENT_DEPRECATED) != 0
|
179
|
+
@doc_optional_output[details[:arg_name]] = details
|
180
|
+
end
|
142
181
|
end
|
143
182
|
|
144
183
|
def self.get name
|
@@ -150,7 +189,6 @@ module Vips
|
|
150
189
|
introspect.add_yard_introspection name
|
151
190
|
introspect
|
152
191
|
end
|
153
|
-
|
154
192
|
end
|
155
193
|
|
156
194
|
class Operation < Object
|
@@ -176,7 +214,7 @@ module Vips
|
|
176
214
|
# allow init with a pointer so we can wrap the return values from
|
177
215
|
# things like _build
|
178
216
|
if value.is_a? String
|
179
|
-
value = Vips
|
217
|
+
value = Vips.vips_operation_new value
|
180
218
|
raise Vips::Error if value.null?
|
181
219
|
end
|
182
220
|
|
@@ -184,66 +222,65 @@ module Vips
|
|
184
222
|
end
|
185
223
|
|
186
224
|
def build
|
187
|
-
op = Vips
|
225
|
+
op = Vips.vips_cache_operation_build self
|
188
226
|
if op.null?
|
189
|
-
Vips
|
227
|
+
Vips.vips_object_unref_outputs self
|
190
228
|
raise Vips::Error
|
191
229
|
end
|
192
230
|
|
193
|
-
|
231
|
+
Operation.new op
|
194
232
|
end
|
195
233
|
|
196
234
|
def argument_map &block
|
197
|
-
fn =
|
235
|
+
fn = proc do |_op, pspec, argument_class, argument_instance, _a, _b|
|
198
236
|
block.call pspec, argument_class, argument_instance
|
199
237
|
end
|
200
|
-
|
201
|
-
Vips::vips_argument_map self, fn, nil, nil
|
238
|
+
Vips.vips_argument_map self, fn, nil, nil
|
202
239
|
end
|
203
240
|
|
204
|
-
# Search an object for the first element to match a predicate. Search
|
241
|
+
# Search an object for the first element to match a predicate. Search
|
205
242
|
# inside subarrays and sub-hashes. Equlvalent to x.flatten.find{}.
|
206
243
|
def self.flat_find object, &block
|
207
244
|
if object.respond_to? :each
|
208
|
-
object.each do |x|
|
209
|
-
result = flat_find x, &block
|
210
|
-
return result
|
245
|
+
object.each do |x|
|
246
|
+
result = flat_find x, &block
|
247
|
+
return result unless result.nil?
|
211
248
|
end
|
212
|
-
|
213
|
-
return object
|
249
|
+
elsif yield object
|
250
|
+
return object
|
214
251
|
end
|
215
252
|
|
216
|
-
|
253
|
+
nil
|
217
254
|
end
|
218
255
|
|
219
256
|
# expand a constant into an image
|
220
257
|
def self.imageize match_image, value
|
221
|
-
return value if value.is_a?
|
258
|
+
return value if value.is_a?(Image) || value.is_a?(MutableImage)
|
222
259
|
|
223
260
|
# 2D array values become tiny 2D images
|
224
261
|
# if there's nothing to match to, we also make a 2D image
|
225
|
-
if (value.is_a?(Array) && value[0].is_a?(Array)) ||
|
226
|
-
|
227
|
-
return Image.new_from_array value
|
262
|
+
if (value.is_a?(Array) && value[0].is_a?(Array)) || match_image.nil?
|
263
|
+
Image.new_from_array value
|
228
264
|
else
|
229
265
|
# we have a 1D array ... use that as a pixel constant and
|
230
266
|
# expand to match match_image
|
231
|
-
|
267
|
+
match_image.new_from_image value
|
232
268
|
end
|
233
269
|
end
|
234
270
|
|
235
271
|
# set an operation argument, expanding constants and copying images as
|
236
272
|
# required
|
237
|
-
def set name, value, match_image, flags, gtype
|
273
|
+
def set name, value, match_image, flags, gtype, destructive
|
238
274
|
if gtype == IMAGE_TYPE
|
239
|
-
value = Operation
|
275
|
+
value = Operation.imageize match_image, value
|
240
276
|
|
241
|
-
|
242
|
-
|
277
|
+
# in non-destructive mode, make sure we have a unique copy
|
278
|
+
if (flags & ARGUMENT_MODIFY) != 0 &&
|
279
|
+
!destructive
|
243
280
|
value = value.copy.copy_memory
|
244
281
|
end
|
245
282
|
elsif gtype == ARRAY_IMAGE_TYPE
|
246
|
-
value = value.map { |x| Operation
|
283
|
+
value = value.map { |x| Operation.imageize match_image, x }
|
247
284
|
end
|
248
285
|
|
249
286
|
super name, value
|
@@ -319,8 +356,8 @@ module Vips
|
|
319
356
|
# the constant value 255.
|
320
357
|
|
321
358
|
def self.call name, supplied, optional = {}, option_string = ""
|
322
|
-
GLib
|
323
|
-
"name = #{name}, supplied = #{supplied}, "
|
359
|
+
GLib.logger.debug("Vips::VipsOperation.call") {
|
360
|
+
"name = #{name}, supplied = #{supplied}, " \
|
324
361
|
"optional = #{optional}, option_string = #{option_string}"
|
325
362
|
}
|
326
363
|
|
@@ -329,20 +366,21 @@ module Vips
|
|
329
366
|
required_output = introspect.required_output
|
330
367
|
optional_input = introspect.optional_input
|
331
368
|
optional_output = introspect.optional_output
|
369
|
+
destructive = introspect.destructive
|
332
370
|
|
333
371
|
unless supplied.is_a? Array
|
334
|
-
raise Vips::Error, "unable to call #{name}: "
|
335
|
-
|
372
|
+
raise Vips::Error, "unable to call #{name}: " \
|
373
|
+
"argument array is not an array"
|
336
374
|
end
|
337
375
|
unless optional.is_a? Hash
|
338
|
-
raise Vips::Error, "unable to call #{name}: "
|
339
|
-
|
376
|
+
raise Vips::Error, "unable to call #{name}: " \
|
377
|
+
"optional arguments are not a hash"
|
340
378
|
end
|
341
379
|
|
342
380
|
if supplied.length != required_input.length
|
343
|
-
raise Vips::Error, "unable to call #{name}: "
|
344
|
-
|
345
|
-
|
381
|
+
raise Vips::Error, "unable to call #{name}: " \
|
382
|
+
"you supplied #{supplied.length} arguments, " \
|
383
|
+
"but operation needs #{required_input.length}."
|
346
384
|
end
|
347
385
|
|
348
386
|
# all supplied_optional keys should be in optional_input or
|
@@ -352,8 +390,8 @@ module Vips
|
|
352
390
|
|
353
391
|
unless optional_input.has_key?(arg_name) ||
|
354
392
|
optional_output.has_key?(arg_name)
|
355
|
-
raise Vips::Error, "unable to call #{name}: "
|
356
|
-
|
393
|
+
raise Vips::Error, "unable to call #{name}: " \
|
394
|
+
"unknown option #{arg_name}"
|
357
395
|
end
|
358
396
|
end
|
359
397
|
|
@@ -362,17 +400,58 @@ module Vips
|
|
362
400
|
#
|
363
401
|
# look inside array and hash arguments, since we may be passing an
|
364
402
|
# array of images
|
365
|
-
|
403
|
+
#
|
404
|
+
# also enforce the rules around mutable and non-mutable images
|
405
|
+
match_image = nil
|
406
|
+
flat_find(supplied) do |value|
|
407
|
+
if match_image
|
408
|
+
# no non-first image arg can ever be mutable
|
409
|
+
if value.is_a?(MutableImage)
|
410
|
+
raise Vips::Error, "unable to call #{name}: " \
|
411
|
+
"only the first image argument can be mutable"
|
412
|
+
end
|
413
|
+
elsif destructive
|
414
|
+
if value.is_a?(Image)
|
415
|
+
raise Vips::Error, "unable to call #{name}: " \
|
416
|
+
"first image argument to a destructive " \
|
417
|
+
"operation must be mutable"
|
418
|
+
elsif value.is_a?(MutableImage)
|
419
|
+
match_image = value
|
420
|
+
end
|
421
|
+
elsif value.is_a?(MutableImage)
|
422
|
+
# non destructive operation, so no mutable images
|
423
|
+
raise Vips::Error, "unable to call #{name}: " \
|
424
|
+
"must not pass mutable images to " \
|
425
|
+
"non-destructive operations"
|
426
|
+
elsif value.is_a?(Image)
|
427
|
+
match_image = value
|
428
|
+
end
|
366
429
|
|
367
|
-
|
430
|
+
# keep looping
|
431
|
+
false
|
432
|
+
end
|
433
|
+
|
434
|
+
op = Operation.new introspect.vips_name
|
368
435
|
|
369
436
|
# set any string args first so they can't be overridden
|
370
|
-
|
371
|
-
if Vips
|
437
|
+
unless option_string.nil?
|
438
|
+
if Vips.vips_object_set_from_string(op, option_string) != 0
|
372
439
|
raise Vips::Error
|
373
440
|
end
|
374
441
|
end
|
375
442
|
|
443
|
+
# collect a list of all input references here
|
444
|
+
references = Set.new
|
445
|
+
|
446
|
+
add_reference = lambda do |x|
|
447
|
+
if x.is_a?(Vips::Image)
|
448
|
+
x.references.each do |i|
|
449
|
+
references << i
|
450
|
+
end
|
451
|
+
end
|
452
|
+
false
|
453
|
+
end
|
454
|
+
|
376
455
|
# set all required inputs
|
377
456
|
required_input.each_index do |i|
|
378
457
|
details = required_input[i]
|
@@ -381,7 +460,8 @@ module Vips
|
|
381
460
|
gtype = details[:gtype]
|
382
461
|
value = supplied[i]
|
383
462
|
|
384
|
-
|
463
|
+
flat_find value, &add_reference
|
464
|
+
op.set arg_name, value, match_image, flags, gtype, destructive
|
385
465
|
end
|
386
466
|
|
387
467
|
# set all optional inputs
|
@@ -395,16 +475,27 @@ module Vips
|
|
395
475
|
flags = details[:flags]
|
396
476
|
gtype = details[:gtype]
|
397
477
|
|
398
|
-
|
478
|
+
flat_find value, &add_reference
|
479
|
+
op.set arg_name, value, match_image, flags, gtype, destructive
|
399
480
|
end
|
400
481
|
end
|
401
482
|
|
402
483
|
op = op.build
|
403
484
|
|
485
|
+
# attach all input refs to output x
|
486
|
+
set_reference = lambda do |x|
|
487
|
+
if x.is_a? Vips::Image
|
488
|
+
x.references += references
|
489
|
+
end
|
490
|
+
false
|
491
|
+
end
|
492
|
+
|
404
493
|
# get all required results
|
405
494
|
result = []
|
406
495
|
required_output.each do |details|
|
407
|
-
|
496
|
+
value = details[:arg_name]
|
497
|
+
flat_find value, &set_reference
|
498
|
+
result << op.get(value)
|
408
499
|
end
|
409
500
|
|
410
501
|
# fetch all optional ones
|
@@ -413,7 +504,9 @@ module Vips
|
|
413
504
|
arg_name = key.to_s
|
414
505
|
|
415
506
|
if optional_output.has_key? arg_name
|
416
|
-
|
507
|
+
value = op.get arg_name
|
508
|
+
flat_find value, &set_reference
|
509
|
+
optional_results[arg_name] = value
|
417
510
|
end
|
418
511
|
end
|
419
512
|
|
@@ -425,11 +518,11 @@ module Vips
|
|
425
518
|
result = nil
|
426
519
|
end
|
427
520
|
|
428
|
-
GLib
|
521
|
+
GLib.logger.debug("Vips::Operation.call") { "result = #{result}" }
|
429
522
|
|
430
|
-
Vips
|
523
|
+
Vips.vips_object_unref_outputs op
|
431
524
|
|
432
|
-
|
525
|
+
result
|
433
526
|
end
|
434
527
|
end
|
435
528
|
end
|
data/lib/vips/region.rb
CHANGED
@@ -4,12 +4,12 @@
|
|
4
4
|
# Author:: John Cupitt (mailto:jcupitt@gmail.com)
|
5
5
|
# License:: MIT
|
6
6
|
|
7
|
-
require
|
7
|
+
require "ffi"
|
8
8
|
|
9
9
|
module Vips
|
10
10
|
attach_function :vips_region_new, [:pointer], :pointer
|
11
11
|
|
12
|
-
if Vips
|
12
|
+
if Vips.at_least_libvips?(8, 8)
|
13
13
|
attach_function :vips_region_fetch, [:pointer, :int, :int, :int, :int, SizeStruct.ptr], :pointer
|
14
14
|
attach_function :vips_region_width, [:pointer], :int
|
15
15
|
attach_function :vips_region_height, [:pointer], :int
|
@@ -44,24 +44,24 @@ module Vips
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def initialize(name)
|
47
|
-
ptr = Vips
|
47
|
+
ptr = Vips.vips_region_new name
|
48
48
|
raise Vips::Error if ptr.null?
|
49
49
|
|
50
50
|
super ptr
|
51
51
|
end
|
52
52
|
|
53
53
|
def width
|
54
|
-
Vips
|
54
|
+
Vips.vips_region_width self
|
55
55
|
end
|
56
56
|
|
57
57
|
def height
|
58
|
-
Vips
|
58
|
+
Vips.vips_region_height self
|
59
59
|
end
|
60
60
|
|
61
61
|
# Fetch a region filled with pixel data.
|
62
62
|
def fetch(left, top, width, height)
|
63
63
|
len = Vips::SizeStruct.new
|
64
|
-
ptr = Vips
|
64
|
+
ptr = Vips.vips_region_fetch self, left, top, width, height, len
|
65
65
|
raise Vips::Error if ptr.null?
|
66
66
|
|
67
67
|
# wrap up as an autopointer
|
data/lib/vips/source.rb
CHANGED
@@ -4,10 +4,10 @@
|
|
4
4
|
# Author:: John Cupitt (mailto:jcupitt@gmail.com)
|
5
5
|
# License:: MIT
|
6
6
|
|
7
|
-
require
|
7
|
+
require "ffi"
|
8
8
|
|
9
9
|
module Vips
|
10
|
-
if Vips
|
10
|
+
if Vips.at_least_libvips?(8, 9)
|
11
11
|
attach_function :vips_source_new_from_descriptor, [:int], :pointer
|
12
12
|
attach_function :vips_source_new_from_file, [:pointer], :pointer
|
13
13
|
attach_function :vips_source_new_from_memory, [:pointer, :size_t], :pointer
|
@@ -42,26 +42,26 @@ module Vips
|
|
42
42
|
#
|
43
43
|
# Pass sources to {Image.new_from_source} to load images from
|
44
44
|
# them.
|
45
|
-
#
|
45
|
+
#
|
46
46
|
# @param descriptor [Integer] the file descriptor
|
47
47
|
# @return [Source] the new Vips::Source
|
48
48
|
def self.new_from_descriptor(descriptor)
|
49
|
-
ptr = Vips
|
49
|
+
ptr = Vips.vips_source_new_from_descriptor descriptor
|
50
50
|
raise Vips::Error if ptr.null?
|
51
51
|
|
52
52
|
Vips::Source.new ptr
|
53
53
|
end
|
54
54
|
|
55
|
-
# Create a new source from a file name.
|
55
|
+
# Create a new source from a file name.
|
56
56
|
#
|
57
57
|
# Pass sources to {Image.new_from_source} to load images from
|
58
58
|
# them.
|
59
|
-
#
|
59
|
+
#
|
60
60
|
# @param filename [String] the name of the file
|
61
61
|
# @return [Source] the new Vips::Source
|
62
62
|
def self.new_from_file(filename)
|
63
63
|
raise Vips::Error, "filename is nil" if filename.nil?
|
64
|
-
ptr = Vips
|
64
|
+
ptr = Vips.vips_source_new_from_file filename
|
65
65
|
raise Vips::Error if ptr.null?
|
66
66
|
|
67
67
|
Vips::Source.new ptr
|
@@ -72,18 +72,17 @@ module Vips
|
|
72
72
|
#
|
73
73
|
# Pass sources to {Image.new_from_source} to load images from
|
74
74
|
# them.
|
75
|
-
#
|
76
|
-
# @param data [String] memory area
|
75
|
+
#
|
76
|
+
# @param data [String] memory area
|
77
77
|
# @return [Source] the new Vips::Source
|
78
78
|
def self.new_from_memory(data)
|
79
|
-
ptr = Vips
|
79
|
+
ptr = Vips.vips_source_new_from_memory data, data.bytesize
|
80
80
|
raise Vips::Error if ptr.null?
|
81
81
|
|
82
|
-
# FIXME do we need to keep a ref to the underlying memory area? what
|
82
|
+
# FIXME do we need to keep a ref to the underlying memory area? what
|
83
83
|
# about Image.new_from_buffer? Does that need a secret ref too?
|
84
84
|
|
85
85
|
Vips::Source.new ptr
|
86
86
|
end
|
87
|
-
|
88
87
|
end
|
89
88
|
end
|
data/lib/vips/sourcecustom.rb
CHANGED
@@ -4,14 +4,14 @@
|
|
4
4
|
# Author:: John Cupitt (mailto:jcupitt@gmail.com)
|
5
5
|
# License:: MIT
|
6
6
|
|
7
|
-
require
|
7
|
+
require "ffi"
|
8
8
|
|
9
9
|
module Vips
|
10
|
-
if Vips
|
10
|
+
if Vips.at_least_libvips?(8, 9)
|
11
11
|
attach_function :vips_source_custom_new, [], :pointer
|
12
12
|
end
|
13
13
|
|
14
|
-
# A source you can attach action signal handlers to to implement
|
14
|
+
# A source you can attach action signal handlers to to implement
|
15
15
|
# custom input types.
|
16
16
|
#
|
17
17
|
# For example:
|
@@ -23,7 +23,7 @@ module Vips
|
|
23
23
|
# image = Vips::Image.new_from_source source
|
24
24
|
# ```
|
25
25
|
#
|
26
|
-
# (just an example -- of course in practice you'd use {Source#new_from_file}
|
26
|
+
# (just an example -- of course in practice you'd use {Source#new_from_file}
|
27
27
|
# to read from a named file)
|
28
28
|
class SourceCustom < Vips::Source
|
29
29
|
module SourceCustomLayout
|
@@ -44,7 +44,7 @@ module Vips
|
|
44
44
|
end
|
45
45
|
|
46
46
|
def initialize
|
47
|
-
pointer = Vips
|
47
|
+
pointer = Vips.vips_source_custom_new
|
48
48
|
raise Vips::Error if pointer.null?
|
49
49
|
|
50
50
|
super pointer
|
@@ -60,7 +60,7 @@ module Vips
|
|
60
60
|
def on_read &block
|
61
61
|
signal_connect "read" do |buf, len|
|
62
62
|
chunk = block.call len
|
63
|
-
return 0 if chunk
|
63
|
+
return 0 if chunk.nil?
|
64
64
|
bytes_read = chunk.bytesize
|
65
65
|
buf.put_bytes(0, chunk, 0, bytes_read)
|
66
66
|
chunk.clear
|
@@ -70,7 +70,7 @@ module Vips
|
|
70
70
|
end
|
71
71
|
|
72
72
|
# The block is executed to seek the source. The interface is exactly as
|
73
|
-
# IO::seek, ie. it should take an offset and whence, and return the
|
73
|
+
# IO::seek, ie. it should take an offset and whence, and return the
|
74
74
|
# new read position.
|
75
75
|
#
|
76
76
|
# This handler is optional -- if you do not attach a seek handler,
|
@@ -85,6 +85,5 @@ module Vips
|
|
85
85
|
block.call offset, whence
|
86
86
|
end
|
87
87
|
end
|
88
|
-
|
89
88
|
end
|
90
89
|
end
|