ruby-vips 0.3.14 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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
+