ruby-vips 2.0.14 → 2.1.1

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