ruby-vips8 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+