ruby-vips 0.3.14 → 1.0.0

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