ruby-vips 2.0.14 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +42 -0
  3. data/.github/workflows/test.yml +80 -0
  4. data/.standard.yml +17 -0
  5. data/.yardopts +0 -1
  6. data/CHANGELOG.md +41 -0
  7. data/Gemfile +3 -1
  8. data/README.md +42 -41
  9. data/Rakefile +13 -21
  10. data/TODO +18 -10
  11. data/VERSION +1 -1
  12. data/example/annotate.rb +6 -6
  13. data/example/connection.rb +26 -0
  14. data/example/daltonize8.rb +16 -18
  15. data/example/draw_lines.rb +30 -0
  16. data/example/example1.rb +5 -6
  17. data/example/example2.rb +6 -6
  18. data/example/example3.rb +5 -5
  19. data/example/example4.rb +4 -4
  20. data/example/example5.rb +6 -7
  21. data/example/inheritance_with_refcount.rb +36 -54
  22. data/example/progress.rb +30 -0
  23. data/example/thumb.rb +8 -10
  24. data/example/trim8.rb +5 -5
  25. data/example/watermark.rb +2 -2
  26. data/example/wobble.rb +1 -1
  27. data/lib/ruby-vips.rb +1 -1
  28. data/lib/vips.rb +199 -93
  29. data/lib/vips/align.rb +0 -1
  30. data/lib/vips/angle.rb +0 -1
  31. data/lib/vips/angle45.rb +0 -1
  32. data/lib/vips/bandformat.rb +0 -2
  33. data/lib/vips/blend_mode.rb +29 -27
  34. data/lib/vips/coding.rb +0 -1
  35. data/lib/vips/compass_direction.rb +0 -1
  36. data/lib/vips/connection.rb +46 -0
  37. data/lib/vips/direction.rb +0 -1
  38. data/lib/vips/extend.rb +0 -1
  39. data/lib/vips/gobject.rb +26 -15
  40. data/lib/vips/gvalue.rb +61 -55
  41. data/lib/vips/image.rb +455 -282
  42. data/lib/vips/interesting.rb +0 -1
  43. data/lib/vips/interpolate.rb +3 -7
  44. data/lib/vips/interpretation.rb +0 -1
  45. data/lib/vips/kernel.rb +0 -1
  46. data/lib/vips/methods.rb +791 -124
  47. data/lib/vips/mutableimage.rb +173 -0
  48. data/lib/vips/object.rb +178 -68
  49. data/lib/vips/operation.rb +277 -130
  50. data/lib/vips/operationboolean.rb +0 -1
  51. data/lib/vips/operationcomplex.rb +0 -1
  52. data/lib/vips/operationcomplex2.rb +0 -1
  53. data/lib/vips/operationcomplexget.rb +0 -1
  54. data/lib/vips/operationmath.rb +0 -1
  55. data/lib/vips/operationmath2.rb +0 -1
  56. data/lib/vips/operationrelational.rb +0 -1
  57. data/lib/vips/operationround.rb +0 -1
  58. data/lib/vips/region.rb +73 -0
  59. data/lib/vips/size.rb +0 -1
  60. data/lib/vips/source.rb +88 -0
  61. data/lib/vips/sourcecustom.rb +89 -0
  62. data/lib/vips/target.rb +86 -0
  63. data/lib/vips/targetcustom.rb +77 -0
  64. data/lib/vips/version.rb +1 -2
  65. data/ruby-vips.gemspec +26 -21
  66. metadata +39 -51
  67. data/.rubocop.yml +0 -10
  68. data/.rubocop_todo.yml +0 -730
  69. data/.travis.yml +0 -62
  70. data/install-vips.sh +0 -26
data/lib/vips/image.rb CHANGED
@@ -4,16 +4,19 @@
4
4
  # Author:: John Cupitt (mailto:jcupitt@gmail.com)
5
5
  # License:: MIT
6
6
 
7
- require 'ffi'
7
+ require "ffi"
8
8
 
9
9
  module Vips
10
10
  private
11
11
 
12
12
  attach_function :vips_image_new_matrix_from_array,
13
- [:int, :int, :pointer, :int], :pointer
13
+ [:int, :int, :pointer, :int], :pointer
14
14
 
15
15
  attach_function :vips_image_copy_memory, [:pointer], :pointer
16
16
 
17
+ attach_function :vips_image_set_progress, [:pointer, :bool], :void
18
+ attach_function :vips_image_set_kill, [:pointer, :bool], :void
19
+
17
20
  attach_function :vips_filename_get_filename, [:string], :pointer
18
21
  attach_function :vips_filename_get_options, [:string], :pointer
19
22
 
@@ -22,30 +25,35 @@ module Vips
22
25
  attach_function :vips_foreign_find_load_buffer, [:pointer, :size_t], :string
23
26
  attach_function :vips_foreign_find_save_buffer, [:string], :string
24
27
 
28
+ if Vips.at_least_libvips?(8, 9)
29
+ attach_function :vips_foreign_find_load_source, [:pointer], :string
30
+ attach_function :vips_foreign_find_save_target, [:string], :string
31
+ end
32
+
25
33
  attach_function :vips_image_write_to_memory,
26
- [:pointer, SizeStruct.ptr], :pointer
34
+ [:pointer, SizeStruct.ptr], :pointer
27
35
 
28
36
  attach_function :vips_image_get_typeof, [:pointer, :string], :GType
29
37
  attach_function :vips_image_get,
30
- [:pointer, :string, GObject::GValue.ptr], :int
38
+ [:pointer, :string, GObject::GValue.ptr], :int
31
39
 
32
- # vips_image_get_fields was added in libvips 8.5
33
- begin
40
+ attach_function :vips_image_get_width, [:pointer], :int
41
+ attach_function :vips_image_get_height, [:pointer], :int
42
+ attach_function :vips_image_get_bands, [:pointer], :int
43
+
44
+ if Vips.at_least_libvips?(8, 5)
34
45
  attach_function :vips_image_get_fields, [:pointer], :pointer
35
- rescue FFI::NotFoundError
36
- nil
46
+ attach_function :vips_image_hasalpha, [:pointer], :int
37
47
  end
38
48
 
39
- # vips_addalpha was added in libvips 8.6
40
- if Vips::at_least_libvips?(8, 6)
49
+ if Vips.at_least_libvips?(8, 6)
41
50
  attach_function :vips_addalpha, [:pointer, :pointer, :varargs], :int
42
51
  end
43
- if Vips::at_least_libvips?(8, 5)
44
- attach_function :vips_image_hasalpha, [:pointer], :int
45
- end
46
52
 
53
+ # move these three lines to mutableimage when we finally remove set and
54
+ # remove in this class
47
55
  attach_function :vips_image_set,
48
- [:pointer, :string, GObject::GValue.ptr], :void
56
+ [:pointer, :string, GObject::GValue.ptr], :void
49
57
  attach_function :vips_image_remove, [:pointer, :string], :void
50
58
 
51
59
  attach_function :vips_band_format_iscomplex, [:int], :int
@@ -53,6 +61,9 @@ module Vips
53
61
 
54
62
  attach_function :nickname_find, :vips_nickname_find, [:GType], :string
55
63
 
64
+ attach_function :vips_image_new_from_memory, [:pointer, :size_t, :int, :int, :int, :int], :pointer
65
+ attach_function :vips_image_new_from_memory_copy, [:pointer, :size_t, :int, :int, :int, :int], :pointer
66
+
56
67
  # turn a raw pointer that must be freed into a self-freeing Ruby string
57
68
  def self.p2str(pointer)
58
69
  pointer = FFI::AutoPointer.new(pointer, GLib::G_FREE)
@@ -81,12 +92,10 @@ module Vips
81
92
 
82
93
  class Struct < Vips::Object::Struct
83
94
  include ImageLayout
84
-
85
95
  end
86
96
 
87
97
  class ManagedStruct < Vips::Object::ManagedStruct
88
98
  include ImageLayout
89
-
90
99
  end
91
100
 
92
101
  class GenericPtr < FFI::Struct
@@ -96,17 +105,17 @@ module Vips
96
105
  # handy for overloads ... want to be able to apply a function to an
97
106
  # array or to a scalar
98
107
  def self.smap x, &block
99
- x.is_a?(Array) ? x.map {|y| smap(y, &block)} : block.(x)
108
+ x.is_a?(Array) ? x.map { |y| smap(y, &block) } : block.call(x)
100
109
  end
101
110
 
102
111
  def self.complex? format
103
112
  format_number = GObject::GValue.from_nick BAND_FORMAT_TYPE, format
104
- Vips::vips_band_format_iscomplex(format_number) != 0
113
+ Vips.vips_band_format_iscomplex(format_number) != 0
105
114
  end
106
115
 
107
116
  def self.float? format
108
117
  format_number = GObject::GValue.from_nick BAND_FORMAT_TYPE, format
109
- Vips::vips_band_format_isfloat(format_number) != 0
118
+ Vips.vips_band_format_isfloat(format_number) != 0
110
119
  end
111
120
 
112
121
  # run a complex operation on a complex image, or an image with an even
@@ -115,12 +124,12 @@ module Vips
115
124
  def self.run_cmplx image, &block
116
125
  original_format = image.format
117
126
 
118
- unless Image::complex? image.format
127
+ unless Image.complex? image.format
119
128
  if image.bands % 2 != 0
120
- raise Error, "not an even number of bands"
129
+ raise Vips::Error, "not an even number of bands"
121
130
  end
122
131
 
123
- unless Image::float? image.format
132
+ unless Image.float? image.format
124
133
  image = image.cast :float
125
134
  end
126
135
 
@@ -128,9 +137,9 @@ module Vips
128
137
  image = image.copy format: new_format, bands: image.bands / 2
129
138
  end
130
139
 
131
- image = block.(image)
140
+ image = block.call(image)
132
141
 
133
- unless Image::complex? original_format
142
+ unless Image.complex? original_format
134
143
  new_format = image.format == :dpcomplex ? :double : :float
135
144
  image = image.copy format: new_format, bands: image.bands * 2
136
145
  end
@@ -178,26 +187,30 @@ module Vips
178
187
  public
179
188
 
180
189
  def inspect
181
- "#<Image #{width}x#{height} #{format}, #{bands} bands, " +
182
- "#{interpretation}>"
190
+ "#<Image #{width}x#{height} #{format}, #{bands} bands, #{interpretation}>"
183
191
  end
184
192
 
185
193
  def respond_to? name, include_all = false
186
194
  # To support keyword args, we need to tell Ruby that final image
187
195
  # arguments cannot be hashes of keywords.
188
196
  #
189
- # https://makandracards.com/makandra/36013-heads-up-ruby-implicitly-converts-a-hash-to-keyword-arguments
197
+ # https://makandracards.com/makandra/
198
+ # 36013-heads-up-ruby-implicitly-converts-a-hash-to-keyword-arguments
190
199
  return false if name == :to_hash
191
200
 
201
+ super
202
+ end
203
+
204
+ def respond_to_missing? name, include_all = false
192
205
  # respond to all vips operations by nickname
193
- return true if Vips::type_find("VipsOperation", name.to_s) != 0
206
+ return true if Vips.type_find("VipsOperation", name.to_s) != 0
194
207
 
195
208
  super
196
209
  end
197
210
 
198
- def self.respond_to? name, include_all = false
211
+ def self.respond_to_missing? name, include_all = false
199
212
  # respond to all vips operations by nickname
200
- return true if Vips::type_find("VipsOperation", name.to_s) != 0
213
+ return true if Vips.type_find("VipsOperation", name.to_s) != 0
201
214
 
202
215
  super
203
216
  end
@@ -221,13 +234,13 @@ module Vips
221
234
  # load options, for example:
222
235
  #
223
236
  # ```
224
- # image = Vips::new_from_file "fred.jpg[shrink=2]"
237
+ # image = Vips::Image.new_from_file "fred.jpg[shrink=2]"
225
238
  # ```
226
239
  #
227
240
  # You can also supply options as a hash, for example:
228
241
  #
229
242
  # ```
230
- # image = Vips::new_from_file "fred.jpg", shrink: 2
243
+ # image = Vips::Image.new_from_file "fred.jpg", shrink: 2
231
244
  # ```
232
245
  #
233
246
  # The full set of options available depend upon the load operation that
@@ -255,18 +268,18 @@ module Vips
255
268
  def self.new_from_file name, **opts
256
269
  # very common, and Vips::vips_filename_get_filename will segv if we
257
270
  # pass this
258
- raise Vips::Error, "filename is nil" if name == nil
271
+ raise Vips::Error, "filename is nil" if name.nil?
259
272
 
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
273
+ filename = Vips.p2str(Vips.vips_filename_get_filename(name))
274
+ option_string = Vips.p2str(Vips.vips_filename_get_options(name))
275
+ loader = Vips.vips_foreign_find_load filename
276
+ raise Vips::Error if loader.nil?
264
277
 
265
278
  Operation.call loader, [filename], opts, option_string
266
279
  end
267
280
 
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
281
+ # Create a new {Image} for an image encoded in a format such as
282
+ # JPEG in a binary string. Load options may be passed as
270
283
  # strings or appended as a hash. For example:
271
284
  #
272
285
  # ```
@@ -297,17 +310,119 @@ module Vips
297
310
  # @macro vips.loadopts
298
311
  # @return [Image] the loaded image
299
312
  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
313
+ loader = Vips.vips_foreign_find_load_buffer data, data.bytesize
314
+ raise Vips::Error if loader.nil?
302
315
 
303
316
  Vips::Operation.call loader, [data], opts, option_string
304
317
  end
305
318
 
319
+ # Create a new {Image} from a C-style array held in memory. For example:
320
+ #
321
+ # ```
322
+ # image = Vips::Image.black(16, 16) + 128
323
+ # data = image.write_to_memory
324
+ #
325
+ # x = Vips::Image.new_from_memory data,
326
+ # image.width, image.height, image.bands, image.format
327
+ # ```
328
+ #
329
+ # {new_from_memory} keeps a reference to the array of pixels you pass in
330
+ # to try to prevent that memory from being freed by the Ruby GC while it
331
+ # is being used.
332
+ #
333
+ # See {new_from_memory_copy} for a version of this method which does not
334
+ # keep a reference.
335
+ #
336
+ # @param data [String, FFI::Pointer] the data to load from
337
+ # @param width [Integer] width in pixels
338
+ # @param height [Integer] height in pixels
339
+ # @param bands [Integer] number of bands
340
+ # @param format [Symbol] band format
341
+ # @return [Image] the loaded image
342
+ def self.new_from_memory data, width, height, bands, format
343
+ size = data.bytesize
344
+
345
+ # prevent data from being freed with JRuby FFI
346
+ if defined?(JRUBY_VERSION) && !data.is_a?(FFI::Pointer)
347
+ data = ::FFI::MemoryPointer.new(:char, data.bytesize).write_bytes data
348
+ end
349
+
350
+ format_number = GObject::GValue.from_nick BAND_FORMAT_TYPE, format
351
+ vi = Vips.vips_image_new_from_memory data, size,
352
+ width, height, bands, format_number
353
+ raise Vips::Error if vi.null?
354
+ image = new(vi)
355
+
356
+ # keep a secret ref to the underlying object .. this reference will be
357
+ # inherited by things that in turn depend on us, so the memory we are
358
+ # using will not be freed
359
+ image.references << data
360
+
361
+ image
362
+ end
363
+
364
+ # Create a new {Image} from memory and copies the memory area. See
365
+ # {new_from_memory} for a version of this method which does not copy the
366
+ # memory area.
367
+ #
368
+ # @param data [String, FFI::Pointer] the data to load from
369
+ # @param width [Integer] width in pixels
370
+ # @param height [Integer] height in pixels
371
+ # @param bands [Integer] number of bands
372
+ # @param format [Symbol] band format
373
+ # @return [Image] the loaded image
374
+ def self.new_from_memory_copy data, width, height, bands, format
375
+ format_number = GObject::GValue.from_nick BAND_FORMAT_TYPE, format
376
+ vi = Vips.vips_image_new_from_memory_copy data, data.bytesize,
377
+ width, height, bands, format_number
378
+ raise Vips::Error if vi.null?
379
+ new(vi)
380
+ end
381
+
382
+ # Create a new {Image} from a source. Load options may be passed as
383
+ # strings or appended as a hash. For example:
384
+ #
385
+ # ```
386
+ # source = Vips::Source.new_from_file("k2.jpg")
387
+ # image = Vips::Image.new_from_source source, "shrink=2"
388
+ # ```
389
+ #
390
+ # or alternatively:
391
+ #
392
+ # ```
393
+ # image = Vips::Image.new_from_source source, "", shrink: 2
394
+ # ```
395
+ #
396
+ # The options available depend on the file format. Try something like:
397
+ #
398
+ # ```
399
+ # $ vips jpegload_source
400
+ # ```
401
+ #
402
+ # at the command-line to see the available options. Not all loaders
403
+ # support load from source, but at least JPEG, PNG and
404
+ # TIFF images will work.
405
+ #
406
+ # Loading is fast: only enough data is read to be able to fill
407
+ # out the header. Pixels will only be read and decompressed when they are
408
+ # needed.
409
+ #
410
+ # @param source [Vips::Source] the source to load from
411
+ # @param option_string [String] load options as a string
412
+ # @macro vips.loadopts
413
+ # @return [Image] the loaded image
414
+ def self.new_from_source source, option_string, **opts
415
+ loader = Vips.vips_foreign_find_load_source source
416
+ raise Vips::Error if loader.nil?
417
+
418
+ Vips::Operation.call loader, [source], opts, option_string
419
+ end
420
+
306
421
  def self.matrix_from_array width, height, array
307
422
  ptr = FFI::MemoryPointer.new :double, array.length
308
423
  ptr.write_array_of_double array
309
- image = Vips::vips_image_new_matrix_from_array width, height,
310
- ptr, array.length
424
+ image = Vips.vips_image_new_matrix_from_array width, height,
425
+ ptr, array.length
311
426
  Vips::Image.new image
312
427
  end
313
428
 
@@ -319,13 +434,13 @@ module Vips
319
434
  # For example:
320
435
  #
321
436
  # ```
322
- # image = Vips::new_from_array [1, 2, 3]
437
+ # image = Vips::Image.new_from_array [1, 2, 3]
323
438
  # ```
324
439
  #
325
440
  # or
326
441
  #
327
442
  # ```
328
- # image = Vips::new_from_array [
443
+ # image = Vips::Image.new_from_array [
329
444
  # [-1, -1, -1],
330
445
  # [-1, 16, -1],
331
446
  # [-1, -1, -1]], 8
@@ -347,30 +462,35 @@ module Vips
347
462
  if array[0].is_a? Array
348
463
  height = array.length
349
464
  width = array[0].length
350
- unless array.all? {|x| x.is_a? Array}
465
+ unless array.all? { |x| x.is_a? Array }
351
466
  raise Vips::Error, "Not a 2D array."
352
467
  end
353
- unless array.all? {|x| x.length == width}
468
+ unless array.all? { |x| x.length == width }
354
469
  raise Vips::Error, "Array not rectangular."
355
470
  end
471
+
356
472
  array = array.flatten
357
473
  else
358
474
  height = 1
359
475
  width = array.length
360
476
  end
361
477
 
362
- unless array.all? {|x| x.is_a? Numeric}
478
+ unless array.length == width * height
479
+ raise Vips::Error, "Bad array dimensions."
480
+ end
481
+
482
+ unless array.all? { |x| x.is_a? Numeric }
363
483
  raise Vips::Error, "Not all array elements are Numeric."
364
484
  end
365
485
 
366
486
  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
487
+ raise Vips::Error if image.nil?
372
488
 
373
- return image
489
+ image.mutate do |mutable|
490
+ # be careful to set them as double
491
+ mutable.set_type! GObject::GDOUBLE_TYPE, "scale", scale.to_f
492
+ mutable.set_type! GObject::GDOUBLE_TYPE, "offset", offset.to_f
493
+ end
374
494
  end
375
495
 
376
496
  # A new image is created with the same width, height, format,
@@ -385,8 +505,8 @@ module Vips
385
505
  def new_from_image value
386
506
  pixel = (Vips::Image.black(1, 1) + value).cast(format)
387
507
  image = pixel.embed 0, 0, width, height, extend: :copy
388
- image.copy interpretation: interpretation,
389
- xres: xres, yres: yres, xoffset: xoffset, yoffset: yoffset
508
+ image.copy interpretation: interpretation, xres: xres, yres: yres,
509
+ xoffset: xoffset, yoffset: yoffset
390
510
  end
391
511
 
392
512
  # Write this image to a file. Save options may be encoded in the
@@ -419,12 +539,12 @@ module Vips
419
539
  #
420
540
  # @param name [String] filename to write to
421
541
  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
542
+ raise Vips::Error, "filename is nil" if name.nil?
543
+
544
+ filename = Vips.p2str(Vips.vips_filename_get_filename(name))
545
+ option_string = Vips.p2str(Vips.vips_filename_get_options(name))
546
+ saver = Vips.vips_foreign_find_save filename
547
+ raise Vips::Error if saver.nil?
428
548
 
429
549
  Vips::Operation.call saver, [self, filename], opts, option_string
430
550
 
@@ -457,21 +577,55 @@ module Vips
457
577
  # @macro vips.saveopts
458
578
  # @return [String] the image saved in the specified format
459
579
  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
580
+ raise Vips::Error, "filename is nil" if format_string.nil?
581
+ filename = Vips.p2str(Vips.vips_filename_get_filename(format_string))
582
+ option_string = Vips.p2str(Vips.vips_filename_get_options(format_string))
583
+ saver = Vips.vips_foreign_find_save_buffer filename
584
+ raise Vips::Error if saver.nil?
468
585
 
469
586
  buffer = Vips::Operation.call saver, [self], opts, option_string
470
- raise Vips::Error if buffer == nil
587
+ raise Vips::Error if buffer.nil?
471
588
 
472
589
  write_gc
473
590
 
474
- return buffer
591
+ buffer
592
+ end
593
+
594
+ # Write this image to a target. Save options may be encoded in
595
+ # the format_string or given as a hash. For example:
596
+ #
597
+ # ```ruby
598
+ # target = Vips::Target.new_to_file "k2.jpg"
599
+ # image.write_to_target target, ".jpg[Q=90]"
600
+ # ```
601
+ #
602
+ # or equivalently:
603
+ #
604
+ # ```ruby
605
+ # image.write_to_target target, ".jpg", Q: 90
606
+ # ```
607
+ #
608
+ # The full set of save options depend on the selected saver. Try
609
+ # something like:
610
+ #
611
+ # ```
612
+ # $ vips jpegsave_target
613
+ # ```
614
+ #
615
+ # to see all the available options for JPEG save.
616
+ #
617
+ # @param target [Vips::Target] the target to write to
618
+ # @param format_string [String] save format plus string options
619
+ # @macro vips.saveopts
620
+ def write_to_target target, format_string, **opts
621
+ raise Vips::Error, "filename is nil" if format_string.nil?
622
+ filename = Vips.p2str(Vips.vips_filename_get_filename(format_string))
623
+ option_string = Vips.p2str(Vips.vips_filename_get_options(format_string))
624
+ saver = Vips.vips_foreign_find_save_target filename
625
+ raise Vips::Error if saver.nil?
626
+
627
+ Vips::Operation.call saver, [self, target], opts, option_string
628
+ write_gc
475
629
  end
476
630
 
477
631
  # Write this image to a large memory buffer.
@@ -479,7 +633,8 @@ module Vips
479
633
  # @return [String] the pixels as a huge binary string
480
634
  def write_to_memory
481
635
  len = Vips::SizeStruct.new
482
- ptr = Vips::vips_image_write_to_memory self, len
636
+ ptr = Vips.vips_image_write_to_memory self, len
637
+ raise Vips::Error if ptr.nil?
483
638
 
484
639
  # wrap up as an autopointer
485
640
  ptr = FFI::AutoPointer.new(ptr, GLib::G_FREE)
@@ -487,6 +642,28 @@ module Vips
487
642
  ptr.get_bytes 0, len[:value]
488
643
  end
489
644
 
645
+ # Turn progress signalling on and off.
646
+ #
647
+ # If this is on, the most-downstream image from this image will issue
648
+ # progress signals.
649
+ #
650
+ # @see Object#signal_connect
651
+ # @param state [Boolean] progress signalling state
652
+ def set_progress state
653
+ Vips.vips_image_set_progress self, state
654
+ end
655
+
656
+ # Kill computation of this time.
657
+ #
658
+ # Set true to stop computation of this image. You can call this from a
659
+ # progress handler, for example.
660
+ #
661
+ # @see Object#signal_connect
662
+ # @param kill [Boolean] stop computation
663
+ def set_kill kill
664
+ Vips.vips_image_set_kill self, kill
665
+ end
666
+
490
667
  # Get the `GType` of a metadata field. The result is 0 if no such field
491
668
  # exists.
492
669
  #
@@ -496,12 +673,12 @@ module Vips
496
673
  def get_typeof name
497
674
  # on libvips before 8.5, property types must be searched first,
498
675
  # since vips_image_get_typeof returned built-in enums as int
499
- unless Vips::at_least_libvips?(8, 5)
676
+ unless Vips.at_least_libvips?(8, 5)
500
677
  gtype = parent_get_typeof name
501
678
  return gtype if gtype != 0
502
679
  end
503
680
 
504
- Vips::vips_image_get_typeof self, name
681
+ Vips.vips_image_get_typeof self, name
505
682
  end
506
683
 
507
684
  # Get a metadata item from an image. Ruby types are constructed
@@ -520,15 +697,16 @@ module Vips
520
697
  def get name
521
698
  # with old libvips, we must fetch properties (as opposed to
522
699
  # metadata) via VipsObject
523
- unless Vips::at_least_libvips?(8, 5)
700
+ unless Vips.at_least_libvips?(8, 5)
524
701
  return super if parent_get_typeof(name) != 0
525
702
  end
526
703
 
527
704
  gvalue = GObject::GValue.alloc
528
- result = Vips::vips_image_get self, name, gvalue
529
- raise Vips::Error if result != 0
705
+ raise Vips::Error if Vips.vips_image_get(self, name, gvalue) != 0
706
+ result = gvalue.get
707
+ gvalue.unset
530
708
 
531
- gvalue.get
709
+ result
532
710
  end
533
711
 
534
712
  # Get the names of all fields on an image. Use this to loop over all
@@ -539,66 +717,64 @@ module Vips
539
717
  # vips_image_get_fields() was added in libvips 8.5
540
718
  return [] unless Vips.respond_to? :vips_image_get_fields
541
719
 
542
- array = Vips::vips_image_get_fields self
720
+ array = Vips.vips_image_get_fields self
543
721
 
544
722
  names = []
545
723
  p = array
546
724
  until (q = p.read_pointer).null?
547
725
  names << q.read_string
548
- GLib::g_free q
726
+ GLib.g_free q
549
727
  p += FFI::Type::POINTER.size
550
728
  end
551
- GLib::g_free array
729
+ GLib.g_free array
552
730
 
553
731
  names
554
732
  end
555
733
 
556
- # Create a metadata item on an image of the specifed type. Ruby types
557
- # are automatically transformed into the matching `GType`, if possible.
734
+ # Mutate an image with a block. Inside the block, you can call methods
735
+ # which modify the image, such as setting or removing metadata, or
736
+ # modifying pixels.
558
737
  #
559
- # For example, you can use this to set an image's ICC profile:
738
+ # For example:
560
739
  #
561
- # ```
562
- # x = y.set_type Vips::BLOB_TYPE, "icc-profile-data", profile
740
+ # ```ruby
741
+ # image = image.mutate do |x|
742
+ # (0 ... 1).step(0.01) do |i|
743
+ # x.draw_line! 255, x.width * i, 0, 0, x.height * (1 - i)
744
+ # end
745
+ # end
563
746
  # ```
564
747
  #
565
- # where `profile` is an ICC profile held as a binary string object.
748
+ # See {MutableImage}.
749
+ def mutate
750
+ mutable = Vips::MutableImage.new self
751
+ yield mutable
752
+ mutable.image
753
+ end
754
+
755
+ # This method is deprecated.
566
756
  #
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
757
+ # Please use {MutableImage#set_type!} instead.
571
758
  def set_type gtype, name, value
572
759
  gvalue = GObject::GValue.alloc
573
760
  gvalue.init gtype
574
761
  gvalue.set value
575
- Vips::vips_image_set self, name, gvalue
762
+ Vips.vips_image_set self, name, gvalue
763
+ gvalue.unset
576
764
  end
577
765
 
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.
766
+ # This method is deprecated.
581
767
  #
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
768
+ # Please use {MutableImage#set!} instead.
593
769
  def set name, value
594
770
  set_type get_typeof(name), name, value
595
771
  end
596
772
 
597
- # Remove a metadata item from an image.
773
+ # This method is deprecated.
598
774
  #
599
- # @param name [String] Metadata field to remove
775
+ # Please use {MutableImage#remove!} instead.
600
776
  def remove name
601
- Vips::vips_image_remove self, name
777
+ Vips.vips_image_remove self, name
602
778
  end
603
779
 
604
780
  # compatibility: old name for get
@@ -606,7 +782,9 @@ module Vips
606
782
  get name
607
783
  end
608
784
 
609
- # compatibility: old name for set
785
+ # This method is deprecated.
786
+ #
787
+ # Please use {MutableImage#set!} instead.
610
788
  def set_value name, value
611
789
  set name, value
612
790
  end
@@ -615,21 +793,21 @@ module Vips
615
793
  #
616
794
  # @return [Integer] image width, in pixels
617
795
  def width
618
- get "width"
796
+ Vips.vips_image_get_width self
619
797
  end
620
798
 
621
799
  # Get image height, in pixels.
622
800
  #
623
801
  # @return [Integer] image height, in pixels
624
802
  def height
625
- get "height"
803
+ Vips.vips_image_get_height self
626
804
  end
627
805
 
628
806
  # Get number of image bands.
629
807
  #
630
808
  # @return [Integer] number of image bands
631
809
  def bands
632
- get "bands"
810
+ Vips.vips_image_get_bands self
633
811
  end
634
812
 
635
813
  # Get image format.
@@ -713,23 +891,23 @@ module Vips
713
891
  [width, height]
714
892
  end
715
893
 
716
- if Vips::at_least_libvips?(8, 5)
894
+ if Vips.at_least_libvips?(8, 5)
717
895
  # Detect if image has an alpha channel
718
896
  #
719
897
  # @return [Boolean] true if image has an alpha channel.
720
898
  def has_alpha?
721
- return Vips::vips_image_hasalpha(self) != 0
899
+ Vips.vips_image_hasalpha(self) != 0
722
900
  end
723
901
  end
724
902
 
725
903
  # vips_addalpha was added in libvips 8.6
726
- if Vips::at_least_libvips?(8, 6)
904
+ if Vips.at_least_libvips?(8, 6)
727
905
  # Append an alpha channel to an image.
728
906
  #
729
907
  # @return [Image] new image
730
908
  def add_alpha
731
909
  ptr = GenericPtr.new
732
- result = Vips::vips_addalpha self, ptr
910
+ result = Vips.vips_addalpha self, ptr
733
911
  raise Vips::Error if result != 0
734
912
 
735
913
  Vips::Image.new ptr[:value]
@@ -744,7 +922,7 @@ module Vips
744
922
  #
745
923
  # @return [Image] new memory image
746
924
  def copy_memory
747
- new_image = Vips::vips_image_copy_memory self
925
+ new_image = Vips.vips_image_copy_memory self
748
926
  Vips::Image.new new_image
749
927
  end
750
928
 
@@ -754,7 +932,7 @@ module Vips
754
932
  #
755
933
  # @return [Image] modified image
756
934
  def draw_point ink, left, top, **opts
757
- draw_rect ink, left, top, 1, 1, opts
935
+ draw_rect ink, left, top, 1, 1, **opts
758
936
  end
759
937
 
760
938
  # Add an image, constant or array.
@@ -772,7 +950,7 @@ module Vips
772
950
  # @return [Image] result of subtraction
773
951
  def - other
774
952
  other.is_a?(Vips::Image) ?
775
- subtract(other) : linear(1, Image::smap(other) {|x| x * -1})
953
+ subtract(other) : linear(1, Image.smap(other) { |x| x * -1 })
776
954
  end
777
955
 
778
956
  # Multiply an image, constant or array.
@@ -790,7 +968,7 @@ module Vips
790
968
  # @return [Image] result of division
791
969
  def / other
792
970
  other.is_a?(Vips::Image) ?
793
- divide(other) : linear(Image::smap(other) {|x| 1.0 / x}, 0)
971
+ divide(other) : linear(Image.smap(other) { |x| 1.0 / x }, 0)
794
972
  end
795
973
 
796
974
  # Remainder after integer division with an image, constant or array.
@@ -916,7 +1094,7 @@ module Vips
916
1094
  # @return [Image] result of equality
917
1095
  def == other
918
1096
  # for equality, we must allow tests against nil
919
- if other == nil
1097
+ if other.nil?
920
1098
  false
921
1099
  else
922
1100
  call_enum "relational", other, :equal
@@ -929,7 +1107,7 @@ module Vips
929
1107
  # @return [Image] result of inequality
930
1108
  def != other
931
1109
  # for equality, we must allow tests against nil
932
- if other == nil
1110
+ if other.nil?
933
1111
  true
934
1112
  else
935
1113
  call_enum "relational", other, :noteq
@@ -951,38 +1129,40 @@ module Vips
951
1129
  end
952
1130
  end
953
1131
 
954
- # Convert to an Array. This will be slow for large images.
1132
+ # Convert to an Enumerator. Similar to `#to_a` but lazier.
955
1133
  #
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
-
1134
+ # @return [Enumerator] Enumerator of Enumerators of Arrays of Numerics
1135
+ def to_enum
962
1136
  # make the template for unpack
963
1137
  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] + '*'
1138
+ char: "c",
1139
+ uchar: "C",
1140
+ short: "s_",
1141
+ ushort: "S_",
1142
+ int: "i_",
1143
+ uint: "I_",
1144
+ float: "f",
1145
+ double: "d",
1146
+ complex: "f",
1147
+ dpcomplex: "d"
1148
+ }[format] + "*"
975
1149
 
976
- # and unpack into something like [1, 2, 3, 4 ..]
977
- array = memory.unpack(template)
1150
+ # we render the image to a big string, then unpack into
1151
+ # one-dimensional array as a Ruby array of the correct type
1152
+ array = write_to_memory.unpack template
978
1153
 
979
- # gather band elements together
980
- pixel_array = array.each_slice(bands).to_a
1154
+ # gather bands of a pixel together
1155
+ pixel_array = array.each_slice bands
981
1156
 
982
- # build rows
983
- row_array = pixel_array.each_slice(width).to_a
1157
+ # gather pixels of a row together
1158
+ pixel_array.each_slice width
1159
+ end
984
1160
 
985
- return row_array
1161
+ # Convert to an Array. This will be slow for large images.
1162
+ #
1163
+ # @return [Array] Array of Arrays of Arrays of Numerics
1164
+ def to_a
1165
+ to_enum.to_a
986
1166
  end
987
1167
 
988
1168
  # Return the largest integral value not greater than the argument.
@@ -1031,7 +1211,7 @@ module Vips
1031
1211
  #
1032
1212
  # @return [Array<Image>] Array of n one-band images
1033
1213
  def bandsplit
1034
- (0...bands).map {|i| extract_band i}
1214
+ (0...bands).map { |i| extract_band i }
1035
1215
  end
1036
1216
 
1037
1217
  # Join a set of images bandwise.
@@ -1044,7 +1224,7 @@ module Vips
1044
1224
  end
1045
1225
 
1046
1226
  # if other is just Numeric, we can use bandjoin_const
1047
- not_all_real = !other.all?{|x| x.is_a? Numeric}
1227
+ not_all_real = !other.all? { |x| x.is_a? Numeric }
1048
1228
 
1049
1229
  if not_all_real
1050
1230
  Vips::Image.bandjoin([self] + other)
@@ -1058,7 +1238,10 @@ module Vips
1058
1238
  # @param overlay [Image, Array<Image>] images to composite
1059
1239
  # @param mode [BlendMode, Array<BlendMode>] blend modes to use
1060
1240
  # @param opts [Hash] Set of options
1061
- # @option opts [Vips::Interpretation] :compositing_space Composite images in this colour space
1241
+ # @option opts [Array<Integer>] :x x positions of overlay
1242
+ # @option opts [Array<Integer>] :y y positions of overlay
1243
+ # @option opts [Vips::Interpretation] :compositing_space Composite images
1244
+ # in this colour space
1062
1245
  # @option opts [Boolean] :premultiplied Images have premultiplied alpha
1063
1246
  # @return [Image] blended image
1064
1247
  def composite overlay, mode, **opts
@@ -1073,7 +1256,7 @@ module Vips
1073
1256
  GObject::GValue.from_nick Vips::BLEND_MODE_TYPE, x
1074
1257
  end
1075
1258
 
1076
- Vips::Image.composite([self] + overlay, mode, opts)
1259
+ Vips::Image.composite([self] + overlay, mode, **opts)
1077
1260
  end
1078
1261
 
1079
1262
  # Return the coordinates of the image maximum.
@@ -1082,9 +1265,9 @@ module Vips
1082
1265
  # coordinate of maximum
1083
1266
  def maxpos
1084
1267
  v, opts = max x: true, y: true
1085
- x = opts['x']
1086
- y = opts['y']
1087
- return v, x, y
1268
+ x = opts["x"]
1269
+ y = opts["y"]
1270
+ [v, x, y]
1088
1271
  end
1089
1272
 
1090
1273
  # Return the coordinates of the image minimum.
@@ -1093,9 +1276,9 @@ module Vips
1093
1276
  # coordinate of minimum
1094
1277
  def minpos
1095
1278
  v, opts = min x: true, y: true
1096
- x = opts['x']
1097
- y = opts['y']
1098
- return v, x, y
1279
+ x = opts["x"]
1280
+ y = opts["y"]
1281
+ [v, x, y]
1099
1282
  end
1100
1283
 
1101
1284
  # a median filter
@@ -1103,7 +1286,7 @@ module Vips
1103
1286
  # @param size [Integer] size of filter window
1104
1287
  # @return [Image] result of median filter
1105
1288
  def median size = 3
1106
- rank size, size, (size * size) / 2
1289
+ rank size, size, size**2 / 2
1107
1290
  end
1108
1291
 
1109
1292
  # Return the real part of a complex image.
@@ -1130,7 +1313,7 @@ module Vips
1130
1313
  # @see xyz
1131
1314
  # @return [Image] image converted to polar coordinates
1132
1315
  def polar
1133
- Image::run_cmplx(self) {|x| x.complex :polar}
1316
+ Image.run_cmplx(self) { |x| x.complex :polar }
1134
1317
  end
1135
1318
 
1136
1319
  # Return an image with polar pixels converted to rectangular.
@@ -1143,7 +1326,7 @@ module Vips
1143
1326
  # @see xyz
1144
1327
  # @return [Image] image converted to rectangular coordinates
1145
1328
  def rect
1146
- Image::run_cmplx(self) {|x| x.complex :rect}
1329
+ Image.run_cmplx(self) { |x| x.complex :rect }
1147
1330
  end
1148
1331
 
1149
1332
  # Return the complex conjugate of an image.
@@ -1155,7 +1338,7 @@ module Vips
1155
1338
  #
1156
1339
  # @return [Image] complex conjugate
1157
1340
  def conj
1158
- Image::run_cmplx(self) {|x| x.complex :conj}
1341
+ Image.run_cmplx(self) { |x| x.complex :conj }
1159
1342
  end
1160
1343
 
1161
1344
  # Calculate the cross phase of two images.
@@ -1305,7 +1488,7 @@ module Vips
1305
1488
  # @option opts [Boolean] :blend (false) Blend smoothly between th and el
1306
1489
  # @return [Image] merged image
1307
1490
  def ifthenelse(th, el, **opts)
1308
- match_image = [th, el, self].find {|x| x.is_a? Vips::Image}
1491
+ match_image = [th, el, self].find { |x| x.is_a? Vips::Image }
1309
1492
 
1310
1493
  unless th.is_a? Vips::Image
1311
1494
  th = Operation.imageize match_image, th
@@ -1323,147 +1506,125 @@ module Vips
1323
1506
  # @param opts [Hash] Set of options
1324
1507
  # @return [Vips::Image] Output image
1325
1508
  def scaleimage **opts
1326
- Vips::Image.scale self, opts
1509
+ Vips::Image.scale self, **opts
1327
1510
  end
1328
-
1329
1511
  end
1330
1512
  end
1331
1513
 
1332
1514
  module Vips
1333
-
1334
- # This method generates yard comments for all the dynamically bound
1515
+ # This module generates yard comments for all the dynamically bound
1335
1516
  # vips operations.
1336
1517
  #
1337
1518
  # Regenerate with something like:
1338
1519
  #
1339
1520
  # ```
1340
1521
  # $ ruby > methods.rb
1341
- # require 'vips'; Vips::generate_yard
1522
+ # require "vips"; Vips::Yard.generate
1342
1523
  # ^D
1343
1524
  # ```
1344
1525
 
1345
- def self.generate_yard
1346
- # these have hand-written methods, see above
1347
- no_generate = ["scale", "bandjoin", "composite", "ifthenelse"]
1348
-
1526
+ module Yard
1349
1527
  # 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>",
1528
+ MAP_GO_TO_RUBY = {
1529
+ "gboolean" => "Boolean",
1530
+ "gint" => "Integer",
1531
+ "gdouble" => "Float",
1532
+ "gfloat" => "Float",
1533
+ "gchararray" => "String",
1534
+ "VipsImage" => "Vips::Image",
1535
+ "VipsInterpolate" => "Vips::Interpolate",
1536
+ "VipsConnection" => "Vips::Connection",
1537
+ "VipsSource" => "Vips::Source",
1538
+ "VipsTarget" => "Vips::Target",
1539
+ "VipsSourceCustom" => "Vips::SourceCustom",
1540
+ "VipsTargetCustom" => "Vips::TargetCustom",
1541
+ "VipsArrayDouble" => "Array<Double>",
1542
+ "VipsArrayInt" => "Array<Integer>",
1543
+ "VipsArrayImage" => "Array<Image>",
1544
+ "VipsArrayString" => "Array<String>"
1362
1545
  }
1363
1546
 
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
1409
- end
1410
- else
1411
- optional_input << value
1412
- end
1413
- end
1547
+ # these have hand-written methods, see above
1548
+ NO_GENERATE = ["scale", "bandjoin", "composite", "ifthenelse"]
1414
1549
 
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
1550
+ # these are aliased (appear under several names)
1551
+ ALIAS = ["crop"]
1552
+
1553
+ # turn a gtype into a ruby type name
1554
+ def self.gtype_to_ruby gtype
1555
+ fundamental = GObject.g_type_fundamental gtype
1556
+ type_name = GObject.g_type_name gtype
1557
+
1558
+ if MAP_GO_TO_RUBY.include? type_name
1559
+ type_name = MAP_GO_TO_RUBY[type_name]
1560
+ end
1425
1561
 
1562
+ if fundamental == GObject::GFLAGS_TYPE ||
1563
+ fundamental == GObject::GENUM_TYPE
1564
+ type_name = "Vips::" + type_name[/Vips(.*)/, 1]
1426
1565
  end
1427
1566
 
1567
+ type_name
1568
+ end
1569
+
1570
+ def self.generate_operation introspect
1571
+ return if (introspect.flags & OPERATION_DEPRECATED) != 0
1572
+ return if NO_GENERATE.include? introspect.name
1573
+
1574
+ method_args = introspect.method_args
1575
+ required_output = introspect.required_output
1576
+ optional_input = introspect.optional_input
1577
+ optional_output = introspect.optional_output
1578
+
1428
1579
  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
1580
+ print "self." unless introspect.member_x
1581
+ print "#{introspect.name}("
1582
+ print method_args.map { |x| x[:yard_name] }.join(", ")
1583
+ print ", " if method_args.length > 0
1433
1584
  puts "**opts)"
1434
1585
 
1435
- puts "# #{description.capitalize}."
1586
+ puts "# #{introspect.description.capitalize}."
1587
+
1588
+ method_args.each do |details|
1589
+ yard_name = details[:yard_name]
1590
+ gtype = details[:gtype]
1591
+ blurb = details[:blurb]
1436
1592
 
1437
- required_input.each do |arg|
1438
- puts "# @param #{arg[:name]} [#{arg[:type_name]}] " +
1439
- "#{arg[:blurb]}"
1593
+ puts "# @param #{yard_name} [#{gtype_to_ruby(gtype)}] #{blurb}"
1440
1594
  end
1441
1595
 
1442
1596
  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]}"
1597
+ optional_input.each do |arg_name, details|
1598
+ yard_name = details[:yard_name]
1599
+ gtype = details[:gtype]
1600
+ blurb = details[:blurb]
1601
+
1602
+ puts "# @option opts [#{gtype_to_ruby(gtype)}] :#{yard_name} #{blurb}"
1446
1603
  end
1447
- optional_output.each do |arg|
1448
- print "# @option opts [#{arg[:type_name]}] :#{arg[:name]}"
1449
- puts " Output #{arg[:blurb]}"
1604
+ optional_output.each do |arg_name, details|
1605
+ yard_name = details[:yard_name]
1606
+ gtype = details[:gtype]
1607
+ blurb = details[:blurb]
1608
+
1609
+ print "# @option opts [#{gtype_to_ruby(gtype)}] :#{yard_name}"
1610
+ puts " Output #{blurb}"
1450
1611
  end
1451
1612
 
1452
1613
  print "# @return ["
1453
1614
  if required_output.length == 0
1454
1615
  print "nil"
1455
1616
  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(", ")
1617
+ print gtype_to_ruby(required_output.first[:gtype])
1618
+ else
1619
+ print "Array<"
1620
+ print required_output.map { |x| gtype_to_ruby(x[:gtype]) }.join(", ")
1460
1621
  print ">"
1461
1622
  end
1462
1623
  if optional_output.length > 0
1463
1624
  print ", Hash<Symbol => Object>"
1464
1625
  end
1465
1626
  print "] "
1466
- print required_output.map{|x| x[:blurb]}.join(", ")
1627
+ print required_output.map { |x| x[:blurb] }.join(", ")
1467
1628
  if optional_output.length > 0
1468
1629
  print ", " if required_output.length > 0
1469
1630
  print "Hash of optional output items"
@@ -1473,30 +1634,42 @@ module Vips
1473
1634
  puts ""
1474
1635
  end
1475
1636
 
1476
- generate_class = lambda do |gtype, a|
1477
- nickname = Vips::nickname_find gtype
1637
+ def self.generate
1638
+ alias_gtypes = {}
1639
+ ALIAS.each do |name|
1640
+ gtype = Vips.type_find "VipsOperation", name
1641
+ alias_gtypes[gtype] = name
1642
+ end
1643
+
1644
+ generate_class = lambda do |gtype, _|
1645
+ name = if alias_gtypes.key? gtype
1646
+ alias_gtypes[gtype]
1647
+ else
1648
+ Vips.nickname_find gtype
1649
+ end
1478
1650
 
1479
- if nickname
1480
- begin
1481
- # can fail for abstract types
1482
- op = Vips::Operation.new nickname
1483
- rescue
1651
+ if name
1652
+ begin
1653
+ # can fail for abstract types
1654
+ introspect = Vips::Introspect.get_yard name
1655
+ rescue Vips::Error
1656
+ nil
1657
+ end
1658
+
1659
+ generate_operation(introspect) if introspect
1484
1660
  end
1485
1661
 
1486
- generate_operation.(gtype, nickname, op) if op
1662
+ Vips.vips_type_map gtype, generate_class, nil
1487
1663
  end
1488
1664
 
1489
- Vips::vips_type_map gtype, generate_class, nil
1490
- end
1491
-
1492
- puts "module Vips"
1493
- puts " class Image"
1494
- puts ""
1665
+ puts "module Vips"
1666
+ puts " class Image"
1667
+ puts ""
1495
1668
 
1496
- generate_class.(GObject::g_type_from_name("VipsOperation"), nil)
1669
+ generate_class.call(GObject.g_type_from_name("VipsOperation"), nil)
1497
1670
 
1498
- puts " end"
1499
- puts "end"
1671
+ puts " end"
1672
+ puts "end"
1673
+ end
1500
1674
  end
1501
-
1502
1675
  end