ruby-vips 2.0.13 → 2.0.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +10 -0
  3. data/.rubocop_todo.yml +730 -0
  4. data/.travis.yml +13 -6
  5. data/CHANGELOG.md +8 -0
  6. data/README.md +5 -8
  7. data/Rakefile +6 -0
  8. data/VERSION +1 -1
  9. data/example/annotate.rb +2 -2
  10. data/example/daltonize8.rb +14 -14
  11. data/example/example2.rb +6 -6
  12. data/example/example3.rb +5 -5
  13. data/example/example4.rb +4 -4
  14. data/example/example5.rb +2 -2
  15. data/example/inheritance_with_refcount.rb +207 -207
  16. data/example/thumb.rb +10 -10
  17. data/example/trim8.rb +2 -2
  18. data/example/watermark.rb +14 -35
  19. data/example/wobble.rb +24 -24
  20. data/install-vips.sh +1 -1
  21. data/lib/vips.rb +335 -306
  22. data/lib/vips/access.rb +9 -9
  23. data/lib/vips/align.rb +7 -7
  24. data/lib/vips/angle.rb +8 -8
  25. data/lib/vips/angle45.rb +12 -12
  26. data/lib/vips/bandformat.rb +16 -16
  27. data/lib/vips/blend_mode.rb +34 -0
  28. data/lib/vips/coding.rb +11 -11
  29. data/lib/vips/compass_direction.rb +13 -13
  30. data/lib/vips/direction.rb +7 -7
  31. data/lib/vips/extend.rb +13 -13
  32. data/lib/vips/gobject.rb +94 -94
  33. data/lib/vips/gvalue.rb +232 -232
  34. data/lib/vips/image.rb +1329 -1335
  35. data/lib/vips/interesting.rb +10 -10
  36. data/lib/vips/interpolate.rb +51 -51
  37. data/lib/vips/interpretation.rb +25 -25
  38. data/lib/vips/kernel.rb +18 -18
  39. data/lib/vips/methods.rb +463 -283
  40. data/lib/vips/object.rb +208 -208
  41. data/lib/vips/operation.rb +323 -323
  42. data/lib/vips/operationboolean.rb +10 -10
  43. data/lib/vips/operationcomplex.rb +8 -8
  44. data/lib/vips/operationcomplex2.rb +6 -6
  45. data/lib/vips/operationcomplexget.rb +7 -7
  46. data/lib/vips/operationmath.rb +14 -14
  47. data/lib/vips/operationmath2.rb +6 -6
  48. data/lib/vips/operationrelational.rb +11 -11
  49. data/lib/vips/operationround.rb +7 -7
  50. data/lib/vips/size.rb +9 -9
  51. data/lib/vips/version.rb +1 -1
  52. data/ruby-vips.gemspec +6 -2
  53. metadata +29 -6
@@ -7,1502 +7,1496 @@
7
7
  require 'ffi'
8
8
 
9
9
  module Vips
10
- private
11
-
12
- attach_function :vips_image_new_matrix_from_array,
13
- [:int, :int, :pointer, :int], :pointer
14
-
15
- attach_function :vips_image_copy_memory, [:pointer], :pointer
16
-
17
- attach_function :vips_filename_get_filename, [:string], :pointer
18
- attach_function :vips_filename_get_options, [:string], :pointer
19
-
20
- attach_function :vips_foreign_find_load, [:string], :string
21
- attach_function :vips_foreign_find_save, [:string], :string
22
- attach_function :vips_foreign_find_load_buffer, [:pointer, :size_t], :string
23
- attach_function :vips_foreign_find_save_buffer, [:string], :string
24
-
25
- attach_function :vips_image_write_to_memory,
26
- [:pointer, SizeStruct.ptr], :pointer
27
-
28
- attach_function :vips_image_get_typeof, [:pointer, :string], :GType
29
- attach_function :vips_image_get,
30
- [:pointer, :string, GObject::GValue.ptr], :int
31
-
32
- # vips_image_get_fields was added in libvips 8.5
33
- begin
34
- attach_function :vips_image_get_fields, [:pointer], :pointer
35
- rescue FFI::NotFoundError
36
- end
37
-
38
- # vips_addalpha was added in libvips 8.6
39
- if Vips::at_least_libvips?(8, 6)
40
- attach_function :vips_addalpha, [:pointer, :pointer, :varargs], :int
41
- end
42
- if Vips::at_least_libvips?(8, 5)
43
- attach_function :vips_image_hasalpha, [:pointer], :int
44
- end
10
+ private
45
11
 
46
- attach_function :vips_image_set,
47
- [:pointer, :string, GObject::GValue.ptr], :void
48
- attach_function :vips_image_remove, [:pointer, :string], :void
12
+ attach_function :vips_image_new_matrix_from_array,
13
+ [:int, :int, :pointer, :int], :pointer
49
14
 
50
- attach_function :vips_band_format_iscomplex, [:int], :int
51
- attach_function :vips_band_format_isfloat, [:int], :int
15
+ attach_function :vips_image_copy_memory, [:pointer], :pointer
52
16
 
53
- attach_function :nickname_find, :vips_nickname_find, [:GType], :string
17
+ attach_function :vips_filename_get_filename, [:string], :pointer
18
+ attach_function :vips_filename_get_options, [:string], :pointer
54
19
 
55
- # turn a raw pointer that must be freed into a self-freeing Ruby string
56
- def self.p2str(pointer)
57
- pointer = FFI::AutoPointer.new(pointer, GLib::G_FREE)
58
- pointer.read_string
59
- end
60
-
61
- public
62
-
63
- # This class represents a libvips image. See the {Vips} module documentation
64
- # for an introduction to using this class.
65
-
66
- class Image < Vips::Object
67
- alias_method :parent_get_typeof, :get_typeof
68
-
69
- private
70
-
71
- # the layout of the VipsImage struct
72
- module ImageLayout
73
- def self.included base
74
- base.class_eval do
75
- layout :parent, Vips::Object::Struct
76
- # rest opaque
77
- end
78
- end
79
- end
80
-
81
- class Struct < Vips::Object::Struct
82
- include ImageLayout
83
-
84
- end
85
-
86
- class ManagedStruct < Vips::Object::ManagedStruct
87
- include ImageLayout
88
-
89
- end
20
+ attach_function :vips_foreign_find_load, [:string], :string
21
+ attach_function :vips_foreign_find_save, [:string], :string
22
+ attach_function :vips_foreign_find_load_buffer, [:pointer, :size_t], :string
23
+ attach_function :vips_foreign_find_save_buffer, [:string], :string
90
24
 
91
- class GenericPtr < FFI::Struct
92
- layout :value, :pointer
93
- end
25
+ attach_function :vips_image_write_to_memory,
26
+ [:pointer, SizeStruct.ptr], :pointer
94
27
 
95
- # handy for overloads ... want to be able to apply a function to an
96
- # array or to a scalar
97
- def self.smap x, &block
98
- x.is_a?(Array) ? x.map {|y| smap(y, &block)} : block.(x)
99
- end
28
+ attach_function :vips_image_get_typeof, [:pointer, :string], :GType
29
+ attach_function :vips_image_get,
30
+ [:pointer, :string, GObject::GValue.ptr], :int
100
31
 
101
- def self.complex? format
102
- format_number = GObject::GValue.from_nick BAND_FORMAT_TYPE, format
103
- Vips::vips_band_format_iscomplex(format_number) != 0
104
- end
32
+ # vips_image_get_fields was added in libvips 8.5
33
+ begin
34
+ attach_function :vips_image_get_fields, [:pointer], :pointer
35
+ rescue FFI::NotFoundError
36
+ nil
37
+ end
105
38
 
106
- def self.float? format
107
- format_number = GObject::GValue.from_nick BAND_FORMAT_TYPE, format
108
- Vips::vips_band_format_isfloat(format_number) != 0
109
- end
39
+ # vips_addalpha was added in libvips 8.6
40
+ if Vips::at_least_libvips?(8, 6)
41
+ attach_function :vips_addalpha, [:pointer, :pointer, :varargs], :int
42
+ end
43
+ if Vips::at_least_libvips?(8, 5)
44
+ attach_function :vips_image_hasalpha, [:pointer], :int
45
+ end
110
46
 
111
- # run a complex operation on a complex image, or an image with an even
112
- # number of bands ... handy for things like running .polar on .index
113
- # images
114
- def self.run_cmplx image, &block
115
- original_format = image.format
47
+ attach_function :vips_image_set,
48
+ [:pointer, :string, GObject::GValue.ptr], :void
49
+ attach_function :vips_image_remove, [:pointer, :string], :void
116
50
 
117
- unless Image::complex? image.format
118
- if image.bands % 2 != 0
119
- raise Error, "not an even number of bands"
120
- end
51
+ attach_function :vips_band_format_iscomplex, [:int], :int
52
+ attach_function :vips_band_format_isfloat, [:int], :int
121
53
 
122
- unless Image::float? image.format
123
- image = image.cast :float
124
- end
54
+ attach_function :nickname_find, :vips_nickname_find, [:GType], :string
125
55
 
126
- new_format = image.format == :double ? :dpcomplex : :complex
127
- image = image.copy format: new_format, bands: image.bands / 2
128
- end
56
+ # turn a raw pointer that must be freed into a self-freeing Ruby string
57
+ def self.p2str(pointer)
58
+ pointer = FFI::AutoPointer.new(pointer, GLib::G_FREE)
59
+ pointer.read_string
60
+ end
129
61
 
130
- image = block.(image)
62
+ public
131
63
 
132
- unless Image::complex? original_format
133
- new_format = image.format == :dpcomplex ? :double : :float
134
- image = image.copy format: new_format, bands: image.bands * 2
135
- end
64
+ # This class represents a libvips image. See the {Vips} module documentation
65
+ # for an introduction to using this class.
136
66
 
137
- image
138
- end
67
+ class Image < Vips::Object
68
+ alias_method :parent_get_typeof, :get_typeof
139
69
 
140
- # handy for expanding enum operations
141
- def call_enum(name, other, enum)
142
- if other.is_a?(Vips::Image)
143
- Vips::Operation.call name.to_s, [self, other, enum]
144
- else
145
- Vips::Operation.call name.to_s + "_const", [self, enum, other]
146
- end
147
- end
70
+ private
148
71
 
149
- # Write can fail due to no file descriptors and memory can fill if
150
- # large objects are not collected fairly soon. We can't try a
151
- # write and GC and retry on fail, since the write may take a
152
- # long time and may not be repeatable.
153
- #
154
- # GCing before every write would have a horrible effect on
155
- # performance, so as a compromise we GC every @@gc_interval writes.
156
- #
157
- # ruby2.1 introduced a generational GC which is fast enough to be
158
- # able to GC on every write.
159
-
160
- @@generational_gc = RUBY_ENGINE == "ruby" && RUBY_VERSION.to_f >= 2.1
161
-
162
- @@gc_interval = 100
163
- @@gc_countdown = @@gc_interval
164
-
165
- def write_gc
166
- if @@generational_gc
167
- GC.start full_mark: false
168
- else
169
- @@gc_countdown -= 1
170
- if @@gc_countdown < 0
171
- @@gc_countdown = @@gc_interval
172
- GC.start
173
- end
174
- end
72
+ # the layout of the VipsImage struct
73
+ module ImageLayout
74
+ def self.included base
75
+ base.class_eval do
76
+ layout :parent, Vips::Object::Struct
77
+ # rest opaque
175
78
  end
79
+ end
80
+ end
176
81
 
177
- public
82
+ class Struct < Vips::Object::Struct
83
+ include ImageLayout
178
84
 
179
- def inspect
180
- "#<Image #{width}x#{height} #{format}, #{bands} bands, " +
181
- "#{interpretation}>"
182
- end
85
+ end
183
86
 
184
- def respond_to? name, include_all = false
185
- # To support keyword args, we need to tell Ruby that final image
186
- # arguments cannot be hashes of keywords.
187
- #
188
- # https://makandracards.com/makandra/36013-heads-up-ruby-implicitly-converts-a-hash-to-keyword-arguments
189
- return false if name == :to_hash
87
+ class ManagedStruct < Vips::Object::ManagedStruct
88
+ include ImageLayout
190
89
 
191
- # respond to all vips operations by nickname
192
- return true if Vips::type_find("VipsOperation", name.to_s) != 0
90
+ end
193
91
 
194
- super
195
- end
92
+ class GenericPtr < FFI::Struct
93
+ layout :value, :pointer
94
+ end
196
95
 
197
- def self.respond_to? name, include_all = false
198
- # respond to all vips operations by nickname
199
- return true if Vips::type_find("VipsOperation", name.to_s) != 0
96
+ # handy for overloads ... want to be able to apply a function to an
97
+ # array or to a scalar
98
+ def self.smap x, &block
99
+ x.is_a?(Array) ? x.map {|y| smap(y, &block)} : block.(x)
100
+ end
200
101
 
201
- super
202
- end
102
+ def self.complex? format
103
+ format_number = GObject::GValue.from_nick BAND_FORMAT_TYPE, format
104
+ Vips::vips_band_format_iscomplex(format_number) != 0
105
+ end
203
106
 
204
- # Invoke a vips operation with {Vips::Operation.call}, using self as
205
- # the first input argument.
206
- #
207
- # @param name [String] vips operation to call
208
- # @return result of vips operation
209
- def method_missing name, *args, **options
210
- Vips::Operation.call name.to_s, [self, *args], options
211
- end
107
+ def self.float? format
108
+ format_number = GObject::GValue.from_nick BAND_FORMAT_TYPE, format
109
+ Vips::vips_band_format_isfloat(format_number) != 0
110
+ end
212
111
 
213
- # Invoke a vips operation with {Vips::Operation.call}.
214
- def self.method_missing name, *args, **options
215
- Vips::Operation.call name.to_s, args, options
216
- end
112
+ # run a complex operation on a complex image, or an image with an even
113
+ # number of bands ... handy for things like running .polar on .index
114
+ # images
115
+ def self.run_cmplx image, &block
116
+ original_format = image.format
217
117
 
218
- # Return a new {Image} for a file on disc. This method can load
219
- # images in any format supported by vips. The filename can include
220
- # load options, for example:
221
- #
222
- # ```
223
- # image = Vips::new_from_file "fred.jpg[shrink=2]"
224
- # ```
225
- #
226
- # You can also supply options as a hash, for example:
227
- #
228
- # ```
229
- # image = Vips::new_from_file "fred.jpg", shrink: 2
230
- # ```
231
- #
232
- # The full set of options available depend upon the load operation that
233
- # will be executed. Try something like:
234
- #
235
- # ```
236
- # $ vips jpegload
237
- # ```
238
- #
239
- # at the command-line to see a summary of the available options for the
240
- # JPEG loader.
241
- #
242
- # Loading is fast: only enough of the image is loaded to be able to fill
243
- # out the header. Pixels will only be decompressed when they are needed.
244
- #
245
- # @!macro [new] vips.loadopts
246
- # @param opts [Hash] set of options
247
- # @option opts [Boolean] :disc (true) Open large images via a
248
- # temporary disc file
249
- # @option opts [Vips::Access] :access (:random) Access mode for file
250
- #
251
- # @param name [String] the filename to load from
252
- # @macro vips.loadopts
253
- # @return [Image] the loaded image
254
- def self.new_from_file name, opts = {}
255
- # very common, and Vips::vips_filename_get_filename will segv if we
256
- # pass this
257
- raise Vips::Error, "filename is nil" if name == nil
258
-
259
- filename = Vips::p2str(Vips::vips_filename_get_filename name)
260
- option_string = Vips::p2str(Vips::vips_filename_get_options name)
261
- loader = Vips::vips_foreign_find_load filename
262
- raise Vips::Error if loader == nil
263
-
264
- Operation.call loader, [filename], opts, option_string
118
+ unless Image::complex? image.format
119
+ if image.bands % 2 != 0
120
+ raise Error, "not an even number of bands"
265
121
  end
266
122
 
267
- # Create a new {Image} for an image encoded, in a format such as
268
- # JPEG, in a memory string. Load options may be passed as
269
- # strings or appended as a hash. For example:
270
- #
271
- # ```
272
- # image = Vips::Image.new_from_buffer memory_buffer, "shrink=2"
273
- # ```
274
- #
275
- # or alternatively:
276
- #
277
- # ```
278
- # image = Vips::Image.new_from_buffer memory_buffer, "", shrink: 2
279
- # ```
280
- #
281
- # The options available depend on the file format. Try something like:
282
- #
283
- # ```
284
- # $ vips jpegload_buffer
285
- # ```
286
- #
287
- # at the command-line to see the available options. Not all loaders
288
- # support load from buffer, but at least JPEG, PNG and
289
- # TIFF images will work.
290
- #
291
- # Loading is fast: only enough of the image is loaded to be able to fill
292
- # out the header. Pixels will only be decompressed when they are needed.
293
- #
294
- # @param data [String] the data to load from
295
- # @param option_string [String] load options as a string
296
- # @macro vips.loadopts
297
- # @return [Image] the loaded image
298
- def self.new_from_buffer data, option_string, opts = {}
299
- loader = Vips::vips_foreign_find_load_buffer data, data.bytesize
300
- raise Vips::Error if loader == nil
301
-
302
- Vips::Operation.call loader, [data], opts, option_string
123
+ unless Image::float? image.format
124
+ image = image.cast :float
303
125
  end
304
126
 
305
- def self.matrix_from_array width, height, array
306
- ptr = FFI::MemoryPointer.new :double, array.length
307
- ptr.write_array_of_double array
308
- image = Vips::vips_image_new_matrix_from_array width, height,
309
- ptr, array.length
310
- Vips::Image.new image
311
- end
127
+ new_format = image.format == :double ? :dpcomplex : :complex
128
+ image = image.copy format: new_format, bands: image.bands / 2
129
+ end
312
130
 
313
- # Create a new Image from a 1D or 2D array. A 1D array becomes an
314
- # image with height 1. Use `scale` and `offset` to set the scale and
315
- # offset fields in the header. These are useful for integer
316
- # convolutions.
317
- #
318
- # For example:
319
- #
320
- # ```
321
- # image = Vips::new_from_array [1, 2, 3]
322
- # ```
323
- #
324
- # or
325
- #
326
- # ```
327
- # image = Vips::new_from_array [
328
- # [-1, -1, -1],
329
- # [-1, 16, -1],
330
- # [-1, -1, -1]], 8
331
- # ```
332
- #
333
- # for a simple sharpening mask.
334
- #
335
- # @param array [Array] the pixel data as an array of numbers
336
- # @param scale [Real] the convolution scale
337
- # @param offset [Real] the convolution offset
338
- # @return [Image] the image
339
- def self.new_from_array array, scale = 1, offset = 0
340
- # we accept a 1D array and assume height == 1, or a 2D array
341
- # and check all lines are the same length
342
- unless array.is_a? Array
343
- raise Vips::Error, "Argument is not an array."
344
- end
131
+ image = block.(image)
345
132
 
346
- if array[0].is_a? Array
347
- height = array.length
348
- width = array[0].length
349
- unless array.all? {|x| x.is_a? Array}
350
- raise Vips::Error, "Not a 2D array."
351
- end
352
- unless array.all? {|x| x.length == width}
353
- raise Vips::Error, "Array not rectangular."
354
- end
355
- array = array.flatten
356
- else
357
- height = 1
358
- width = array.length
359
- end
133
+ unless Image::complex? original_format
134
+ new_format = image.format == :dpcomplex ? :double : :float
135
+ image = image.copy format: new_format, bands: image.bands * 2
136
+ end
360
137
 
361
- unless array.all? {|x| x.is_a? Numeric}
362
- raise Vips::Error, "Not all array elements are Numeric."
363
- end
364
-
365
- image = Vips::Image.matrix_from_array width, height, array
366
- raise Vips::Error if image == nil
367
-
368
- # be careful to set them as double
369
- image.set_type GObject::GDOUBLE_TYPE, 'scale', scale.to_f
370
- image.set_type GObject::GDOUBLE_TYPE, 'offset', offset.to_f
371
-
372
- return image
373
- end
374
-
375
- # A new image is created with the same width, height, format,
376
- # interpretation, resolution and offset as self, but with every pixel
377
- # set to the specified value.
378
- #
379
- # You can pass an array to make a many-band image, or a single value to
380
- # make a one-band image.
381
- #
382
- # @param value [Real, Array<Real>] value to put in each pixel
383
- # @return [Image] constant image
384
- def new_from_image value
385
- pixel = (Vips::Image.black(1, 1) + value).cast(format)
386
- image = pixel.embed 0, 0, width, height, extend: :copy
387
- image.copy interpretation: interpretation,
388
- xres: xres, yres: yres, xoffset: xoffset, yoffset: yoffset
389
- end
390
-
391
- # Write this image to a file. Save options may be encoded in the
392
- # filename or given as a hash. For example:
393
- #
394
- # ```
395
- # image.write_to_file "fred.jpg[Q=90]"
396
- # ```
397
- #
398
- # or equivalently:
399
- #
400
- # ```
401
- # image.write_to_file "fred.jpg", Q: 90
402
- # ```
403
- #
404
- # The full set of save options depend on the selected saver. Try
405
- # something like:
406
- #
407
- # ```
408
- # $ vips jpegsave
409
- # ```
410
- #
411
- # to see all the available options for JPEG save.
412
- #
413
- # @!macro [new] vips.saveopts
414
- # @param opts [Hash] set of options
415
- # @option opts [Boolean] :strip (false) Strip all metadata from image
416
- # @option opts [Array<Float>] :background (0) Background colour to
417
- # flatten alpha against, if necessary
418
- #
419
- # @param name [String] filename to write to
420
- def write_to_file name, opts = {}
421
- filename = Vips::p2str(Vips::vips_filename_get_filename name)
422
- option_string = Vips::p2str(Vips::vips_filename_get_options name)
423
- saver = Vips::vips_foreign_find_save filename
424
- if saver == nil
425
- raise Vips::Error, "No known saver for '#{filename}'."
426
- end
138
+ image
139
+ end
427
140
 
428
- Vips::Operation.call saver, [self, filename], opts, option_string
429
-
430
- write_gc
431
- end
141
+ # handy for expanding enum operations
142
+ def call_enum(name, other, enum)
143
+ if other.is_a?(Vips::Image)
144
+ Vips::Operation.call name.to_s, [self, other, enum]
145
+ else
146
+ Vips::Operation.call name.to_s + "_const", [self, enum, other]
147
+ end
148
+ end
432
149
 
433
- # Write this image to a memory buffer. Save options may be encoded in
434
- # the format_string or given as a hash. For example:
435
- #
436
- # ```
437
- # buffer = image.write_to_buffer ".jpg[Q=90]"
438
- # ```
439
- #
440
- # or equivalently:
441
- #
442
- # ```
443
- # image.write_to_buffer ".jpg", Q: 90
444
- # ```
445
- #
446
- # The full set of save options depend on the selected saver. Try
447
- # something like:
448
- #
449
- # ```
450
- # $ vips jpegsave
451
- # ```
452
- #
453
- # to see all the available options for JPEG save.
454
- #
455
- # @param format_string [String] save format plus options
456
- # @macro vips.saveopts
457
- # @return [String] the image saved in the specified format
458
- def write_to_buffer format_string, opts = {}
459
- filename =
460
- Vips::p2str(Vips::vips_filename_get_filename format_string)
461
- option_string =
462
- Vips::p2str(Vips::vips_filename_get_options format_string)
463
- saver = Vips::vips_foreign_find_save_buffer filename
464
- if saver == nil
465
- raise Vips::Error, "No known saver for '#{filename}'."
466
- end
150
+ # Write can fail due to no file descriptors and memory can fill if
151
+ # large objects are not collected fairly soon. We can't try a
152
+ # write and GC and retry on fail, since the write may take a
153
+ # long time and may not be repeatable.
154
+ #
155
+ # GCing before every write would have a horrible effect on
156
+ # performance, so as a compromise we GC every @@gc_interval writes.
157
+ #
158
+ # ruby2.1 introduced a generational GC which is fast enough to be
159
+ # able to GC on every write.
467
160
 
468
- buffer = Vips::Operation.call saver, [self], opts, option_string
469
- raise Vips::Error if buffer == nil
161
+ @@generational_gc = RUBY_ENGINE == "ruby" && RUBY_VERSION.to_f >= 2.1
470
162
 
471
- write_gc
163
+ @@gc_interval = 100
164
+ @@gc_countdown = @@gc_interval
472
165
 
473
- return buffer
166
+ def write_gc
167
+ if @@generational_gc
168
+ GC.start full_mark: false
169
+ else
170
+ @@gc_countdown -= 1
171
+ if @@gc_countdown < 0
172
+ @@gc_countdown = @@gc_interval
173
+ GC.start
474
174
  end
175
+ end
176
+ end
475
177
 
476
- # Write this image to a large memory buffer.
477
- #
478
- # @return [String] the pixels as a huge binary string
479
- def write_to_memory
480
- len = Vips::SizeStruct.new
481
- ptr = Vips::vips_image_write_to_memory self, len
178
+ public
482
179
 
483
- # wrap up as an autopointer
484
- ptr = FFI::AutoPointer.new(ptr, GLib::G_FREE)
180
+ def inspect
181
+ "#<Image #{width}x#{height} #{format}, #{bands} bands, " +
182
+ "#{interpretation}>"
183
+ end
485
184
 
486
- ptr.get_bytes 0, len[:value]
487
- end
185
+ def respond_to? name, include_all = false
186
+ # To support keyword args, we need to tell Ruby that final image
187
+ # arguments cannot be hashes of keywords.
188
+ #
189
+ # https://makandracards.com/makandra/36013-heads-up-ruby-implicitly-converts-a-hash-to-keyword-arguments
190
+ return false if name == :to_hash
488
191
 
489
- # Fetch a `GType` from an image. `GType` will be 0 for no such field.
490
- #
491
- # @see get
492
- # @param name [String] Metadata field to fetch
493
- # @return [Integer] GType
494
- def get_typeof name
495
- # on libvips before 8.5, property types must be searched first,
496
- # since vips_image_get_typeof returned built-in enums as int
497
- unless Vips::at_least_libvips?(8, 5)
498
- gtype = parent_get_typeof name
499
- return gtype if gtype != 0
500
- end
192
+ # respond to all vips operations by nickname
193
+ return true if Vips::type_find("VipsOperation", name.to_s) != 0
501
194
 
502
- Vips::vips_image_get_typeof self, name
503
- end
195
+ super
196
+ end
504
197
 
505
- # Get a metadata item from an image. Ruby types are constructed
506
- # automatically from the `GValue`, if possible.
507
- #
508
- # For example, you can read the ICC profile from an image like this:
509
- #
510
- # ```
511
- # profile = image.get "icc-profile-data"
512
- # ```
513
- #
514
- # and profile will be an array containing the profile.
515
- #
516
- # @param name [String] Metadata field to get
517
- # @return [Object] Value of field
518
- def get name
519
- # with old libvips, we must fetch properties (as opposed to
520
- # metadata) via VipsObject
521
- unless Vips::at_least_libvips?(8, 5)
522
- return super if parent_get_typeof(name) != 0
523
- end
198
+ def self.respond_to? name, include_all = false
199
+ # respond to all vips operations by nickname
200
+ return true if Vips::type_find("VipsOperation", name.to_s) != 0
524
201
 
525
- gvalue = GObject::GValue.alloc
526
- result = Vips::vips_image_get self, name, gvalue
527
- raise Vips::Error if result != 0
202
+ super
203
+ end
528
204
 
529
- return gvalue.get
530
- end
205
+ # Invoke a vips operation with {Vips::Operation.call}, using self as
206
+ # the first input argument.
207
+ #
208
+ # @param name [String] vips operation to call
209
+ # @return result of vips operation
210
+ def method_missing name, *args, **options
211
+ Vips::Operation.call name.to_s, [self, *args], options
212
+ end
531
213
 
532
- # Get the names of all fields on an image. Use this to loop over all
533
- # image metadata.
534
- #
535
- # @return [[String]] array of field names
536
- def get_fields
537
- # vips_image_get_fields() was added in libvips 8.5
538
- return [] unless Vips.respond_to? :vips_image_get_fields
539
-
540
- array = Vips::vips_image_get_fields self
541
-
542
- names = []
543
- p = array
544
- until ((q = p.read_pointer).null?)
545
- names << q.read_string
546
- GLib::g_free q
547
- p += FFI::Type::POINTER.size
548
- end
549
- GLib::g_free array
214
+ # Invoke a vips operation with {Vips::Operation.call}.
215
+ def self.method_missing name, *args, **options
216
+ Vips::Operation.call name.to_s, args, options
217
+ end
550
218
 
551
- return names
552
- end
219
+ # Return a new {Image} for a file on disc. This method can load
220
+ # images in any format supported by vips. The filename can include
221
+ # load options, for example:
222
+ #
223
+ # ```
224
+ # image = Vips::new_from_file "fred.jpg[shrink=2]"
225
+ # ```
226
+ #
227
+ # You can also supply options as a hash, for example:
228
+ #
229
+ # ```
230
+ # image = Vips::new_from_file "fred.jpg", shrink: 2
231
+ # ```
232
+ #
233
+ # The full set of options available depend upon the load operation that
234
+ # will be executed. Try something like:
235
+ #
236
+ # ```
237
+ # $ vips jpegload
238
+ # ```
239
+ #
240
+ # at the command-line to see a summary of the available options for the
241
+ # JPEG loader.
242
+ #
243
+ # Loading is fast: only enough of the image is loaded to be able to fill
244
+ # out the header. Pixels will only be decompressed when they are needed.
245
+ #
246
+ # @!macro [new] vips.loadopts
247
+ # @param opts [Hash] set of options
248
+ # @option opts [Boolean] :disc (true) Open large images via a
249
+ # temporary disc file
250
+ # @option opts [Vips::Access] :access (:random) Access mode for file
251
+ #
252
+ # @param name [String] the filename to load from
253
+ # @macro vips.loadopts
254
+ # @return [Image] the loaded image
255
+ def self.new_from_file name, **opts
256
+ # very common, and Vips::vips_filename_get_filename will segv if we
257
+ # pass this
258
+ raise Vips::Error, "filename is nil" if name == nil
259
+
260
+ filename = Vips::p2str(Vips::vips_filename_get_filename name)
261
+ option_string = Vips::p2str(Vips::vips_filename_get_options name)
262
+ loader = Vips::vips_foreign_find_load filename
263
+ raise Vips::Error if loader == nil
264
+
265
+ Operation.call loader, [filename], opts, option_string
266
+ end
553
267
 
554
- # Create a metadata item on an image, of the specifed type. Ruby types
555
- # are automatically
556
- # transformed into the matching `GType`, if possible.
557
- #
558
- # For example, you can use this to set an image's ICC profile:
559
- #
560
- # ```
561
- # x = y.set_type Vips::BLOB_TYPE, "icc-profile-data", profile
562
- # ```
563
- #
564
- # where `profile` is an ICC profile held as a binary string object.
565
- #
566
- # @see set
567
- # @param gtype [Integer] GType of item
568
- # @param name [String] Metadata field to set
569
- # @param value [Object] Value to set
570
- def set_type gtype, name, value
571
- gvalue = GObject::GValue.alloc
572
- gvalue.init gtype
573
- gvalue.set value
574
- Vips::vips_image_set self, name, gvalue
575
- end
268
+ # Create a new {Image} for an image encoded, in a format such as
269
+ # JPEG, in a binary string. Load options may be passed as
270
+ # strings or appended as a hash. For example:
271
+ #
272
+ # ```
273
+ # image = Vips::Image.new_from_buffer memory_buffer, "shrink=2"
274
+ # ```
275
+ #
276
+ # or alternatively:
277
+ #
278
+ # ```
279
+ # image = Vips::Image.new_from_buffer memory_buffer, "", shrink: 2
280
+ # ```
281
+ #
282
+ # The options available depend on the file format. Try something like:
283
+ #
284
+ # ```
285
+ # $ vips jpegload_buffer
286
+ # ```
287
+ #
288
+ # at the command-line to see the available options. Not all loaders
289
+ # support load from buffer, but at least JPEG, PNG and
290
+ # TIFF images will work.
291
+ #
292
+ # Loading is fast: only enough of the image is loaded to be able to fill
293
+ # out the header. Pixels will only be decompressed when they are needed.
294
+ #
295
+ # @param data [String] the data to load from
296
+ # @param option_string [String] load options as a string
297
+ # @macro vips.loadopts
298
+ # @return [Image] the loaded image
299
+ def self.new_from_buffer data, option_string, **opts
300
+ loader = Vips::vips_foreign_find_load_buffer data, data.bytesize
301
+ raise Vips::Error if loader == nil
302
+
303
+ Vips::Operation.call loader, [data], opts, option_string
304
+ end
576
305
 
577
- # Set the value of a metadata item on an image. The metadata item must
578
- # already exist. Ruby types are automatically
579
- # transformed into the matching `GValue`, if possible.
580
- #
581
- # For example, you can use this to set an image's ICC profile:
582
- #
583
- # ```
584
- # x = y.set "icc-profile-data", profile
585
- # ```
586
- #
587
- # where `profile` is an ICC profile held as a binary string object.
588
- #
589
- # @see set_type
590
- # @param name [String] Metadata field to set
591
- # @param value [Object] Value to set
592
- def set name, value
593
- set_type get_typeof(name), name, value
594
- end
306
+ def self.matrix_from_array width, height, array
307
+ ptr = FFI::MemoryPointer.new :double, array.length
308
+ ptr.write_array_of_double array
309
+ image = Vips::vips_image_new_matrix_from_array width, height,
310
+ ptr, array.length
311
+ Vips::Image.new image
312
+ end
595
313
 
596
- # Remove a metadata item from an image.
597
- #
598
- # @param name [String] Metadata field to remove
599
- def remove name
600
- Vips::vips_image_remove self, name
601
- end
314
+ # Create a new Image from a 1D or 2D array. A 1D array becomes an
315
+ # image with height 1. Use `scale` and `offset` to set the scale and
316
+ # offset fields in the header. These are useful for integer
317
+ # convolutions.
318
+ #
319
+ # For example:
320
+ #
321
+ # ```
322
+ # image = Vips::new_from_array [1, 2, 3]
323
+ # ```
324
+ #
325
+ # or
326
+ #
327
+ # ```
328
+ # image = Vips::new_from_array [
329
+ # [-1, -1, -1],
330
+ # [-1, 16, -1],
331
+ # [-1, -1, -1]], 8
332
+ # ```
333
+ #
334
+ # for a simple sharpening mask.
335
+ #
336
+ # @param array [Array] the pixel data as an array of numbers
337
+ # @param scale [Real] the convolution scale
338
+ # @param offset [Real] the convolution offset
339
+ # @return [Image] the image
340
+ def self.new_from_array array, scale = 1, offset = 0
341
+ # we accept a 1D array and assume height == 1, or a 2D array
342
+ # and check all lines are the same length
343
+ unless array.is_a? Array
344
+ raise Vips::Error, "Argument is not an array."
345
+ end
346
+
347
+ if array[0].is_a? Array
348
+ height = array.length
349
+ width = array[0].length
350
+ unless array.all? {|x| x.is_a? Array}
351
+ raise Vips::Error, "Not a 2D array."
352
+ end
353
+ unless array.all? {|x| x.length == width}
354
+ raise Vips::Error, "Array not rectangular."
355
+ end
356
+ array = array.flatten
357
+ else
358
+ height = 1
359
+ width = array.length
360
+ end
361
+
362
+ unless array.all? {|x| x.is_a? Numeric}
363
+ raise Vips::Error, "Not all array elements are Numeric."
364
+ end
365
+
366
+ image = Vips::Image.matrix_from_array width, height, array
367
+ raise Vips::Error if image == nil
368
+
369
+ # be careful to set them as double
370
+ image.set_type GObject::GDOUBLE_TYPE, 'scale', scale.to_f
371
+ image.set_type GObject::GDOUBLE_TYPE, 'offset', offset.to_f
372
+
373
+ return image
374
+ end
602
375
 
603
- # compatibility: old name for get
604
- def get_value name
605
- get name
606
- end
376
+ # A new image is created with the same width, height, format,
377
+ # interpretation, resolution and offset as self, but with every pixel
378
+ # set to the specified value.
379
+ #
380
+ # You can pass an array to make a many-band image, or a single value to
381
+ # make a one-band image.
382
+ #
383
+ # @param value [Real, Array<Real>] value to put in each pixel
384
+ # @return [Image] constant image
385
+ def new_from_image value
386
+ pixel = (Vips::Image.black(1, 1) + value).cast(format)
387
+ image = pixel.embed 0, 0, width, height, extend: :copy
388
+ image.copy interpretation: interpretation,
389
+ xres: xres, yres: yres, xoffset: xoffset, yoffset: yoffset
390
+ end
607
391
 
608
- # compatibility: old name for set
609
- def set_value name, value
610
- set name, value
611
- end
392
+ # Write this image to a file. Save options may be encoded in the
393
+ # filename or given as a hash. For example:
394
+ #
395
+ # ```
396
+ # image.write_to_file "fred.jpg[Q=90]"
397
+ # ```
398
+ #
399
+ # or equivalently:
400
+ #
401
+ # ```
402
+ # image.write_to_file "fred.jpg", Q: 90
403
+ # ```
404
+ #
405
+ # The full set of save options depend on the selected saver. Try
406
+ # something like:
407
+ #
408
+ # ```
409
+ # $ vips jpegsave
410
+ # ```
411
+ #
412
+ # to see all the available options for JPEG save.
413
+ #
414
+ # @!macro [new] vips.saveopts
415
+ # @param opts [Hash] set of options
416
+ # @option opts [Boolean] :strip (false) Strip all metadata from image
417
+ # @option opts [Array<Float>] :background (0) Background colour to
418
+ # flatten alpha against, if necessary
419
+ #
420
+ # @param name [String] filename to write to
421
+ def write_to_file name, **opts
422
+ filename = Vips::p2str(Vips::vips_filename_get_filename name)
423
+ option_string = Vips::p2str(Vips::vips_filename_get_options name)
424
+ saver = Vips::vips_foreign_find_save filename
425
+ if saver == nil
426
+ raise Vips::Error, "No known saver for '#{filename}'."
427
+ end
428
+
429
+ Vips::Operation.call saver, [self, filename], opts, option_string
430
+
431
+ write_gc
432
+ end
612
433
 
613
- # Get image width, in pixels.
614
- #
615
- # @return [Integer] image width, in pixels
616
- def width
617
- get "width"
618
- end
434
+ # Write this image to a memory buffer. Save options may be encoded in
435
+ # the format_string or given as a hash. For example:
436
+ #
437
+ # ```
438
+ # buffer = image.write_to_buffer ".jpg[Q=90]"
439
+ # ```
440
+ #
441
+ # or equivalently:
442
+ #
443
+ # ```
444
+ # image.write_to_buffer ".jpg", Q: 90
445
+ # ```
446
+ #
447
+ # The full set of save options depend on the selected saver. Try
448
+ # something like:
449
+ #
450
+ # ```
451
+ # $ vips jpegsave
452
+ # ```
453
+ #
454
+ # to see all the available options for JPEG save.
455
+ #
456
+ # @param format_string [String] save format plus options
457
+ # @macro vips.saveopts
458
+ # @return [String] the image saved in the specified format
459
+ def write_to_buffer format_string, **opts
460
+ filename =
461
+ Vips::p2str(Vips::vips_filename_get_filename format_string)
462
+ option_string =
463
+ Vips::p2str(Vips::vips_filename_get_options format_string)
464
+ saver = Vips::vips_foreign_find_save_buffer filename
465
+ if saver == nil
466
+ raise Vips::Error, "No known saver for '#{filename}'."
467
+ end
468
+
469
+ buffer = Vips::Operation.call saver, [self], opts, option_string
470
+ raise Vips::Error if buffer == nil
471
+
472
+ write_gc
473
+
474
+ return buffer
475
+ end
619
476
 
620
- # Get image height, in pixels.
621
- #
622
- # @return [Integer] image height, in pixels
623
- def height
624
- get "height"
625
- end
477
+ # Write this image to a large memory buffer.
478
+ #
479
+ # @return [String] the pixels as a huge binary string
480
+ def write_to_memory
481
+ len = Vips::SizeStruct.new
482
+ ptr = Vips::vips_image_write_to_memory self, len
626
483
 
627
- # Get number of image bands.
628
- #
629
- # @return [Integer] number of image bands
630
- def bands
631
- get "bands"
632
- end
484
+ # wrap up as an autopointer
485
+ ptr = FFI::AutoPointer.new(ptr, GLib::G_FREE)
633
486
 
634
- # Get image format.
635
- #
636
- # @return [Symbol] image format
637
- def format
638
- get "format"
639
- end
487
+ ptr.get_bytes 0, len[:value]
488
+ end
640
489
 
641
- # Get image interpretation.
642
- #
643
- # @return [Symbol] image interpretation
644
- def interpretation
645
- get "interpretation"
646
- end
490
+ # Get the `GType` of a metadata field. The result is 0 if no such field
491
+ # exists.
492
+ #
493
+ # @see get
494
+ # @param name [String] Metadata field to fetch
495
+ # @return [Integer] GType
496
+ def get_typeof name
497
+ # on libvips before 8.5, property types must be searched first,
498
+ # since vips_image_get_typeof returned built-in enums as int
499
+ unless Vips::at_least_libvips?(8, 5)
500
+ gtype = parent_get_typeof name
501
+ return gtype if gtype != 0
502
+ end
503
+
504
+ Vips::vips_image_get_typeof self, name
505
+ end
647
506
 
648
- # Get image coding.
649
- #
650
- # @return [Symbol] image coding
651
- def coding
652
- get "coding"
653
- end
507
+ # Get a metadata item from an image. Ruby types are constructed
508
+ # automatically from the `GValue`, if possible.
509
+ #
510
+ # For example, you can read the ICC profile from an image like this:
511
+ #
512
+ # ```
513
+ # profile = image.get "icc-profile-data"
514
+ # ```
515
+ #
516
+ # and profile will be an array containing the profile.
517
+ #
518
+ # @param name [String] Metadata field to get
519
+ # @return [Object] Value of field
520
+ def get name
521
+ # with old libvips, we must fetch properties (as opposed to
522
+ # metadata) via VipsObject
523
+ unless Vips::at_least_libvips?(8, 5)
524
+ return super if parent_get_typeof(name) != 0
525
+ end
526
+
527
+ gvalue = GObject::GValue.alloc
528
+ result = Vips::vips_image_get self, name, gvalue
529
+ raise Vips::Error if result != 0
530
+
531
+ gvalue.get
532
+ end
654
533
 
655
- # Get image filename, if any.
656
- #
657
- # @return [String] image filename
658
- def filename
659
- get "filename"
660
- end
534
+ # Get the names of all fields on an image. Use this to loop over all
535
+ # image metadata.
536
+ #
537
+ # @return [[String]] array of field names
538
+ def get_fields
539
+ # vips_image_get_fields() was added in libvips 8.5
540
+ return [] unless Vips.respond_to? :vips_image_get_fields
541
+
542
+ array = Vips::vips_image_get_fields self
543
+
544
+ names = []
545
+ p = array
546
+ until (q = p.read_pointer).null?
547
+ names << q.read_string
548
+ GLib::g_free q
549
+ p += FFI::Type::POINTER.size
550
+ end
551
+ GLib::g_free array
552
+
553
+ names
554
+ end
661
555
 
662
- # Get image xoffset.
663
- #
664
- # @return [Integer] image xoffset
665
- def xoffset
666
- get "xoffset"
667
- end
556
+ # Create a metadata item on an image of the specifed type. Ruby types
557
+ # are automatically transformed into the matching `GType`, if possible.
558
+ #
559
+ # For example, you can use this to set an image's ICC profile:
560
+ #
561
+ # ```
562
+ # x = y.set_type Vips::BLOB_TYPE, "icc-profile-data", profile
563
+ # ```
564
+ #
565
+ # where `profile` is an ICC profile held as a binary string object.
566
+ #
567
+ # @see set
568
+ # @param gtype [Integer] GType of item
569
+ # @param name [String] Metadata field to set
570
+ # @param value [Object] Value to set
571
+ def set_type gtype, name, value
572
+ gvalue = GObject::GValue.alloc
573
+ gvalue.init gtype
574
+ gvalue.set value
575
+ Vips::vips_image_set self, name, gvalue
576
+ end
668
577
 
669
- # Get image yoffset.
670
- #
671
- # @return [Integer] image yoffset
672
- def yoffset
673
- get "yoffset"
674
- end
578
+ # Set the value of a metadata item on an image. The metadata item must
579
+ # already exist. Ruby types are automatically transformed into the
580
+ # matching `GValue`, if possible.
581
+ #
582
+ # For example, you can use this to set an image's ICC profile:
583
+ #
584
+ # ```
585
+ # x = y.set "icc-profile-data", profile
586
+ # ```
587
+ #
588
+ # where `profile` is an ICC profile held as a binary string object.
589
+ #
590
+ # @see set_type
591
+ # @param name [String] Metadata field to set
592
+ # @param value [Object] Value to set
593
+ def set name, value
594
+ set_type get_typeof(name), name, value
595
+ end
675
596
 
676
- # Get image x resolution.
677
- #
678
- # @return [Float] image x resolution
679
- def xres
680
- get "xres"
681
- end
597
+ # Remove a metadata item from an image.
598
+ #
599
+ # @param name [String] Metadata field to remove
600
+ def remove name
601
+ Vips::vips_image_remove self, name
602
+ end
682
603
 
683
- # Get image y resolution.
684
- #
685
- # @return [Float] image y resolution
686
- def yres
687
- get "yres"
688
- end
604
+ # compatibility: old name for get
605
+ def get_value name
606
+ get name
607
+ end
689
608
 
690
- # Get scale metadata.
691
- #
692
- # @return [Float] image scale
693
- def scale
694
- return 1 if get_typeof("scale") == 0
609
+ # compatibility: old name for set
610
+ def set_value name, value
611
+ set name, value
612
+ end
695
613
 
696
- get "scale"
697
- end
614
+ # Get image width, in pixels.
615
+ #
616
+ # @return [Integer] image width, in pixels
617
+ def width
618
+ get "width"
619
+ end
698
620
 
699
- # Get offset metadata.
700
- #
701
- # @return [Float] image offset
702
- def offset
703
- return 0 if get_typeof("offset") == 0
621
+ # Get image height, in pixels.
622
+ #
623
+ # @return [Integer] image height, in pixels
624
+ def height
625
+ get "height"
626
+ end
704
627
 
705
- get "offset"
706
- end
628
+ # Get number of image bands.
629
+ #
630
+ # @return [Integer] number of image bands
631
+ def bands
632
+ get "bands"
633
+ end
707
634
 
708
- # Get the image size.
709
- #
710
- # @return [Integer, Integer] image width and height
711
- def size
712
- [width, height]
713
- end
635
+ # Get image format.
636
+ #
637
+ # @return [Symbol] image format
638
+ def format
639
+ get "format"
640
+ end
714
641
 
715
- if Vips::at_least_libvips?(8, 5)
716
- # Detect if image has an alpha channel
717
- #
718
- # @return [Boolean] true if image has an alpha channel.
719
- def has_alpha?
720
- return Vips::vips_image_hasalpha(self) != 0
721
- end
722
- end
642
+ # Get image interpretation.
643
+ #
644
+ # @return [Symbol] image interpretation
645
+ def interpretation
646
+ get "interpretation"
647
+ end
723
648
 
724
- # vips_addalpha was added in libvips 8.6
725
- if Vips::at_least_libvips?(8, 6)
726
- # Append an alpha channel to an image.
727
- #
728
- # @return [Image] new image
729
- def add_alpha
730
- ptr = GenericPtr.new
731
- result = Vips::vips_addalpha self, ptr
732
- raise Vips::Error if result != 0
733
-
734
- Vips::Image.new ptr[:value]
735
- end
736
- end
649
+ # Get image coding.
650
+ #
651
+ # @return [Symbol] image coding
652
+ def coding
653
+ get "coding"
654
+ end
737
655
 
738
- # Copy an image to a memory area.
739
- #
740
- # This can be useful for reusing results, but can obviously use a lot of
741
- # memory for large images. See {Image#tilecache} for a way of caching
742
- # parts of an image.
743
- #
744
- # @return [Image] new memory image
745
- def copy_memory
746
- new_image = Vips::vips_image_copy_memory self
747
- Vips::Image.new new_image
748
- end
656
+ # Get image filename, if any.
657
+ #
658
+ # @return [String] image filename
659
+ def filename
660
+ get "filename"
661
+ end
749
662
 
750
- # Draw a point on an image.
751
- #
752
- # See {Image#draw_rect}.
753
- #
754
- # @return [Image] modified image
755
- def draw_point ink, left, top, opts = {}
756
- draw_rect ink, left, top, 1, 1, opts
757
- end
663
+ # Get image xoffset.
664
+ #
665
+ # @return [Integer] image xoffset
666
+ def xoffset
667
+ get "xoffset"
668
+ end
758
669
 
759
- # Add an image, constant or array.
760
- #
761
- # @param other [Image, Real, Array<Real>] Thing to add to self
762
- # @return [Image] result of addition
763
- def + other
764
- other.is_a?(Vips::Image) ?
765
- add(other) : linear(1, other)
766
- end
670
+ # Get image yoffset.
671
+ #
672
+ # @return [Integer] image yoffset
673
+ def yoffset
674
+ get "yoffset"
675
+ end
767
676
 
768
- # Subtract an image, constant or array.
769
- #
770
- # @param other [Image, Real, Array<Real>] Thing to subtract from self
771
- # @return [Image] result of subtraction
772
- def - other
773
- other.is_a?(Vips::Image) ?
774
- subtract(other) : linear(1, Image::smap(other) {|x| x * -1})
775
- end
677
+ # Get image x resolution.
678
+ #
679
+ # @return [Float] image x resolution
680
+ def xres
681
+ get "xres"
682
+ end
776
683
 
777
- # Multiply an image, constant or array.
778
- #
779
- # @param other [Image, Real, Array<Real>] Thing to multiply by self
780
- # @return [Image] result of multiplication
781
- def * other
782
- other.is_a?(Vips::Image) ?
783
- multiply(other) : linear(other, 0)
784
- end
684
+ # Get image y resolution.
685
+ #
686
+ # @return [Float] image y resolution
687
+ def yres
688
+ get "yres"
689
+ end
785
690
 
786
- # Divide an image, constant or array.
787
- #
788
- # @param other [Image, Real, Array<Real>] Thing to divide self by
789
- # @return [Image] result of division
790
- def / other
791
- other.is_a?(Vips::Image) ?
792
- divide(other) : linear(Image::smap(other) {|x| 1.0 / x}, 0)
793
- end
691
+ # Get scale metadata.
692
+ #
693
+ # @return [Float] image scale
694
+ def scale
695
+ return 1 if get_typeof("scale") == 0
794
696
 
795
- # Remainder after integer division with an image, constant or array.
796
- #
797
- # @param other [Image, Real, Array<Real>] self modulo this
798
- # @return [Image] result of modulo
799
- def % other
800
- other.is_a?(Vips::Image) ?
801
- remainder(other) : remainder_const(other)
802
- end
697
+ get "scale"
698
+ end
803
699
 
804
- # Raise to power of an image, constant or array.
805
- #
806
- # @param other [Image, Real, Array<Real>] self to the power of this
807
- # @return [Image] result of power
808
- def ** other
809
- call_enum "math2", other, :pow
810
- end
700
+ # Get offset metadata.
701
+ #
702
+ # @return [Float] image offset
703
+ def offset
704
+ return 0 if get_typeof("offset") == 0
811
705
 
812
- # Integer left shift with an image, constant or array.
813
- #
814
- # @param other [Image, Real, Array<Real>] shift left by this much
815
- # @return [Image] result of left shift
816
- def << other
817
- call_enum "boolean", other, :lshift
818
- end
706
+ get "offset"
707
+ end
819
708
 
820
- # Integer right shift with an image, constant or array.
821
- #
822
- # @param other [Image, Real, Array<Real>] shift right by this much
823
- # @return [Image] result of right shift
824
- def >> other
825
- call_enum "boolean", other, :rshift
826
- end
709
+ # Get the image size.
710
+ #
711
+ # @return [Integer, Integer] image width and height
712
+ def size
713
+ [width, height]
714
+ end
827
715
 
828
- # Integer bitwise OR with an image, constant or array.
829
- #
830
- # @param other [Image, Real, Array<Real>] bitwise OR with this
831
- # @return [Image] result of bitwise OR
832
- def | other
833
- call_enum "boolean", other, :or
834
- end
716
+ if Vips::at_least_libvips?(8, 5)
717
+ # Detect if image has an alpha channel
718
+ #
719
+ # @return [Boolean] true if image has an alpha channel.
720
+ def has_alpha?
721
+ return Vips::vips_image_hasalpha(self) != 0
722
+ end
723
+ end
835
724
 
836
- # Integer bitwise AND with an image, constant or array.
837
- #
838
- # @param other [Image, Real, Array<Real>] bitwise AND with this
839
- # @return [Image] result of bitwise AND
840
- def & other
841
- call_enum "boolean", other, :and
842
- end
725
+ # vips_addalpha was added in libvips 8.6
726
+ if Vips::at_least_libvips?(8, 6)
727
+ # Append an alpha channel to an image.
728
+ #
729
+ # @return [Image] new image
730
+ def add_alpha
731
+ ptr = GenericPtr.new
732
+ result = Vips::vips_addalpha self, ptr
733
+ raise Vips::Error if result != 0
734
+
735
+ Vips::Image.new ptr[:value]
736
+ end
737
+ end
843
738
 
844
- # Integer bitwise EOR with an image, constant or array.
845
- #
846
- # @param other [Image, Real, Array<Real>] bitwise EOR with this
847
- # @return [Image] result of bitwise EOR
848
- def ^ other
849
- call_enum "boolean", other, :eor
850
- end
739
+ # Copy an image to a memory area.
740
+ #
741
+ # This can be useful for reusing results, but can obviously use a lot of
742
+ # memory for large images. See {Image#tilecache} for a way of caching
743
+ # parts of an image.
744
+ #
745
+ # @return [Image] new memory image
746
+ def copy_memory
747
+ new_image = Vips::vips_image_copy_memory self
748
+ Vips::Image.new new_image
749
+ end
851
750
 
852
- # Equivalent to image ^ -1
853
- #
854
- # @return [Image] image with bits flipped
855
- def !
856
- self ^ -1
857
- end
751
+ # Draw a point on an image.
752
+ #
753
+ # See {Image#draw_rect}.
754
+ #
755
+ # @return [Image] modified image
756
+ def draw_point ink, left, top, **opts
757
+ draw_rect ink, left, top, 1, 1, opts
758
+ end
858
759
 
859
- # Equivalent to image ^ -1
860
- #
861
- # @return [Image] image with bits flipped
862
- def ~
863
- self ^ -1
864
- end
760
+ # Add an image, constant or array.
761
+ #
762
+ # @param other [Image, Real, Array<Real>] Thing to add to self
763
+ # @return [Image] result of addition
764
+ def + other
765
+ other.is_a?(Vips::Image) ?
766
+ add(other) : linear(1, other)
767
+ end
865
768
 
866
- # @return [Image] image
867
- def +@
868
- self
869
- end
769
+ # Subtract an image, constant or array.
770
+ #
771
+ # @param other [Image, Real, Array<Real>] Thing to subtract from self
772
+ # @return [Image] result of subtraction
773
+ def - other
774
+ other.is_a?(Vips::Image) ?
775
+ subtract(other) : linear(1, Image::smap(other) {|x| x * -1})
776
+ end
870
777
 
871
- # Equivalent to image * -1
872
- #
873
- # @return [Image] negative of image
874
- def -@
875
- self * -1
876
- end
778
+ # Multiply an image, constant or array.
779
+ #
780
+ # @param other [Image, Real, Array<Real>] Thing to multiply by self
781
+ # @return [Image] result of multiplication
782
+ def * other
783
+ other.is_a?(Vips::Image) ?
784
+ multiply(other) : linear(other, 0)
785
+ end
877
786
 
878
- # Relational less than with an image, constant or array.
879
- #
880
- # @param other [Image, Real, Array<Real>] relational less than with this
881
- # @return [Image] result of less than
882
- def < other
883
- call_enum "relational", other, :less
884
- end
787
+ # Divide an image, constant or array.
788
+ #
789
+ # @param other [Image, Real, Array<Real>] Thing to divide self by
790
+ # @return [Image] result of division
791
+ def / other
792
+ other.is_a?(Vips::Image) ?
793
+ divide(other) : linear(Image::smap(other) {|x| 1.0 / x}, 0)
794
+ end
885
795
 
886
- # Relational less than or equal to with an image, constant or array.
887
- #
888
- # @param other [Image, Real, Array<Real>] relational less than or
889
- # equal to with this
890
- # @return [Image] result of less than or equal to
891
- def <= other
892
- call_enum "relational", other, :lesseq
893
- end
796
+ # Remainder after integer division with an image, constant or array.
797
+ #
798
+ # @param other [Image, Real, Array<Real>] self modulo this
799
+ # @return [Image] result of modulo
800
+ def % other
801
+ other.is_a?(Vips::Image) ?
802
+ remainder(other) : remainder_const(other)
803
+ end
894
804
 
895
- # Relational more than with an image, constant or array.
896
- #
897
- # @param other [Image, Real, Array<Real>] relational more than with this
898
- # @return [Image] result of more than
899
- def > other
900
- call_enum "relational", other, :more
901
- end
805
+ # Raise to power of an image, constant or array.
806
+ #
807
+ # @param other [Image, Real, Array<Real>] self to the power of this
808
+ # @return [Image] result of power
809
+ def ** other
810
+ call_enum "math2", other, :pow
811
+ end
902
812
 
903
- # Relational more than or equal to with an image, constant or array.
904
- #
905
- # @param other [Image, Real, Array<Real>] relational more than or
906
- # equal to with this
907
- # @return [Image] result of more than or equal to
908
- def >= other
909
- call_enum "relational", other, :moreeq
910
- end
813
+ # Integer left shift with an image, constant or array.
814
+ #
815
+ # @param other [Image, Real, Array<Real>] shift left by this much
816
+ # @return [Image] result of left shift
817
+ def << other
818
+ call_enum "boolean", other, :lshift
819
+ end
911
820
 
912
- # Compare equality to nil, an image, constant or array.
913
- #
914
- # @param other [nil, Image, Real, Array<Real>] test equality to this
915
- # @return [Image] result of equality
916
- def == other
917
- # for equality, we must allow tests against nil
918
- if other == nil
919
- false
920
- else
921
- call_enum "relational", other, :equal
922
- end
923
- end
821
+ # Integer right shift with an image, constant or array.
822
+ #
823
+ # @param other [Image, Real, Array<Real>] shift right by this much
824
+ # @return [Image] result of right shift
825
+ def >> other
826
+ call_enum "boolean", other, :rshift
827
+ end
924
828
 
925
- # Compare inequality to nil, an image, constant or array.
926
- #
927
- # @param other [nil, Image, Real, Array<Real>] test inequality to this
928
- # @return [Image] result of inequality
929
- def != other
930
- # for equality, we must allow tests against nil
931
- if other == nil
932
- true
933
- else
934
- call_enum "relational", other, :noteq
935
- end
936
- end
829
+ # Integer bitwise OR with an image, constant or array.
830
+ #
831
+ # @param other [Image, Real, Array<Real>] bitwise OR with this
832
+ # @return [Image] result of bitwise OR
833
+ def | other
834
+ call_enum "boolean", other, :or
835
+ end
937
836
 
938
- # Fetch bands using a number or a range
939
- #
940
- # @param index [Numeric, Range] extract these band(s)
941
- # @return [Image] extracted band(s)
942
- def [] index
943
- if index.is_a? Range
944
- n = index.size
945
- extract_band index.begin, n: n
946
- elsif index.is_a? Numeric
947
- extract_band index
948
- else
949
- raise Vips::Error, "[] index is not range or numeric."
950
- end
951
- end
837
+ # Integer bitwise AND with an image, constant or array.
838
+ #
839
+ # @param other [Image, Real, Array<Real>] bitwise AND with this
840
+ # @return [Image] result of bitwise AND
841
+ def & other
842
+ call_enum "boolean", other, :and
843
+ end
952
844
 
953
- # Convert to an Array. This will be slow for large images.
954
- #
955
- # @return [Array] array of Fixnum
956
- def to_a
957
- # we render the image to a big string, then unpack
958
- # as a Ruby array of the correct type
959
- memory = write_to_memory
960
-
961
- # make the template for unpack
962
- template = {
963
- :char => 'c',
964
- :uchar => 'C',
965
- :short => 's_',
966
- :ushort => 'S_',
967
- :int => 'i_',
968
- :uint => 'I_',
969
- :float => 'f',
970
- :double => 'd',
971
- :complex => 'f',
972
- :dpcomplex => 'd'
973
- }[format] + '*'
974
-
975
- # and unpack into something like [1, 2, 3, 4 ..]
976
- array = memory.unpack(template)
977
-
978
- # gather band elements together
979
- pixel_array = array.each_slice(bands).to_a
980
-
981
- # build rows
982
- row_array = pixel_array.each_slice(width).to_a
983
-
984
- return row_array
985
- end
845
+ # Integer bitwise EOR with an image, constant or array.
846
+ #
847
+ # @param other [Image, Real, Array<Real>] bitwise EOR with this
848
+ # @return [Image] result of bitwise EOR
849
+ def ^ other
850
+ call_enum "boolean", other, :eor
851
+ end
986
852
 
987
- # Return the largest integral value not greater than the argument.
988
- #
989
- # @return [Image] floor of image
990
- def floor
991
- round :floor
992
- end
853
+ # Equivalent to image ^ -1
854
+ #
855
+ # @return [Image] image with bits flipped
856
+ def !
857
+ self ^ -1
858
+ end
993
859
 
994
- # Return the smallest integral value not less than the argument.
995
- #
996
- # @return [Image] ceil of image
997
- def ceil
998
- round :ceil
999
- end
860
+ # Equivalent to image ^ -1
861
+ #
862
+ # @return [Image] image with bits flipped
863
+ def ~
864
+ self ^ -1
865
+ end
1000
866
 
1001
- # Return the nearest integral value.
1002
- #
1003
- # @return [Image] rint of image
1004
- def rint
1005
- round :rint
1006
- end
867
+ # @return [Image] image
868
+ def +@
869
+ self
870
+ end
1007
871
 
1008
- # AND the bands of an image together
1009
- #
1010
- # @return [Image] all bands ANDed together
1011
- def bandand
1012
- bandbool :and
1013
- end
872
+ # Equivalent to image * -1
873
+ #
874
+ # @return [Image] negative of image
875
+ def -@
876
+ self * -1
877
+ end
1014
878
 
1015
- # OR the bands of an image together
1016
- #
1017
- # @return [Image] all bands ORed together
1018
- def bandor
1019
- bandbool :or
1020
- end
879
+ # Relational less than with an image, constant or array.
880
+ #
881
+ # @param other [Image, Real, Array<Real>] relational less than with this
882
+ # @return [Image] result of less than
883
+ def < other
884
+ call_enum "relational", other, :less
885
+ end
1021
886
 
1022
- # EOR the bands of an image together
1023
- #
1024
- # @return [Image] all bands EORed together
1025
- def bandeor
1026
- bandbool :eor
1027
- end
887
+ # Relational less than or equal to with an image, constant or array.
888
+ #
889
+ # @param other [Image, Real, Array<Real>] relational less than or
890
+ # equal to with this
891
+ # @return [Image] result of less than or equal to
892
+ def <= other
893
+ call_enum "relational", other, :lesseq
894
+ end
1028
895
 
1029
- # Split an n-band image into n separate images.
1030
- #
1031
- # @return [Array<Image>] Array of n one-band images
1032
- def bandsplit
1033
- (0...bands).map {|i| extract_band i}
1034
- end
896
+ # Relational more than with an image, constant or array.
897
+ #
898
+ # @param other [Image, Real, Array<Real>] relational more than with this
899
+ # @return [Image] result of more than
900
+ def > other
901
+ call_enum "relational", other, :more
902
+ end
1035
903
 
1036
- # Join a set of images bandwise.
1037
- #
1038
- # @param other [Image, Array<Image>, Real, Array<Real>] bands to append
1039
- # @return [Image] many band image
1040
- def bandjoin other
1041
- unless other.is_a? Array
1042
- other = [other]
1043
- end
904
+ # Relational more than or equal to with an image, constant or array.
905
+ #
906
+ # @param other [Image, Real, Array<Real>] relational more than or
907
+ # equal to with this
908
+ # @return [Image] result of more than or equal to
909
+ def >= other
910
+ call_enum "relational", other, :moreeq
911
+ end
1044
912
 
1045
- # if other is just Numeric, we can use bandjoin_const
1046
- not_all_real = !other.all?{|x| x.is_a? Numeric}
913
+ # Compare equality to nil, an image, constant or array.
914
+ #
915
+ # @param other [nil, Image, Real, Array<Real>] test equality to this
916
+ # @return [Image] result of equality
917
+ def == other
918
+ # for equality, we must allow tests against nil
919
+ if other == nil
920
+ false
921
+ else
922
+ call_enum "relational", other, :equal
923
+ end
924
+ end
1047
925
 
1048
- if not_all_real
1049
- Vips::Image.bandjoin([self] + other)
1050
- else
1051
- bandjoin_const other
1052
- end
1053
- end
926
+ # Compare inequality to nil, an image, constant or array.
927
+ #
928
+ # @param other [nil, Image, Real, Array<Real>] test inequality to this
929
+ # @return [Image] result of inequality
930
+ def != other
931
+ # for equality, we must allow tests against nil
932
+ if other == nil
933
+ true
934
+ else
935
+ call_enum "relational", other, :noteq
936
+ end
937
+ end
1054
938
 
1055
- # Composite a set of images with a set of blend modes.
1056
- #
1057
- # @param other [Image, Array<Image>, Real, Array<Real>] bands to append
1058
- # @return [Image] many band image
1059
- def composite other, mode, opts = {}
1060
- unless other.is_a? Array
1061
- other = [other]
1062
- end
1063
- unless mode.is_a? Array
1064
- mode = [mode]
1065
- end
939
+ # Fetch bands using a number or a range
940
+ #
941
+ # @param index [Numeric, Range] extract these band(s)
942
+ # @return [Image] extracted band(s)
943
+ def [] index
944
+ if index.is_a? Range
945
+ n = index.size
946
+ extract_band index.begin, n: n
947
+ elsif index.is_a? Numeric
948
+ extract_band index
949
+ else
950
+ raise Vips::Error, "[] index is not range or numeric."
951
+ end
952
+ end
1066
953
 
1067
- mode = mode.map do |x|
1068
- GObject::GValue.from_nick Vips::BLEND_MODE_TYPE, x
1069
- end
954
+ # Convert to an Array. This will be slow for large images.
955
+ #
956
+ # @return [Array] array of Fixnum
957
+ def to_a
958
+ # we render the image to a big string, then unpack
959
+ # as a Ruby array of the correct type
960
+ memory = write_to_memory
961
+
962
+ # make the template for unpack
963
+ template = {
964
+ :char => 'c',
965
+ :uchar => 'C',
966
+ :short => 's_',
967
+ :ushort => 'S_',
968
+ :int => 'i_',
969
+ :uint => 'I_',
970
+ :float => 'f',
971
+ :double => 'd',
972
+ :complex => 'f',
973
+ :dpcomplex => 'd'
974
+ }[format] + '*'
975
+
976
+ # and unpack into something like [1, 2, 3, 4 ..]
977
+ array = memory.unpack(template)
978
+
979
+ # gather band elements together
980
+ pixel_array = array.each_slice(bands).to_a
981
+
982
+ # build rows
983
+ row_array = pixel_array.each_slice(width).to_a
984
+
985
+ return row_array
986
+ end
1070
987
 
1071
- Vips::Image.composite([self] + other, mode, opts)
1072
- end
988
+ # Return the largest integral value not greater than the argument.
989
+ #
990
+ # @return [Image] floor of image
991
+ def floor
992
+ round :floor
993
+ end
1073
994
 
1074
- # Return the coordinates of the image maximum.
1075
- #
1076
- # @return [Real, Real, Real] maximum value, x coordinate of maximum, y
1077
- # coordinate of maximum
1078
- def maxpos
1079
- v, opts = max x: true, y: true
1080
- x = opts['x']
1081
- y = opts['y']
1082
- return v, x, y
1083
- end
995
+ # Return the smallest integral value not less than the argument.
996
+ #
997
+ # @return [Image] ceil of image
998
+ def ceil
999
+ round :ceil
1000
+ end
1084
1001
 
1085
- # Return the coordinates of the image minimum.
1086
- #
1087
- # @return [Real, Real, Real] minimum value, x coordinate of minimum, y
1088
- # coordinate of minimum
1089
- def minpos
1090
- v, opts = min x: true, y: true
1091
- x = opts['x']
1092
- y = opts['y']
1093
- return v, x, y
1094
- end
1002
+ # Return the nearest integral value.
1003
+ #
1004
+ # @return [Image] rint of image
1005
+ def rint
1006
+ round :rint
1007
+ end
1095
1008
 
1096
- # get the value of a pixel as an array
1097
- #
1098
- # @param x [Integer] x coordinate to sample
1099
- # @param y [Integer] y coordinate to sample
1100
- # @return [Array<Float>] the pixel values as an array
1101
- def getpoint x, y
1102
- # vips has an operation that does this, but we can't call it via
1103
- # gobject-introspection 3.1 since it's missing array double
1104
- # get
1105
- #
1106
- # remove this def when gobject-introspection updates
1107
- crop(x, y, 1, 1).bandsplit.map(&:avg)
1108
- end
1009
+ # AND the bands of an image together
1010
+ #
1011
+ # @return [Image] all bands ANDed together
1012
+ def bandand
1013
+ bandbool :and
1014
+ end
1109
1015
 
1110
- # a median filter
1111
- #
1112
- # @param size [Integer] size of filter window
1113
- # @return [Image] result of median filter
1114
- def median size = 3
1115
- rank size, size, (size * size) / 2
1116
- end
1016
+ # OR the bands of an image together
1017
+ #
1018
+ # @return [Image] all bands ORed together
1019
+ def bandor
1020
+ bandbool :or
1021
+ end
1117
1022
 
1118
- # Return the real part of a complex image.
1119
- #
1120
- # @return [Image] real part of complex image
1121
- def real
1122
- complexget :real
1123
- end
1023
+ # EOR the bands of an image together
1024
+ #
1025
+ # @return [Image] all bands EORed together
1026
+ def bandeor
1027
+ bandbool :eor
1028
+ end
1124
1029
 
1125
- # Return the imaginary part of a complex image.
1126
- #
1127
- # @return [Image] imaginary part of complex image
1128
- def imag
1129
- complexget :imag
1130
- end
1030
+ # Split an n-band image into n separate images.
1031
+ #
1032
+ # @return [Array<Image>] Array of n one-band images
1033
+ def bandsplit
1034
+ (0...bands).map {|i| extract_band i}
1035
+ end
1131
1036
 
1132
- # Return an image with rectangular pixels converted to polar.
1133
- #
1134
- # The image
1135
- # can be complex, in which case the return image will also be complex,
1136
- # or must have an even number of bands, in which case pairs of
1137
- # bands are treated as (x, y) coordinates.
1138
- #
1139
- # @see xyz
1140
- # @return [Image] image converted to polar coordinates
1141
- def polar
1142
- Image::run_cmplx(self) {|x| x.complex :polar}
1143
- end
1037
+ # Join a set of images bandwise.
1038
+ #
1039
+ # @param other [Image, Array<Image>, Real, Array<Real>] bands to append
1040
+ # @return [Image] many band image
1041
+ def bandjoin other
1042
+ unless other.is_a? Array
1043
+ other = [other]
1044
+ end
1045
+
1046
+ # if other is just Numeric, we can use bandjoin_const
1047
+ not_all_real = !other.all?{|x| x.is_a? Numeric}
1048
+
1049
+ if not_all_real
1050
+ Vips::Image.bandjoin([self] + other)
1051
+ else
1052
+ bandjoin_const other
1053
+ end
1054
+ end
1144
1055
 
1145
- # Return an image with polar pixels converted to rectangular.
1146
- #
1147
- # The image
1148
- # can be complex, in which case the return image will also be complex,
1149
- # or must have an even number of bands, in which case pairs of
1150
- # bands are treated as (x, y) coordinates.
1151
- #
1152
- # @see xyz
1153
- # @return [Image] image converted to rectangular coordinates
1154
- def rect
1155
- Image::run_cmplx(self) {|x| x.complex :rect}
1156
- end
1056
+ # Composite a set of images with a set of blend modes.
1057
+ #
1058
+ # @param overlay [Image, Array<Image>] images to composite
1059
+ # @param mode [BlendMode, Array<BlendMode>] blend modes to use
1060
+ # @param opts [Hash] Set of options
1061
+ # @option opts [Vips::Interpretation] :compositing_space Composite images in this colour space
1062
+ # @option opts [Boolean] :premultiplied Images have premultiplied alpha
1063
+ # @return [Image] blended image
1064
+ def composite overlay, mode, **opts
1065
+ unless overlay.is_a? Array
1066
+ overlay = [overlay]
1067
+ end
1068
+ unless mode.is_a? Array
1069
+ mode = [mode]
1070
+ end
1071
+
1072
+ mode = mode.map do |x|
1073
+ GObject::GValue.from_nick Vips::BLEND_MODE_TYPE, x
1074
+ end
1075
+
1076
+ Vips::Image.composite([self] + overlay, mode, opts)
1077
+ end
1157
1078
 
1158
- # Return the complex conjugate of an image.
1159
- #
1160
- # The image
1161
- # can be complex, in which case the return image will also be complex,
1162
- # or must have an even number of bands, in which case pairs of
1163
- # bands are treated as (x, y) coordinates.
1164
- #
1165
- # @return [Image] complex conjugate
1166
- def conj
1167
- Image::run_cmplx(self) {|x| x.complex :conj}
1168
- end
1079
+ # Return the coordinates of the image maximum.
1080
+ #
1081
+ # @return [Real, Real, Real] maximum value, x coordinate of maximum, y
1082
+ # coordinate of maximum
1083
+ def maxpos
1084
+ v, opts = max x: true, y: true
1085
+ x = opts['x']
1086
+ y = opts['y']
1087
+ return v, x, y
1088
+ end
1169
1089
 
1170
- # Calculate the cross phase of two images.
1171
- #
1172
- # @param other [Image, Real, Array<Real>] cross phase with this
1173
- # @return [Image] cross phase
1174
- def cross_phase other
1175
- complex2 other, :cross_phase
1176
- end
1090
+ # Return the coordinates of the image minimum.
1091
+ #
1092
+ # @return [Real, Real, Real] minimum value, x coordinate of minimum, y
1093
+ # coordinate of minimum
1094
+ def minpos
1095
+ v, opts = min x: true, y: true
1096
+ x = opts['x']
1097
+ y = opts['y']
1098
+ return v, x, y
1099
+ end
1177
1100
 
1178
- # Return the sine of an image in degrees.
1179
- #
1180
- # @return [Image] sine of each pixel
1181
- def sin
1182
- math :sin
1183
- end
1101
+ # a median filter
1102
+ #
1103
+ # @param size [Integer] size of filter window
1104
+ # @return [Image] result of median filter
1105
+ def median size = 3
1106
+ rank size, size, (size * size) / 2
1107
+ end
1184
1108
 
1185
- # Return the cosine of an image in degrees.
1186
- #
1187
- # @return [Image] cosine of each pixel
1188
- def cos
1189
- math :cos
1190
- end
1109
+ # Return the real part of a complex image.
1110
+ #
1111
+ # @return [Image] real part of complex image
1112
+ def real
1113
+ complexget :real
1114
+ end
1191
1115
 
1192
- # Return the tangent of an image in degrees.
1193
- #
1194
- # @return [Image] tangent of each pixel
1195
- def tan
1196
- math :tan
1197
- end
1116
+ # Return the imaginary part of a complex image.
1117
+ #
1118
+ # @return [Image] imaginary part of complex image
1119
+ def imag
1120
+ complexget :imag
1121
+ end
1198
1122
 
1199
- # Return the inverse sine of an image in degrees.
1200
- #
1201
- # @return [Image] inverse sine of each pixel
1202
- def asin
1203
- math :asin
1204
- end
1123
+ # Return an image with rectangular pixels converted to polar.
1124
+ #
1125
+ # The image
1126
+ # can be complex, in which case the return image will also be complex,
1127
+ # or must have an even number of bands, in which case pairs of
1128
+ # bands are treated as (x, y) coordinates.
1129
+ #
1130
+ # @see xyz
1131
+ # @return [Image] image converted to polar coordinates
1132
+ def polar
1133
+ Image::run_cmplx(self) {|x| x.complex :polar}
1134
+ end
1205
1135
 
1206
- # Return the inverse cosine of an image in degrees.
1207
- #
1208
- # @return [Image] inverse cosine of each pixel
1209
- def acos
1210
- math :acos
1211
- end
1136
+ # Return an image with polar pixels converted to rectangular.
1137
+ #
1138
+ # The image
1139
+ # can be complex, in which case the return image will also be complex,
1140
+ # or must have an even number of bands, in which case pairs of
1141
+ # bands are treated as (x, y) coordinates.
1142
+ #
1143
+ # @see xyz
1144
+ # @return [Image] image converted to rectangular coordinates
1145
+ def rect
1146
+ Image::run_cmplx(self) {|x| x.complex :rect}
1147
+ end
1212
1148
 
1213
- # Return the inverse tangent of an image in degrees.
1214
- #
1215
- # @return [Image] inverse tangent of each pixel
1216
- def atan
1217
- math :atan
1218
- end
1149
+ # Return the complex conjugate of an image.
1150
+ #
1151
+ # The image
1152
+ # can be complex, in which case the return image will also be complex,
1153
+ # or must have an even number of bands, in which case pairs of
1154
+ # bands are treated as (x, y) coordinates.
1155
+ #
1156
+ # @return [Image] complex conjugate
1157
+ def conj
1158
+ Image::run_cmplx(self) {|x| x.complex :conj}
1159
+ end
1219
1160
 
1220
- # Return the natural log of an image.
1221
- #
1222
- # @return [Image] natural log of each pixel
1223
- def log
1224
- math :log
1225
- end
1161
+ # Calculate the cross phase of two images.
1162
+ #
1163
+ # @param other [Image, Real, Array<Real>] cross phase with this
1164
+ # @return [Image] cross phase
1165
+ def cross_phase other
1166
+ complex2 other, :cross_phase
1167
+ end
1226
1168
 
1227
- # Return the log base 10 of an image.
1228
- #
1229
- # @return [Image] base 10 log of each pixel
1230
- def log10
1231
- math :log10
1232
- end
1169
+ # Return the sine of an image in degrees.
1170
+ #
1171
+ # @return [Image] sine of each pixel
1172
+ def sin
1173
+ math :sin
1174
+ end
1233
1175
 
1234
- # Return e ** pixel.
1235
- #
1236
- # @return [Image] e ** pixel
1237
- def exp
1238
- math :exp
1239
- end
1176
+ # Return the cosine of an image in degrees.
1177
+ #
1178
+ # @return [Image] cosine of each pixel
1179
+ def cos
1180
+ math :cos
1181
+ end
1240
1182
 
1241
- # Return 10 ** pixel.
1242
- #
1243
- # @return [Image] 10 ** pixel
1244
- def exp10
1245
- math :exp10
1246
- end
1183
+ # Return the tangent of an image in degrees.
1184
+ #
1185
+ # @return [Image] tangent of each pixel
1186
+ def tan
1187
+ math :tan
1188
+ end
1247
1189
 
1248
- # Flip horizontally.
1249
- #
1250
- # @return [Image] image flipped horizontally
1251
- def fliphor
1252
- flip :horizontal
1253
- end
1190
+ # Return the inverse sine of an image in degrees.
1191
+ #
1192
+ # @return [Image] inverse sine of each pixel
1193
+ def asin
1194
+ math :asin
1195
+ end
1254
1196
 
1255
- # Flip vertically.
1256
- #
1257
- # @return [Image] image flipped vertically
1258
- def flipver
1259
- flip :vertical
1260
- end
1197
+ # Return the inverse cosine of an image in degrees.
1198
+ #
1199
+ # @return [Image] inverse cosine of each pixel
1200
+ def acos
1201
+ math :acos
1202
+ end
1261
1203
 
1262
- # Erode with a structuring element.
1263
- #
1264
- # The structuring element must be an array with 0 for black, 255 for
1265
- # white and 128 for don't care.
1266
- #
1267
- # @param mask [Image, Array<Real>, Array<Array<Real>>] structuring
1268
- # element
1269
- # @return [Image] eroded image
1270
- def erode mask
1271
- morph mask, :erode
1272
- end
1204
+ # Return the inverse tangent of an image in degrees.
1205
+ #
1206
+ # @return [Image] inverse tangent of each pixel
1207
+ def atan
1208
+ math :atan
1209
+ end
1273
1210
 
1274
- # Dilate with a structuring element.
1275
- #
1276
- # The structuring element must be an array with 0 for black, 255 for
1277
- # white and 128 for don't care.
1278
- #
1279
- # @param mask [Image, Array<Real>, Array<Array<Real>>] structuring
1280
- # element
1281
- # @return [Image] dilated image
1282
- def dilate mask
1283
- morph mask, :dilate
1284
- end
1211
+ # Return the natural log of an image.
1212
+ #
1213
+ # @return [Image] natural log of each pixel
1214
+ def log
1215
+ math :log
1216
+ end
1285
1217
 
1286
- # Rotate by 90 degrees clockwise.
1287
- #
1288
- # @return [Image] rotated image
1289
- def rot90
1290
- rot :d90
1291
- end
1218
+ # Return the log base 10 of an image.
1219
+ #
1220
+ # @return [Image] base 10 log of each pixel
1221
+ def log10
1222
+ math :log10
1223
+ end
1292
1224
 
1293
- # Rotate by 180 degrees clockwise.
1294
- #
1295
- # @return [Image] rotated image
1296
- def rot180
1297
- rot :d180
1298
- end
1225
+ # Return e ** pixel.
1226
+ #
1227
+ # @return [Image] e ** pixel
1228
+ def exp
1229
+ math :exp
1230
+ end
1299
1231
 
1300
- # Rotate by 270 degrees clockwise.
1301
- #
1302
- # @return [Image] rotated image
1303
- def rot270
1304
- rot :d270
1305
- end
1232
+ # Return 10 ** pixel.
1233
+ #
1234
+ # @return [Image] 10 ** pixel
1235
+ def exp10
1236
+ math :exp10
1237
+ end
1306
1238
 
1307
- # Select pixels from `th` if `self` is non-zero and from `el` if
1308
- # `self` is zero. Use the `:blend` option to fade smoothly
1309
- # between `th` and `el`.
1310
- #
1311
- # @param th [Image, Real, Array<Real>] true values
1312
- # @param el [Image, Real, Array<Real>] false values
1313
- # @param opts [Hash] set of options
1314
- # @option opts [Boolean] :blend (false) Blend smoothly between th and el
1315
- # @return [Image] merged image
1316
- def ifthenelse(th, el, opts = {})
1317
- match_image = [th, el, self].find {|x| x.is_a? Vips::Image}
1318
-
1319
- unless th.is_a? Vips::Image
1320
- th = Operation.imageize match_image, th
1321
- end
1322
- unless el.is_a? Vips::Image
1323
- el = Operation.imageize match_image, el
1324
- end
1239
+ # Flip horizontally.
1240
+ #
1241
+ # @return [Image] image flipped horizontally
1242
+ def fliphor
1243
+ flip :horizontal
1244
+ end
1325
1245
 
1326
- Vips::Operation.call "ifthenelse", [self, th, el], opts
1327
- end
1246
+ # Flip vertically.
1247
+ #
1248
+ # @return [Image] image flipped vertically
1249
+ def flipver
1250
+ flip :vertical
1251
+ end
1328
1252
 
1329
- # Scale an image to uchar. This is the vips `scale` operation, but
1330
- # renamed to avoid a clash with the `.scale` property.
1331
- #
1332
- # @param opts [Hash] Set of options
1333
- # @return [Vips::Image] Output image
1334
- def scaleimage opts = {}
1335
- Vips::Image.scale self, opts
1336
- end
1253
+ # Erode with a structuring element.
1254
+ #
1255
+ # The structuring element must be an array with 0 for black, 255 for
1256
+ # white and 128 for don't care.
1257
+ #
1258
+ # @param mask [Image, Array<Real>, Array<Array<Real>>] structuring
1259
+ # element
1260
+ # @return [Image] eroded image
1261
+ def erode mask
1262
+ morph mask, :erode
1263
+ end
1337
1264
 
1265
+ # Dilate with a structuring element.
1266
+ #
1267
+ # The structuring element must be an array with 0 for black, 255 for
1268
+ # white and 128 for don't care.
1269
+ #
1270
+ # @param mask [Image, Array<Real>, Array<Array<Real>>] structuring
1271
+ # element
1272
+ # @return [Image] dilated image
1273
+ def dilate mask
1274
+ morph mask, :dilate
1338
1275
  end
1339
1276
 
1340
- # This method generates yard comments for all the dynamically bound
1341
- # vips operations.
1277
+ # Rotate by 90 degrees clockwise.
1342
1278
  #
1343
- # Regenerate with something like:
1279
+ # @return [Image] rotated image
1280
+ def rot90
1281
+ rot :d90
1282
+ end
1283
+
1284
+ # Rotate by 180 degrees clockwise.
1344
1285
  #
1345
- # ```
1346
- # $ ruby > methods.rb
1347
- # require 'vips'; Vips::generate_yard
1348
- # ^D
1349
- # ```
1286
+ # @return [Image] rotated image
1287
+ def rot180
1288
+ rot :d180
1289
+ end
1350
1290
 
1351
- def self.generate_yard
1352
- # these have hand-written methods, see above
1353
- no_generate = ["scale", "bandjoin", "composite", "ifthenelse"]
1354
-
1355
- # map gobject's type names to Ruby
1356
- map_go_to_ruby = {
1357
- "gboolean" => "Boolean",
1358
- "gint" => "Integer",
1359
- "gdouble" => "Float",
1360
- "gfloat" => "Float",
1361
- "gchararray" => "String",
1362
- "VipsImage" => "Vips::Image",
1363
- "VipsInterpolate" => "Vips::Interpolate",
1364
- "VipsArrayDouble" => "Array<Double>",
1365
- "VipsArrayInt" => "Array<Integer>",
1366
- "VipsArrayImage" => "Array<Image>",
1367
- "VipsArrayString" => "Array<String>",
1368
- }
1369
-
1370
- generate_operation = lambda do |gtype, nickname, op|
1371
- op_flags = op.get_flags
1372
- return if (op_flags & OPERATION_DEPRECATED) != 0
1373
- return if no_generate.include? nickname
1374
- description = Vips::vips_object_get_description op
1375
-
1376
- # find and classify all the arguments the operator can take
1377
- required_input = []
1378
- optional_input = []
1379
- required_output = []
1380
- optional_output = []
1381
- member_x = nil
1382
- op.argument_map do |pspec, argument_class, argument_instance|
1383
- arg_flags = argument_class[:flags]
1384
- next if (arg_flags & ARGUMENT_CONSTRUCT) == 0
1385
- next if (arg_flags & ARGUMENT_DEPRECATED) != 0
1386
-
1387
- name = pspec[:name].tr("-", "_")
1388
- # 'in' as a param name confuses yard
1389
- name = "im" if name == "in"
1390
- gtype = pspec[:value_type]
1391
- fundamental = GObject::g_type_fundamental gtype
1392
- type_name = GObject::g_type_name gtype
1393
- if map_go_to_ruby.include? type_name
1394
- type_name = map_go_to_ruby[type_name]
1395
- end
1396
- if fundamental == GObject::GFLAGS_TYPE ||
1397
- fundamental == GObject::GENUM_TYPE
1398
- type_name = "Vips::" + type_name[/Vips(.*)/, 1]
1399
- end
1400
- blurb = GObject::g_param_spec_get_blurb pspec
1401
- value = {:name => name,
1402
- :flags => arg_flags,
1403
- :gtype => gtype,
1404
- :type_name => type_name,
1405
- :blurb => blurb}
1406
-
1407
- if (arg_flags & ARGUMENT_INPUT) != 0
1408
- if (arg_flags & ARGUMENT_REQUIRED) != 0
1409
- # note the first required input image, if any ... we
1410
- # will be a method of this instance
1411
- if !member_x && gtype == Vips::IMAGE_TYPE
1412
- member_x = value
1413
- else
1414
- required_input << value
1415
- end
1416
- else
1417
- optional_input << value
1418
- end
1419
- end
1420
-
1421
- # MODIFY INPUT args count as OUTPUT as well
1422
- if (arg_flags & ARGUMENT_OUTPUT) != 0 ||
1423
- ((arg_flags & ARGUMENT_INPUT) != 0 &&
1424
- (arg_flags & ARGUMENT_MODIFY) != 0)
1425
- if (arg_flags & ARGUMENT_REQUIRED) != 0
1426
- required_output << value
1427
- else
1428
- optional_output << value
1429
- end
1430
- end
1291
+ # Rotate by 270 degrees clockwise.
1292
+ #
1293
+ # @return [Image] rotated image
1294
+ def rot270
1295
+ rot :d270
1296
+ end
1431
1297
 
1432
- end
1298
+ # Select pixels from `th` if `self` is non-zero and from `el` if
1299
+ # `self` is zero. Use the `:blend` option to fade smoothly
1300
+ # between `th` and `el`.
1301
+ #
1302
+ # @param th [Image, Real, Array<Real>] true values
1303
+ # @param el [Image, Real, Array<Real>] false values
1304
+ # @param opts [Hash] set of options
1305
+ # @option opts [Boolean] :blend (false) Blend smoothly between th and el
1306
+ # @return [Image] merged image
1307
+ def ifthenelse(th, el, **opts)
1308
+ match_image = [th, el, self].find {|x| x.is_a? Vips::Image}
1309
+
1310
+ unless th.is_a? Vips::Image
1311
+ th = Operation.imageize match_image, th
1312
+ end
1313
+ unless el.is_a? Vips::Image
1314
+ el = Operation.imageize match_image, el
1315
+ end
1316
+
1317
+ Vips::Operation.call "ifthenelse", [self, th, el], opts
1318
+ end
1433
1319
 
1434
- print "# @!method "
1435
- print "self." unless member_x
1436
- print "#{nickname}("
1437
- print required_input.map{|x| x[:name]}.join(", ")
1438
- print ", " if required_input.length > 0
1439
- puts "opts = {})"
1320
+ # Scale an image to uchar. This is the vips `scale` operation, but
1321
+ # renamed to avoid a clash with the `.scale` property.
1322
+ #
1323
+ # @param opts [Hash] Set of options
1324
+ # @return [Vips::Image] Output image
1325
+ def scaleimage **opts
1326
+ Vips::Image.scale self, opts
1327
+ end
1440
1328
 
1441
- puts "# #{description.capitalize}."
1329
+ end
1330
+ end
1442
1331
 
1443
- required_input.each do |arg|
1444
- puts "# @param #{arg[:name]} [#{arg[:type_name]}] " +
1445
- "#{arg[:blurb]}"
1446
- end
1332
+ module Vips
1447
1333
 
1448
- puts "# @param opts [Hash] Set of options"
1449
- optional_input.each do |arg|
1450
- puts "# @option opts [#{arg[:type_name]}] :#{arg[:name]} " +
1451
- "#{arg[:blurb]}"
1452
- end
1453
- optional_output.each do |arg|
1454
- print "# @option opts [#{arg[:type_name]}] :#{arg[:name]}"
1455
- puts " Output #{arg[:blurb]}"
1334
+ # This method generates yard comments for all the dynamically bound
1335
+ # vips operations.
1336
+ #
1337
+ # Regenerate with something like:
1338
+ #
1339
+ # ```
1340
+ # $ ruby > methods.rb
1341
+ # require 'vips'; Vips::generate_yard
1342
+ # ^D
1343
+ # ```
1344
+
1345
+ def self.generate_yard
1346
+ # these have hand-written methods, see above
1347
+ no_generate = ["scale", "bandjoin", "composite", "ifthenelse"]
1348
+
1349
+ # map gobject's type names to Ruby
1350
+ map_go_to_ruby = {
1351
+ "gboolean" => "Boolean",
1352
+ "gint" => "Integer",
1353
+ "gdouble" => "Float",
1354
+ "gfloat" => "Float",
1355
+ "gchararray" => "String",
1356
+ "VipsImage" => "Vips::Image",
1357
+ "VipsInterpolate" => "Vips::Interpolate",
1358
+ "VipsArrayDouble" => "Array<Double>",
1359
+ "VipsArrayInt" => "Array<Integer>",
1360
+ "VipsArrayImage" => "Array<Image>",
1361
+ "VipsArrayString" => "Array<String>",
1362
+ }
1363
+
1364
+ generate_operation = lambda do |gtype, nickname, op|
1365
+ op_flags = op.get_flags
1366
+ return if (op_flags & OPERATION_DEPRECATED) != 0
1367
+ return if no_generate.include? nickname
1368
+ description = Vips::vips_object_get_description op
1369
+
1370
+ # find and classify all the arguments the operator can take
1371
+ required_input = []
1372
+ optional_input = []
1373
+ required_output = []
1374
+ optional_output = []
1375
+ member_x = nil
1376
+ op.argument_map do |pspec, argument_class, argument_instance|
1377
+ arg_flags = argument_class[:flags]
1378
+ next if (arg_flags & ARGUMENT_CONSTRUCT) == 0
1379
+ next if (arg_flags & ARGUMENT_DEPRECATED) != 0
1380
+
1381
+ name = pspec[:name].tr("-", "_")
1382
+ # 'in' as a param name confuses yard
1383
+ name = "im" if name == "in"
1384
+ gtype = pspec[:value_type]
1385
+ fundamental = GObject::g_type_fundamental gtype
1386
+ type_name = GObject::g_type_name gtype
1387
+ if map_go_to_ruby.include? type_name
1388
+ type_name = map_go_to_ruby[type_name]
1389
+ end
1390
+ if fundamental == GObject::GFLAGS_TYPE ||
1391
+ fundamental == GObject::GENUM_TYPE
1392
+ type_name = "Vips::" + type_name[/Vips(.*)/, 1]
1393
+ end
1394
+ blurb = GObject::g_param_spec_get_blurb pspec
1395
+ value = {:name => name,
1396
+ :flags => arg_flags,
1397
+ :gtype => gtype,
1398
+ :type_name => type_name,
1399
+ :blurb => blurb}
1400
+
1401
+ if (arg_flags & ARGUMENT_INPUT) != 0
1402
+ if (arg_flags & ARGUMENT_REQUIRED) != 0
1403
+ # note the first required input image, if any ... we
1404
+ # will be a method of this instance
1405
+ if !member_x && gtype == Vips::IMAGE_TYPE
1406
+ member_x = value
1407
+ else
1408
+ required_input << value
1456
1409
  end
1410
+ else
1411
+ optional_input << value
1412
+ end
1413
+ end
1414
+
1415
+ # MODIFY INPUT args count as OUTPUT as well
1416
+ if (arg_flags & ARGUMENT_OUTPUT) != 0 ||
1417
+ ((arg_flags & ARGUMENT_INPUT) != 0 &&
1418
+ (arg_flags & ARGUMENT_MODIFY) != 0)
1419
+ if (arg_flags & ARGUMENT_REQUIRED) != 0
1420
+ required_output << value
1421
+ else
1422
+ optional_output << value
1423
+ end
1424
+ end
1425
+
1426
+ end
1427
+
1428
+ print "# @!method "
1429
+ print "self." unless member_x
1430
+ print "#{nickname}("
1431
+ print required_input.map{|x| x[:name]}.join(", ")
1432
+ print ", " if required_input.length > 0
1433
+ puts "**opts)"
1434
+
1435
+ puts "# #{description.capitalize}."
1436
+
1437
+ required_input.each do |arg|
1438
+ puts "# @param #{arg[:name]} [#{arg[:type_name]}] " +
1439
+ "#{arg[:blurb]}"
1440
+ end
1441
+
1442
+ puts "# @param opts [Hash] Set of options"
1443
+ optional_input.each do |arg|
1444
+ puts "# @option opts [#{arg[:type_name]}] :#{arg[:name]} " +
1445
+ "#{arg[:blurb]}"
1446
+ end
1447
+ optional_output.each do |arg|
1448
+ print "# @option opts [#{arg[:type_name]}] :#{arg[:name]}"
1449
+ puts " Output #{arg[:blurb]}"
1450
+ end
1451
+
1452
+ print "# @return ["
1453
+ if required_output.length == 0
1454
+ print "nil"
1455
+ elsif required_output.length == 1
1456
+ print required_output.first[:type_name]
1457
+ elsif
1458
+ print "Array<"
1459
+ print required_output.map{|x| x[:type_name]}.join(", ")
1460
+ print ">"
1461
+ end
1462
+ if optional_output.length > 0
1463
+ print ", Hash<Symbol => Object>"
1464
+ end
1465
+ print "] "
1466
+ print required_output.map{|x| x[:blurb]}.join(", ")
1467
+ if optional_output.length > 0
1468
+ print ", " if required_output.length > 0
1469
+ print "Hash of optional output items"
1470
+ end
1471
+ puts ""
1472
+
1473
+ puts ""
1474
+ end
1457
1475
 
1458
- print "# @return ["
1459
- if required_output.length == 0
1460
- print "nil"
1461
- elsif required_output.length == 1
1462
- print required_output.first[:type_name]
1463
- elsif
1464
- print "Array<"
1465
- print required_output.map{|x| x[:type_name]}.join(", ")
1466
- print ">"
1467
- end
1468
- if optional_output.length > 0
1469
- print ", Hash<Symbol => Object>"
1470
- end
1471
- print "] "
1472
- print required_output.map{|x| x[:blurb]}.join(", ")
1473
- if optional_output.length > 0
1474
- print ", " if required_output.length > 0
1475
- print "Hash of optional output items"
1476
- end
1477
- puts ""
1476
+ generate_class = lambda do |gtype, a|
1477
+ nickname = Vips::nickname_find gtype
1478
1478
 
1479
- puts ""
1479
+ if nickname
1480
+ begin
1481
+ # can fail for abstract types
1482
+ op = Vips::Operation.new nickname
1483
+ rescue
1480
1484
  end
1481
1485
 
1482
- generate_class = lambda do |gtype, a|
1483
- nickname = Vips::nickname_find gtype
1484
-
1485
- if nickname
1486
- begin
1487
- # can fail for abstract types
1488
- op = Vips::Operation.new nickname
1489
- rescue
1490
- end
1491
-
1492
- generate_operation.(gtype, nickname, op) if op
1493
- end
1486
+ generate_operation.(gtype, nickname, op) if op
1487
+ end
1494
1488
 
1495
- Vips::vips_type_map gtype, generate_class, nil
1496
- end
1489
+ Vips::vips_type_map gtype, generate_class, nil
1490
+ end
1497
1491
 
1498
- puts "module Vips"
1499
- puts " class Image"
1500
- puts ""
1492
+ puts "module Vips"
1493
+ puts " class Image"
1494
+ puts ""
1501
1495
 
1502
- generate_class.(GObject::g_type_from_name("VipsOperation"), nil)
1496
+ generate_class.(GObject::g_type_from_name("VipsOperation"), nil)
1503
1497
 
1504
- puts " end"
1505
- puts "end"
1506
- end
1498
+ puts " end"
1499
+ puts "end"
1500
+ end
1507
1501
 
1508
1502
  end