ruby-vips8 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +1 -0
  3. data/.yardopts +10 -0
  4. data/CHANGELOG.md +5 -0
  5. data/Gemfile +15 -0
  6. data/Gemfile.lock +84 -0
  7. data/LICENSE.txt +20 -0
  8. data/README.md +170 -0
  9. data/Rakefile +45 -0
  10. data/TODO +11 -0
  11. data/VERSION +1 -0
  12. data/example/annotate.rb +17 -0
  13. data/example/daltonize8.rb +75 -0
  14. data/example/example1.rb +84 -0
  15. data/example/example2.rb +31 -0
  16. data/example/example3.rb +19 -0
  17. data/example/example4.rb +18 -0
  18. data/example/example5.rb +31 -0
  19. data/example/trim8.rb +41 -0
  20. data/example/watermark.rb +44 -0
  21. data/example/wobble.rb +36 -0
  22. data/lib/vips8.rb +153 -0
  23. data/lib/vips8/access.rb +14 -0
  24. data/lib/vips8/align.rb +11 -0
  25. data/lib/vips8/angle.rb +12 -0
  26. data/lib/vips8/angle45.rb +16 -0
  27. data/lib/vips8/argument.rb +163 -0
  28. data/lib/vips8/bandformat.rb +20 -0
  29. data/lib/vips8/call.rb +302 -0
  30. data/lib/vips8/coding.rb +14 -0
  31. data/lib/vips8/demandstyle.rb +35 -0
  32. data/lib/vips8/direction.rb +11 -0
  33. data/lib/vips8/error.rb +30 -0
  34. data/lib/vips8/extend.rb +22 -0
  35. data/lib/vips8/foreignflags.rb +20 -0
  36. data/lib/vips8/image.rb +1383 -0
  37. data/lib/vips8/interpolate.rb +37 -0
  38. data/lib/vips8/interpretation.rb +28 -0
  39. data/lib/vips8/methods.rb +1807 -0
  40. data/lib/vips8/operation.rb +19 -0
  41. data/ruby-vips8.gemspec +112 -0
  42. data/spec/image_spec.rb +515 -0
  43. data/spec/samples/balloon.v +0 -0
  44. data/spec/samples/ghost.ppm +405 -0
  45. data/spec/samples/huge.jpg +0 -0
  46. data/spec/samples/icc.jpg +0 -0
  47. data/spec/samples/lcd.icc +0 -0
  48. data/spec/samples/lion.svg +154 -0
  49. data/spec/samples/sample.csv +7 -0
  50. data/spec/samples/sample.exr +0 -0
  51. data/spec/samples/wagon.jpg +0 -0
  52. data/spec/samples/wagon.v +0 -0
  53. data/spec/spec_helper.rb +49 -0
  54. data/spec/vips_spec.rb +74 -0
  55. metadata +198 -0
@@ -0,0 +1,14 @@
1
+ module Vips
2
+
3
+ # How pixels are coded.
4
+ #
5
+ # Normally, pixels are uncoded and can be manipulated as you would expect.
6
+ # However some file formats code pixels for compression, and sometimes it's
7
+ # useful to be able to manipulate images in the coded format.
8
+ #
9
+ # * `:none` pixels are not coded
10
+ # * `:labq` pixels encode 3 float CIELAB values as 4 uchar
11
+ # * `:rad` pixels encode 3 float RGB as 4 uchar (Radiance coding)
12
+ class Coding
13
+ end
14
+ end
@@ -0,0 +1,35 @@
1
+ module Vips
2
+
3
+ # Operations can hint to the VIPS image IO
4
+ # system about the kind of demand geometry they prefer.
5
+ #
6
+ # These demand styles are given below in order of increasing
7
+ # restrictiveness. When demanding output from a pipeline,
8
+ # vips_image_generate()
9
+ # will use the most restrictive of the styles requested by the operations
10
+ # in the pipeline.
11
+ #
12
+ # * `:thinstrip` --- This operation would like to output strips
13
+ # the width of the image and a few pels high. This is option suitable
14
+ # for point-to-point operations, such as those in the arithmetic
15
+ # package.
16
+ #
17
+ # This option is only efficient for cases where each output pel depends
18
+ # upon the pel in the corresponding position in the input image.
19
+ #
20
+ # * `:fatstrip` --- This operation would like to output strips
21
+ # the width of the image and as high as possible. This option is
22
+ # suitable for area operations which do not violently transform
23
+ # coordinates, such as vips_conv().
24
+ #
25
+ # * `:smalltile` --- This is the most general demand format.
26
+ # Output is demanded in small (around 100x100 pel) sections. This style
27
+ # works reasonably efficiently, even for bizzare operations like 45
28
+ # degree rotate.
29
+ #
30
+ # * `:any` --- This image is not being demand-read from a disc
31
+ # file (even indirectly) so any demand style is OK. It's used for
32
+ # things like vips_black() where the pixels are calculated.
33
+ class DemandStyle
34
+ end
35
+ end
@@ -0,0 +1,11 @@
1
+ module Vips
2
+
3
+ # Operations like {Vips::Image.flip} need to be told whether to flip
4
+ # left-right or top-bottom.
5
+ #
6
+ # * `:horizontal` left-right
7
+ # * `:vertical` top-bottom
8
+
9
+ class Direction
10
+ end
11
+ end
@@ -0,0 +1,30 @@
1
+ module Vips
2
+
3
+ # The ruby-vips8 error class.
4
+ class Error < RuntimeError
5
+ # @param msg [String] The error message. If this is not supplied, grab
6
+ # and clear the vips error buffer and use that.
7
+ def initialize(msg = nil)
8
+ if msg
9
+ @details = msg
10
+ elsif Vips::error_buffer != ""
11
+ @details = Vips::error_buffer
12
+ Vips::error_clear
13
+ else
14
+ @details = nil
15
+ end
16
+ end
17
+
18
+ # Pretty-print a {Vips::Error}.
19
+ #
20
+ # @return [String] The error message
21
+ def to_s
22
+ if @details != nil
23
+ @details
24
+ else
25
+ super.to_s
26
+ end
27
+ end
28
+ end
29
+
30
+ end
@@ -0,0 +1,22 @@
1
+ module Vips
2
+
3
+ # When the edges of an image are extended, you can specify
4
+ # how you want the extension done.
5
+ # See {Vips::Image.embed}, {Vips::Image.conv}, {Vips::Image.affine} and
6
+ # so on.
7
+ #
8
+ # * `:black` new pixels are black, ie. all bits are zero.
9
+ #
10
+ # * `:copy` each new pixel takes the value of the nearest edge pixel
11
+ #
12
+ # * `:repeat` the image is tiled to fill the new area
13
+ #
14
+ # * `:mirror` the image is reflected and tiled to reduce hash edges
15
+ #
16
+ # * `:white` new pixels are white, ie. all bits are set
17
+ #
18
+ # * `:background` colour set from the @background property
19
+
20
+ class Extend
21
+ end
22
+ end
@@ -0,0 +1,20 @@
1
+ module Vips
2
+
3
+ # Some hints about the image loader.
4
+ #
5
+ # * `:partial` means that the image can be read directly from the
6
+ # file without needing to be unpacked to a temporary image first.
7
+ #
8
+ # * `:sequential` means that the loader supports lazy reading, but
9
+ # only top-to-bottom (sequential) access. Formats like PNG can read
10
+ # sets of scanlines, for example, but only in order.
11
+ #
12
+ # If neither partial` or sequential` is set, the loader only supports
13
+ # whole image read. Setting both partial` and sequential` is an error.
14
+ #
15
+ # * `:bigendian` means that image pixels are most-significant byte
16
+ # first. Depending on the native byte order of the host machine, you may
17
+ # need to swap bytes. See vips_copy().
18
+ class ForeignFlags
19
+ end
20
+ end
@@ -0,0 +1,1383 @@
1
+
2
+ # This module provides a set of overrides for the [vips image processing
3
+ # library](http://www.vips.ecs.soton.ac.uk)
4
+ # used via the [gobject-introspection
5
+ # gem](https://rubygems.org/gems/gobject-introspection).
6
+ #
7
+ # It needs vips-8.2 or later to be installed,
8
+ # and `Vips-8.0.typelib`, the vips typelib, needs to be on your
9
+ # `GI_TYPELIB_PATH`.
10
+ #
11
+ # # Example
12
+ #
13
+ # ```ruby
14
+ # require 'vips8'
15
+ #
16
+ # if ARGV.length < 2
17
+ # raise "usage: #{$PROGRAM_NAME}: input-file output-file"
18
+ # end
19
+ #
20
+ # im = Vips::Image.new_from_file ARGV[0], :access => :sequential
21
+ #
22
+ # im *= [1, 2, 1]
23
+ #
24
+ # mask = Vips::Image.new_from_array [
25
+ # [-1, -1, -1],
26
+ # [-1, 16, -1],
27
+ # [-1, -1, -1]], 8
28
+ # im = im.conv mask
29
+ #
30
+ # im.write_to_file ARGV[1]
31
+ # ```
32
+ #
33
+ # This example loads a file, boosts the green channel (I'm not sure why),
34
+ # sharpens the image, and saves it back to disc again.
35
+ #
36
+ # Reading this example line by line, we have:
37
+ #
38
+ # ```ruby
39
+ # im = Vips::Image.new_from_file ARGV[0], :access => :sequential
40
+ # ```
41
+ #
42
+ # {Image.new_from_file} can load any image file supported by vips. In this
43
+ # example, we will be accessing pixels top-to-bottom as we sweep through the
44
+ # image reading and writing, so `:sequential` access mode is best for us. The
45
+ # default mode is `:random`, this allows for full random access to image pixels,
46
+ # but is slower and needs more memory. See {Access}
47
+ # for full details
48
+ # on the various modes available. You can also load formatted images from
49
+ # memory buffers or create images that wrap C-style memory arrays.
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 {Vips::Image.conv}) for details on the convolution operator.
75
+ #
76
+ # Finally:
77
+ #
78
+ # ```ruby
79
+ # im.write_to_file ARGV[1]
80
+ # ```
81
+ #
82
+ # {Vips::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-vips8` 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](http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips/).
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-vips8` 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 {Vips::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, {Vips::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, {Vips::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, {Vips::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 {Vips::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, {Vips::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 {Vips::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 operation expects.
235
+ #
236
+ # Use the [C API
237
+ # docs](http://www.vips.ecs.soton.ac.uk/supported/current/doc/html/libvips)
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
+ # # Draw operations
246
+ #
247
+ # Paint operations like {Vips::Image.draw_circle} and {Vips::Image.draw_line}
248
+ # modify their input image. This
249
+ # makes them hard to use with the rest of libvips: you need to be very careful
250
+ # about the order in which operations execute or you can get nasty crashes.
251
+ #
252
+ # The wrapper spots operations of this type and makes a private copy of the
253
+ # image in memory before calling the operation. This stops crashes, but it does
254
+ # make it inefficient. If you draw 100 lines on an image, for example, you'll
255
+ # copy the image 100 times. The wrapper does make sure that memory is recycled
256
+ # where possible, so you won't have 100 copies in memory.
257
+ #
258
+ # If you want to avoid the copies, you'll need to call drawing operations
259
+ # yourself.
260
+ #
261
+ # # Overloads
262
+ #
263
+ # The wrapper defines the usual set of arithmetic, boolean and relational
264
+ # overloads on image. You can mix images, constants and lists of constants
265
+ # (almost) freely. For example, you can write:
266
+ #
267
+ # ```ruby
268
+ # result_image = ((image * [1, 2, 3]).abs < 128) | 4
269
+ # ```
270
+ #
271
+ # # Expansions
272
+ #
273
+ # Some vips operators take an enum to select an action, for example
274
+ # {Vips::Image.math} can be used to calculate sine of every pixel like this:
275
+ #
276
+ # ```ruby
277
+ # result_image = image.math :sin
278
+ # ```
279
+ #
280
+ # This is annoying, so the wrapper expands all these enums into separate members
281
+ # named after the enum. So you can write:
282
+ #
283
+ # ```ruby
284
+ # result_image = image.sin
285
+ # ```
286
+ #
287
+ # # Convenience functions
288
+ #
289
+ # The wrapper defines a few extra useful utility functions:
290
+ # {Vips::Image.get_value}, {Vips::Image.set_value}, {Vips::Image.bandsplit},
291
+ # {Vips::Image.maxpos}, {Vips::Image.minpos},
292
+ # {Vips::Image.median}.
293
+
294
+ module Vips
295
+
296
+ # This class represents a libvips image. See the {Vips} module documentation
297
+ # for an introduction to using this module.
298
+
299
+ class Image
300
+ private
301
+
302
+ # handy for overloads ... want to be able to apply a function to an
303
+ # array or to a scalar
304
+ def self.smap(x, &block)
305
+ x.is_a?(Array) ? x.map {|x| smap(x, &block)} : block.(x)
306
+ end
307
+
308
+ # run a complex operation on a complex image, or an image with an even
309
+ # number of bands ... handy for things like running .polar on .index
310
+ # images
311
+ def self.run_cmplx(image, &block)
312
+ original_format = image.format
313
+
314
+ if not Vips::band_format_iscomplex image.format
315
+ if image.bands % 2 != 0
316
+ raise Error, "not an even number of bands"
317
+ end
318
+
319
+ if not Vips::band_format_isfloat image.format
320
+ image = image.cast :float
321
+ end
322
+
323
+ new_format = image.format == :double ? :dpcomplex : :complex
324
+ image = image.copy :format => new_format,
325
+ :bands => image.bands / 2
326
+ end
327
+
328
+ image = block.(image)
329
+
330
+ if not Vips::band_format_iscomplex original_format
331
+ new_format = image.format == :dpcomplex ? :double : :float
332
+ image = image.copy :format => new_format,
333
+ :bands => image.bands * 2
334
+ end
335
+
336
+ image
337
+ end
338
+
339
+ # Write can fail due to no file descriptors and memory can fill if
340
+ # large objects are not collected fairly soon. We can't try a
341
+ # write and GC and retry on fail, since the write may take a
342
+ # long time and may not be repeatable.
343
+ #
344
+ # GCing before every write would have a horrible effect on
345
+ # performance, so as a compromise we GC every @@gc_interval writes.
346
+ #
347
+ # ruby2.1 introduced a generational GC which is fast enough to be
348
+ # able to GC on every write.
349
+
350
+ @@generational_gc = RUBY_ENGINE == "ruby" && RUBY_VERSION.to_f >= 2.1
351
+
352
+ @@gc_interval = 100
353
+ @@gc_countdown = @@gc_interval
354
+
355
+ def write_gc
356
+ if @@generational_gc
357
+ GC.start full_mark: false
358
+ else
359
+ @@gc_countdown -= 1
360
+ if @@gc_countdown < 0
361
+ @@gc_countdown = @@gc_interval
362
+ GC.start
363
+ end
364
+ end
365
+ end
366
+
367
+ public
368
+
369
+ # Invoke a vips operation with {call}, using self as the first
370
+ # input image argument.
371
+ #
372
+ # @param name [String] vips operation to call
373
+ # @return result of vips operation
374
+ def method_missing(name, *args)
375
+ Vips::call_base(name.to_s, self, "", args)
376
+ end
377
+
378
+ # Invoke a vips operation with {call}.
379
+ def self.method_missing(name, *args)
380
+ Vips::call_base name.to_s, nil, "", args
381
+ end
382
+
383
+ # Return a new {Image} for a file on disc. This method can load
384
+ # images in any format supported by vips. The filename can include
385
+ # load options, for example:
386
+ #
387
+ # ```
388
+ # image = Vips::new_from_file "fred.jpg[shrink=2]"
389
+ # ```
390
+ #
391
+ # You can also supply options as a hash, for example:
392
+ #
393
+ # ```
394
+ # image = Vips::new_from_file "fred.jpg", :shrink => 2
395
+ # ```
396
+ #
397
+ # The full set of options available depend upon the load operation that
398
+ # will be executed. Try something like:
399
+ #
400
+ # ```
401
+ # $ vips jpegload
402
+ # ```
403
+ #
404
+ # at the command-line to see a summary of the available options.
405
+ #
406
+ # Loading is fast: only enough of the image is loaded to be able to fill
407
+ # out the header. Pixels will only be processed when they are needed.
408
+ #
409
+ # @!macro [new] vips.loadopts
410
+ # @param [Hash] opts set of options
411
+ # @option opts [Boolean] :disc (true) Open large images via a
412
+ # temporary disc file
413
+ # @option opts [Vips::Access] :access (:random) Access mode for file
414
+ #
415
+ # @param name [String] the filename to load from
416
+ # @macro vips.loadopts
417
+ # @return [Image] the loaded image
418
+ def self.new_from_file(name, opts = {})
419
+ # very common, and Vips::filename_get_filename will segv if we pass
420
+ # this
421
+ if name == nil
422
+ raise Error, "filename is nil"
423
+ end
424
+ filename = Vips::filename_get_filename name
425
+ option_string = Vips::filename_get_options name
426
+ loader = Vips::Foreign.find_load filename
427
+ if loader == nil
428
+ raise Vips::Error
429
+ end
430
+
431
+ Vips::call_base loader, nil, option_string, [filename, opts]
432
+ end
433
+
434
+ # Create a new {Image} for an image encoded in a format, such as
435
+ # JPEG, in a memory string. Load options may be passed encoded as
436
+ # strings, or appended as a hash. For example:
437
+ #
438
+ # ```
439
+ # image = Vips::new_from_from_buffer memory_buffer, "shrink=2"
440
+ # ```
441
+ #
442
+ # or alternatively:
443
+ #
444
+ # ```
445
+ # image = Vips::new_from_from_buffer memory_buffer, "", :shrink => 2
446
+ # ```
447
+ #
448
+ # The options available depend on the file format. Try something like:
449
+ #
450
+ # ```
451
+ # $ vips jpegload_buffer
452
+ # ```
453
+ #
454
+ # at the command-line to see the available options. Only JPEG, PNG and
455
+ # TIFF images can be read from memory buffers.
456
+ #
457
+ # Loading is fast: only enough of the image is loaded to be able to fill
458
+ # out the header. Pixels will only be processed when they are needed.
459
+ #
460
+ # @param data [String] the data to load from
461
+ # @param option_string [String] load options as a string
462
+ # @macro vips.loadopts
463
+ # @return [Image] the loaded image
464
+ def self.new_from_buffer(data, option_string, opts = {})
465
+ loader = Vips::Foreign.find_load_buffer data
466
+ if loader == nil
467
+ raise Vips::Error
468
+ end
469
+
470
+ Vips::call_base loader, nil, option_string, [data, opts]
471
+ end
472
+
473
+ # Create a new Image from a 1D or 2D array. A 1D array becomes an
474
+ # image with height 1. Use `scale` and `offset` to set the scale and
475
+ # offset fields in the header. These are useful for integer
476
+ # convolutions.
477
+ #
478
+ # For example:
479
+ #
480
+ # ```
481
+ # image = Vips::new_from_array [1, 2, 3]
482
+ # ```
483
+ #
484
+ # or
485
+ #
486
+ # ```
487
+ # image = Vips::new_from_array [
488
+ # [-1, -1, -1],
489
+ # [-1, 16, -1],
490
+ # [-1, -1, -1]], 8
491
+ # ```
492
+ #
493
+ # for a simple sharpening mask.
494
+ #
495
+ # @param array [Array] the pixel data as an array of numbers
496
+ # @param scale [Real] the convolution scale
497
+ # @param offset [Real] the convolution offset
498
+ # @return [Image] the image
499
+ def self.new_from_array(array, scale = 1, offset = 0)
500
+ # we accept a 1D array and assume height == 1, or a 2D array
501
+ # and check all lines are the same length
502
+ if not array.is_a? Array
503
+ raise Vips::Error, "Argument is not an array."
504
+ end
505
+
506
+ if array[0].is_a? Array
507
+ height = array.length
508
+ width = array[0].length
509
+ if not array.all? {|x| x.is_a? Array}
510
+ raise Vips::Error, "Not a 2D array."
511
+ end
512
+ if not array.all? {|x| x.length == width}
513
+ raise Vips::Error, "Array not rectangular."
514
+ end
515
+ array = array.flatten
516
+ else
517
+ height = 1
518
+ width = array.length
519
+ end
520
+
521
+ if not array.all? {|x| x.is_a? Numeric}
522
+ raise Vips::Error, "Not all array elements are Numeric."
523
+ end
524
+
525
+ image = Vips::Image.matrix_from_array width, height, array
526
+ if image == nil
527
+ raise Vips::Error
528
+ end
529
+
530
+ # be careful to set them as double
531
+ image.set_double 'scale', scale.to_f
532
+ image.set_double 'offset', offset.to_f
533
+
534
+ return image
535
+ end
536
+
537
+ # Write this image to a file. Save options may be encoded in the
538
+ # filename or given as a hash. For example:
539
+ #
540
+ # ```
541
+ # image.write_to_file "fred.jpg[Q=90]"
542
+ # ```
543
+ #
544
+ # or equivalently:
545
+ #
546
+ # ```
547
+ # image.write_to_file "fred.jpg", :Q => 90
548
+ # ```
549
+ #
550
+ # The full set of save options depend on the selected saver. Try
551
+ # something like:
552
+ #
553
+ # ```
554
+ # $ vips jpegsave
555
+ # ```
556
+ #
557
+ # to see all the available options.
558
+ #
559
+ # @!macro [new] vips.saveopts
560
+ # @param [Hash] opts set of options
561
+ # @option opts [Boolean] :strip (false) Strip all metadata from image
562
+ # @option opts [Array<Float>] :background (0) Background colour to
563
+ # flatten alpha against, if necessary
564
+ #
565
+ # @param name [String] filename to write to
566
+ def write_to_file(name, opts = {})
567
+ filename = Vips::filename_get_filename name
568
+ option_string = Vips::filename_get_options name
569
+ saver = Vips::Foreign.find_save filename
570
+ if saver == nil
571
+ raise Vips::Error, "No known saver for '#{filename}'."
572
+ end
573
+
574
+ Vips::call_base saver, self, option_string, [filename, opts]
575
+
576
+ write_gc
577
+ end
578
+
579
+ # Write this image to a memory buffer. Save options may be encoded in
580
+ # the format_string or given as a hash. For example:
581
+ #
582
+ # ```
583
+ # buffer = image.write_to_buffer ".jpg[Q=90]"
584
+ # ```
585
+ #
586
+ # or equivalently:
587
+ #
588
+ # ```
589
+ # image.write_to_buffer ".jpg", :Q => 90
590
+ # ```
591
+ #
592
+ # The full set of save options depend on the selected saver. Try
593
+ # something like:
594
+ #
595
+ # ```
596
+ # $ vips jpegsave
597
+ # ```
598
+ #
599
+ # to see all the available options.
600
+ #
601
+ # @param format_string [String] save format plus options
602
+ # @macro vips.saveopts
603
+ # @return [String] the image saved in the specified format
604
+ def write_to_buffer(format_string, opts = {})
605
+ filename = Vips::filename_get_filename format_string
606
+ option_string = Vips::filename_get_options format_string
607
+ saver = Vips::Foreign.find_save_buffer filename
608
+ if saver == nil
609
+ raise Vips::Error, "No known saver for '#{filename}'."
610
+ end
611
+
612
+ buffer = Vips::call_base saver, self, option_string, [opts]
613
+
614
+ write_gc
615
+
616
+ return buffer
617
+ end
618
+
619
+ # @!attribute [r] width
620
+ # @return [Integer] image width, in pixels
621
+ # @!attribute [r] height
622
+ # @return [Integer] image height, in pixels
623
+ # @!attribute [r] bands
624
+ # @return [Integer] image bands
625
+ # @!attribute [r] format
626
+ # @return [Vips::BandFormat] image format
627
+ # @!attribute [r] interpretation
628
+ # @return [Vips::Interpretation] image interpretation
629
+ # @!attribute [r] coding
630
+ # @return [Vips::Coding] image coding
631
+ # @!attribute [r] filename
632
+ # @return [String] image filename
633
+ # @!attribute [r] xres
634
+ # @return [Float] horizontal image resolution, in pixels per mm
635
+ # @!attribute [r] yres
636
+ # @return [Float] vertical image resolution, in pixels per mm
637
+
638
+ # Fetch a `GType` from an image. `GType` will be 0 for no such field.
639
+ #
640
+ # @see get
641
+ # @see get_value
642
+ # @!method get_typeof(name)
643
+ # @param name [String] Metadata field to fetch
644
+ # @return [Integer] GType
645
+
646
+ # Fetch a `GValue` from an image. The return status is 0 for success, -1
647
+ # for failure.
648
+ #
649
+ # @see get_value
650
+ # @see get_typeof
651
+ # @!method get(name)
652
+ # @param name [String] Metadata field to fetch
653
+ # @return [Integer, GValue] Return status, GValue from image
654
+
655
+ # Set a `GValue` on an image
656
+ #
657
+ # @see set_value
658
+ # @!method set(name, value)
659
+ # @param name [String] Metadata field to set
660
+ # @param value [GValue] GValue to set
661
+
662
+ # Get a metadata item from an image. Ruby types are constructed
663
+ # automatically from the `GValue`, if possible.
664
+ #
665
+ # For example, you can read the ICC profile from an image like this:
666
+ #
667
+ # ```
668
+ # profile = image.get_value "icc-profile-data"
669
+ # ```
670
+ #
671
+ # and profile will be an array containing the profile.
672
+ #
673
+ # @see get
674
+ # @param name [String] Metadata field to set
675
+ # @return [Object] Value of field
676
+ def get_value(name)
677
+ ret, gval = get name
678
+ if ret[0] != 0
679
+ raise Vips::Error, "Field #{name} not found."
680
+ end
681
+ value = gval.value
682
+
683
+ Argument::unwrap(value)
684
+ end
685
+
686
+ # Set a metadata item on an image. Ruby types are automatically
687
+ # transformed into the matching `GValue`, if possible.
688
+ #
689
+ # For example, you can use this to set an image's ICC profile:
690
+ #
691
+ # ```
692
+ # x = y.set_value "icc-profile-data", profile
693
+ # ```
694
+ #
695
+ # where `profile` is an ICC profile held as a binary string object.
696
+ #
697
+ # @see set
698
+ # @param name [String] Metadata field to set
699
+ # @param value [Object] Value to set
700
+ def set_value(name, value)
701
+ gtype = get_typeof name
702
+ if gtype != 0
703
+ # array-ize
704
+ value = Argument::arrayize gtype, value
705
+
706
+ # blob-ize
707
+ if gtype.type_is_a? GLib::Type["VipsBlob"]
708
+ if not value.is_a? Vips::Blob
709
+ value = Vips::Blob.copy value
710
+ end
711
+ end
712
+
713
+ # image-ize
714
+ if gtype.type_is_a? GLib::Type["VipsImage"]
715
+ if not value.is_a? Vips::Image
716
+ value = imageize match_image, value
717
+ end
718
+ end
719
+
720
+ end
721
+
722
+ set name, value
723
+ end
724
+
725
+ # Add an image, constant or array.
726
+ #
727
+ # @param other [Image, Real, Array<Real>] Thing to add to self
728
+ # @return [Image] result of addition
729
+ def +(other)
730
+ other.is_a?(Vips::Image) ? add(other) : linear(1, other)
731
+ end
732
+
733
+ # Subtract an image, constant or array.
734
+ #
735
+ # @param other [Image, Real, Array<Real>] Thing to subtract from self
736
+ # @return [Image] result of subtraction
737
+ def -(other)
738
+ other.is_a?(Vips::Image) ?
739
+ subtract(other) : linear(1, Image::smap(other) {|x| x * -1})
740
+ end
741
+
742
+ # Multiply an image, constant or array.
743
+ #
744
+ # @param other [Image, Real, Array<Real>] Thing to multiply by self
745
+ # @return [Image] result of multiplication
746
+ def *(other)
747
+ other.is_a?(Vips::Image) ? multiply(other) : linear(other, 0)
748
+ end
749
+
750
+ # Divide an image, constant or array.
751
+ #
752
+ # @param other [Image, Real, Array<Real>] Thing to divide self by
753
+ # @return [Image] result of division
754
+ def /(other)
755
+ other.is_a?(Vips::Image) ?
756
+ divide(other) : linear(Image::smap(other) {|x| 1.0 / x}, 0)
757
+ end
758
+
759
+ # Remainder after integer division with an image, constant or array.
760
+ #
761
+ # @param other [Image, Real, Array<Real>] self modulo this
762
+ # @return [Image] result of modulo
763
+ def %(other)
764
+ other.is_a?(Vips::Image) ?
765
+ remainder(other) : remainder_const(other)
766
+ end
767
+
768
+ # Raise to power of an image, constant or array.
769
+ #
770
+ # @param other [Image, Real, Array<Real>] self to the power of this
771
+ # @return [Image] result of power
772
+ def **(other)
773
+ other.is_a?(Vips::Image) ?
774
+ math2(other, :pow) : math2_const(other, :pow)
775
+ end
776
+
777
+ # Integer left shift with an image, constant or array.
778
+ #
779
+ # @param other [Image, Real, Array<Real>] shift left by this much
780
+ # @return [Image] result of left shift
781
+ def <<(other)
782
+ other.is_a?(Vips::Image) ?
783
+ boolean(other, :lshift) : boolean_const(other, :lshift)
784
+ end
785
+
786
+ # Integer right shift with an image, constant or array.
787
+ #
788
+ # @param other [Image, Real, Array<Real>] shift right by this much
789
+ # @return [Image] result of right shift
790
+ def >>(other)
791
+ other.is_a?(Vips::Image) ?
792
+ boolean(other, :rshift) : boolean_const(other, :rshift)
793
+ end
794
+
795
+ # Integer bitwise OR with an image, constant or array.
796
+ #
797
+ # @param other [Image, Real, Array<Real>] bitwise OR with this
798
+ # @return [Image] result of bitwise OR
799
+ def |(other)
800
+ other.is_a?(Vips::Image) ?
801
+ boolean(other, :or) : boolean_const(other, :or)
802
+ end
803
+
804
+ # Integer bitwise AND with an image, constant or array.
805
+ #
806
+ # @param other [Image, Real, Array<Real>] bitwise AND with this
807
+ # @return [Image] result of bitwise AND
808
+ def &(other)
809
+ other.is_a?(Vips::Image) ?
810
+ boolean(other, :and) : boolean_const(other, :and)
811
+ end
812
+
813
+ # Integer bitwise EOR with an image, constant or array.
814
+ #
815
+ # @param other [Image, Real, Array<Real>] bitwise EOR with this
816
+ # @return [Image] result of bitwise EOR
817
+ def ^(other)
818
+ other.is_a?(Vips::Image) ?
819
+ boolean(other, :eor) : boolean_const(other, :eor)
820
+ end
821
+
822
+ # Equivalent to image ^ -1
823
+ #
824
+ # @return [Image] image with bits flipped
825
+ def !
826
+ self ^ -1
827
+ end
828
+
829
+ # Equivalent to image ^ -1
830
+ #
831
+ # @return [Image] image with bits flipped
832
+ def ~
833
+ self ^ -1
834
+ end
835
+
836
+ # @return [Image] image
837
+ def +@
838
+ self
839
+ end
840
+
841
+ # Equivalent to image * -1
842
+ #
843
+ # @return [Image] negative of image
844
+ def -@
845
+ self * -1
846
+ end
847
+
848
+ # Relational less than with an image, constant or array.
849
+ #
850
+ # @param other [Image, Real, Array<Real>] relational less than with this
851
+ # @return [Image] result of less than
852
+ def <(other)
853
+ other.is_a?(Vips::Image) ?
854
+ relational(other, :less) : relational_const(other, :less)
855
+ end
856
+
857
+ # Relational less than or equal to with an image, constant or array.
858
+ #
859
+ # @param other [Image, Real, Array<Real>] relational less than or
860
+ # equal to with this
861
+ # @return [Image] result of less than or equal to
862
+ def <=(other)
863
+ other.is_a?(Vips::Image) ?
864
+ relational(other, :lesseq) : relational_const(other, :lesseq)
865
+ end
866
+
867
+ # Relational more than with an image, constant or array.
868
+ #
869
+ # @param other [Image, Real, Array<Real>] relational more than with this
870
+ # @return [Image] result of more than
871
+ def >(other)
872
+ other.is_a?(Vips::Image) ?
873
+ relational(other, :more) : relational_const(other, :more)
874
+ end
875
+
876
+ # Relational more than or equal to with an image, constant or array.
877
+ #
878
+ # @param other [Image, Real, Array<Real>] relational more than or
879
+ # equal to with this
880
+ # @return [Image] result of more than or equal to
881
+ def >=(other)
882
+ other.is_a?(Vips::Image) ?
883
+ relational(other, :moreeq) : relational_const(other, :moreeq)
884
+ end
885
+
886
+ # Compare equality to nil, an image, constant or array.
887
+ #
888
+ # @param other [nil, Image, Real, Array<Real>] test equality to this
889
+ # @return [Image] result of equality
890
+ def ==(other)
891
+ if other == nil
892
+ false
893
+ elsif other.is_a?(Vips::Image)
894
+ relational(other, :equal)
895
+ else
896
+ relational_const(other, :equal)
897
+ end
898
+ end
899
+
900
+ # Compare inequality to nil, an image, constant or array.
901
+ #
902
+ # @param other [nil, Image, Real, Array<Real>] test inequality to this
903
+ # @return [Image] result of inequality
904
+ def !=(other)
905
+ if other == nil
906
+ true
907
+ elsif other.is_a?(Vips::Image)
908
+ relational(other, :noteq)
909
+ else
910
+ relational_const(other, :noteq)
911
+ end
912
+ end
913
+
914
+ # Fetch bands using a number or a range
915
+ #
916
+ # @param index [Numeric, Range] extract these band(s)
917
+ # @return [Image] extracted band(s)
918
+ def [](index)
919
+ if index.is_a? Range
920
+ n = index.end - index.begin
921
+ n += 1 if not index.exclude_end?
922
+ extract_band index.begin, :n => n
923
+ elsif index.is_a? Numeric
924
+ extract_band index
925
+ else
926
+ raise Vips::Error, "[] index is not range or numeric."
927
+ end
928
+ end
929
+
930
+ # Return the largest integral value not greater than the argument.
931
+ #
932
+ # @return [Image] floor of image
933
+ def floor
934
+ round :floor
935
+ end
936
+
937
+ # Return the smallest integral value not less than the argument.
938
+ #
939
+ # @return [Image] ceil of image
940
+ def ceil
941
+ round :ceil
942
+ end
943
+
944
+ # Return the nearest integral value.
945
+ #
946
+ # @return [Image] rint of image
947
+ def rint
948
+ round :rint
949
+ end
950
+
951
+ # AND the bands of an image together
952
+ #
953
+ # @return [Image] all bands ANDed together
954
+ def bandand
955
+ bandbool :and
956
+ end
957
+
958
+ # OR the bands of an image together
959
+ #
960
+ # @return [Image] all bands ORed together
961
+ def bandor
962
+ bandbool :or
963
+ end
964
+
965
+ # EOR the bands of an image together
966
+ #
967
+ # @return [Image] all bands EORed together
968
+ def bandeor
969
+ bandbool :eor
970
+ end
971
+
972
+ # Split an n-band image into n separate images.
973
+ #
974
+ # @return [Array<Image>] Array of n one-band images
975
+ def bandsplit
976
+ (0...bands).map {|i| extract_band(i)}
977
+ end
978
+
979
+ # Join a set of images bandwise.
980
+ #
981
+ # @param other [Image, Array<Image>, Real, Array<Real>] bands to append
982
+ # @return [Image] many band image
983
+ def bandjoin(other)
984
+ if not other.is_a? Array
985
+ other = [other]
986
+ end
987
+
988
+ Vips::Image.bandjoin([self] + other)
989
+ end
990
+
991
+ # Return the coordinates of the image maximum.
992
+ #
993
+ # @return [Real, Real, Real] maximum value, x coordinate of maximum, y
994
+ # coordinate of maximum
995
+ def maxpos
996
+ v, opts = max :x => true, :y => true
997
+ x = opts['x']
998
+ y = opts['y']
999
+ return v, x, y
1000
+ end
1001
+
1002
+ # Return the coordinates of the image minimum.
1003
+ #
1004
+ # @return [Real, Real, Real] minimum value, x coordinate of minimum, y
1005
+ # coordinate of minimum
1006
+ def minpos
1007
+ v, opts = min :x => true, :y => true
1008
+ x = opts['x']
1009
+ y = opts['y']
1010
+ return v, x, y
1011
+ end
1012
+
1013
+ # get the value of a pixel as an array
1014
+ #
1015
+ # @param x [Integer] x coordinate to sample
1016
+ # @param y [Integer] y coordinate to sample
1017
+ # @return [Array<Float>] the pixel values as an array
1018
+ def getpoint(x, y)
1019
+ # vips has an operation that does this, but we can't call it via
1020
+ # gobject-introspection 3.0.7 since it's missing array double
1021
+ # get
1022
+ #
1023
+ # remove this def when gobject-introspection updates
1024
+ crop(x, y, 1, 1).bandsplit.map {|i| i.avg}
1025
+ end
1026
+
1027
+ # a median filter
1028
+ #
1029
+ # @param size [Integer] size of filter window
1030
+ # @return [Image] result of median filter
1031
+ def median(size = 3)
1032
+ rank(size, size, (size * size) / 2)
1033
+ end
1034
+
1035
+ # Return the real part of a complex image.
1036
+ #
1037
+ # @return [Image] real part of complex image
1038
+ def real
1039
+ complexget :real
1040
+ end
1041
+
1042
+ # Return the imaginary part of a complex image.
1043
+ #
1044
+ # @return [Image] imaginary part of complex image
1045
+ def imag
1046
+ complexget :imag
1047
+ end
1048
+
1049
+ # Return an image with rectangular pixels converted to polar.
1050
+ #
1051
+ # The image
1052
+ # can be complex, in which case the return image will also be complex,
1053
+ # or must have an even number of bands, in which case pairs of
1054
+ # bands are treated as (x, y) coordinates.
1055
+ #
1056
+ # @see xyz
1057
+ # @return [Image] image converted to polar coordinates
1058
+ def polar
1059
+ Image::run_cmplx(self) {|x| x.complex :polar}
1060
+ end
1061
+
1062
+ # Return an image with polar pixels converted to rectangular.
1063
+ #
1064
+ # The image
1065
+ # can be complex, in which case the return image will also be complex,
1066
+ # or must have an even number of bands, in which case pairs of
1067
+ # bands are treated as (x, y) coordinates.
1068
+ #
1069
+ # @see xyz
1070
+ # @return [Image] image converted to rectangular coordinates
1071
+ def rect
1072
+ Image::run_cmplx(self) {|x| x.complex :rect}
1073
+ end
1074
+
1075
+ # Return the complex conjugate of an image.
1076
+ #
1077
+ # The image
1078
+ # can be complex, in which case the return image will also be complex,
1079
+ # or must have an even number of bands, in which case pairs of
1080
+ # bands are treated as (x, y) coordinates.
1081
+ #
1082
+ # @return [Image] complex conjugate
1083
+ def conj
1084
+ Image::run_cmplx(self) {|x| x.complex :conj}
1085
+ end
1086
+
1087
+ # Return the sine of an image in degrees.
1088
+ #
1089
+ # @return [Image] sine of each pixel
1090
+ def sin
1091
+ math :sin
1092
+ end
1093
+
1094
+ # Return the cosine of an image in degrees.
1095
+ #
1096
+ # @return [Image] cosine of each pixel
1097
+ def cos
1098
+ math :cos
1099
+ end
1100
+
1101
+ # Return the tangent of an image in degrees.
1102
+ #
1103
+ # @return [Image] tangent of each pixel
1104
+ def tan
1105
+ math :tan
1106
+ end
1107
+
1108
+ # Return the inverse sine of an image in degrees.
1109
+ #
1110
+ # @return [Image] inverse sine of each pixel
1111
+ def asin
1112
+ math :asin
1113
+ end
1114
+
1115
+ # Return the inverse cosine of an image in degrees.
1116
+ #
1117
+ # @return [Image] inverse cosine of each pixel
1118
+ def acos
1119
+ math :acos
1120
+ end
1121
+
1122
+ # Return the inverse tangent of an image in degrees.
1123
+ #
1124
+ # @return [Image] inverse tangent of each pixel
1125
+ def atan
1126
+ math :atan
1127
+ end
1128
+
1129
+ # Return the natural log of an image.
1130
+ #
1131
+ # @return [Image] natural log of each pixel
1132
+ def log
1133
+ math :log
1134
+ end
1135
+
1136
+ # Return the log base 10 of an image.
1137
+ #
1138
+ # @return [Image] base 10 log of each pixel
1139
+ def log10
1140
+ math :log10
1141
+ end
1142
+
1143
+ # Return e ** pixel.
1144
+ #
1145
+ # @return [Image] e ** pixel
1146
+ def exp
1147
+ math :exp
1148
+ end
1149
+
1150
+ # Return 10 ** pixel.
1151
+ #
1152
+ # @return [Image] 10 ** pixel
1153
+ def exp10
1154
+ math :exp10
1155
+ end
1156
+
1157
+ # Flip horizontally.
1158
+ #
1159
+ # @return [Image] image flipped horizontally
1160
+ def fliphor
1161
+ flip :horizontal
1162
+ end
1163
+
1164
+ # Flip vertically.
1165
+ #
1166
+ # @return [Image] image flipped vertically
1167
+ def flipver
1168
+ flip :vertical
1169
+ end
1170
+
1171
+ # Erode with a structuring element.
1172
+ #
1173
+ # The structuring element must be an array with 0 for black, 255 for
1174
+ # white and 128 for don't care.
1175
+ #
1176
+ # @param mask [Image, Array<Real>, Array<Array<Real>>] structuring
1177
+ # element
1178
+ # @return [Image] eroded image
1179
+ def erode(mask)
1180
+ morph mask, :erode
1181
+ end
1182
+
1183
+ # Dilate with a structuring element.
1184
+ #
1185
+ # The structuring element must be an array with 0 for black, 255 for
1186
+ # white and 128 for don't care.
1187
+ #
1188
+ # @param mask [Image, Array<Real>, Array<Array<Real>>] structuring
1189
+ # element
1190
+ # @return [Image] dilated image
1191
+ def dilate(mask)
1192
+ morph mask, :dilate
1193
+ end
1194
+
1195
+ # Rotate by 90 degrees clockwise.
1196
+ #
1197
+ # @return [Image] rotated image
1198
+ def rot90
1199
+ rot :d90
1200
+ end
1201
+
1202
+ # Rotate by 180 degrees clockwise.
1203
+ #
1204
+ # @return [Image] rotated image
1205
+ def rot180
1206
+ rot :d180
1207
+ end
1208
+
1209
+ # Rotate by 270 degrees clockwise.
1210
+ #
1211
+ # @return [Image] rotated image
1212
+ def rot270
1213
+ rot :d270
1214
+ end
1215
+
1216
+ # Select pixels from `th` if `self` is non-zero and from `el` if
1217
+ # `self` is zero. Use the `:blend` option to fade smoothly
1218
+ # between `th` and `el`.
1219
+ #
1220
+ # @param th [Image, Real, Array<Real>] true values
1221
+ # @param el [Image, Real, Array<Real>] false values
1222
+ # @param [Hash] opts set of options
1223
+ # @option opts [Boolean] :blend (false) Blend smoothly between th and el
1224
+ # @return [Image] merged image
1225
+ def ifthenelse(th, el, opts = {})
1226
+ match_image = [th, el, self].find {|x| x.is_a? Vips::Image}
1227
+
1228
+ if not th.is_a? Vips::Image
1229
+ th = Argument::imageize match_image, th
1230
+ end
1231
+ if not el.is_a? Vips::Image
1232
+ el = Argument::imageize match_image, el
1233
+ end
1234
+
1235
+ Vips::call_base "ifthenelse", self, "", [th, el, opts]
1236
+ end
1237
+
1238
+ end
1239
+
1240
+ # This method generates yard comments for all the dynamically bound
1241
+ # vips operations.
1242
+ #
1243
+ # Regenerate with something like:
1244
+ #
1245
+ # ruby > methods.rb
1246
+ # require 'vips8'; Vips::generate_yard
1247
+ # ^D
1248
+
1249
+ def self.generate_yard
1250
+ # these have hand-written methods, see above
1251
+ no_generate = ["bandjoin", "ifthenelse"]
1252
+
1253
+ generate_operation = lambda do |op|
1254
+ flags = op.flags
1255
+ return if (flags & :deprecated) != 0
1256
+ nickname = Vips::nickname_find op.gtype
1257
+
1258
+ return if no_generate.include? nickname
1259
+
1260
+ all_args = op.get_args.select {|arg| not arg.isset}
1261
+
1262
+ # separate args into various categories
1263
+
1264
+ required_input = all_args.select do |arg|
1265
+ (arg.flags & :input) != 0 and
1266
+ (arg.flags & :required) != 0
1267
+ end
1268
+
1269
+ optional_input = all_args.select do |arg|
1270
+ (arg.flags & :input) != 0 and
1271
+ (arg.flags & :required) == 0
1272
+ end
1273
+
1274
+ required_output = all_args.select do |arg|
1275
+ (arg.flags & :output) != 0 and
1276
+ (arg.flags & :required) != 0
1277
+ end
1278
+
1279
+ # required input args with :modify are copied and appended to
1280
+ # output
1281
+ modified_required_input = required_input.select do |arg|
1282
+ (arg.flags & :modify) != 0
1283
+ end
1284
+ required_output += modified_required_input
1285
+
1286
+ optional_output = all_args.select do |arg|
1287
+ (arg.flags & :output) != 0 and
1288
+ (arg.flags & :required) == 0
1289
+ end
1290
+
1291
+ # optional input args with :modify are copied and appended to
1292
+ # output
1293
+ modified_optional_input = optional_input.select do |arg|
1294
+ (arg.flags & :modify) != 0
1295
+ end
1296
+ optional_output += modified_optional_input
1297
+
1298
+ # find the first input image, if any ... we will be a method of this
1299
+ # instance
1300
+ member_x = required_input.find do |x|
1301
+ x.gtype.type_is_a? GLib::Type["VipsImage"]
1302
+ end
1303
+ if member_x != nil
1304
+ required_input.delete member_x
1305
+ end
1306
+
1307
+ print "# @!method "
1308
+ print "self." if not member_x
1309
+ print "#{nickname}("
1310
+ print required_input.map(&:name).join(", ")
1311
+ puts ", opts = {})"
1312
+
1313
+ puts "# #{op.description.capitalize}."
1314
+
1315
+ required_input.each do |arg|
1316
+ puts "# @param #{arg.name} [#{arg.type}] #{arg.blurb}"
1317
+ end
1318
+
1319
+ puts "# @param [Hash] opts Set of options"
1320
+ optional_input.each do |arg|
1321
+ puts "# @option opts [#{arg.type}] :#{arg.name} #{arg.blurb}"
1322
+ end
1323
+ optional_output.each do |arg|
1324
+ print "# @option opts [#{arg.type}] :#{arg.name}"
1325
+ puts " Output #{arg.blurb}"
1326
+ end
1327
+
1328
+ print "# @return ["
1329
+ if required_output.length == 0
1330
+ print "nil"
1331
+ elsif required_output.length == 1
1332
+ print required_output[0].type
1333
+ elsif
1334
+ print "Array<"
1335
+ print required_output.map(&:type).join(", ")
1336
+ print ">"
1337
+ end
1338
+ if optional_output.length > 0
1339
+ print ", Hash<Symbol => Object>"
1340
+ end
1341
+ print "] "
1342
+ print required_output.map(&:blurb).join(", ")
1343
+ if optional_output.length > 0
1344
+ print ", " if required_output.length > 0
1345
+ print "Hash of optional output items"
1346
+ end
1347
+ puts ""
1348
+
1349
+ puts ""
1350
+ end
1351
+
1352
+ generate_class = lambda do |gtype|
1353
+ begin
1354
+ # can fail for abstract types
1355
+ # can't find a way to get to #abstract? from a gtype
1356
+ op = Vips::Operation.new gtype.name
1357
+ rescue
1358
+ op = nil
1359
+ end
1360
+
1361
+ generate_operation.(op) if op
1362
+
1363
+ gtype.children.each do |x|
1364
+ generate_class.(x)
1365
+ end
1366
+ end
1367
+
1368
+ puts "module Vips"
1369
+ puts " class Image"
1370
+ puts ""
1371
+
1372
+ # gobject-introspection 3.0.7 crashes a lot if it GCs while doing
1373
+ # something
1374
+ GC.disable
1375
+
1376
+ generate_class.(GLib::Type["VipsOperation"])
1377
+
1378
+ puts " end"
1379
+ puts "end"
1380
+ end
1381
+
1382
+ end
1383
+