vips 8.8.0.3 → 8.10.5
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 +5 -2
- data/README.md +3 -1
- data/example/connection.rb +17 -0
- data/example/daltonize8.rb +13 -15
- data/example/example1.rb +1 -2
- data/example/example4.rb +2 -2
- data/example/example5.rb +4 -5
- data/example/inheritance_with_refcount.rb +2 -19
- data/example/progress.rb +30 -0
- data/example/thumb.rb +2 -4
- data/example/trim8.rb +4 -4
- data/ext/Rakefile +2 -2
- data/lib/vips.rb +101 -35
- 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 +0 -2
- 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 +8 -4
- data/lib/vips/gvalue.rb +15 -9
- data/lib/vips/image.rb +269 -204
- data/lib/vips/interesting.rb +0 -1
- data/lib/vips/interpolate.rb +0 -5
- data/lib/vips/interpretation.rb +0 -1
- data/lib/vips/kernel.rb +0 -1
- data/lib/vips/methods.rb +150 -59
- data/lib/vips/object.rb +126 -18
- data/lib/vips/operation.rb +169 -101
- 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 +89 -0
- data/lib/vips/sourcecustom.rb +90 -0
- data/lib/vips/target.rb +87 -0
- data/lib/vips/targetcustom.rb +78 -0
- data/lib/vips/version.rb +1 -1
- metadata +14 -7
- data/CHANGELOG.md +0 -266
data/lib/vips/align.rb
CHANGED
data/lib/vips/angle.rb
CHANGED
data/lib/vips/angle45.rb
CHANGED
data/lib/vips/bandformat.rb
CHANGED
data/lib/vips/blend_mode.rb
CHANGED
data/lib/vips/coding.rb
CHANGED
@@ -0,0 +1,46 @@
|
|
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
|
+
if Vips::at_least_libvips?(8, 9)
|
11
|
+
attach_function :vips_connection_filename, [:pointer], :string
|
12
|
+
attach_function :vips_connection_nick, [:pointer], :string
|
13
|
+
end
|
14
|
+
|
15
|
+
# Abstract base class for connections.
|
16
|
+
class Connection < Vips::Object
|
17
|
+
# The layout of the VipsRegion struct.
|
18
|
+
module ConnectionLayout
|
19
|
+
def self.included(base)
|
20
|
+
base.class_eval do
|
21
|
+
layout :parent, Vips::Object::Struct
|
22
|
+
# rest opaque
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class Struct < Vips::Object::Struct
|
28
|
+
include ConnectionLayout
|
29
|
+
end
|
30
|
+
|
31
|
+
class ManagedStruct < Vips::Object::ManagedStruct
|
32
|
+
include ConnectionLayout
|
33
|
+
end
|
34
|
+
|
35
|
+
# Get any filename associated with a connection, or nil.
|
36
|
+
def filename
|
37
|
+
Vips::vips_connection_filename self
|
38
|
+
end
|
39
|
+
|
40
|
+
# Get a nickname (short description) of a connection that could be shown to
|
41
|
+
# the user.
|
42
|
+
def nick
|
43
|
+
Vips::vips_connection_nick self
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/lib/vips/direction.rb
CHANGED
data/lib/vips/extend.rb
CHANGED
data/lib/vips/gobject.rb
CHANGED
@@ -8,7 +8,6 @@ require 'ffi'
|
|
8
8
|
require 'forwardable'
|
9
9
|
|
10
10
|
module GObject
|
11
|
-
|
12
11
|
# we have a number of things we need to inherit in different ways:
|
13
12
|
#
|
14
13
|
# - we want to be able to subclass GObject in Ruby in a simple way
|
@@ -64,7 +63,6 @@ module GObject
|
|
64
63
|
# the plain struct ... cast with this
|
65
64
|
class Struct < FFI::Struct
|
66
65
|
include GObjectLayout
|
67
|
-
|
68
66
|
end
|
69
67
|
|
70
68
|
# don't allow ptr == nil, we never want to allocate a GObject struct
|
@@ -75,6 +73,9 @@ module GObject
|
|
75
73
|
def initialize ptr
|
76
74
|
# GLib::logger.debug("GObject::GObject.initialize") {"ptr = #{ptr}"}
|
77
75
|
@struct = ffi_managed_struct.new ptr
|
76
|
+
|
77
|
+
# sometimes we need to keep refs across C calls ... hide them here
|
78
|
+
@references = []
|
78
79
|
end
|
79
80
|
|
80
81
|
# access to the casting struct for this class
|
@@ -98,7 +99,6 @@ module GObject
|
|
98
99
|
self.const_get :ManagedStruct
|
99
100
|
end
|
100
101
|
end
|
101
|
-
|
102
102
|
end
|
103
103
|
|
104
104
|
class GParamSpec < FFI::Struct
|
@@ -114,9 +114,13 @@ module GObject
|
|
114
114
|
layout :value, GParamSpec.ptr
|
115
115
|
end
|
116
116
|
|
117
|
-
attach_function :g_param_spec_get_blurb, [
|
117
|
+
attach_function :g_param_spec_get_blurb, [:pointer], :string
|
118
118
|
|
119
119
|
attach_function :g_object_ref, [:pointer], :void
|
120
120
|
attach_function :g_object_unref, [:pointer], :void
|
121
121
|
|
122
|
+
# we just use one gcallback type for every signal, hopefully this is OK
|
123
|
+
callback :gcallback, [:pointer], :void
|
124
|
+
attach_function :g_signal_connect_data,
|
125
|
+
[:pointer, :string, :gcallback, :pointer, :pointer, :int], :long
|
122
126
|
end
|
data/lib/vips/gvalue.rb
CHANGED
@@ -6,7 +6,6 @@
|
|
6
6
|
require 'ffi'
|
7
7
|
|
8
8
|
module GObject
|
9
|
-
|
10
9
|
# Represent a GValue. Example use:
|
11
10
|
#
|
12
11
|
# ```ruby
|
@@ -14,6 +13,8 @@ module GObject
|
|
14
13
|
# gvalue.init GObject::GDOUBLE_TYPE
|
15
14
|
# gvalue.set 3.1415
|
16
15
|
# value = gvalue.get
|
16
|
+
# # optional -- drop any ref the gvalue had
|
17
|
+
# gvalue.unset
|
17
18
|
# ```
|
18
19
|
#
|
19
20
|
# Lifetime is managed automatically. It doesn't know about all GType values,
|
@@ -28,7 +29,9 @@ module GObject
|
|
28
29
|
value = value.to_s if value.is_a? Symbol
|
29
30
|
|
30
31
|
if value.is_a? String
|
31
|
-
|
32
|
+
# libvips expects "-" as a separator in enum names, but "_" is more
|
33
|
+
# convenient for ruby, eg. :b_w
|
34
|
+
value = Vips::vips_enum_from_nick "ruby-vips", gtype, value.tr("_", "-")
|
32
35
|
if value == -1
|
33
36
|
raise Vips::Error
|
34
37
|
end
|
@@ -134,7 +137,7 @@ module GObject
|
|
134
137
|
ptr.write_array_of_pointer value
|
135
138
|
|
136
139
|
# the gvalue needs a ref on each of the images
|
137
|
-
value.each {|image| ::GObject::g_object_ref image}
|
140
|
+
value.each { |image| ::GObject::g_object_ref image }
|
138
141
|
|
139
142
|
when Vips::BLOB_TYPE
|
140
143
|
len = value.bytesize
|
@@ -156,8 +159,7 @@ module GObject
|
|
156
159
|
|
157
160
|
else
|
158
161
|
raise Vips::Error, "unimplemented gtype for set: " +
|
159
|
-
|
160
|
-
|
162
|
+
"#{::GObject::g_type_name gtype} (#{gtype})"
|
161
163
|
end
|
162
164
|
end
|
163
165
|
end
|
@@ -233,8 +235,7 @@ module GObject
|
|
233
235
|
|
234
236
|
else
|
235
237
|
raise Vips::Error, "unimplemented gtype for get: " +
|
236
|
-
|
237
|
-
|
238
|
+
"#{::GObject::g_type_name gtype} (#{gtype})"
|
238
239
|
end
|
239
240
|
end
|
240
241
|
|
@@ -243,9 +244,15 @@ module GObject
|
|
243
244
|
# }
|
244
245
|
|
245
246
|
return result
|
246
|
-
|
247
247
|
end
|
248
248
|
|
249
|
+
# Clear the thing held by a GValue.
|
250
|
+
#
|
251
|
+
# This happens automatically when a GValue is GCed, but this method can be
|
252
|
+
# handy if you need to drop a reference explicitly for some reason.
|
253
|
+
def unset
|
254
|
+
::GObject::g_value_unset self
|
255
|
+
end
|
249
256
|
end
|
250
257
|
|
251
258
|
attach_function :g_value_init, [GValue.ptr, :GType], :void
|
@@ -277,5 +284,4 @@ module GObject
|
|
277
284
|
[:pointer, :string, GValue.ptr], :void
|
278
285
|
attach_function :g_object_get_property,
|
279
286
|
[:pointer, :string, GValue.ptr], :void
|
280
|
-
|
281
287
|
end
|
data/lib/vips/image.rb
CHANGED
@@ -14,6 +14,9 @@ module Vips
|
|
14
14
|
|
15
15
|
attach_function :vips_image_copy_memory, [:pointer], :pointer
|
16
16
|
|
17
|
+
attach_function :vips_image_set_progress, [:pointer, :bool], :void
|
18
|
+
attach_function :vips_image_set_kill, [:pointer, :bool], :void
|
19
|
+
|
17
20
|
attach_function :vips_filename_get_filename, [:string], :pointer
|
18
21
|
attach_function :vips_filename_get_options, [:string], :pointer
|
19
22
|
|
@@ -22,6 +25,11 @@ module Vips
|
|
22
25
|
attach_function :vips_foreign_find_load_buffer, [:pointer, :size_t], :string
|
23
26
|
attach_function :vips_foreign_find_save_buffer, [:string], :string
|
24
27
|
|
28
|
+
if Vips::at_least_libvips?(8, 9)
|
29
|
+
attach_function :vips_foreign_find_load_source, [:pointer], :string
|
30
|
+
attach_function :vips_foreign_find_save_target, [:string], :string
|
31
|
+
end
|
32
|
+
|
25
33
|
attach_function :vips_image_write_to_memory,
|
26
34
|
[:pointer, SizeStruct.ptr], :pointer
|
27
35
|
|
@@ -29,20 +37,14 @@ module Vips
|
|
29
37
|
attach_function :vips_image_get,
|
30
38
|
[:pointer, :string, GObject::GValue.ptr], :int
|
31
39
|
|
32
|
-
|
33
|
-
begin
|
40
|
+
if Vips::at_least_libvips?(8, 5)
|
34
41
|
attach_function :vips_image_get_fields, [:pointer], :pointer
|
35
|
-
|
36
|
-
nil
|
42
|
+
attach_function :vips_image_hasalpha, [:pointer], :int
|
37
43
|
end
|
38
44
|
|
39
|
-
# vips_addalpha was added in libvips 8.6
|
40
45
|
if Vips::at_least_libvips?(8, 6)
|
41
46
|
attach_function :vips_addalpha, [:pointer, :pointer, :varargs], :int
|
42
47
|
end
|
43
|
-
if Vips::at_least_libvips?(8, 5)
|
44
|
-
attach_function :vips_image_hasalpha, [:pointer], :int
|
45
|
-
end
|
46
48
|
|
47
49
|
attach_function :vips_image_set,
|
48
50
|
[:pointer, :string, GObject::GValue.ptr], :void
|
@@ -53,6 +55,8 @@ module Vips
|
|
53
55
|
|
54
56
|
attach_function :nickname_find, :vips_nickname_find, [:GType], :string
|
55
57
|
|
58
|
+
attach_function :vips_image_invalidate_all, [:pointer], :void
|
59
|
+
|
56
60
|
# turn a raw pointer that must be freed into a self-freeing Ruby string
|
57
61
|
def self.p2str(pointer)
|
58
62
|
pointer = FFI::AutoPointer.new(pointer, GLib::G_FREE)
|
@@ -67,6 +71,10 @@ module Vips
|
|
67
71
|
class Image < Vips::Object
|
68
72
|
alias_method :parent_get_typeof, :get_typeof
|
69
73
|
|
74
|
+
def close
|
75
|
+
Vips.vips_image_invalidate_all(self)
|
76
|
+
end
|
77
|
+
|
70
78
|
private
|
71
79
|
|
72
80
|
# the layout of the VipsImage struct
|
@@ -81,12 +89,10 @@ module Vips
|
|
81
89
|
|
82
90
|
class Struct < Vips::Object::Struct
|
83
91
|
include ImageLayout
|
84
|
-
|
85
92
|
end
|
86
93
|
|
87
94
|
class ManagedStruct < Vips::Object::ManagedStruct
|
88
95
|
include ImageLayout
|
89
|
-
|
90
96
|
end
|
91
97
|
|
92
98
|
class GenericPtr < FFI::Struct
|
@@ -96,7 +102,7 @@ module Vips
|
|
96
102
|
# handy for overloads ... want to be able to apply a function to an
|
97
103
|
# array or to a scalar
|
98
104
|
def self.smap x, &block
|
99
|
-
x.is_a?(Array) ? x.map {|y| smap(y, &block)} : block.(x)
|
105
|
+
x.is_a?(Array) ? x.map { |y| smap(y, &block) } : block.(x)
|
100
106
|
end
|
101
107
|
|
102
108
|
def self.complex? format
|
@@ -117,7 +123,7 @@ module Vips
|
|
117
123
|
|
118
124
|
unless Image::complex? image.format
|
119
125
|
if image.bands % 2 != 0
|
120
|
-
raise Error, "not an even number of bands"
|
126
|
+
raise Vips::Error, "not an even number of bands"
|
121
127
|
end
|
122
128
|
|
123
129
|
unless Image::float? image.format
|
@@ -147,46 +153,18 @@ module Vips
|
|
147
153
|
end
|
148
154
|
end
|
149
155
|
|
150
|
-
# Write can fail due to no file descriptors and memory can fill if
|
151
|
-
# large objects are not collected fairly soon. We can't try a
|
152
|
-
# write and GC and retry on fail, since the write may take a
|
153
|
-
# long time and may not be repeatable.
|
154
|
-
#
|
155
|
-
# GCing before every write would have a horrible effect on
|
156
|
-
# performance, so as a compromise we GC every @@gc_interval writes.
|
157
|
-
#
|
158
|
-
# ruby2.1 introduced a generational GC which is fast enough to be
|
159
|
-
# able to GC on every write.
|
160
|
-
|
161
|
-
@@generational_gc = RUBY_ENGINE == "ruby" && RUBY_VERSION.to_f >= 2.1
|
162
|
-
|
163
|
-
@@gc_interval = 100
|
164
|
-
@@gc_countdown = @@gc_interval
|
165
|
-
|
166
|
-
def write_gc
|
167
|
-
if @@generational_gc
|
168
|
-
GC.start full_mark: false
|
169
|
-
else
|
170
|
-
@@gc_countdown -= 1
|
171
|
-
if @@gc_countdown < 0
|
172
|
-
@@gc_countdown = @@gc_interval
|
173
|
-
GC.start
|
174
|
-
end
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
156
|
public
|
179
157
|
|
180
158
|
def inspect
|
181
|
-
"#<Image #{width}x#{height} #{format}, #{bands} bands, "
|
182
|
-
"#{interpretation}>"
|
159
|
+
"#<Image #{width}x#{height} #{format}, #{bands} bands, #{interpretation}>"
|
183
160
|
end
|
184
161
|
|
185
162
|
def respond_to? name, include_all = false
|
186
163
|
# To support keyword args, we need to tell Ruby that final image
|
187
164
|
# arguments cannot be hashes of keywords.
|
188
165
|
#
|
189
|
-
# https://makandracards.com/makandra/
|
166
|
+
# https://makandracards.com/makandra/
|
167
|
+
# 36013-heads-up-ruby-implicitly-converts-a-hash-to-keyword-arguments
|
190
168
|
return false if name == :to_hash
|
191
169
|
|
192
170
|
# respond to all vips operations by nickname
|
@@ -221,13 +199,13 @@ module Vips
|
|
221
199
|
# load options, for example:
|
222
200
|
#
|
223
201
|
# ```
|
224
|
-
# image = Vips::new_from_file "fred.jpg[shrink=2]"
|
202
|
+
# image = Vips::Image.new_from_file "fred.jpg[shrink=2]"
|
225
203
|
# ```
|
226
204
|
#
|
227
205
|
# You can also supply options as a hash, for example:
|
228
206
|
#
|
229
207
|
# ```
|
230
|
-
# image = Vips::new_from_file "fred.jpg", shrink: 2
|
208
|
+
# image = Vips::Image.new_from_file "fred.jpg", shrink: 2
|
231
209
|
# ```
|
232
210
|
#
|
233
211
|
# The full set of options available depend upon the load operation that
|
@@ -298,11 +276,50 @@ module Vips
|
|
298
276
|
# @return [Image] the loaded image
|
299
277
|
def self.new_from_buffer data, option_string, **opts
|
300
278
|
loader = Vips::vips_foreign_find_load_buffer data, data.bytesize
|
301
|
-
raise Vips::Error if loader
|
279
|
+
raise Vips::Error if loader.nil?
|
302
280
|
|
303
281
|
Vips::Operation.call loader, [data], opts, option_string
|
304
282
|
end
|
305
283
|
|
284
|
+
# Create a new {Image} from a source. Load options may be passed as
|
285
|
+
# strings or appended as a hash. For example:
|
286
|
+
#
|
287
|
+
# ```
|
288
|
+
# source = Vips::Source.new_from_file("k2.jpg")
|
289
|
+
# image = Vips::Image.new_from_source source, "shrink=2"
|
290
|
+
# ```
|
291
|
+
#
|
292
|
+
# or alternatively:
|
293
|
+
#
|
294
|
+
# ```
|
295
|
+
# image = Vips::Image.new_from_source source, "", shrink: 2
|
296
|
+
# ```
|
297
|
+
#
|
298
|
+
# The options available depend on the file format. Try something like:
|
299
|
+
#
|
300
|
+
# ```
|
301
|
+
# $ vips jpegload_source
|
302
|
+
# ```
|
303
|
+
#
|
304
|
+
# at the command-line to see the available options. Not all loaders
|
305
|
+
# support load from source, but at least JPEG, PNG and
|
306
|
+
# TIFF images will work.
|
307
|
+
#
|
308
|
+
# Loading is fast: only enough data is read to be able to fill
|
309
|
+
# out the header. Pixels will only be read and decompressed when they are
|
310
|
+
# needed.
|
311
|
+
#
|
312
|
+
# @param source [Vips::Source] the source to load from
|
313
|
+
# @param option_string [String] load options as a string
|
314
|
+
# @macro vips.loadopts
|
315
|
+
# @return [Image] the loaded image
|
316
|
+
def self.new_from_source source, option_string, **opts
|
317
|
+
loader = Vips::vips_foreign_find_load_source source
|
318
|
+
raise Vips::Error if loader.nil?
|
319
|
+
|
320
|
+
Vips::Operation.call loader, [source], opts, option_string
|
321
|
+
end
|
322
|
+
|
306
323
|
def self.matrix_from_array width, height, array
|
307
324
|
ptr = FFI::MemoryPointer.new :double, array.length
|
308
325
|
ptr.write_array_of_double array
|
@@ -319,13 +336,13 @@ module Vips
|
|
319
336
|
# For example:
|
320
337
|
#
|
321
338
|
# ```
|
322
|
-
# image = Vips::new_from_array [1, 2, 3]
|
339
|
+
# image = Vips::Image.new_from_array [1, 2, 3]
|
323
340
|
# ```
|
324
341
|
#
|
325
342
|
# or
|
326
343
|
#
|
327
344
|
# ```
|
328
|
-
# image = Vips::new_from_array [
|
345
|
+
# image = Vips::Image.new_from_array [
|
329
346
|
# [-1, -1, -1],
|
330
347
|
# [-1, 16, -1],
|
331
348
|
# [-1, -1, -1]], 8
|
@@ -347,19 +364,20 @@ module Vips
|
|
347
364
|
if array[0].is_a? Array
|
348
365
|
height = array.length
|
349
366
|
width = array[0].length
|
350
|
-
unless array.all? {|x| x.is_a? Array}
|
367
|
+
unless array.all? { |x| x.is_a? Array }
|
351
368
|
raise Vips::Error, "Not a 2D array."
|
352
369
|
end
|
353
|
-
unless array.all? {|x| x.length == width}
|
370
|
+
unless array.all? { |x| x.length == width }
|
354
371
|
raise Vips::Error, "Array not rectangular."
|
355
372
|
end
|
373
|
+
|
356
374
|
array = array.flatten
|
357
375
|
else
|
358
376
|
height = 1
|
359
377
|
width = array.length
|
360
378
|
end
|
361
379
|
|
362
|
-
unless array.all? {|x| x.is_a? Numeric}
|
380
|
+
unless array.all? { |x| x.is_a? Numeric }
|
363
381
|
raise Vips::Error, "Not all array elements are Numeric."
|
364
382
|
end
|
365
383
|
|
@@ -385,8 +403,8 @@ module Vips
|
|
385
403
|
def new_from_image value
|
386
404
|
pixel = (Vips::Image.black(1, 1) + value).cast(format)
|
387
405
|
image = pixel.embed 0, 0, width, height, extend: :copy
|
388
|
-
image.copy interpretation: interpretation,
|
389
|
-
|
406
|
+
image.copy interpretation: interpretation, xres: xres, yres: yres,
|
407
|
+
xoffset: xoffset, yoffset: yoffset
|
390
408
|
end
|
391
409
|
|
392
410
|
# Write this image to a file. Save options may be encoded in the
|
@@ -427,8 +445,6 @@ module Vips
|
|
427
445
|
end
|
428
446
|
|
429
447
|
Vips::Operation.call saver, [self, filename], opts, option_string
|
430
|
-
|
431
|
-
write_gc
|
432
448
|
end
|
433
449
|
|
434
450
|
# Write this image to a memory buffer. Save options may be encoded in
|
@@ -457,29 +473,63 @@ module Vips
|
|
457
473
|
# @macro vips.saveopts
|
458
474
|
# @return [String] the image saved in the specified format
|
459
475
|
def write_to_buffer format_string, **opts
|
460
|
-
filename =
|
461
|
-
|
462
|
-
option_string =
|
463
|
-
Vips::p2str(Vips::vips_filename_get_options format_string)
|
476
|
+
filename = Vips::p2str(Vips::vips_filename_get_filename format_string)
|
477
|
+
option_string = Vips::p2str(Vips::vips_filename_get_options format_string)
|
464
478
|
saver = Vips::vips_foreign_find_save_buffer filename
|
465
479
|
if saver == nil
|
466
|
-
raise Vips::Error, "No known saver for '#{filename}'."
|
480
|
+
raise Vips::Error, "No known buffer saver for '#{filename}'."
|
467
481
|
end
|
468
482
|
|
469
483
|
buffer = Vips::Operation.call saver, [self], opts, option_string
|
470
484
|
raise Vips::Error if buffer == nil
|
471
485
|
|
472
|
-
write_gc
|
473
|
-
|
474
486
|
return buffer
|
475
487
|
end
|
476
488
|
|
489
|
+
# Write this image to a target. Save options may be encoded in
|
490
|
+
# the format_string or given as a hash. For example:
|
491
|
+
#
|
492
|
+
# ```ruby
|
493
|
+
# target = Vips::Target.new_to_file "k2.jpg"
|
494
|
+
# image.write_to_target target, ".jpg[Q=90]"
|
495
|
+
# ```
|
496
|
+
#
|
497
|
+
# or equivalently:
|
498
|
+
#
|
499
|
+
# ```ruby
|
500
|
+
# image.write_to_target target, ".jpg", Q: 90
|
501
|
+
# ```
|
502
|
+
#
|
503
|
+
# The full set of save options depend on the selected saver. Try
|
504
|
+
# something like:
|
505
|
+
#
|
506
|
+
# ```
|
507
|
+
# $ vips jpegsave_target
|
508
|
+
# ```
|
509
|
+
#
|
510
|
+
# to see all the available options for JPEG save.
|
511
|
+
#
|
512
|
+
# @param target [Vips::Target] the target to write to
|
513
|
+
# @param format_string [String] save format plus string options
|
514
|
+
# @macro vips.saveopts
|
515
|
+
def write_to_target target, format_string, **opts
|
516
|
+
filename = Vips::p2str(Vips::vips_filename_get_filename format_string)
|
517
|
+
option_string = Vips::p2str(Vips::vips_filename_get_options format_string)
|
518
|
+
saver = Vips::vips_foreign_find_save_target filename
|
519
|
+
if saver == nil
|
520
|
+
raise Vips::Error, "No known target saver for '#{filename}'."
|
521
|
+
end
|
522
|
+
|
523
|
+
Vips::Operation.call saver, [self, target], opts, option_string
|
524
|
+
end
|
525
|
+
|
477
526
|
# Write this image to a large memory buffer.
|
478
527
|
#
|
479
528
|
# @return [String] the pixels as a huge binary string
|
480
529
|
def write_to_memory
|
481
530
|
len = Vips::SizeStruct.new
|
482
531
|
ptr = Vips::vips_image_write_to_memory self, len
|
532
|
+
raise Vips::Error if ptr == nil
|
483
533
|
|
484
534
|
# wrap up as an autopointer
|
485
535
|
ptr = FFI::AutoPointer.new(ptr, GLib::G_FREE)
|
@@ -487,6 +537,28 @@ module Vips
|
|
487
537
|
ptr.get_bytes 0, len[:value]
|
488
538
|
end
|
489
539
|
|
540
|
+
# Turn progress signalling on and off.
|
541
|
+
#
|
542
|
+
# If this is on, the most-downstream image from this image will issue
|
543
|
+
# progress signals.
|
544
|
+
#
|
545
|
+
# @see Object#signal_connect
|
546
|
+
# @param state [Boolean] progress signalling state
|
547
|
+
def set_progress state
|
548
|
+
Vips::vips_image_set_progress self, state
|
549
|
+
end
|
550
|
+
|
551
|
+
# Kill computation of this time.
|
552
|
+
#
|
553
|
+
# Set true to stop computation of this image. You can call this from a
|
554
|
+
# progress handler, for example.
|
555
|
+
#
|
556
|
+
# @see Object#signal_connect
|
557
|
+
# @param kill [Boolean] stop computation
|
558
|
+
def set_kill kill
|
559
|
+
Vips::vips_image_set_kill self, kill
|
560
|
+
end
|
561
|
+
|
490
562
|
# Get the `GType` of a metadata field. The result is 0 if no such field
|
491
563
|
# exists.
|
492
564
|
#
|
@@ -525,10 +597,11 @@ module Vips
|
|
525
597
|
end
|
526
598
|
|
527
599
|
gvalue = GObject::GValue.alloc
|
528
|
-
|
529
|
-
|
600
|
+
raise Vips::Error if Vips::vips_image_get(self, name, gvalue) != 0
|
601
|
+
result = gvalue.get
|
602
|
+
gvalue.unset
|
530
603
|
|
531
|
-
|
604
|
+
result
|
532
605
|
end
|
533
606
|
|
534
607
|
# Get the names of all fields on an image. Use this to loop over all
|
@@ -573,6 +646,7 @@ module Vips
|
|
573
646
|
gvalue.init gtype
|
574
647
|
gvalue.set value
|
575
648
|
Vips::vips_image_set self, name, gvalue
|
649
|
+
gvalue.unset
|
576
650
|
end
|
577
651
|
|
578
652
|
# Set the value of a metadata item on an image. The metadata item must
|
@@ -772,7 +846,7 @@ module Vips
|
|
772
846
|
# @return [Image] result of subtraction
|
773
847
|
def - other
|
774
848
|
other.is_a?(Vips::Image) ?
|
775
|
-
subtract(other) : linear(1, Image::smap(other) {|x| x * -1})
|
849
|
+
subtract(other) : linear(1, Image::smap(other) { |x| x * -1 })
|
776
850
|
end
|
777
851
|
|
778
852
|
# Multiply an image, constant or array.
|
@@ -790,7 +864,7 @@ module Vips
|
|
790
864
|
# @return [Image] result of division
|
791
865
|
def / other
|
792
866
|
other.is_a?(Vips::Image) ?
|
793
|
-
divide(other) : linear(Image::smap(other) {|x| 1.0 / x}, 0)
|
867
|
+
divide(other) : linear(Image::smap(other) { |x| 1.0 / x }, 0)
|
794
868
|
end
|
795
869
|
|
796
870
|
# Remainder after integer division with an image, constant or array.
|
@@ -961,16 +1035,16 @@ module Vips
|
|
961
1035
|
|
962
1036
|
# make the template for unpack
|
963
1037
|
template = {
|
964
|
-
|
965
|
-
|
966
|
-
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
1038
|
+
char: 'c',
|
1039
|
+
uchar: 'C',
|
1040
|
+
short: 's_',
|
1041
|
+
ushort: 'S_',
|
1042
|
+
int: 'i_',
|
1043
|
+
uint: 'I_',
|
1044
|
+
float: 'f',
|
1045
|
+
double: 'd',
|
1046
|
+
complex: 'f',
|
1047
|
+
dpcomplex: 'd'
|
974
1048
|
}[format] + '*'
|
975
1049
|
|
976
1050
|
# and unpack into something like [1, 2, 3, 4 ..]
|
@@ -1031,7 +1105,7 @@ module Vips
|
|
1031
1105
|
#
|
1032
1106
|
# @return [Array<Image>] Array of n one-band images
|
1033
1107
|
def bandsplit
|
1034
|
-
(0...bands).map {|i| extract_band i}
|
1108
|
+
(0...bands).map { |i| extract_band i }
|
1035
1109
|
end
|
1036
1110
|
|
1037
1111
|
# Join a set of images bandwise.
|
@@ -1044,7 +1118,7 @@ module Vips
|
|
1044
1118
|
end
|
1045
1119
|
|
1046
1120
|
# if other is just Numeric, we can use bandjoin_const
|
1047
|
-
not_all_real = !other.all?{|x| x.is_a? Numeric}
|
1121
|
+
not_all_real = !other.all? { |x| x.is_a? Numeric }
|
1048
1122
|
|
1049
1123
|
if not_all_real
|
1050
1124
|
Vips::Image.bandjoin([self] + other)
|
@@ -1061,7 +1135,7 @@ module Vips
|
|
1061
1135
|
# @option opts [Vips::Interpretation] :compositing_space Composite images in this colour space
|
1062
1136
|
# @option opts [Boolean] :premultiplied Images have premultiplied alpha
|
1063
1137
|
# @return [Image] blended image
|
1064
|
-
def composite overlay, mode, **
|
1138
|
+
def composite overlay, mode, **options
|
1065
1139
|
unless overlay.is_a? Array
|
1066
1140
|
overlay = [overlay]
|
1067
1141
|
end
|
@@ -1073,7 +1147,7 @@ module Vips
|
|
1073
1147
|
GObject::GValue.from_nick Vips::BLEND_MODE_TYPE, x
|
1074
1148
|
end
|
1075
1149
|
|
1076
|
-
Vips::Image.composite([self] + overlay, mode,
|
1150
|
+
Vips::Image.composite([self] + overlay, mode, **options)
|
1077
1151
|
end
|
1078
1152
|
|
1079
1153
|
# Return the coordinates of the image maximum.
|
@@ -1130,7 +1204,7 @@ module Vips
|
|
1130
1204
|
# @see xyz
|
1131
1205
|
# @return [Image] image converted to polar coordinates
|
1132
1206
|
def polar
|
1133
|
-
Image::run_cmplx(self) {|x| x.complex :polar}
|
1207
|
+
Image::run_cmplx(self) { |x| x.complex :polar }
|
1134
1208
|
end
|
1135
1209
|
|
1136
1210
|
# Return an image with polar pixels converted to rectangular.
|
@@ -1143,7 +1217,7 @@ module Vips
|
|
1143
1217
|
# @see xyz
|
1144
1218
|
# @return [Image] image converted to rectangular coordinates
|
1145
1219
|
def rect
|
1146
|
-
Image::run_cmplx(self) {|x| x.complex :rect}
|
1220
|
+
Image::run_cmplx(self) { |x| x.complex :rect }
|
1147
1221
|
end
|
1148
1222
|
|
1149
1223
|
# Return the complex conjugate of an image.
|
@@ -1155,7 +1229,7 @@ module Vips
|
|
1155
1229
|
#
|
1156
1230
|
# @return [Image] complex conjugate
|
1157
1231
|
def conj
|
1158
|
-
Image::run_cmplx(self) {|x| x.complex :conj}
|
1232
|
+
Image::run_cmplx(self) { |x| x.complex :conj }
|
1159
1233
|
end
|
1160
1234
|
|
1161
1235
|
# Calculate the cross phase of two images.
|
@@ -1305,7 +1379,7 @@ module Vips
|
|
1305
1379
|
# @option opts [Boolean] :blend (false) Blend smoothly between th and el
|
1306
1380
|
# @return [Image] merged image
|
1307
1381
|
def ifthenelse(th, el, **opts)
|
1308
|
-
match_image = [th, el, self].find {|x| x.is_a? Vips::Image}
|
1382
|
+
match_image = [th, el, self].find { |x| x.is_a? Vips::Image }
|
1309
1383
|
|
1310
1384
|
unless th.is_a? Vips::Image
|
1311
1385
|
th = Operation.imageize match_image, th
|
@@ -1322,148 +1396,127 @@ module Vips
|
|
1322
1396
|
#
|
1323
1397
|
# @param opts [Hash] Set of options
|
1324
1398
|
# @return [Vips::Image] Output image
|
1325
|
-
def scaleimage **
|
1326
|
-
Vips::Image.scale self,
|
1399
|
+
def scaleimage **options
|
1400
|
+
Vips::Image.scale self, **options
|
1327
1401
|
end
|
1328
|
-
|
1329
1402
|
end
|
1330
1403
|
end
|
1331
1404
|
|
1332
1405
|
module Vips
|
1333
|
-
|
1334
|
-
# This method generates yard comments for all the dynamically bound
|
1406
|
+
# This module generates yard comments for all the dynamically bound
|
1335
1407
|
# vips operations.
|
1336
1408
|
#
|
1337
1409
|
# Regenerate with something like:
|
1338
1410
|
#
|
1339
1411
|
# ```
|
1340
1412
|
# $ ruby > methods.rb
|
1341
|
-
# require 'vips'; Vips::
|
1413
|
+
# require 'vips'; Vips::Yard.generate
|
1342
1414
|
# ^D
|
1343
1415
|
# ```
|
1344
1416
|
|
1345
|
-
|
1346
|
-
# these have hand-written methods, see above
|
1347
|
-
no_generate = ["scale", "bandjoin", "composite", "ifthenelse"]
|
1348
|
-
|
1417
|
+
module Yard
|
1349
1418
|
# map gobject's type names to Ruby
|
1350
|
-
|
1351
|
-
|
1352
|
-
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1357
|
-
|
1358
|
-
|
1359
|
-
|
1360
|
-
|
1361
|
-
|
1419
|
+
MAP_GO_TO_RUBY = {
|
1420
|
+
"gboolean" => "Boolean",
|
1421
|
+
"gint" => "Integer",
|
1422
|
+
"gdouble" => "Float",
|
1423
|
+
"gfloat" => "Float",
|
1424
|
+
"gchararray" => "String",
|
1425
|
+
"VipsImage" => "Vips::Image",
|
1426
|
+
"VipsInterpolate" => "Vips::Interpolate",
|
1427
|
+
"VipsConnection" => "Vips::Connection",
|
1428
|
+
"VipsSource" => "Vips::Source",
|
1429
|
+
"VipsTarget" => "Vips::Target",
|
1430
|
+
"VipsSourceCustom" => "Vips::SourceCustom",
|
1431
|
+
"VipsTargetCustom" => "Vips::TargetCustom",
|
1432
|
+
"VipsArrayDouble" => "Array<Double>",
|
1433
|
+
"VipsArrayInt" => "Array<Integer>",
|
1434
|
+
"VipsArrayImage" => "Array<Image>",
|
1435
|
+
"VipsArrayString" => "Array<String>",
|
1362
1436
|
}
|
1363
1437
|
|
1364
|
-
|
1365
|
-
|
1366
|
-
return if (op_flags & OPERATION_DEPRECATED) != 0
|
1367
|
-
return if no_generate.include? nickname
|
1368
|
-
description = Vips::vips_object_get_description op
|
1369
|
-
|
1370
|
-
# find and classify all the arguments the operator can take
|
1371
|
-
required_input = []
|
1372
|
-
optional_input = []
|
1373
|
-
required_output = []
|
1374
|
-
optional_output = []
|
1375
|
-
member_x = nil
|
1376
|
-
op.argument_map do |pspec, argument_class, argument_instance|
|
1377
|
-
arg_flags = argument_class[:flags]
|
1378
|
-
next if (arg_flags & ARGUMENT_CONSTRUCT) == 0
|
1379
|
-
next if (arg_flags & ARGUMENT_DEPRECATED) != 0
|
1380
|
-
|
1381
|
-
name = pspec[:name].tr("-", "_")
|
1382
|
-
# 'in' as a param name confuses yard
|
1383
|
-
name = "im" if name == "in"
|
1384
|
-
gtype = pspec[:value_type]
|
1385
|
-
fundamental = GObject::g_type_fundamental gtype
|
1386
|
-
type_name = GObject::g_type_name gtype
|
1387
|
-
if map_go_to_ruby.include? type_name
|
1388
|
-
type_name = map_go_to_ruby[type_name]
|
1389
|
-
end
|
1390
|
-
if fundamental == GObject::GFLAGS_TYPE ||
|
1391
|
-
fundamental == GObject::GENUM_TYPE
|
1392
|
-
type_name = "Vips::" + type_name[/Vips(.*)/, 1]
|
1393
|
-
end
|
1394
|
-
blurb = GObject::g_param_spec_get_blurb pspec
|
1395
|
-
value = {:name => name,
|
1396
|
-
:flags => arg_flags,
|
1397
|
-
:gtype => gtype,
|
1398
|
-
:type_name => type_name,
|
1399
|
-
:blurb => blurb}
|
1400
|
-
|
1401
|
-
if (arg_flags & ARGUMENT_INPUT) != 0
|
1402
|
-
if (arg_flags & ARGUMENT_REQUIRED) != 0
|
1403
|
-
# note the first required input image, if any ... we
|
1404
|
-
# will be a method of this instance
|
1405
|
-
if !member_x && gtype == Vips::IMAGE_TYPE
|
1406
|
-
member_x = value
|
1407
|
-
else
|
1408
|
-
required_input << value
|
1409
|
-
end
|
1410
|
-
else
|
1411
|
-
optional_input << value
|
1412
|
-
end
|
1413
|
-
end
|
1438
|
+
# these have hand-written methods, see above
|
1439
|
+
NO_GENERATE = ["scale", "bandjoin", "composite", "ifthenelse"]
|
1414
1440
|
|
1415
|
-
|
1416
|
-
|
1417
|
-
((arg_flags & ARGUMENT_INPUT) != 0 &&
|
1418
|
-
(arg_flags & ARGUMENT_MODIFY) != 0)
|
1419
|
-
if (arg_flags & ARGUMENT_REQUIRED) != 0
|
1420
|
-
required_output << value
|
1421
|
-
else
|
1422
|
-
optional_output << value
|
1423
|
-
end
|
1424
|
-
end
|
1441
|
+
# these are aliased (appear under several names)
|
1442
|
+
ALIAS = ["crop"]
|
1425
1443
|
|
1444
|
+
# turn a gtype into a ruby type name
|
1445
|
+
def self.gtype_to_ruby gtype
|
1446
|
+
fundamental = GObject::g_type_fundamental gtype
|
1447
|
+
type_name = GObject::g_type_name gtype
|
1448
|
+
|
1449
|
+
if MAP_GO_TO_RUBY.include? type_name
|
1450
|
+
type_name = MAP_GO_TO_RUBY[type_name]
|
1451
|
+
end
|
1452
|
+
|
1453
|
+
if fundamental == GObject::GFLAGS_TYPE ||
|
1454
|
+
fundamental == GObject::GENUM_TYPE
|
1455
|
+
type_name = "Vips::" + type_name[/Vips(.*)/, 1]
|
1426
1456
|
end
|
1427
1457
|
|
1458
|
+
type_name
|
1459
|
+
end
|
1460
|
+
|
1461
|
+
def self.generate_operation introspect
|
1462
|
+
return if (introspect.flags & OPERATION_DEPRECATED) != 0
|
1463
|
+
return if NO_GENERATE.include? introspect.name
|
1464
|
+
|
1465
|
+
method_args = introspect.method_args
|
1466
|
+
required_output = introspect.required_output
|
1467
|
+
optional_input = introspect.optional_input
|
1468
|
+
optional_output = introspect.optional_output
|
1469
|
+
|
1428
1470
|
print "# @!method "
|
1429
|
-
print "self." unless member_x
|
1430
|
-
print "#{
|
1431
|
-
print
|
1432
|
-
print ", " if
|
1471
|
+
print "self." unless introspect.member_x
|
1472
|
+
print "#{introspect.name}("
|
1473
|
+
print method_args.map{ |x| x[:yard_name] }.join(", ")
|
1474
|
+
print ", " if method_args.length > 0
|
1433
1475
|
puts "**opts)"
|
1434
1476
|
|
1435
|
-
puts "# #{description.capitalize}."
|
1477
|
+
puts "# #{introspect.description.capitalize}."
|
1436
1478
|
|
1437
|
-
|
1438
|
-
|
1439
|
-
|
1479
|
+
method_args.each do |details|
|
1480
|
+
yard_name = details[:yard_name]
|
1481
|
+
gtype = details[:gtype]
|
1482
|
+
blurb = details[:blurb]
|
1483
|
+
|
1484
|
+
puts "# @param #{yard_name} [#{gtype_to_ruby(gtype)}] #{blurb}"
|
1440
1485
|
end
|
1441
1486
|
|
1442
1487
|
puts "# @param opts [Hash] Set of options"
|
1443
|
-
optional_input.each do |
|
1444
|
-
|
1445
|
-
|
1488
|
+
optional_input.each do |arg_name, details|
|
1489
|
+
yard_name = details[:yard_name]
|
1490
|
+
gtype = details[:gtype]
|
1491
|
+
blurb = details[:blurb]
|
1492
|
+
|
1493
|
+
puts "# @option opts [#{gtype_to_ruby(gtype)}] :#{yard_name} " +
|
1494
|
+
"#{blurb}"
|
1446
1495
|
end
|
1447
|
-
optional_output.each do |
|
1448
|
-
|
1449
|
-
|
1496
|
+
optional_output.each do |arg_name, details|
|
1497
|
+
yard_name = details[:yard_name]
|
1498
|
+
gtype = details[:gtype]
|
1499
|
+
blurb = details[:blurb]
|
1500
|
+
|
1501
|
+
print "# @option opts [#{gtype_to_ruby(gtype)}] :#{yard_name}"
|
1502
|
+
puts " Output #{blurb}"
|
1450
1503
|
end
|
1451
1504
|
|
1452
1505
|
print "# @return ["
|
1453
1506
|
if required_output.length == 0
|
1454
1507
|
print "nil"
|
1455
1508
|
elsif required_output.length == 1
|
1456
|
-
print required_output.first[:
|
1457
|
-
|
1458
|
-
|
1459
|
-
print required_output.map{|x| x[:
|
1509
|
+
print gtype_to_ruby(required_output.first[:gtype])
|
1510
|
+
else
|
1511
|
+
print "Array<"
|
1512
|
+
print required_output.map{ |x| gtype_to_ruby(x[:gtype]) }.join(", ")
|
1460
1513
|
print ">"
|
1461
1514
|
end
|
1462
1515
|
if optional_output.length > 0
|
1463
1516
|
print ", Hash<Symbol => Object>"
|
1464
1517
|
end
|
1465
1518
|
print "] "
|
1466
|
-
print required_output.map{|x| x[:blurb]}.join(", ")
|
1519
|
+
print required_output.map{ |x| x[:blurb] }.join(", ")
|
1467
1520
|
if optional_output.length > 0
|
1468
1521
|
print ", " if required_output.length > 0
|
1469
1522
|
print "Hash of optional output items"
|
@@ -1473,30 +1526,42 @@ module Vips
|
|
1473
1526
|
puts ""
|
1474
1527
|
end
|
1475
1528
|
|
1476
|
-
|
1477
|
-
|
1529
|
+
def self.generate
|
1530
|
+
alias_gtypes = {}
|
1531
|
+
ALIAS.each do |name|
|
1532
|
+
gtype = Vips::type_find "VipsOperation", name
|
1533
|
+
alias_gtypes[gtype] = name
|
1534
|
+
end
|
1478
1535
|
|
1479
|
-
|
1480
|
-
|
1481
|
-
|
1482
|
-
|
1483
|
-
|
1536
|
+
generate_class = lambda do |gtype, _|
|
1537
|
+
if alias_gtypes.key? gtype
|
1538
|
+
name = alias_gtypes[gtype]
|
1539
|
+
else
|
1540
|
+
name = Vips::nickname_find gtype
|
1484
1541
|
end
|
1485
1542
|
|
1486
|
-
|
1487
|
-
|
1543
|
+
if name
|
1544
|
+
begin
|
1545
|
+
# can fail for abstract types
|
1546
|
+
introspect = Vips::Introspect.get_yard name
|
1547
|
+
rescue Vips::Error
|
1548
|
+
nil
|
1549
|
+
end
|
1488
1550
|
|
1489
|
-
|
1490
|
-
|
1551
|
+
generate_operation(introspect) if introspect
|
1552
|
+
end
|
1491
1553
|
|
1492
|
-
|
1493
|
-
|
1494
|
-
puts ""
|
1554
|
+
Vips::vips_type_map gtype, generate_class, nil
|
1555
|
+
end
|
1495
1556
|
|
1496
|
-
|
1557
|
+
puts "module Vips"
|
1558
|
+
puts " class Image"
|
1559
|
+
puts ""
|
1497
1560
|
|
1498
|
-
|
1499
|
-
puts "end"
|
1500
|
-
end
|
1561
|
+
generate_class.(GObject::g_type_from_name("VipsOperation"), nil)
|
1501
1562
|
|
1563
|
+
puts " end"
|
1564
|
+
puts "end"
|
1565
|
+
end
|
1566
|
+
end
|
1502
1567
|
end
|