ruby-vips 1.0.6 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
|