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/image.rb
CHANGED
@@ -1,362 +1,127 @@
|
|
1
|
-
# This module provides
|
2
|
-
#
|
3
|
-
# used via the [gobject-introspection
|
4
|
-
# gem](https://rubygems.org/gems/gobject-introspection).
|
1
|
+
# This module provides an interface to the vips image processing library
|
2
|
+
# via ruby-ffi.
|
5
3
|
#
|
6
|
-
#
|
7
|
-
#
|
8
|
-
|
9
|
-
|
10
|
-
# # Example
|
11
|
-
#
|
12
|
-
# ```ruby
|
13
|
-
# require 'vips'
|
14
|
-
#
|
15
|
-
# if ARGV.length < 2
|
16
|
-
# raise "usage: #{$PROGRAM_NAME}: input-file output-file"
|
17
|
-
# end
|
18
|
-
#
|
19
|
-
# im = Vips::Image.new_from_file ARGV[0], :access => :sequential
|
20
|
-
#
|
21
|
-
# im *= [1, 2, 1]
|
22
|
-
#
|
23
|
-
# mask = Vips::Image.new_from_array [
|
24
|
-
# [-1, -1, -1],
|
25
|
-
# [-1, 16, -1],
|
26
|
-
# [-1, -1, -1]], 8
|
27
|
-
# im = im.conv mask
|
28
|
-
#
|
29
|
-
# im.write_to_file ARGV[1]
|
30
|
-
# ```
|
31
|
-
#
|
32
|
-
# This example loads a file, boosts the green channel (I'm not sure why),
|
33
|
-
# sharpens the image, and saves it back to disc again.
|
34
|
-
#
|
35
|
-
# Reading this example line by line, we have:
|
36
|
-
#
|
37
|
-
# ```ruby
|
38
|
-
# im = Vips::Image.new_from_file ARGV[0], :access => :sequential
|
39
|
-
# ```
|
40
|
-
#
|
41
|
-
# {Image.new_from_file} can load any image file supported by vips. In this
|
42
|
-
# example, we will be accessing pixels top-to-bottom as we sweep through the
|
43
|
-
# image reading and writing, so `:sequential` access mode is best for us. The
|
44
|
-
# default mode is `:random`, this allows for full random access to image pixels,
|
45
|
-
# but is slower and needs more memory. See {Access}
|
46
|
-
# for full details
|
47
|
-
# on the various modes available. You can also load formatted images from
|
48
|
-
# memory buffers, create images that wrap C-style memory arrays, or make images
|
49
|
-
# from constants.
|
50
|
-
#
|
51
|
-
# The next line:
|
52
|
-
#
|
53
|
-
# ```ruby
|
54
|
-
# im *= [1, 2, 1]
|
55
|
-
# ```
|
56
|
-
#
|
57
|
-
# Multiplying the image by an array constant uses one array element for each
|
58
|
-
# image band. This line assumes that the input image has three bands and will
|
59
|
-
# double the middle band. For RGB images, that's doubling green.
|
60
|
-
#
|
61
|
-
# Next we have:
|
62
|
-
#
|
63
|
-
# ```ruby
|
64
|
-
# mask = Vips::Image.new_from_array [
|
65
|
-
# [-1, -1, -1],
|
66
|
-
# [-1, 16, -1],
|
67
|
-
# [-1, -1, -1]], 8
|
68
|
-
# im = im.conv mask
|
69
|
-
# ```
|
70
|
-
#
|
71
|
-
# {Image.new_from_array} creates an image from an array constant. The 8 at
|
72
|
-
# the end sets the scale: the amount to divide the image by after
|
73
|
-
# integer convolution. See the libvips API docs for `vips_conv()` (the operation
|
74
|
-
# invoked by {Image#conv}) for details on the convolution operator.
|
75
|
-
#
|
76
|
-
# Finally:
|
77
|
-
#
|
78
|
-
# ```ruby
|
79
|
-
# im.write_to_file ARGV[1]
|
80
|
-
# ```
|
81
|
-
#
|
82
|
-
# {Image#write_to_file} writes an image back to the filesystem. It can
|
83
|
-
# write any format supported by vips: the file type is set from the filename
|
84
|
-
# suffix. You can also write formatted images to memory buffers, or dump
|
85
|
-
# image data to a raw memory array.
|
86
|
-
#
|
87
|
-
# # How it works
|
88
|
-
#
|
89
|
-
# The C sources to libvips include a set of specially formatted
|
90
|
-
# comments which describe its interfaces. When you compile the library,
|
91
|
-
# gobject-introspection generates `Vips-8.0.typelib`, a file
|
92
|
-
# describing how to use libvips.
|
93
|
-
#
|
94
|
-
# The `gobject-introspection` gem loads this typelib and uses it to let you
|
95
|
-
# call
|
96
|
-
# functions in libvips directly from Ruby. However, the interface you get
|
97
|
-
# from raw gobject-introspection is rather ugly, so the `ruby-vips` gem
|
98
|
-
# adds a set
|
99
|
-
# of overrides which try to make it nicer to use.
|
100
|
-
#
|
101
|
-
# The API you end up with is a Ruby-ish version of the [VIPS C
|
102
|
-
# API](https://jcupitt.github.io/libvips/API/current).
|
103
|
-
# Full documentation
|
104
|
-
# on the operations and what they do is there, you can use it directly. This
|
105
|
-
# document explains the extra features of the Ruby API and lists the available
|
106
|
-
# operations very briefly.
|
107
|
-
#
|
108
|
-
# # Automatic wrapping
|
109
|
-
#
|
110
|
-
# `ruby-vips` adds a {Image.method_missing} handler to {Image} and uses
|
111
|
-
# it to look up vips operations. For example, the libvips operation `add`, which
|
112
|
-
# appears in C as `vips_add()`, appears in Ruby as {Image#add}.
|
113
|
-
#
|
114
|
-
# The operation's list of required arguments is searched and the first input
|
115
|
-
# image is set to the value of `self`. Operations which do not take an input
|
116
|
-
# image, such as {Image.black}, appear as class methods. The remainder of
|
117
|
-
# the arguments you supply in the function call are used to set the other
|
118
|
-
# required input arguments. If the final supplied argument is a hash, it is used
|
119
|
-
# to set any optional input arguments. The result is the required output
|
120
|
-
# argument if there is only one result, or an array of values if the operation
|
121
|
-
# produces several results. If the operation has optional output objects, they
|
122
|
-
# are returned as a final hash.
|
123
|
-
#
|
124
|
-
# For example, {Image#min}, the vips operation that searches an image for
|
125
|
-
# the minimum value, has a large number of optional arguments. You can use it to
|
126
|
-
# find the minimum value like this:
|
127
|
-
#
|
128
|
-
# ```ruby
|
129
|
-
# min_value = image.min
|
130
|
-
# ```
|
131
|
-
#
|
132
|
-
# You can ask it to return the position of the minimum with `:x` and `:y`.
|
133
|
-
#
|
134
|
-
# ```ruby
|
135
|
-
# min_value, opts = min :x => true, :y => true
|
136
|
-
# x_pos = opts['x']
|
137
|
-
# y_pos = opts['y']
|
138
|
-
# ```
|
139
|
-
#
|
140
|
-
# Now `x_pos` and `y_pos` will have the coordinates of the minimum value.
|
141
|
-
# There's actually a convenience function for this, {Image#minpos}.
|
142
|
-
#
|
143
|
-
# You can also ask for the top *n* minimum, for example:
|
144
|
-
#
|
145
|
-
# ```ruby
|
146
|
-
# min_value, opts = min :size => 10, :x_array => true, :y_array => true
|
147
|
-
# x_pos = opts['x_array']
|
148
|
-
# y_pos = opts['y_array']
|
149
|
-
# ```
|
150
|
-
#
|
151
|
-
# Now `x_pos` and `y_pos` will be 10-element arrays.
|
152
|
-
#
|
153
|
-
# Because operations are member functions and return the result image, you can
|
154
|
-
# chain them. For example, you can write:
|
155
|
-
#
|
156
|
-
# ```ruby
|
157
|
-
# result_image = image.real.cos
|
158
|
-
# ```
|
159
|
-
#
|
160
|
-
# to calculate the cosine of the real part of a complex image.
|
161
|
-
# There are also a full set
|
162
|
-
# of arithmetic operator overloads, see below.
|
163
|
-
#
|
164
|
-
# libvips types are also automatically wrapped. The override looks at the type
|
165
|
-
# of argument required by the operation and converts the value you supply,
|
166
|
-
# when it can. For example, {Image#linear} takes a `VipsArrayDouble` as
|
167
|
-
# an argument
|
168
|
-
# for the set of constants to use for multiplication. You can supply this
|
169
|
-
# value as an integer, a float, or some kind of compound object and it
|
170
|
-
# will be converted for you. You can write:
|
171
|
-
#
|
172
|
-
# ```ruby
|
173
|
-
# result_image = image.linear 1, 3
|
174
|
-
# result_image = image.linear 12.4, 13.9
|
175
|
-
# result_image = image.linear [1, 2, 3], [4, 5, 6]
|
176
|
-
# result_image = image.linear 1, [4, 5, 6]
|
177
|
-
# ```
|
178
|
-
#
|
179
|
-
# And so on. A set of overloads are defined for {Image#linear}, see below.
|
180
|
-
#
|
181
|
-
# It does a couple of more ambitious conversions. It will automatically convert
|
182
|
-
# to and from the various vips types, like `VipsBlob` and `VipsArrayImage`. For
|
183
|
-
# example, you can read the ICC profile out of an image like this:
|
184
|
-
#
|
185
|
-
# ```ruby
|
186
|
-
# profile = im.get_value "icc-profile-data"
|
187
|
-
# ```
|
188
|
-
#
|
189
|
-
# and profile will be a byte array.
|
190
|
-
#
|
191
|
-
# If an operation takes several input images, you can use a constant for all but
|
192
|
-
# one of them and the wrapper will expand the constant to an image for you. For
|
193
|
-
# example, {Image#ifthenelse} uses a condition image to pick pixels
|
194
|
-
# between a then and an else image:
|
195
|
-
#
|
196
|
-
# ```ruby
|
197
|
-
# result_image = condition_image.ifthenelse then_image, else_image
|
198
|
-
# ```
|
199
|
-
#
|
200
|
-
# You can use a constant instead of either the then or the else parts and it
|
201
|
-
# will be expanded to an image for you. If you use a constant for both then and
|
202
|
-
# else, it will be expanded to match the condition image. For example:
|
203
|
-
#
|
204
|
-
# ```ruby
|
205
|
-
# result_image = condition_image.ifthenelse [0, 255, 0], [255, 0, 0]
|
206
|
-
# ```
|
207
|
-
#
|
208
|
-
# Will make an image where true pixels are green and false pixels are red.
|
209
|
-
#
|
210
|
-
# This is useful for {Image#bandjoin}, the thing to join two or more
|
211
|
-
# images up bandwise. You can write:
|
212
|
-
#
|
213
|
-
# ```ruby
|
214
|
-
# rgba = rgb.bandjoin 255
|
215
|
-
# ```
|
216
|
-
#
|
217
|
-
# to append a constant 255 band to an image, perhaps to add an alpha channel. Of
|
218
|
-
# course you can also write:
|
219
|
-
#
|
220
|
-
# ```ruby
|
221
|
-
# result_image = image1.bandjoin image2
|
222
|
-
# result_image = image1.bandjoin [image2, image3]
|
223
|
-
# result_image = Vips::Image.bandjoin [image1, image2, image3]
|
224
|
-
# result_image = image1.bandjoin [image2, 255]
|
225
|
-
# ```
|
226
|
-
#
|
227
|
-
# and so on.
|
228
|
-
#
|
229
|
-
# # Automatic YARD documentation
|
230
|
-
#
|
231
|
-
# The bulk of these API docs are generated automatically by
|
232
|
-
# {Vips::generate_yard}. It examines
|
233
|
-
# libvips and writes a summary of each operation and the arguments and options
|
234
|
-
# that that operation expects.
|
235
|
-
#
|
236
|
-
# Use the [C API
|
237
|
-
# docs](https://jcupitt.github.io/libvips/API/current)
|
238
|
-
# for more detail.
|
239
|
-
#
|
240
|
-
# # Exceptions
|
241
|
-
#
|
242
|
-
# The wrapper spots errors from vips operations and raises the {Vips::Error}
|
243
|
-
# exception. You can catch it in the usual way.
|
244
|
-
#
|
245
|
-
# # Enums
|
246
|
-
#
|
247
|
-
# The libvips enums, such as `VipsBandFormat` appear in ruby-vips as classes
|
248
|
-
# like {Vips::BandFormat}. Overloads let you manipulate them in the obvious
|
249
|
-
# way. For example:
|
250
|
-
#
|
251
|
-
# ```ruby
|
252
|
-
# irb(main):002:0> im = Vips::Image.new_from_file "IMG_1867.JPG"
|
253
|
-
# => #<Vips::Image:0x13e9760 ptr=0x1a88010>
|
254
|
-
# irb(main):003:0> im.format
|
255
|
-
# => #<Vips::BandFormat uchar>
|
256
|
-
# irb(main):004:0> im.format == :uchar
|
257
|
-
# => true
|
258
|
-
# irb(main):005:0> im.format == "uchar"
|
259
|
-
# => true
|
260
|
-
# irb(main):007:0> im.format == 0
|
261
|
-
# => true
|
262
|
-
# ```
|
263
|
-
#
|
264
|
-
# The `0` is the C value of the enum.
|
265
|
-
#
|
266
|
-
# # Draw operations
|
267
|
-
#
|
268
|
-
# Paint operations like {Image#draw_circle} and {Image#draw_line}
|
269
|
-
# modify their input image. This
|
270
|
-
# makes them hard to use with the rest of libvips: you need to be very careful
|
271
|
-
# about the order in which operations execute or you can get nasty crashes.
|
272
|
-
#
|
273
|
-
# The wrapper spots operations of this type and makes a private copy of the
|
274
|
-
# image in memory before calling the operation. This stops crashes, but it does
|
275
|
-
# make it inefficient. If you draw 100 lines on an image, for example, you'll
|
276
|
-
# copy the image 100 times. The wrapper does make sure that memory is recycled
|
277
|
-
# where possible, so you won't have 100 copies in memory.
|
278
|
-
#
|
279
|
-
# If you want to avoid the copies, you'll need to call drawing operations
|
280
|
-
# yourself.
|
281
|
-
#
|
282
|
-
# # Overloads
|
283
|
-
#
|
284
|
-
# The wrapper defines the usual set of arithmetic, boolean and relational
|
285
|
-
# overloads on image. You can mix images, constants and lists of constants
|
286
|
-
# (almost) freely. For example, you can write:
|
287
|
-
#
|
288
|
-
# ```ruby
|
289
|
-
# result_image = ((image * [1, 2, 3]).abs < 128) | 4
|
290
|
-
# ```
|
291
|
-
#
|
292
|
-
# # Expansions
|
293
|
-
#
|
294
|
-
# Some vips operators take an enum to select an action, for example
|
295
|
-
# {Image#math} can be used to calculate sine of every pixel like this:
|
296
|
-
#
|
297
|
-
# ```ruby
|
298
|
-
# result_image = image.math :sin
|
299
|
-
# ```
|
300
|
-
#
|
301
|
-
# This is annoying, so the wrapper expands all these enums into separate members
|
302
|
-
# named after the enum. So you can write:
|
303
|
-
#
|
304
|
-
# ```ruby
|
305
|
-
# result_image = image.sin
|
306
|
-
# ```
|
307
|
-
#
|
308
|
-
# # Convenience functions
|
309
|
-
#
|
310
|
-
# The wrapper defines a few extra useful utility functions:
|
311
|
-
# {Image#get_value}, {Image#set_value}, {Image#bandsplit},
|
312
|
-
# {Image#maxpos}, {Image#minpos},
|
313
|
-
# {Image#median}.
|
4
|
+
# Author:: John Cupitt (mailto:jcupitt@gmail.com)
|
5
|
+
# License:: MIT
|
6
|
+
|
7
|
+
require 'ffi'
|
314
8
|
|
315
9
|
module Vips
|
10
|
+
private
|
11
|
+
|
12
|
+
attach_function :vips_image_new_matrix_from_array,
|
13
|
+
[:int, :int, :pointer, :int], :pointer
|
14
|
+
|
15
|
+
attach_function :vips_image_copy_memory, [:pointer], :pointer
|
16
|
+
|
17
|
+
attach_function :vips_filename_get_filename, [:string], :string
|
18
|
+
attach_function :vips_filename_get_options, [:string], :string
|
19
|
+
attach_function :vips_filename_get_options, [:string], :string
|
20
|
+
|
21
|
+
attach_function :vips_foreign_find_load, [:string], :string
|
22
|
+
attach_function :vips_foreign_find_save, [:string], :string
|
23
|
+
attach_function :vips_foreign_find_load_buffer, [:pointer, :size_t], :string
|
24
|
+
attach_function :vips_foreign_find_save_buffer, [:string], :string
|
25
|
+
|
26
|
+
attach_function :vips_image_write_to_memory,
|
27
|
+
[:pointer, SizeStruct.ptr], :pointer
|
28
|
+
|
29
|
+
attach_function :vips_image_get_typeof, [:pointer, :string], :GType
|
30
|
+
attach_function :vips_image_get,
|
31
|
+
[:pointer, :string, GObject::GValue.ptr], :int
|
32
|
+
attach_function :vips_image_set,
|
33
|
+
[:pointer, :string, GObject::GValue.ptr], :void
|
34
|
+
attach_function :vips_image_remove, [:pointer, :string], :void
|
35
|
+
|
36
|
+
attach_function :vips_band_format_iscomplex, [:int], :int
|
37
|
+
attach_function :vips_band_format_isfloat, [:int], :int
|
38
|
+
|
39
|
+
attach_function :nickname_find, :vips_nickname_find, [:GType], :string
|
40
|
+
|
41
|
+
public
|
316
42
|
|
317
43
|
# This class represents a libvips image. See the {Vips} module documentation
|
318
|
-
# for an introduction to using this
|
44
|
+
# for an introduction to using this class.
|
319
45
|
|
320
|
-
class Image
|
46
|
+
class Image < Vips::Object
|
321
47
|
private
|
322
48
|
|
49
|
+
# the layout of the VipsImage struct
|
50
|
+
module ImageLayout
|
51
|
+
def self.included base
|
52
|
+
base.class_eval do
|
53
|
+
layout :parent, Vips::Object::Struct
|
54
|
+
# rest opaque
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class Struct < Vips::Object::Struct
|
60
|
+
include ImageLayout
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
class ManagedStruct < Vips::Object::ManagedStruct
|
65
|
+
include ImageLayout
|
66
|
+
|
67
|
+
end
|
68
|
+
|
323
69
|
# handy for overloads ... want to be able to apply a function to an
|
324
70
|
# array or to a scalar
|
325
|
-
def self.smap
|
71
|
+
def self.smap x, &block
|
326
72
|
x.is_a?(Array) ? x.map {|y| smap(y, &block)} : block.(x)
|
327
73
|
end
|
328
74
|
|
75
|
+
def self.complex? format
|
76
|
+
format_number = Vips::vips_enum_from_nick "complex?",
|
77
|
+
BAND_FORMAT_TYPE, format.to_s
|
78
|
+
Vips::vips_band_format_iscomplex(format_number) != 0
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.float? format
|
82
|
+
format_number = Vips::vips_enum_from_nick "float?",
|
83
|
+
BAND_FORMAT_TYPE, format.to_s
|
84
|
+
Vips::vips_band_format_isfloat(format_number) != 0
|
85
|
+
end
|
86
|
+
|
329
87
|
# run a complex operation on a complex image, or an image with an even
|
330
88
|
# number of bands ... handy for things like running .polar on .index
|
331
89
|
# images
|
332
|
-
def self.run_cmplx
|
90
|
+
def self.run_cmplx image, &block
|
333
91
|
original_format = image.format
|
334
92
|
|
335
|
-
if not
|
93
|
+
if not Image::complex? image.format
|
336
94
|
if image.bands % 2 != 0
|
337
95
|
raise Error, "not an even number of bands"
|
338
96
|
end
|
339
97
|
|
340
|
-
if not
|
98
|
+
if not Image::float? image.format
|
341
99
|
image = image.cast :float
|
342
100
|
end
|
343
101
|
|
344
102
|
new_format = image.format == :double ? :dpcomplex : :complex
|
345
|
-
image = image.copy :
|
346
|
-
:bands => image.bands / 2
|
103
|
+
image = image.copy format: new_format, bands: image.bands / 2
|
347
104
|
end
|
348
105
|
|
349
106
|
image = block.(image)
|
350
107
|
|
351
|
-
if not
|
108
|
+
if not Image::complex? original_format
|
352
109
|
new_format = image.format == :dpcomplex ? :double : :float
|
353
|
-
image = image.copy :
|
354
|
-
:bands => image.bands * 2
|
110
|
+
image = image.copy format: new_format, bands: image.bands * 2
|
355
111
|
end
|
356
112
|
|
357
113
|
image
|
358
114
|
end
|
359
115
|
|
116
|
+
# handy for expanding enum operations
|
117
|
+
def call_enum(name, other, enum)
|
118
|
+
if other.is_a?(Vips::Image)
|
119
|
+
Vips::Operation.call name.to_s, [self, other, enum]
|
120
|
+
else
|
121
|
+
Vips::Operation.call name.to_s + "_const", [self, enum, other]
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
360
125
|
# Write can fail due to no file descriptors and memory can fill if
|
361
126
|
# large objects are not collected fairly soon. We can't try a
|
362
127
|
# write and GC and retry on fail, since the write may take a
|
@@ -385,38 +150,45 @@ module Vips
|
|
385
150
|
end
|
386
151
|
end
|
387
152
|
|
388
|
-
|
389
|
-
|
390
|
-
def
|
391
|
-
|
392
|
-
|
153
|
+
public
|
154
|
+
|
155
|
+
def inspect
|
156
|
+
"#<Image #{width}x#{height} #{format}, #{bands} bands, " +
|
157
|
+
"#{interpretation}>"
|
393
158
|
end
|
394
159
|
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
160
|
+
def respond_to? name, include_all = false
|
161
|
+
# To support keyword args, we need to tell Ruby that final image
|
162
|
+
# arguments cannot be hashes of keywords.
|
163
|
+
#
|
164
|
+
# https://makandracards.com/makandra/36013-heads-up-ruby-implicitly-converts-a-hash-to-keyword-arguments
|
165
|
+
return false if name == :to_hash
|
401
166
|
|
402
|
-
|
403
|
-
|
167
|
+
# respond to all vips operations by nickname
|
168
|
+
return true if Vips::type_find("VipsOperation", name.to_s) != 0
|
169
|
+
|
170
|
+
super
|
404
171
|
end
|
405
172
|
|
406
|
-
|
173
|
+
def self.respond_to? name, include_all = false
|
174
|
+
# respond to all vips operations by nickname
|
175
|
+
return true if Vips::type_find("VipsOperation", name.to_s) != 0
|
407
176
|
|
408
|
-
|
409
|
-
|
177
|
+
super
|
178
|
+
end
|
179
|
+
|
180
|
+
# Invoke a vips operation with {Vips::Operation.call}, using self as
|
181
|
+
# the first input argument.
|
410
182
|
#
|
411
183
|
# @param name [String] vips operation to call
|
412
184
|
# @return result of vips operation
|
413
|
-
def method_missing
|
414
|
-
Vips::
|
185
|
+
def method_missing name, *args, **options
|
186
|
+
Vips::Operation.call name.to_s, [self, *args], options
|
415
187
|
end
|
416
188
|
|
417
|
-
# Invoke a vips operation with {call}.
|
418
|
-
def self.method_missing
|
419
|
-
Vips::
|
189
|
+
# Invoke a vips operation with {Vips::Operation.call}.
|
190
|
+
def self.method_missing name, *args, **options
|
191
|
+
Vips::Operation.call name.to_s, args, options
|
420
192
|
end
|
421
193
|
|
422
194
|
# Return a new {Image} for a file on disc. This method can load
|
@@ -430,7 +202,7 @@ module Vips
|
|
430
202
|
# You can also supply options as a hash, for example:
|
431
203
|
#
|
432
204
|
# ```
|
433
|
-
# image = Vips::new_from_file "fred.jpg", :
|
205
|
+
# image = Vips::new_from_file "fred.jpg", shrink: 2
|
434
206
|
# ```
|
435
207
|
#
|
436
208
|
# The full set of options available depend upon the load operation that
|
@@ -447,7 +219,7 @@ module Vips
|
|
447
219
|
# out the header. Pixels will only be decompressed when they are needed.
|
448
220
|
#
|
449
221
|
# @!macro [new] vips.loadopts
|
450
|
-
# @param [Hash]
|
222
|
+
# @param opts [Hash] set of options
|
451
223
|
# @option opts [Boolean] :disc (true) Open large images via a
|
452
224
|
# temporary disc file
|
453
225
|
# @option opts [Vips::Access] :access (:random) Access mode for file
|
@@ -455,25 +227,22 @@ module Vips
|
|
455
227
|
# @param name [String] the filename to load from
|
456
228
|
# @macro vips.loadopts
|
457
229
|
# @return [Image] the loaded image
|
458
|
-
def self.new_from_file
|
459
|
-
# very common, and Vips::
|
460
|
-
# this
|
461
|
-
if name == nil
|
462
|
-
raise Error, "filename is nil"
|
463
|
-
end
|
464
|
-
filename = Vips::filename_get_filename name
|
465
|
-
option_string = Vips::filename_get_options name
|
466
|
-
loader = Vips::Foreign.find_load filename
|
467
|
-
if loader == nil
|
468
|
-
raise Vips::Error
|
469
|
-
end
|
230
|
+
def self.new_from_file name, opts = {}
|
231
|
+
# very common, and Vips::vips_filename_get_filename will segv if we
|
232
|
+
# pass this
|
233
|
+
raise Vips::Error, "filename is nil" if name == nil
|
470
234
|
|
471
|
-
Vips::
|
235
|
+
filename = Vips::vips_filename_get_filename name
|
236
|
+
option_string = Vips::vips_filename_get_options name
|
237
|
+
loader = Vips::vips_foreign_find_load filename
|
238
|
+
raise Vips::Error if loader == nil
|
239
|
+
|
240
|
+
Operation.call loader, [filename], opts, option_string
|
472
241
|
end
|
473
242
|
|
474
243
|
# Create a new {Image} for an image encoded, in a format such as
|
475
244
|
# JPEG, in a memory string. Load options may be passed as
|
476
|
-
# strings
|
245
|
+
# strings or appended as a hash. For example:
|
477
246
|
#
|
478
247
|
# ```
|
479
248
|
# image = Vips::new_from_from_buffer memory_buffer, "shrink=2"
|
@@ -482,7 +251,7 @@ module Vips
|
|
482
251
|
# or alternatively:
|
483
252
|
#
|
484
253
|
# ```
|
485
|
-
# image = Vips::new_from_from_buffer memory_buffer, "", :
|
254
|
+
# image = Vips::new_from_from_buffer memory_buffer, "", shrink: 2
|
486
255
|
# ```
|
487
256
|
#
|
488
257
|
# The options available depend on the file format. Try something like:
|
@@ -502,13 +271,19 @@ module Vips
|
|
502
271
|
# @param option_string [String] load options as a string
|
503
272
|
# @macro vips.loadopts
|
504
273
|
# @return [Image] the loaded image
|
505
|
-
def self.new_from_buffer
|
506
|
-
loader = Vips::
|
507
|
-
if loader == nil
|
508
|
-
|
509
|
-
|
274
|
+
def self.new_from_buffer data, option_string, opts = {}
|
275
|
+
loader = Vips::vips_foreign_find_load_buffer data, data.length
|
276
|
+
raise Vips::Error if loader == nil
|
277
|
+
|
278
|
+
Vips::Operation.call loader, [data], opts, option_string
|
279
|
+
end
|
510
280
|
|
511
|
-
|
281
|
+
def self.matrix_from_array width, height, array
|
282
|
+
ptr = FFI::MemoryPointer.new :double, array.length
|
283
|
+
ptr.write_array_of_double array
|
284
|
+
image = Vips::vips_image_new_matrix_from_array width, height,
|
285
|
+
ptr, array.length
|
286
|
+
Vips::Image.new image
|
512
287
|
end
|
513
288
|
|
514
289
|
# Create a new Image from a 1D or 2D array. A 1D array becomes an
|
@@ -537,7 +312,7 @@ module Vips
|
|
537
312
|
# @param scale [Real] the convolution scale
|
538
313
|
# @param offset [Real] the convolution offset
|
539
314
|
# @return [Image] the image
|
540
|
-
def self.new_from_array
|
315
|
+
def self.new_from_array array, scale = 1, offset = 0
|
541
316
|
# we accept a 1D array and assume height == 1, or a 2D array
|
542
317
|
# and check all lines are the same length
|
543
318
|
if not array.is_a? Array
|
@@ -564,13 +339,11 @@ module Vips
|
|
564
339
|
end
|
565
340
|
|
566
341
|
image = Vips::Image.matrix_from_array width, height, array
|
567
|
-
if image == nil
|
568
|
-
raise Vips::Error
|
569
|
-
end
|
342
|
+
raise Vips::Error if image == nil
|
570
343
|
|
571
344
|
# be careful to set them as double
|
572
|
-
image.
|
573
|
-
image.
|
345
|
+
image.set_type GObject::GDOUBLE_TYPE, 'scale', scale.to_f
|
346
|
+
image.set_type GObject::GDOUBLE_TYPE, 'offset', offset.to_f
|
574
347
|
|
575
348
|
return image
|
576
349
|
end
|
@@ -582,14 +355,13 @@ module Vips
|
|
582
355
|
# You can pass an array to make a many-band image, or a single value to
|
583
356
|
# make a one-band image.
|
584
357
|
#
|
585
|
-
# @param
|
358
|
+
# @param value [Real, Array<Real>] value to put in each pixel
|
586
359
|
# @return [Image] constant image
|
587
|
-
def new_from_image
|
360
|
+
def new_from_image value
|
588
361
|
pixel = (Vips::Image.black(1, 1) + value).cast(format)
|
589
|
-
image = pixel.embed
|
590
|
-
image.copy :
|
591
|
-
:
|
592
|
-
:xoffset => xoffset, :yoffset => yoffset
|
362
|
+
image = pixel.embed 0, 0, width, height, extend: :copy
|
363
|
+
image.copy interpretation: interpretation,
|
364
|
+
xres: xres, yres: yres, xoffset: xoffset, yoffset: yoffset
|
593
365
|
end
|
594
366
|
|
595
367
|
# Write this image to a file. Save options may be encoded in the
|
@@ -602,7 +374,7 @@ module Vips
|
|
602
374
|
# or equivalently:
|
603
375
|
#
|
604
376
|
# ```
|
605
|
-
# image.write_to_file "fred.jpg", :
|
377
|
+
# image.write_to_file "fred.jpg", Q: 90
|
606
378
|
# ```
|
607
379
|
#
|
608
380
|
# The full set of save options depend on the selected saver. Try
|
@@ -615,21 +387,21 @@ module Vips
|
|
615
387
|
# to see all the available options for JPEG save.
|
616
388
|
#
|
617
389
|
# @!macro [new] vips.saveopts
|
618
|
-
# @param [Hash]
|
390
|
+
# @param opts [Hash] set of options
|
619
391
|
# @option opts [Boolean] :strip (false) Strip all metadata from image
|
620
392
|
# @option opts [Array<Float>] :background (0) Background colour to
|
621
393
|
# flatten alpha against, if necessary
|
622
394
|
#
|
623
395
|
# @param name [String] filename to write to
|
624
|
-
def write_to_file
|
625
|
-
filename = Vips::
|
626
|
-
option_string = Vips::
|
627
|
-
saver = Vips::
|
396
|
+
def write_to_file name, opts = {}
|
397
|
+
filename = Vips::vips_filename_get_filename name
|
398
|
+
option_string = Vips::vips_filename_get_options name
|
399
|
+
saver = Vips::vips_foreign_find_save filename
|
628
400
|
if saver == nil
|
629
401
|
raise Vips::Error, "No known saver for '#{filename}'."
|
630
402
|
end
|
631
403
|
|
632
|
-
Vips::
|
404
|
+
Vips::Operation.call saver, [self, filename], opts, option_string
|
633
405
|
|
634
406
|
write_gc
|
635
407
|
end
|
@@ -644,7 +416,7 @@ module Vips
|
|
644
416
|
# or equivalently:
|
645
417
|
#
|
646
418
|
# ```
|
647
|
-
# image.write_to_buffer ".jpg", :
|
419
|
+
# image.write_to_buffer ".jpg", Q: 90
|
648
420
|
# ```
|
649
421
|
#
|
650
422
|
# The full set of save options depend on the selected saver. Try
|
@@ -659,63 +431,43 @@ module Vips
|
|
659
431
|
# @param format_string [String] save format plus options
|
660
432
|
# @macro vips.saveopts
|
661
433
|
# @return [String] the image saved in the specified format
|
662
|
-
def write_to_buffer
|
663
|
-
filename = Vips::
|
664
|
-
option_string = Vips::
|
665
|
-
saver = Vips::
|
434
|
+
def write_to_buffer format_string, opts = {}
|
435
|
+
filename = Vips::vips_filename_get_filename format_string
|
436
|
+
option_string = Vips::vips_filename_get_options format_string
|
437
|
+
saver = Vips::vips_foreign_find_save_buffer filename
|
666
438
|
if saver == nil
|
667
439
|
raise Vips::Error, "No known saver for '#{filename}'."
|
668
440
|
end
|
669
441
|
|
670
|
-
buffer = Vips::
|
442
|
+
buffer = Vips::Operation.call saver, [self], opts, option_string
|
443
|
+
raise Vips::Error if buffer == nil
|
671
444
|
|
672
445
|
write_gc
|
673
446
|
|
674
447
|
return buffer
|
675
448
|
end
|
676
449
|
|
677
|
-
#
|
678
|
-
#
|
679
|
-
#
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
|
687
|
-
|
688
|
-
|
689
|
-
# @!attribute [r] filename
|
690
|
-
# @return [String] image filename
|
691
|
-
# @!attribute [r] xres
|
692
|
-
# @return [Float] horizontal image resolution, in pixels per mm
|
693
|
-
# @!attribute [r] yres
|
694
|
-
# @return [Float] vertical image resolution, in pixels per mm
|
450
|
+
# Write this image to a large memory buffer.
|
451
|
+
#
|
452
|
+
# @return [String] the pixels as a huge binary string
|
453
|
+
def write_to_memory
|
454
|
+
len = Vips::SizeStruct.new
|
455
|
+
ptr = Vips::vips_image_write_to_memory self, len
|
456
|
+
|
457
|
+
# wrap up as an autopointer
|
458
|
+
ptr = FFI::AutoPointer.new(ptr, GLib::G_FREE)
|
459
|
+
|
460
|
+
ptr.get_bytes 0, len[:value]
|
461
|
+
end
|
695
462
|
|
696
463
|
# Fetch a `GType` from an image. `GType` will be 0 for no such field.
|
697
464
|
#
|
698
465
|
# @see get
|
699
|
-
# @see get_value
|
700
|
-
# @!method get_typeof(name)
|
701
466
|
# @param name [String] Metadata field to fetch
|
702
467
|
# @return [Integer] GType
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
#
|
707
|
-
# @see get_value
|
708
|
-
# @see get_typeof
|
709
|
-
# @!method get(name)
|
710
|
-
# @param name [String] Metadata field to fetch
|
711
|
-
# @return [Integer, GValue] Return status, GValue from image
|
712
|
-
|
713
|
-
# Set a `GValue` on an image
|
714
|
-
#
|
715
|
-
# @see set_value
|
716
|
-
# @!method set(name, value)
|
717
|
-
# @param name [String] Metadata field to set
|
718
|
-
# @param value [GValue] GValue to set
|
468
|
+
def get_typeof name
|
469
|
+
Vips::vips_image_get_typeof self, name
|
470
|
+
end
|
719
471
|
|
720
472
|
# Get a metadata item from an image. Ruby types are constructed
|
721
473
|
# automatically from the `GValue`, if possible.
|
@@ -723,63 +475,177 @@ module Vips
|
|
723
475
|
# For example, you can read the ICC profile from an image like this:
|
724
476
|
#
|
725
477
|
# ```
|
726
|
-
# profile = image.
|
478
|
+
# profile = image.get "icc-profile-data"
|
727
479
|
# ```
|
728
480
|
#
|
729
481
|
# and profile will be an array containing the profile.
|
730
482
|
#
|
731
|
-
# @
|
732
|
-
# @param name [String] Metadata field to set
|
483
|
+
# @param name [String] Metadata field to get
|
733
484
|
# @return [Object] Value of field
|
734
|
-
def
|
735
|
-
|
736
|
-
|
737
|
-
|
485
|
+
def get name
|
486
|
+
gvalue = GObject::GValue.alloc
|
487
|
+
result = Vips::vips_image_get self, name, gvalue
|
488
|
+
if result != 0
|
489
|
+
raise Vips::Error
|
738
490
|
end
|
739
|
-
value = gval.value
|
740
491
|
|
741
|
-
|
492
|
+
return gvalue.get
|
742
493
|
end
|
743
494
|
|
744
|
-
#
|
745
|
-
#
|
495
|
+
# Create a metadata item on an image, of the specifed type. Ruby types
|
496
|
+
# are automatically
|
497
|
+
# transformed into the matching `GType`, if possible.
|
746
498
|
#
|
747
499
|
# For example, you can use this to set an image's ICC profile:
|
748
500
|
#
|
749
501
|
# ```
|
750
|
-
# x = y.
|
502
|
+
# x = y.set Vips::BLOB_TYPE, "icc-profile-data", profile
|
751
503
|
# ```
|
752
504
|
#
|
753
505
|
# where `profile` is an ICC profile held as a binary string object.
|
754
506
|
#
|
755
507
|
# @see set
|
508
|
+
# @param gtype [Integer] GType of item
|
756
509
|
# @param name [String] Metadata field to set
|
757
510
|
# @param value [Object] Value to set
|
758
|
-
def
|
759
|
-
|
760
|
-
|
761
|
-
|
762
|
-
|
763
|
-
|
764
|
-
# blob-ize
|
765
|
-
if gtype.type_is_a? GLib::Type["VipsBlob"]
|
766
|
-
if not value.is_a? Vips::Blob
|
767
|
-
value = Vips::Blob.copy value
|
768
|
-
end
|
769
|
-
end
|
511
|
+
def set_type gtype, name, value
|
512
|
+
gvalue = GObject::GValue.alloc
|
513
|
+
gvalue.init gtype
|
514
|
+
gvalue.set value
|
515
|
+
Vips::vips_image_set self, name, gvalue
|
516
|
+
end
|
770
517
|
|
771
|
-
|
772
|
-
|
773
|
-
|
774
|
-
|
775
|
-
|
776
|
-
|
518
|
+
# Set the value of a metadata item on an image. The metadata item must
|
519
|
+
# already exist. Ruby types are automatically
|
520
|
+
# transformed into the matching `GValue`, if possible.
|
521
|
+
#
|
522
|
+
# For example, you can use this to set an image's ICC profile:
|
523
|
+
#
|
524
|
+
# ```
|
525
|
+
# x = y.set "icc-profile-data", profile
|
526
|
+
# ```
|
527
|
+
#
|
528
|
+
# where `profile` is an ICC profile held as a binary string object.
|
529
|
+
#
|
530
|
+
# @see set_type
|
531
|
+
# @param name [String] Metadata field to set
|
532
|
+
# @param value [Object] Value to set
|
533
|
+
def set name, value
|
534
|
+
set_type get_typeof(name), name, value
|
535
|
+
end
|
777
536
|
|
778
|
-
|
537
|
+
# Remove a metadata item from an image.
|
538
|
+
#
|
539
|
+
# @param name [String] Metadata field to remove
|
540
|
+
def remove name
|
541
|
+
Vips::vips_image_remove self, name
|
542
|
+
end
|
779
543
|
|
544
|
+
# compatibility: old name for get
|
545
|
+
def get_value name
|
546
|
+
get name
|
547
|
+
end
|
548
|
+
|
549
|
+
# compatibility: old name for set
|
550
|
+
def set_value name, value
|
780
551
|
set name, value
|
781
552
|
end
|
782
553
|
|
554
|
+
# Get image width, in pixels.
|
555
|
+
#
|
556
|
+
# @return [Integer] image width, in pixels
|
557
|
+
def width
|
558
|
+
get "width"
|
559
|
+
end
|
560
|
+
|
561
|
+
# Get image height, in pixels.
|
562
|
+
#
|
563
|
+
# @return [Integer] image height, in pixels
|
564
|
+
def height
|
565
|
+
get "height"
|
566
|
+
end
|
567
|
+
|
568
|
+
# Get number of image bands.
|
569
|
+
#
|
570
|
+
# @return [Integer] number of image bands
|
571
|
+
def bands
|
572
|
+
get "bands"
|
573
|
+
end
|
574
|
+
|
575
|
+
# Get image format.
|
576
|
+
#
|
577
|
+
# @return [Symbol] image format
|
578
|
+
def format
|
579
|
+
get "format"
|
580
|
+
end
|
581
|
+
|
582
|
+
# Get image interpretation.
|
583
|
+
#
|
584
|
+
# @return [Symbol] image interpretation
|
585
|
+
def interpretation
|
586
|
+
get "interpretation"
|
587
|
+
end
|
588
|
+
|
589
|
+
# Get image coding.
|
590
|
+
#
|
591
|
+
# @return [Symbol] image coding
|
592
|
+
def coding
|
593
|
+
get "coding"
|
594
|
+
end
|
595
|
+
|
596
|
+
# Get image filename, if any.
|
597
|
+
#
|
598
|
+
# @return [String] image filename
|
599
|
+
def filename
|
600
|
+
get "filename"
|
601
|
+
end
|
602
|
+
|
603
|
+
# Get image xoffset.
|
604
|
+
#
|
605
|
+
# @return [Integer] image xoffset
|
606
|
+
def xoffset
|
607
|
+
get "xoffset"
|
608
|
+
end
|
609
|
+
|
610
|
+
# Get image yoffset.
|
611
|
+
#
|
612
|
+
# @return [Integer] image yoffset
|
613
|
+
def yoffset
|
614
|
+
get "yoffset"
|
615
|
+
end
|
616
|
+
|
617
|
+
# Get image x resolution.
|
618
|
+
#
|
619
|
+
# @return [Float] image x resolution
|
620
|
+
def xres
|
621
|
+
get "xres"
|
622
|
+
end
|
623
|
+
|
624
|
+
# Get image y resolution.
|
625
|
+
#
|
626
|
+
# @return [Float] image y resolution
|
627
|
+
def yres
|
628
|
+
get "yres"
|
629
|
+
end
|
630
|
+
|
631
|
+
# Get scale metadata.
|
632
|
+
#
|
633
|
+
# @return [Float] image scale
|
634
|
+
def scale
|
635
|
+
return 1 if get_typeof("scale") == 0
|
636
|
+
|
637
|
+
get "scale"
|
638
|
+
end
|
639
|
+
|
640
|
+
# Get offset metadata.
|
641
|
+
#
|
642
|
+
# @return [Float] image offset
|
643
|
+
def offset
|
644
|
+
return 0 if get_typeof("offset") == 0
|
645
|
+
|
646
|
+
get "offset"
|
647
|
+
end
|
648
|
+
|
783
649
|
# Get the image size.
|
784
650
|
#
|
785
651
|
# @return [Integer, Integer] image width and height
|
@@ -787,11 +653,16 @@ module Vips
|
|
787
653
|
[width, height]
|
788
654
|
end
|
789
655
|
|
656
|
+
def copy_memory
|
657
|
+
new_image = Vips::vips_image_copy_memory self
|
658
|
+
Vips::Image.new new_image
|
659
|
+
end
|
660
|
+
|
790
661
|
# Add an image, constant or array.
|
791
662
|
#
|
792
663
|
# @param other [Image, Real, Array<Real>] Thing to add to self
|
793
664
|
# @return [Image] result of addition
|
794
|
-
def +
|
665
|
+
def + other
|
795
666
|
other.is_a?(Vips::Image) ?
|
796
667
|
add(other) : linear(1, other)
|
797
668
|
end
|
@@ -800,7 +671,7 @@ module Vips
|
|
800
671
|
#
|
801
672
|
# @param other [Image, Real, Array<Real>] Thing to subtract from self
|
802
673
|
# @return [Image] result of subtraction
|
803
|
-
def -
|
674
|
+
def - other
|
804
675
|
other.is_a?(Vips::Image) ?
|
805
676
|
subtract(other) : linear(1, Image::smap(other) {|x| x * -1})
|
806
677
|
end
|
@@ -809,7 +680,7 @@ module Vips
|
|
809
680
|
#
|
810
681
|
# @param other [Image, Real, Array<Real>] Thing to multiply by self
|
811
682
|
# @return [Image] result of multiplication
|
812
|
-
def *
|
683
|
+
def * other
|
813
684
|
other.is_a?(Vips::Image) ?
|
814
685
|
multiply(other) : linear(other, 0)
|
815
686
|
end
|
@@ -818,7 +689,7 @@ module Vips
|
|
818
689
|
#
|
819
690
|
# @param other [Image, Real, Array<Real>] Thing to divide self by
|
820
691
|
# @return [Image] result of division
|
821
|
-
def /
|
692
|
+
def / other
|
822
693
|
other.is_a?(Vips::Image) ?
|
823
694
|
divide(other) : linear(Image::smap(other) {|x| 1.0 / x}, 0)
|
824
695
|
end
|
@@ -827,7 +698,7 @@ module Vips
|
|
827
698
|
#
|
828
699
|
# @param other [Image, Real, Array<Real>] self modulo this
|
829
700
|
# @return [Image] result of modulo
|
830
|
-
def %
|
701
|
+
def % other
|
831
702
|
other.is_a?(Vips::Image) ?
|
832
703
|
remainder(other) : remainder_const(other)
|
833
704
|
end
|
@@ -836,48 +707,48 @@ module Vips
|
|
836
707
|
#
|
837
708
|
# @param other [Image, Real, Array<Real>] self to the power of this
|
838
709
|
# @return [Image] result of power
|
839
|
-
def **
|
840
|
-
call_enum
|
710
|
+
def ** other
|
711
|
+
call_enum "math2", other, :pow
|
841
712
|
end
|
842
713
|
|
843
714
|
# Integer left shift with an image, constant or array.
|
844
715
|
#
|
845
716
|
# @param other [Image, Real, Array<Real>] shift left by this much
|
846
717
|
# @return [Image] result of left shift
|
847
|
-
def <<
|
848
|
-
call_enum
|
718
|
+
def << other
|
719
|
+
call_enum "boolean", other, :lshift
|
849
720
|
end
|
850
721
|
|
851
722
|
# Integer right shift with an image, constant or array.
|
852
723
|
#
|
853
724
|
# @param other [Image, Real, Array<Real>] shift right by this much
|
854
725
|
# @return [Image] result of right shift
|
855
|
-
def >>
|
856
|
-
call_enum
|
726
|
+
def >> other
|
727
|
+
call_enum "boolean", other, :rshift
|
857
728
|
end
|
858
729
|
|
859
730
|
# Integer bitwise OR with an image, constant or array.
|
860
731
|
#
|
861
732
|
# @param other [Image, Real, Array<Real>] bitwise OR with this
|
862
733
|
# @return [Image] result of bitwise OR
|
863
|
-
def |
|
864
|
-
call_enum
|
734
|
+
def | other
|
735
|
+
call_enum "boolean", other, :or
|
865
736
|
end
|
866
737
|
|
867
738
|
# Integer bitwise AND with an image, constant or array.
|
868
739
|
#
|
869
740
|
# @param other [Image, Real, Array<Real>] bitwise AND with this
|
870
741
|
# @return [Image] result of bitwise AND
|
871
|
-
def &
|
872
|
-
call_enum
|
742
|
+
def & other
|
743
|
+
call_enum "boolean", other, :and
|
873
744
|
end
|
874
745
|
|
875
746
|
# Integer bitwise EOR with an image, constant or array.
|
876
747
|
#
|
877
748
|
# @param other [Image, Real, Array<Real>] bitwise EOR with this
|
878
749
|
# @return [Image] result of bitwise EOR
|
879
|
-
def ^
|
880
|
-
call_enum
|
750
|
+
def ^ other
|
751
|
+
call_enum "boolean", other, :eor
|
881
752
|
end
|
882
753
|
|
883
754
|
# Equivalent to image ^ -1
|
@@ -910,8 +781,8 @@ module Vips
|
|
910
781
|
#
|
911
782
|
# @param other [Image, Real, Array<Real>] relational less than with this
|
912
783
|
# @return [Image] result of less than
|
913
|
-
def <
|
914
|
-
call_enum
|
784
|
+
def < other
|
785
|
+
call_enum "relational", other, :less
|
915
786
|
end
|
916
787
|
|
917
788
|
# Relational less than or equal to with an image, constant or array.
|
@@ -919,16 +790,16 @@ module Vips
|
|
919
790
|
# @param other [Image, Real, Array<Real>] relational less than or
|
920
791
|
# equal to with this
|
921
792
|
# @return [Image] result of less than or equal to
|
922
|
-
def <=
|
923
|
-
call_enum
|
793
|
+
def <= other
|
794
|
+
call_enum "relational", other, :lesseq
|
924
795
|
end
|
925
796
|
|
926
797
|
# Relational more than with an image, constant or array.
|
927
798
|
#
|
928
799
|
# @param other [Image, Real, Array<Real>] relational more than with this
|
929
800
|
# @return [Image] result of more than
|
930
|
-
def >
|
931
|
-
call_enum
|
801
|
+
def > other
|
802
|
+
call_enum "relational", other, :more
|
932
803
|
end
|
933
804
|
|
934
805
|
# Relational more than or equal to with an image, constant or array.
|
@@ -936,20 +807,20 @@ module Vips
|
|
936
807
|
# @param other [Image, Real, Array<Real>] relational more than or
|
937
808
|
# equal to with this
|
938
809
|
# @return [Image] result of more than or equal to
|
939
|
-
def >=
|
940
|
-
call_enum
|
810
|
+
def >= other
|
811
|
+
call_enum "relational", other, :moreeq
|
941
812
|
end
|
942
813
|
|
943
814
|
# Compare equality to nil, an image, constant or array.
|
944
815
|
#
|
945
816
|
# @param other [nil, Image, Real, Array<Real>] test equality to this
|
946
817
|
# @return [Image] result of equality
|
947
|
-
def ==
|
818
|
+
def == other
|
948
819
|
# for equality, we must allow tests against nil
|
949
820
|
if other == nil
|
950
821
|
false
|
951
822
|
else
|
952
|
-
call_enum
|
823
|
+
call_enum "relational", other, :equal
|
953
824
|
end
|
954
825
|
end
|
955
826
|
|
@@ -957,12 +828,12 @@ module Vips
|
|
957
828
|
#
|
958
829
|
# @param other [nil, Image, Real, Array<Real>] test inequality to this
|
959
830
|
# @return [Image] result of inequality
|
960
|
-
def !=
|
831
|
+
def != other
|
961
832
|
# for equality, we must allow tests against nil
|
962
833
|
if other == nil
|
963
834
|
true
|
964
835
|
else
|
965
|
-
call_enum
|
836
|
+
call_enum "relational", other, :noteq
|
966
837
|
end
|
967
838
|
end
|
968
839
|
|
@@ -970,11 +841,11 @@ module Vips
|
|
970
841
|
#
|
971
842
|
# @param index [Numeric, Range] extract these band(s)
|
972
843
|
# @return [Image] extracted band(s)
|
973
|
-
def []
|
844
|
+
def [] index
|
974
845
|
if index.is_a? Range
|
975
846
|
n = index.end - index.begin
|
976
847
|
n += 1 if not index.exclude_end?
|
977
|
-
extract_band index.begin, :
|
848
|
+
extract_band index.begin, n: n
|
978
849
|
elsif index.is_a? Numeric
|
979
850
|
extract_band index
|
980
851
|
else
|
@@ -988,7 +859,7 @@ module Vips
|
|
988
859
|
def to_a
|
989
860
|
# we render the image to a big string, then unpack
|
990
861
|
# as a Ruby array of the correct type
|
991
|
-
memory = write_to_memory
|
862
|
+
memory = write_to_memory
|
992
863
|
|
993
864
|
# make the template for unpack
|
994
865
|
template = {
|
@@ -1002,7 +873,7 @@ module Vips
|
|
1002
873
|
:double => 'd',
|
1003
874
|
:complex => 'f',
|
1004
875
|
:dpcomplex => 'd'
|
1005
|
-
}[format
|
876
|
+
}[format] + '*'
|
1006
877
|
|
1007
878
|
# and unpack into something like [1, 2, 3, 4 ..]
|
1008
879
|
array = memory.unpack(template)
|
@@ -1071,7 +942,7 @@ module Vips
|
|
1071
942
|
#
|
1072
943
|
# @param other [Image, Array<Image>, Real, Array<Real>] bands to append
|
1073
944
|
# @return [Image] many band image
|
1074
|
-
def bandjoin
|
945
|
+
def bandjoin other
|
1075
946
|
if not other.is_a? Array
|
1076
947
|
other = [other]
|
1077
948
|
end
|
@@ -1091,7 +962,7 @@ module Vips
|
|
1091
962
|
# @return [Real, Real, Real] maximum value, x coordinate of maximum, y
|
1092
963
|
# coordinate of maximum
|
1093
964
|
def maxpos
|
1094
|
-
v, opts = max :
|
965
|
+
v, opts = max x: true, y: true
|
1095
966
|
x = opts['x']
|
1096
967
|
y = opts['y']
|
1097
968
|
return v, x, y
|
@@ -1102,7 +973,7 @@ module Vips
|
|
1102
973
|
# @return [Real, Real, Real] minimum value, x coordinate of minimum, y
|
1103
974
|
# coordinate of minimum
|
1104
975
|
def minpos
|
1105
|
-
v, opts = min :
|
976
|
+
v, opts = min x: true, y: true
|
1106
977
|
x = opts['x']
|
1107
978
|
y = opts['y']
|
1108
979
|
return v, x, y
|
@@ -1113,7 +984,7 @@ module Vips
|
|
1113
984
|
# @param x [Integer] x coordinate to sample
|
1114
985
|
# @param y [Integer] y coordinate to sample
|
1115
986
|
# @return [Array<Float>] the pixel values as an array
|
1116
|
-
def getpoint
|
987
|
+
def getpoint x, y
|
1117
988
|
# vips has an operation that does this, but we can't call it via
|
1118
989
|
# gobject-introspection 3.1 since it's missing array double
|
1119
990
|
# get
|
@@ -1126,8 +997,8 @@ module Vips
|
|
1126
997
|
#
|
1127
998
|
# @param size [Integer] size of filter window
|
1128
999
|
# @return [Image] result of median filter
|
1129
|
-
def median
|
1130
|
-
rank
|
1000
|
+
def median size = 3
|
1001
|
+
rank size, size, (size * size) / 2
|
1131
1002
|
end
|
1132
1003
|
|
1133
1004
|
# Return the real part of a complex image.
|
@@ -1182,6 +1053,14 @@ module Vips
|
|
1182
1053
|
Image::run_cmplx(self) {|x| x.complex :conj}
|
1183
1054
|
end
|
1184
1055
|
|
1056
|
+
# Calculate the cross phase of two images.
|
1057
|
+
#
|
1058
|
+
# @param other [Image, Real, Array<Real>] cross phase with this
|
1059
|
+
# @return [Image] cross phase
|
1060
|
+
def cross_phase other
|
1061
|
+
complex2 other, :cross_phase
|
1062
|
+
end
|
1063
|
+
|
1185
1064
|
# Return the sine of an image in degrees.
|
1186
1065
|
#
|
1187
1066
|
# @return [Image] sine of each pixel
|
@@ -1274,7 +1153,7 @@ module Vips
|
|
1274
1153
|
# @param mask [Image, Array<Real>, Array<Array<Real>>] structuring
|
1275
1154
|
# element
|
1276
1155
|
# @return [Image] eroded image
|
1277
|
-
def erode
|
1156
|
+
def erode mask
|
1278
1157
|
morph mask, :erode
|
1279
1158
|
end
|
1280
1159
|
|
@@ -1286,7 +1165,7 @@ module Vips
|
|
1286
1165
|
# @param mask [Image, Array<Real>, Array<Array<Real>>] structuring
|
1287
1166
|
# element
|
1288
1167
|
# @return [Image] dilated image
|
1289
|
-
def dilate
|
1168
|
+
def dilate mask
|
1290
1169
|
morph mask, :dilate
|
1291
1170
|
end
|
1292
1171
|
|
@@ -1317,28 +1196,28 @@ module Vips
|
|
1317
1196
|
#
|
1318
1197
|
# @param th [Image, Real, Array<Real>] true values
|
1319
1198
|
# @param el [Image, Real, Array<Real>] false values
|
1320
|
-
# @param [Hash]
|
1199
|
+
# @param opts [Hash] set of options
|
1321
1200
|
# @option opts [Boolean] :blend (false) Blend smoothly between th and el
|
1322
1201
|
# @return [Image] merged image
|
1323
1202
|
def ifthenelse(th, el, opts = {})
|
1324
1203
|
match_image = [th, el, self].find {|x| x.is_a? Vips::Image}
|
1325
1204
|
|
1326
1205
|
if not th.is_a? Vips::Image
|
1327
|
-
th =
|
1206
|
+
th = Operation.imageize match_image, th
|
1328
1207
|
end
|
1329
1208
|
if not el.is_a? Vips::Image
|
1330
|
-
el =
|
1209
|
+
el = Operation.imageize match_image, el
|
1331
1210
|
end
|
1332
1211
|
|
1333
|
-
Vips::
|
1212
|
+
Vips::Operation.call "ifthenelse", [self, th, el], opts
|
1334
1213
|
end
|
1335
1214
|
|
1336
1215
|
# Scale an image to uchar. This is the vips `scale` operation, but
|
1337
1216
|
# renamed to avoid a clash with the `.scale` property.
|
1338
1217
|
#
|
1339
|
-
# @param [Hash]
|
1218
|
+
# @param opts [Hash] Set of options
|
1340
1219
|
# @return [Vips::Image] Output image
|
1341
|
-
def scaleimage
|
1220
|
+
def scaleimage opts = {}
|
1342
1221
|
Vips::Image.scale self, opts
|
1343
1222
|
end
|
1344
1223
|
|
@@ -1359,97 +1238,125 @@ module Vips
|
|
1359
1238
|
# these have hand-written methods, see above
|
1360
1239
|
no_generate = ["scale", "bandjoin", "ifthenelse"]
|
1361
1240
|
|
1362
|
-
|
1363
|
-
|
1364
|
-
|
1365
|
-
|
1366
|
-
|
1241
|
+
# map gobject's type names to Ruby
|
1242
|
+
map_go_to_ruby = {
|
1243
|
+
"gboolean" => "Boolean",
|
1244
|
+
"gint" => "Integer",
|
1245
|
+
"gdouble" => "Float",
|
1246
|
+
"gfloat" => "Float",
|
1247
|
+
"gchararray" => "String",
|
1248
|
+
"VipsImage" => "Vips::Image",
|
1249
|
+
"VipsInterpolate" => "Vips::Interpolate",
|
1250
|
+
"VipsArrayDouble" => "Array<Double>",
|
1251
|
+
"VipsArrayInt" => "Array<Integer>",
|
1252
|
+
"VipsArrayImage" => "Array<Image>",
|
1253
|
+
"VipsArrayString" => "Array<String>",
|
1254
|
+
}
|
1255
|
+
|
1256
|
+
generate_operation = lambda do |gtype, nickname, op|
|
1257
|
+
op_flags = op.get_flags
|
1258
|
+
return if (op_flags & OPERATION_DEPRECATED) != 0
|
1367
1259
|
return if no_generate.include? nickname
|
1260
|
+
description = Vips::vips_object_get_description op
|
1261
|
+
|
1262
|
+
# find and classify all the arguments the operator can take
|
1263
|
+
required_input = []
|
1264
|
+
optional_input = []
|
1265
|
+
required_output = []
|
1266
|
+
optional_output = []
|
1267
|
+
member_x = nil
|
1268
|
+
op.argument_map do |pspec, argument_class, argument_instance|
|
1269
|
+
arg_flags = argument_class[:flags]
|
1270
|
+
next if (arg_flags & ARGUMENT_CONSTRUCT) == 0
|
1271
|
+
next if (arg_flags & ARGUMENT_DEPRECATED) != 0
|
1272
|
+
|
1273
|
+
name = pspec[:name].gsub("-", "_")
|
1274
|
+
# 'in' as a param name confuses yard
|
1275
|
+
name = "im" if name == "in"
|
1276
|
+
gtype = pspec[:value_type]
|
1277
|
+
fundamental = GObject::g_type_fundamental gtype
|
1278
|
+
type_name = GObject::g_type_name gtype
|
1279
|
+
if map_go_to_ruby.include? type_name
|
1280
|
+
type_name = map_go_to_ruby[type_name]
|
1281
|
+
end
|
1282
|
+
if fundamental == GObject::GFLAGS_TYPE or
|
1283
|
+
fundamental == GObject::GENUM_TYPE
|
1284
|
+
type_name =~ /Vips(.*)/
|
1285
|
+
type_name = "Vips::" + $~[1]
|
1286
|
+
end
|
1287
|
+
blurb = GObject::g_param_spec_get_blurb pspec
|
1288
|
+
value = {:name => name,
|
1289
|
+
:flags => arg_flags,
|
1290
|
+
:gtype => gtype,
|
1291
|
+
:type_name => type_name,
|
1292
|
+
:blurb => blurb}
|
1293
|
+
|
1294
|
+
if (arg_flags & ARGUMENT_INPUT) != 0
|
1295
|
+
if (arg_flags & ARGUMENT_REQUIRED) != 0
|
1296
|
+
# note the first required input image, if any ... we
|
1297
|
+
# will be a method of this instance
|
1298
|
+
if not member_x and gtype == Vips::IMAGE_TYPE
|
1299
|
+
member_x = value
|
1300
|
+
else
|
1301
|
+
required_input << value
|
1302
|
+
end
|
1303
|
+
else
|
1304
|
+
optional_input << value
|
1305
|
+
end
|
1306
|
+
end
|
1368
1307
|
|
1369
|
-
|
1370
|
-
|
1371
|
-
|
1372
|
-
|
1373
|
-
|
1374
|
-
|
1375
|
-
|
1376
|
-
|
1377
|
-
|
1378
|
-
|
1379
|
-
(arg.flags & :input) != 0 and
|
1380
|
-
(arg.flags & :required) == 0
|
1381
|
-
end
|
1382
|
-
|
1383
|
-
required_output = all_args.select do |arg|
|
1384
|
-
(arg.flags & :output) != 0 and
|
1385
|
-
(arg.flags & :required) != 0
|
1386
|
-
end
|
1387
|
-
|
1388
|
-
# required input args with :modify are copied and appended to
|
1389
|
-
# output
|
1390
|
-
modified_required_input = required_input.select do |arg|
|
1391
|
-
(arg.flags & :modify) != 0
|
1392
|
-
end
|
1393
|
-
required_output += modified_required_input
|
1394
|
-
|
1395
|
-
optional_output = all_args.select do |arg|
|
1396
|
-
(arg.flags & :output) != 0 and
|
1397
|
-
(arg.flags & :required) == 0
|
1398
|
-
end
|
1399
|
-
|
1400
|
-
# optional input args with :modify are copied and appended to
|
1401
|
-
# output
|
1402
|
-
modified_optional_input = optional_input.select do |arg|
|
1403
|
-
(arg.flags & :modify) != 0
|
1404
|
-
end
|
1405
|
-
optional_output += modified_optional_input
|
1308
|
+
# MODIFY INPUT args count as OUTPUT as well
|
1309
|
+
if (arg_flags & ARGUMENT_OUTPUT) != 0 or
|
1310
|
+
((arg_flags & ARGUMENT_INPUT) != 0 and
|
1311
|
+
(arg_flags & ARGUMENT_MODIFY) != 0)
|
1312
|
+
if (arg_flags & ARGUMENT_REQUIRED) != 0 and
|
1313
|
+
required_output << value
|
1314
|
+
else
|
1315
|
+
optional_output << value
|
1316
|
+
end
|
1317
|
+
end
|
1406
1318
|
|
1407
|
-
# find the first input image, if any ... we will be a method of this
|
1408
|
-
# instance
|
1409
|
-
member_x = required_input.find do |x|
|
1410
|
-
x.gtype.type_is_a? GLib::Type["VipsImage"]
|
1411
|
-
end
|
1412
|
-
if member_x != nil
|
1413
|
-
required_input.delete member_x
|
1414
1319
|
end
|
1415
1320
|
|
1416
1321
|
print "# @!method "
|
1417
1322
|
print "self." if not member_x
|
1418
1323
|
print "#{nickname}("
|
1419
|
-
print required_input.map
|
1324
|
+
print required_input.map{|x| x[:name]}.join(", ")
|
1420
1325
|
print ", " if required_input.length > 0
|
1421
1326
|
puts "opts = {})"
|
1422
1327
|
|
1423
|
-
puts "# #{
|
1328
|
+
puts "# #{description.capitalize}."
|
1424
1329
|
|
1425
|
-
required_input.each do |arg|
|
1426
|
-
puts "# @param #{arg
|
1330
|
+
required_input.each do |arg|
|
1331
|
+
puts "# @param #{arg[:name]} [#{arg[:type_name]}] " +
|
1332
|
+
"#{arg[:blurb]}"
|
1427
1333
|
end
|
1428
1334
|
|
1429
|
-
puts "# @param [Hash]
|
1430
|
-
optional_input.each do |arg|
|
1431
|
-
puts "# @option opts [#{arg
|
1335
|
+
puts "# @param opts [Hash] Set of options"
|
1336
|
+
optional_input.each do |arg|
|
1337
|
+
puts "# @option opts [#{arg[:type_name]}] :#{arg[:name]} " +
|
1338
|
+
"#{arg[:blurb]}"
|
1432
1339
|
end
|
1433
|
-
optional_output.each do |arg|
|
1434
|
-
print "# @option opts [#{arg
|
1435
|
-
puts " Output #{arg
|
1340
|
+
optional_output.each do |arg|
|
1341
|
+
print "# @option opts [#{arg[:type_name]}] :#{arg[:name]}"
|
1342
|
+
puts " Output #{arg[:blurb]}"
|
1436
1343
|
end
|
1437
1344
|
|
1438
1345
|
print "# @return ["
|
1439
1346
|
if required_output.length == 0
|
1440
1347
|
print "nil"
|
1441
1348
|
elsif required_output.length == 1
|
1442
|
-
print required_output[
|
1349
|
+
print required_output.first[:type_name]
|
1443
1350
|
elsif
|
1444
1351
|
print "Array<"
|
1445
|
-
print required_output.map
|
1352
|
+
print required_output.map{|x| x[:type_name]}.join(", ")
|
1446
1353
|
print ">"
|
1447
1354
|
end
|
1448
1355
|
if optional_output.length > 0
|
1449
1356
|
print ", Hash<Symbol => Object>"
|
1450
1357
|
end
|
1451
1358
|
print "] "
|
1452
|
-
print required_output.map
|
1359
|
+
print required_output.map{|x| x[:blurb]}.join(", ")
|
1453
1360
|
if optional_output.length > 0
|
1454
1361
|
print ", " if required_output.length > 0
|
1455
1362
|
print "Hash of optional output items"
|
@@ -1459,35 +1366,30 @@ module Vips
|
|
1459
1366
|
puts ""
|
1460
1367
|
end
|
1461
1368
|
|
1462
|
-
generate_class = lambda do |gtype|
|
1463
|
-
|
1464
|
-
# can fail for abstract types
|
1465
|
-
# can't find a way to get to #abstract? from a gtype
|
1466
|
-
op = Vips::Operation.new gtype.name
|
1467
|
-
rescue
|
1468
|
-
op = nil
|
1469
|
-
end
|
1369
|
+
generate_class = lambda do |gtype, a|
|
1370
|
+
nickname = Vips::nickname_find gtype
|
1470
1371
|
|
1471
|
-
|
1372
|
+
if nickname
|
1373
|
+
begin
|
1374
|
+
# can fail for abstract types
|
1375
|
+
op = Vips::Operation.new nickname
|
1376
|
+
rescue
|
1377
|
+
end
|
1472
1378
|
|
1473
|
-
|
1474
|
-
generate_class.(x)
|
1379
|
+
generate_operation.(gtype, nickname, op) if op
|
1475
1380
|
end
|
1381
|
+
|
1382
|
+
Vips::vips_type_map gtype, generate_class, nil
|
1476
1383
|
end
|
1477
1384
|
|
1478
1385
|
puts "module Vips"
|
1479
1386
|
puts " class Image"
|
1480
1387
|
puts ""
|
1481
1388
|
|
1482
|
-
|
1483
|
-
# something
|
1484
|
-
GC.disable
|
1485
|
-
|
1486
|
-
generate_class.(GLib::Type["VipsOperation"])
|
1389
|
+
generate_class.(GObject::g_type_from_name("VipsOperation"), nil)
|
1487
1390
|
|
1488
1391
|
puts " end"
|
1489
1392
|
puts "end"
|
1490
1393
|
end
|
1491
1394
|
|
1492
1395
|
end
|
1493
|
-
|