ruby-vips 2.0.15 → 2.1.2

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 (50) 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 +39 -0
  7. data/Gemfile +3 -1
  8. data/README.md +42 -41
  9. data/Rakefile +13 -21
  10. data/TODO +14 -14
  11. data/VERSION +1 -1
  12. data/example/annotate.rb +6 -6
  13. data/example/connection.rb +26 -0
  14. data/example/daltonize8.rb +6 -6
  15. data/example/draw_lines.rb +30 -0
  16. data/example/example1.rb +4 -4
  17. data/example/example2.rb +6 -6
  18. data/example/example3.rb +5 -5
  19. data/example/example4.rb +2 -2
  20. data/example/example5.rb +4 -4
  21. data/example/inheritance_with_refcount.rb +35 -36
  22. data/example/progress.rb +30 -0
  23. data/example/thumb.rb +6 -6
  24. data/example/trim8.rb +1 -1
  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 +191 -79
  29. data/lib/vips/blend_mode.rb +29 -25
  30. data/lib/vips/connection.rb +46 -0
  31. data/lib/vips/gobject.rb +27 -12
  32. data/lib/vips/gvalue.rb +62 -50
  33. data/lib/vips/image.rb +475 -256
  34. data/lib/vips/interpolate.rb +3 -2
  35. data/lib/vips/methods.rb +788 -121
  36. data/lib/vips/mutableimage.rb +173 -0
  37. data/lib/vips/object.rb +171 -54
  38. data/lib/vips/operation.rb +272 -117
  39. data/lib/vips/region.rb +73 -0
  40. data/lib/vips/source.rb +88 -0
  41. data/lib/vips/sourcecustom.rb +89 -0
  42. data/lib/vips/target.rb +86 -0
  43. data/lib/vips/targetcustom.rb +77 -0
  44. data/lib/vips/version.rb +1 -1
  45. data/ruby-vips.gemspec +26 -20
  46. metadata +39 -50
  47. data/.rubocop.yml +0 -22
  48. data/.rubocop_todo.yml +0 -515
  49. data/.travis.yml +0 -62
  50. 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)
@@ -67,6 +78,11 @@ module Vips
67
78
  class Image < Vips::Object
68
79
  alias_method :parent_get_typeof, :get_typeof
69
80
 
81
+ # FFI sets a pointer's size to this magic value if the size of the memory
82
+ # chunk the pointer points to is unknown to FFI.
83
+ UNKNOWN_POINTER_SIZE = FFI::Pointer.new(1).size
84
+ private_constant :UNKNOWN_POINTER_SIZE
85
+
70
86
  private
71
87
 
72
88
  # the layout of the VipsImage struct
@@ -94,17 +110,17 @@ module Vips
94
110
  # handy for overloads ... want to be able to apply a function to an
95
111
  # array or to a scalar
96
112
  def self.smap x, &block
97
- x.is_a?(Array) ? x.map { |y| smap(y, &block) } : block.(x)
113
+ x.is_a?(Array) ? x.map { |y| smap(y, &block) } : block.call(x)
98
114
  end
99
115
 
100
116
  def self.complex? format
101
117
  format_number = GObject::GValue.from_nick BAND_FORMAT_TYPE, format
102
- Vips::vips_band_format_iscomplex(format_number) != 0
118
+ Vips.vips_band_format_iscomplex(format_number) != 0
103
119
  end
104
120
 
105
121
  def self.float? format
106
122
  format_number = GObject::GValue.from_nick BAND_FORMAT_TYPE, format
107
- Vips::vips_band_format_isfloat(format_number) != 0
123
+ Vips.vips_band_format_isfloat(format_number) != 0
108
124
  end
109
125
 
110
126
  # run a complex operation on a complex image, or an image with an even
@@ -113,12 +129,12 @@ module Vips
113
129
  def self.run_cmplx image, &block
114
130
  original_format = image.format
115
131
 
116
- unless Image::complex? image.format
132
+ unless Image.complex? image.format
117
133
  if image.bands % 2 != 0
118
- raise Error, "not an even number of bands"
134
+ raise Vips::Error, "not an even number of bands"
119
135
  end
120
136
 
121
- unless Image::float? image.format
137
+ unless Image.float? image.format
122
138
  image = image.cast :float
123
139
  end
124
140
 
@@ -126,9 +142,9 @@ module Vips
126
142
  image = image.copy format: new_format, bands: image.bands / 2
127
143
  end
128
144
 
129
- image = block.(image)
145
+ image = block.call(image)
130
146
 
131
- unless Image::complex? original_format
147
+ unless Image.complex? original_format
132
148
  new_format = image.format == :dpcomplex ? :double : :float
133
149
  image = image.copy format: new_format, bands: image.bands * 2
134
150
  end
@@ -187,15 +203,19 @@ module Vips
187
203
  # 36013-heads-up-ruby-implicitly-converts-a-hash-to-keyword-arguments
188
204
  return false if name == :to_hash
189
205
 
206
+ super
207
+ end
208
+
209
+ def respond_to_missing? name, include_all = false
190
210
  # respond to all vips operations by nickname
191
- return true if Vips::type_find("VipsOperation", name.to_s) != 0
211
+ return true if Vips.type_find("VipsOperation", name.to_s) != 0
192
212
 
193
213
  super
194
214
  end
195
215
 
196
- def self.respond_to? name, include_all = false
216
+ def self.respond_to_missing? name, include_all = false
197
217
  # respond to all vips operations by nickname
198
- return true if Vips::type_find("VipsOperation", name.to_s) != 0
218
+ return true if Vips.type_find("VipsOperation", name.to_s) != 0
199
219
 
200
220
  super
201
221
  end
@@ -219,13 +239,13 @@ module Vips
219
239
  # load options, for example:
220
240
  #
221
241
  # ```
222
- # image = Vips::new_from_file "fred.jpg[shrink=2]"
242
+ # image = Vips::Image.new_from_file "fred.jpg[shrink=2]"
223
243
  # ```
224
244
  #
225
245
  # You can also supply options as a hash, for example:
226
246
  #
227
247
  # ```
228
- # image = Vips::new_from_file "fred.jpg", shrink: 2
248
+ # image = Vips::Image.new_from_file "fred.jpg", shrink: 2
229
249
  # ```
230
250
  #
231
251
  # The full set of options available depend upon the load operation that
@@ -253,18 +273,18 @@ module Vips
253
273
  def self.new_from_file name, **opts
254
274
  # very common, and Vips::vips_filename_get_filename will segv if we
255
275
  # pass this
256
- raise Vips::Error, "filename is nil" if name == nil
276
+ raise Vips::Error, "filename is nil" if name.nil?
257
277
 
258
- filename = Vips::p2str(Vips::vips_filename_get_filename name)
259
- option_string = Vips::p2str(Vips::vips_filename_get_options name)
260
- loader = Vips::vips_foreign_find_load filename
261
- raise Vips::Error if loader == nil
278
+ filename = Vips.p2str(Vips.vips_filename_get_filename(name))
279
+ option_string = Vips.p2str(Vips.vips_filename_get_options(name))
280
+ loader = Vips.vips_foreign_find_load filename
281
+ raise Vips::Error if loader.nil?
262
282
 
263
283
  Operation.call loader, [filename], opts, option_string
264
284
  end
265
285
 
266
- # Create a new {Image} for an image encoded, in a format such as
267
- # JPEG, in a binary string. Load options may be passed as
286
+ # Create a new {Image} for an image encoded in a format such as
287
+ # JPEG in a binary string. Load options may be passed as
268
288
  # strings or appended as a hash. For example:
269
289
  #
270
290
  # ```
@@ -295,17 +315,157 @@ module Vips
295
315
  # @macro vips.loadopts
296
316
  # @return [Image] the loaded image
297
317
  def self.new_from_buffer data, option_string, **opts
298
- loader = Vips::vips_foreign_find_load_buffer data, data.bytesize
299
- raise Vips::Error if loader == nil
318
+ loader = Vips.vips_foreign_find_load_buffer data, data.bytesize
319
+ raise Vips::Error if loader.nil?
300
320
 
301
321
  Vips::Operation.call loader, [data], opts, option_string
302
322
  end
303
323
 
324
+ # Create a new {Image} from a C-style array held in memory. For example:
325
+ #
326
+ # ```
327
+ # image = Vips::Image.black(16, 16) + 128
328
+ # data = image.write_to_memory
329
+ #
330
+ # x = Vips::Image.new_from_memory data,
331
+ # image.width, image.height, image.bands, image.format
332
+ # ```
333
+ #
334
+ # Creating a new image from a memory pointer:
335
+ #
336
+ # ```
337
+ # ptr = FFI::MemoryPointer.new(:uchar, 10*10)
338
+ # # => #<FFI::MemoryPointer address=0x00007fc236db31d0 size=100>
339
+ # x = Vips::Image.new_from_memory(ptr, 10, 10, 1, :uchar)
340
+ # ```
341
+ #
342
+ # Creating a new image from an address only pointer:
343
+ #
344
+ # ```
345
+ # ptr = call_to_external_c_library(w: 10, h: 10)
346
+ # # => #<FFI::Pointer address=0x00007f9780813a00>
347
+ # ptr_slice = ptr.slice(0, 10*10)
348
+ # # => #<FFI::Pointer address=0x00007f9780813a00 size=100>
349
+ # x = Vips::Image.new_from_memory(ptr_slice, 10, 10, 1, :uchar)
350
+ # ```
351
+ #
352
+ # {new_from_memory} keeps a reference to the array of pixels you pass in
353
+ # to try to prevent that memory from being freed by the Ruby GC while it
354
+ # is being used.
355
+ #
356
+ # See {new_from_memory_copy} for a version of this method which does not
357
+ # keep a reference.
358
+ #
359
+ # @param data [String, FFI::Pointer] the data to load from
360
+ # @param width [Integer] width in pixels
361
+ # @param height [Integer] height in pixels
362
+ # @param bands [Integer] number of bands
363
+ # @param format [Symbol] band format
364
+ # @return [Image] the loaded image
365
+ def self.new_from_memory data, width, height, bands, format
366
+ # prevent data from being freed with JRuby FFI
367
+ if defined?(JRUBY_VERSION) && !data.is_a?(FFI::Pointer)
368
+ data = ::FFI::MemoryPointer.new(:char, data.bytesize).write_bytes data
369
+ end
370
+
371
+ if data.is_a?(FFI::Pointer)
372
+ # A pointer needs to know about the size of the memory it points to.
373
+ # If you have an address-only pointer, use the .slice method to wrap
374
+ # the pointer in a size aware pointer.
375
+ if data.size == UNKNOWN_POINTER_SIZE
376
+ raise Vips::Error, "size of memory is unknown"
377
+ end
378
+ size = data.size
379
+ else
380
+ size = data.bytesize
381
+ end
382
+
383
+ format_number = GObject::GValue.from_nick BAND_FORMAT_TYPE, format
384
+ vi = Vips.vips_image_new_from_memory data, size,
385
+ width, height, bands, format_number
386
+ raise Vips::Error if vi.null?
387
+ image = new(vi)
388
+
389
+ # keep a secret ref to the underlying object .. this reference will be
390
+ # inherited by things that in turn depend on us, so the memory we are
391
+ # using will not be freed
392
+ image.references << data
393
+
394
+ image
395
+ end
396
+
397
+ # Create a new {Image} from memory and copies the memory area. See
398
+ # {new_from_memory} for a version of this method which does not copy the
399
+ # memory area.
400
+ #
401
+ # @param data [String, FFI::Pointer] the data to load from
402
+ # @param width [Integer] width in pixels
403
+ # @param height [Integer] height in pixels
404
+ # @param bands [Integer] number of bands
405
+ # @param format [Symbol] band format
406
+ # @return [Image] the loaded image
407
+ def self.new_from_memory_copy data, width, height, bands, format
408
+ format_number = GObject::GValue.from_nick BAND_FORMAT_TYPE, format
409
+
410
+ if data.is_a?(FFI::Pointer)
411
+ if data.size == UNKNOWN_POINTER_SIZE
412
+ raise Vips::Error, "size of memory is unknown"
413
+ end
414
+ size = data.size
415
+ else
416
+ size = data.bytesize
417
+ end
418
+
419
+ vi = Vips.vips_image_new_from_memory_copy data, size,
420
+ width, height, bands, format_number
421
+ raise Vips::Error if vi.null?
422
+ new(vi)
423
+ end
424
+
425
+ # Create a new {Image} from a source. Load options may be passed as
426
+ # strings or appended as a hash. For example:
427
+ #
428
+ # ```
429
+ # source = Vips::Source.new_from_file("k2.jpg")
430
+ # image = Vips::Image.new_from_source source, "shrink=2"
431
+ # ```
432
+ #
433
+ # or alternatively:
434
+ #
435
+ # ```
436
+ # image = Vips::Image.new_from_source source, "", shrink: 2
437
+ # ```
438
+ #
439
+ # The options available depend on the file format. Try something like:
440
+ #
441
+ # ```
442
+ # $ vips jpegload_source
443
+ # ```
444
+ #
445
+ # at the command-line to see the available options. Not all loaders
446
+ # support load from source, but at least JPEG, PNG and
447
+ # TIFF images will work.
448
+ #
449
+ # Loading is fast: only enough data is read to be able to fill
450
+ # out the header. Pixels will only be read and decompressed when they are
451
+ # needed.
452
+ #
453
+ # @param source [Vips::Source] the source to load from
454
+ # @param option_string [String] load options as a string
455
+ # @macro vips.loadopts
456
+ # @return [Image] the loaded image
457
+ def self.new_from_source source, option_string, **opts
458
+ loader = Vips.vips_foreign_find_load_source source
459
+ raise Vips::Error if loader.nil?
460
+
461
+ Vips::Operation.call loader, [source], opts, option_string
462
+ end
463
+
304
464
  def self.matrix_from_array width, height, array
305
465
  ptr = FFI::MemoryPointer.new :double, array.length
306
466
  ptr.write_array_of_double array
307
- image = Vips::vips_image_new_matrix_from_array width, height,
308
- ptr, array.length
467
+ image = Vips.vips_image_new_matrix_from_array width, height,
468
+ ptr, array.length
309
469
  Vips::Image.new image
310
470
  end
311
471
 
@@ -317,13 +477,13 @@ module Vips
317
477
  # For example:
318
478
  #
319
479
  # ```
320
- # image = Vips::new_from_array [1, 2, 3]
480
+ # image = Vips::Image.new_from_array [1, 2, 3]
321
481
  # ```
322
482
  #
323
483
  # or
324
484
  #
325
485
  # ```
326
- # image = Vips::new_from_array [
486
+ # image = Vips::Image.new_from_array [
327
487
  # [-1, -1, -1],
328
488
  # [-1, 16, -1],
329
489
  # [-1, -1, -1]], 8
@@ -358,18 +518,22 @@ module Vips
358
518
  width = array.length
359
519
  end
360
520
 
521
+ unless array.length == width * height
522
+ raise Vips::Error, "Bad array dimensions."
523
+ end
524
+
361
525
  unless array.all? { |x| x.is_a? Numeric }
362
526
  raise Vips::Error, "Not all array elements are Numeric."
363
527
  end
364
528
 
365
529
  image = Vips::Image.matrix_from_array width, height, array
366
- raise Vips::Error if image == nil
367
-
368
- # be careful to set them as double
369
- image.set_type GObject::GDOUBLE_TYPE, 'scale', scale.to_f
370
- image.set_type GObject::GDOUBLE_TYPE, 'offset', offset.to_f
530
+ raise Vips::Error if image.nil?
371
531
 
372
- return image
532
+ image.mutate do |mutable|
533
+ # be careful to set them as double
534
+ mutable.set_type! GObject::GDOUBLE_TYPE, "scale", scale.to_f
535
+ mutable.set_type! GObject::GDOUBLE_TYPE, "offset", offset.to_f
536
+ end
373
537
  end
374
538
 
375
539
  # A new image is created with the same width, height, format,
@@ -385,7 +549,7 @@ module Vips
385
549
  pixel = (Vips::Image.black(1, 1) + value).cast(format)
386
550
  image = pixel.embed 0, 0, width, height, extend: :copy
387
551
  image.copy interpretation: interpretation, xres: xres, yres: yres,
388
- xoffset: xoffset, yoffset: yoffset
552
+ xoffset: xoffset, yoffset: yoffset
389
553
  end
390
554
 
391
555
  # Write this image to a file. Save options may be encoded in the
@@ -418,12 +582,12 @@ module Vips
418
582
  #
419
583
  # @param name [String] filename to write to
420
584
  def write_to_file name, **opts
421
- filename = Vips::p2str(Vips::vips_filename_get_filename name)
422
- option_string = Vips::p2str(Vips::vips_filename_get_options name)
423
- saver = Vips::vips_foreign_find_save filename
424
- if saver == nil
425
- raise Vips::Error, "No known saver for '#{filename}'."
426
- end
585
+ raise Vips::Error, "filename is nil" if name.nil?
586
+
587
+ filename = Vips.p2str(Vips.vips_filename_get_filename(name))
588
+ option_string = Vips.p2str(Vips.vips_filename_get_options(name))
589
+ saver = Vips.vips_foreign_find_save filename
590
+ raise Vips::Error if saver.nil?
427
591
 
428
592
  Vips::Operation.call saver, [self, filename], opts, option_string
429
593
 
@@ -456,19 +620,55 @@ module Vips
456
620
  # @macro vips.saveopts
457
621
  # @return [String] the image saved in the specified format
458
622
  def write_to_buffer format_string, **opts
459
- filename = Vips::p2str(Vips::vips_filename_get_filename format_string)
460
- option_string = Vips::p2str(Vips::vips_filename_get_options format_string)
461
- saver = Vips::vips_foreign_find_save_buffer filename
462
- if saver == nil
463
- raise Vips::Error, "No known saver for '#{filename}'."
464
- end
623
+ raise Vips::Error, "filename is nil" if format_string.nil?
624
+ filename = Vips.p2str(Vips.vips_filename_get_filename(format_string))
625
+ option_string = Vips.p2str(Vips.vips_filename_get_options(format_string))
626
+ saver = Vips.vips_foreign_find_save_buffer filename
627
+ raise Vips::Error if saver.nil?
465
628
 
466
629
  buffer = Vips::Operation.call saver, [self], opts, option_string
467
- raise Vips::Error if buffer == nil
630
+ raise Vips::Error if buffer.nil?
468
631
 
469
632
  write_gc
470
633
 
471
- return buffer
634
+ buffer
635
+ end
636
+
637
+ # Write this image to a target. Save options may be encoded in
638
+ # the format_string or given as a hash. For example:
639
+ #
640
+ # ```ruby
641
+ # target = Vips::Target.new_to_file "k2.jpg"
642
+ # image.write_to_target target, ".jpg[Q=90]"
643
+ # ```
644
+ #
645
+ # or equivalently:
646
+ #
647
+ # ```ruby
648
+ # image.write_to_target target, ".jpg", Q: 90
649
+ # ```
650
+ #
651
+ # The full set of save options depend on the selected saver. Try
652
+ # something like:
653
+ #
654
+ # ```
655
+ # $ vips jpegsave_target
656
+ # ```
657
+ #
658
+ # to see all the available options for JPEG save.
659
+ #
660
+ # @param target [Vips::Target] the target to write to
661
+ # @param format_string [String] save format plus string options
662
+ # @macro vips.saveopts
663
+ def write_to_target target, format_string, **opts
664
+ raise Vips::Error, "filename is nil" if format_string.nil?
665
+ filename = Vips.p2str(Vips.vips_filename_get_filename(format_string))
666
+ option_string = Vips.p2str(Vips.vips_filename_get_options(format_string))
667
+ saver = Vips.vips_foreign_find_save_target filename
668
+ raise Vips::Error if saver.nil?
669
+
670
+ Vips::Operation.call saver, [self, target], opts, option_string
671
+ write_gc
472
672
  end
473
673
 
474
674
  # Write this image to a large memory buffer.
@@ -476,8 +676,8 @@ module Vips
476
676
  # @return [String] the pixels as a huge binary string
477
677
  def write_to_memory
478
678
  len = Vips::SizeStruct.new
479
- ptr = Vips::vips_image_write_to_memory self, len
480
- raise Vips::Error if ptr == nil
679
+ ptr = Vips.vips_image_write_to_memory self, len
680
+ raise Vips::Error if ptr.nil?
481
681
 
482
682
  # wrap up as an autopointer
483
683
  ptr = FFI::AutoPointer.new(ptr, GLib::G_FREE)
@@ -485,6 +685,28 @@ module Vips
485
685
  ptr.get_bytes 0, len[:value]
486
686
  end
487
687
 
688
+ # Turn progress signalling on and off.
689
+ #
690
+ # If this is on, the most-downstream image from this image will issue
691
+ # progress signals.
692
+ #
693
+ # @see Object#signal_connect
694
+ # @param state [Boolean] progress signalling state
695
+ def set_progress state
696
+ Vips.vips_image_set_progress self, state
697
+ end
698
+
699
+ # Kill computation of this time.
700
+ #
701
+ # Set true to stop computation of this image. You can call this from a
702
+ # progress handler, for example.
703
+ #
704
+ # @see Object#signal_connect
705
+ # @param kill [Boolean] stop computation
706
+ def set_kill kill
707
+ Vips.vips_image_set_kill self, kill
708
+ end
709
+
488
710
  # Get the `GType` of a metadata field. The result is 0 if no such field
489
711
  # exists.
490
712
  #
@@ -494,12 +716,12 @@ module Vips
494
716
  def get_typeof name
495
717
  # on libvips before 8.5, property types must be searched first,
496
718
  # since vips_image_get_typeof returned built-in enums as int
497
- unless Vips::at_least_libvips?(8, 5)
719
+ unless Vips.at_least_libvips?(8, 5)
498
720
  gtype = parent_get_typeof name
499
721
  return gtype if gtype != 0
500
722
  end
501
723
 
502
- Vips::vips_image_get_typeof self, name
724
+ Vips.vips_image_get_typeof self, name
503
725
  end
504
726
 
505
727
  # Get a metadata item from an image. Ruby types are constructed
@@ -518,15 +740,16 @@ module Vips
518
740
  def get name
519
741
  # with old libvips, we must fetch properties (as opposed to
520
742
  # metadata) via VipsObject
521
- unless Vips::at_least_libvips?(8, 5)
743
+ unless Vips.at_least_libvips?(8, 5)
522
744
  return super if parent_get_typeof(name) != 0
523
745
  end
524
746
 
525
747
  gvalue = GObject::GValue.alloc
526
- result = Vips::vips_image_get self, name, gvalue
527
- raise Vips::Error if result != 0
748
+ raise Vips::Error if Vips.vips_image_get(self, name, gvalue) != 0
749
+ result = gvalue.get
750
+ gvalue.unset
528
751
 
529
- gvalue.get
752
+ result
530
753
  end
531
754
 
532
755
  # Get the names of all fields on an image. Use this to loop over all
@@ -537,66 +760,64 @@ module Vips
537
760
  # vips_image_get_fields() was added in libvips 8.5
538
761
  return [] unless Vips.respond_to? :vips_image_get_fields
539
762
 
540
- array = Vips::vips_image_get_fields self
763
+ array = Vips.vips_image_get_fields self
541
764
 
542
765
  names = []
543
766
  p = array
544
767
  until (q = p.read_pointer).null?
545
768
  names << q.read_string
546
- GLib::g_free q
769
+ GLib.g_free q
547
770
  p += FFI::Type::POINTER.size
548
771
  end
549
- GLib::g_free array
772
+ GLib.g_free array
550
773
 
551
774
  names
552
775
  end
553
776
 
554
- # Create a metadata item on an image of the specifed type. Ruby types
555
- # are automatically transformed into the matching `GType`, if possible.
777
+ # Mutate an image with a block. Inside the block, you can call methods
778
+ # which modify the image, such as setting or removing metadata, or
779
+ # modifying pixels.
556
780
  #
557
- # For example, you can use this to set an image's ICC profile:
781
+ # For example:
558
782
  #
559
- # ```
560
- # x = y.set_type Vips::BLOB_TYPE, "icc-profile-data", profile
783
+ # ```ruby
784
+ # image = image.mutate do |x|
785
+ # (0 ... 1).step(0.01) do |i|
786
+ # x.draw_line! 255, x.width * i, 0, 0, x.height * (1 - i)
787
+ # end
788
+ # end
561
789
  # ```
562
790
  #
563
- # where `profile` is an ICC profile held as a binary string object.
791
+ # See {MutableImage}.
792
+ def mutate
793
+ mutable = Vips::MutableImage.new self
794
+ yield mutable
795
+ mutable.image
796
+ end
797
+
798
+ # This method is deprecated.
564
799
  #
565
- # @see set
566
- # @param gtype [Integer] GType of item
567
- # @param name [String] Metadata field to set
568
- # @param value [Object] Value to set
800
+ # Please use {MutableImage#set_type!} instead.
569
801
  def set_type gtype, name, value
570
802
  gvalue = GObject::GValue.alloc
571
803
  gvalue.init gtype
572
804
  gvalue.set value
573
- Vips::vips_image_set self, name, gvalue
805
+ Vips.vips_image_set self, name, gvalue
806
+ gvalue.unset
574
807
  end
575
808
 
576
- # Set the value of a metadata item on an image. The metadata item must
577
- # already exist. Ruby types are automatically transformed into the
578
- # matching `GValue`, if possible.
579
- #
580
- # For example, you can use this to set an image's ICC profile:
581
- #
582
- # ```
583
- # x = y.set "icc-profile-data", profile
584
- # ```
585
- #
586
- # where `profile` is an ICC profile held as a binary string object.
809
+ # This method is deprecated.
587
810
  #
588
- # @see set_type
589
- # @param name [String] Metadata field to set
590
- # @param value [Object] Value to set
811
+ # Please use {MutableImage#set!} instead.
591
812
  def set name, value
592
813
  set_type get_typeof(name), name, value
593
814
  end
594
815
 
595
- # Remove a metadata item from an image.
816
+ # This method is deprecated.
596
817
  #
597
- # @param name [String] Metadata field to remove
818
+ # Please use {MutableImage#remove!} instead.
598
819
  def remove name
599
- Vips::vips_image_remove self, name
820
+ Vips.vips_image_remove self, name
600
821
  end
601
822
 
602
823
  # compatibility: old name for get
@@ -604,7 +825,9 @@ module Vips
604
825
  get name
605
826
  end
606
827
 
607
- # compatibility: old name for set
828
+ # This method is deprecated.
829
+ #
830
+ # Please use {MutableImage#set!} instead.
608
831
  def set_value name, value
609
832
  set name, value
610
833
  end
@@ -613,21 +836,21 @@ module Vips
613
836
  #
614
837
  # @return [Integer] image width, in pixels
615
838
  def width
616
- get "width"
839
+ Vips.vips_image_get_width self
617
840
  end
618
841
 
619
842
  # Get image height, in pixels.
620
843
  #
621
844
  # @return [Integer] image height, in pixels
622
845
  def height
623
- get "height"
846
+ Vips.vips_image_get_height self
624
847
  end
625
848
 
626
849
  # Get number of image bands.
627
850
  #
628
851
  # @return [Integer] number of image bands
629
852
  def bands
630
- get "bands"
853
+ Vips.vips_image_get_bands self
631
854
  end
632
855
 
633
856
  # Get image format.
@@ -711,23 +934,23 @@ module Vips
711
934
  [width, height]
712
935
  end
713
936
 
714
- if Vips::at_least_libvips?(8, 5)
937
+ if Vips.at_least_libvips?(8, 5)
715
938
  # Detect if image has an alpha channel
716
939
  #
717
940
  # @return [Boolean] true if image has an alpha channel.
718
941
  def has_alpha?
719
- return Vips::vips_image_hasalpha(self) != 0
942
+ Vips.vips_image_hasalpha(self) != 0
720
943
  end
721
944
  end
722
945
 
723
946
  # vips_addalpha was added in libvips 8.6
724
- if Vips::at_least_libvips?(8, 6)
947
+ if Vips.at_least_libvips?(8, 6)
725
948
  # Append an alpha channel to an image.
726
949
  #
727
950
  # @return [Image] new image
728
951
  def add_alpha
729
952
  ptr = GenericPtr.new
730
- result = Vips::vips_addalpha self, ptr
953
+ result = Vips.vips_addalpha self, ptr
731
954
  raise Vips::Error if result != 0
732
955
 
733
956
  Vips::Image.new ptr[:value]
@@ -742,7 +965,7 @@ module Vips
742
965
  #
743
966
  # @return [Image] new memory image
744
967
  def copy_memory
745
- new_image = Vips::vips_image_copy_memory self
968
+ new_image = Vips.vips_image_copy_memory self
746
969
  Vips::Image.new new_image
747
970
  end
748
971
 
@@ -752,7 +975,7 @@ module Vips
752
975
  #
753
976
  # @return [Image] modified image
754
977
  def draw_point ink, left, top, **opts
755
- draw_rect ink, left, top, 1, 1, opts
978
+ draw_rect ink, left, top, 1, 1, **opts
756
979
  end
757
980
 
758
981
  # Add an image, constant or array.
@@ -770,7 +993,7 @@ module Vips
770
993
  # @return [Image] result of subtraction
771
994
  def - other
772
995
  other.is_a?(Vips::Image) ?
773
- subtract(other) : linear(1, Image::smap(other) { |x| x * -1 })
996
+ subtract(other) : linear(1, Image.smap(other) { |x| x * -1 })
774
997
  end
775
998
 
776
999
  # Multiply an image, constant or array.
@@ -788,7 +1011,7 @@ module Vips
788
1011
  # @return [Image] result of division
789
1012
  def / other
790
1013
  other.is_a?(Vips::Image) ?
791
- divide(other) : linear(Image::smap(other) { |x| 1.0 / x }, 0)
1014
+ divide(other) : linear(Image.smap(other) { |x| 1.0 / x }, 0)
792
1015
  end
793
1016
 
794
1017
  # Remainder after integer division with an image, constant or array.
@@ -914,7 +1137,7 @@ module Vips
914
1137
  # @return [Image] result of equality
915
1138
  def == other
916
1139
  # for equality, we must allow tests against nil
917
- if other == nil
1140
+ if other.nil?
918
1141
  false
919
1142
  else
920
1143
  call_enum "relational", other, :equal
@@ -927,7 +1150,7 @@ module Vips
927
1150
  # @return [Image] result of inequality
928
1151
  def != other
929
1152
  # for equality, we must allow tests against nil
930
- if other == nil
1153
+ if other.nil?
931
1154
  true
932
1155
  else
933
1156
  call_enum "relational", other, :noteq
@@ -949,38 +1172,40 @@ module Vips
949
1172
  end
950
1173
  end
951
1174
 
952
- # Convert to an Array. This will be slow for large images.
1175
+ # Convert to an Enumerator. Similar to `#to_a` but lazier.
953
1176
  #
954
- # @return [Array] array of Fixnum
955
- def to_a
956
- # we render the image to a big string, then unpack
957
- # as a Ruby array of the correct type
958
- memory = write_to_memory
959
-
1177
+ # @return [Enumerator] Enumerator of Enumerators of Arrays of Numerics
1178
+ def to_enum
960
1179
  # make the template for unpack
961
1180
  template = {
962
- char: 'c',
963
- uchar: 'C',
964
- short: 's_',
965
- ushort: 'S_',
966
- int: 'i_',
967
- uint: 'I_',
968
- float: 'f',
969
- double: 'd',
970
- complex: 'f',
971
- dpcomplex: 'd'
972
- }[format] + '*'
1181
+ char: "c",
1182
+ uchar: "C",
1183
+ short: "s_",
1184
+ ushort: "S_",
1185
+ int: "i_",
1186
+ uint: "I_",
1187
+ float: "f",
1188
+ double: "d",
1189
+ complex: "f",
1190
+ dpcomplex: "d"
1191
+ }[format] + "*"
973
1192
 
974
- # and unpack into something like [1, 2, 3, 4 ..]
975
- array = memory.unpack(template)
1193
+ # we render the image to a big string, then unpack into
1194
+ # one-dimensional array as a Ruby array of the correct type
1195
+ array = write_to_memory.unpack template
976
1196
 
977
- # gather band elements together
978
- pixel_array = array.each_slice(bands).to_a
1197
+ # gather bands of a pixel together
1198
+ pixel_array = array.each_slice bands
979
1199
 
980
- # build rows
981
- row_array = pixel_array.each_slice(width).to_a
1200
+ # gather pixels of a row together
1201
+ pixel_array.each_slice width
1202
+ end
982
1203
 
983
- return row_array
1204
+ # Convert to an Array. This will be slow for large images.
1205
+ #
1206
+ # @return [Array] Array of Arrays of Arrays of Numerics
1207
+ def to_a
1208
+ to_enum.to_a
984
1209
  end
985
1210
 
986
1211
  # Return the largest integral value not greater than the argument.
@@ -1056,7 +1281,10 @@ module Vips
1056
1281
  # @param overlay [Image, Array<Image>] images to composite
1057
1282
  # @param mode [BlendMode, Array<BlendMode>] blend modes to use
1058
1283
  # @param opts [Hash] Set of options
1059
- # @option opts [Vips::Interpretation] :compositing_space Composite images in this colour space
1284
+ # @option opts [Array<Integer>] :x x positions of overlay
1285
+ # @option opts [Array<Integer>] :y y positions of overlay
1286
+ # @option opts [Vips::Interpretation] :compositing_space Composite images
1287
+ # in this colour space
1060
1288
  # @option opts [Boolean] :premultiplied Images have premultiplied alpha
1061
1289
  # @return [Image] blended image
1062
1290
  def composite overlay, mode, **opts
@@ -1071,7 +1299,7 @@ module Vips
1071
1299
  GObject::GValue.from_nick Vips::BLEND_MODE_TYPE, x
1072
1300
  end
1073
1301
 
1074
- Vips::Image.composite([self] + overlay, mode, opts)
1302
+ Vips::Image.composite([self] + overlay, mode, **opts)
1075
1303
  end
1076
1304
 
1077
1305
  # Return the coordinates of the image maximum.
@@ -1080,9 +1308,9 @@ module Vips
1080
1308
  # coordinate of maximum
1081
1309
  def maxpos
1082
1310
  v, opts = max x: true, y: true
1083
- x = opts['x']
1084
- y = opts['y']
1085
- return v, x, y
1311
+ x = opts["x"]
1312
+ y = opts["y"]
1313
+ [v, x, y]
1086
1314
  end
1087
1315
 
1088
1316
  # Return the coordinates of the image minimum.
@@ -1091,9 +1319,9 @@ module Vips
1091
1319
  # coordinate of minimum
1092
1320
  def minpos
1093
1321
  v, opts = min x: true, y: true
1094
- x = opts['x']
1095
- y = opts['y']
1096
- return v, x, y
1322
+ x = opts["x"]
1323
+ y = opts["y"]
1324
+ [v, x, y]
1097
1325
  end
1098
1326
 
1099
1327
  # a median filter
@@ -1101,7 +1329,7 @@ module Vips
1101
1329
  # @param size [Integer] size of filter window
1102
1330
  # @return [Image] result of median filter
1103
1331
  def median size = 3
1104
- rank size, size, (size * size) / 2
1332
+ rank size, size, size**2 / 2
1105
1333
  end
1106
1334
 
1107
1335
  # Return the real part of a complex image.
@@ -1128,7 +1356,7 @@ module Vips
1128
1356
  # @see xyz
1129
1357
  # @return [Image] image converted to polar coordinates
1130
1358
  def polar
1131
- Image::run_cmplx(self) { |x| x.complex :polar }
1359
+ Image.run_cmplx(self) { |x| x.complex :polar }
1132
1360
  end
1133
1361
 
1134
1362
  # Return an image with polar pixels converted to rectangular.
@@ -1141,7 +1369,7 @@ module Vips
1141
1369
  # @see xyz
1142
1370
  # @return [Image] image converted to rectangular coordinates
1143
1371
  def rect
1144
- Image::run_cmplx(self) { |x| x.complex :rect }
1372
+ Image.run_cmplx(self) { |x| x.complex :rect }
1145
1373
  end
1146
1374
 
1147
1375
  # Return the complex conjugate of an image.
@@ -1153,7 +1381,7 @@ module Vips
1153
1381
  #
1154
1382
  # @return [Image] complex conjugate
1155
1383
  def conj
1156
- Image::run_cmplx(self) { |x| x.complex :conj }
1384
+ Image.run_cmplx(self) { |x| x.complex :conj }
1157
1385
  end
1158
1386
 
1159
1387
  # Calculate the cross phase of two images.
@@ -1321,29 +1549,26 @@ module Vips
1321
1549
  # @param opts [Hash] Set of options
1322
1550
  # @return [Vips::Image] Output image
1323
1551
  def scaleimage **opts
1324
- Vips::Image.scale self, opts
1552
+ Vips::Image.scale self, **opts
1325
1553
  end
1326
1554
  end
1327
1555
  end
1328
1556
 
1329
1557
  module Vips
1330
- # This method generates yard comments for all the dynamically bound
1558
+ # This module generates yard comments for all the dynamically bound
1331
1559
  # vips operations.
1332
1560
  #
1333
1561
  # Regenerate with something like:
1334
1562
  #
1335
1563
  # ```
1336
1564
  # $ ruby > methods.rb
1337
- # require 'vips'; Vips::generate_yard
1565
+ # require "vips"; Vips::Yard.generate
1338
1566
  # ^D
1339
1567
  # ```
1340
1568
 
1341
- def self.generate_yard
1342
- # these have hand-written methods, see above
1343
- no_generate = ["scale", "bandjoin", "composite", "ifthenelse"]
1344
-
1569
+ module Yard
1345
1570
  # map gobject's type names to Ruby
1346
- map_go_to_ruby = {
1571
+ MAP_GO_TO_RUBY = {
1347
1572
  "gboolean" => "Boolean",
1348
1573
  "gint" => "Integer",
1349
1574
  "gdouble" => "Float",
@@ -1351,109 +1576,91 @@ module Vips
1351
1576
  "gchararray" => "String",
1352
1577
  "VipsImage" => "Vips::Image",
1353
1578
  "VipsInterpolate" => "Vips::Interpolate",
1579
+ "VipsConnection" => "Vips::Connection",
1580
+ "VipsSource" => "Vips::Source",
1581
+ "VipsTarget" => "Vips::Target",
1582
+ "VipsSourceCustom" => "Vips::SourceCustom",
1583
+ "VipsTargetCustom" => "Vips::TargetCustom",
1354
1584
  "VipsArrayDouble" => "Array<Double>",
1355
1585
  "VipsArrayInt" => "Array<Integer>",
1356
1586
  "VipsArrayImage" => "Array<Image>",
1357
- "VipsArrayString" => "Array<String>",
1587
+ "VipsArrayString" => "Array<String>"
1358
1588
  }
1359
1589
 
1360
- generate_operation = lambda do |gtype, nickname, op|
1361
- op_flags = op.get_flags
1362
- return if (op_flags & OPERATION_DEPRECATED) != 0
1363
- return if no_generate.include? nickname
1364
-
1365
- description = Vips::vips_object_get_description op
1366
-
1367
- # find and classify all the arguments the operator can take
1368
- required_input = []
1369
- optional_input = []
1370
- required_output = []
1371
- optional_output = []
1372
- member_x = nil
1373
- op.argument_map do |pspec, argument_class, _argument_instance|
1374
- arg_flags = argument_class[:flags]
1375
- next if (arg_flags & ARGUMENT_CONSTRUCT) == 0
1376
- next if (arg_flags & ARGUMENT_DEPRECATED) != 0
1377
-
1378
- name = pspec[:name].tr("-", "_")
1379
- # 'in' as a param name confuses yard
1380
- name = "im" if name == "in"
1381
- gtype = pspec[:value_type]
1382
- fundamental = GObject::g_type_fundamental gtype
1383
- type_name = GObject::g_type_name gtype
1384
- if map_go_to_ruby.include? type_name
1385
- type_name = map_go_to_ruby[type_name]
1386
- end
1387
- if fundamental == GObject::GFLAGS_TYPE ||
1388
- fundamental == GObject::GENUM_TYPE
1389
- type_name = "Vips::" + type_name[/Vips(.*)/, 1]
1390
- end
1391
- blurb = GObject::g_param_spec_get_blurb pspec
1392
- value = {
1393
- name: name,
1394
- flags: arg_flags,
1395
- gtype: gtype,
1396
- type_name: type_name,
1397
- blurb: blurb
1398
- }
1399
-
1400
- if (arg_flags & ARGUMENT_INPUT) != 0
1401
- if (arg_flags & ARGUMENT_REQUIRED) != 0
1402
- # note the first required input image, if any ... we
1403
- # will be a method of this instance
1404
- if !member_x && gtype == Vips::IMAGE_TYPE
1405
- member_x = value
1406
- else
1407
- required_input << value
1408
- end
1409
- else
1410
- optional_input << value
1411
- end
1412
- end
1590
+ # these have hand-written methods, see above
1591
+ NO_GENERATE = ["scale", "bandjoin", "composite", "ifthenelse"]
1413
1592
 
1414
- # MODIFY INPUT args count as OUTPUT as well
1415
- if (arg_flags & ARGUMENT_OUTPUT) != 0 ||
1416
- ((arg_flags & ARGUMENT_INPUT) != 0 &&
1417
- (arg_flags & ARGUMENT_MODIFY) != 0)
1418
- if (arg_flags & ARGUMENT_REQUIRED) != 0
1419
- required_output << value
1420
- else
1421
- optional_output << value
1422
- end
1423
- end
1593
+ # these are aliased (appear under several names)
1594
+ ALIAS = ["crop"]
1595
+
1596
+ # turn a gtype into a ruby type name
1597
+ def self.gtype_to_ruby gtype
1598
+ fundamental = GObject.g_type_fundamental gtype
1599
+ type_name = GObject.g_type_name gtype
1600
+
1601
+ if MAP_GO_TO_RUBY.include? type_name
1602
+ type_name = MAP_GO_TO_RUBY[type_name]
1603
+ end
1604
+
1605
+ if fundamental == GObject::GFLAGS_TYPE ||
1606
+ fundamental == GObject::GENUM_TYPE
1607
+ type_name = "Vips::" + type_name[/Vips(.*)/, 1]
1424
1608
  end
1425
1609
 
1610
+ type_name
1611
+ end
1612
+
1613
+ def self.generate_operation introspect
1614
+ return if (introspect.flags & OPERATION_DEPRECATED) != 0
1615
+ return if NO_GENERATE.include? introspect.name
1616
+
1617
+ method_args = introspect.method_args
1618
+ required_output = introspect.required_output
1619
+ optional_input = introspect.optional_input
1620
+ optional_output = introspect.optional_output
1621
+
1426
1622
  print "# @!method "
1427
- print "self." unless member_x
1428
- print "#{nickname}("
1429
- print required_input.map { |x| x[:name] }.join(", ")
1430
- print ", " if required_input.length > 0
1623
+ print "self." unless introspect.member_x
1624
+ print "#{introspect.name}("
1625
+ print method_args.map { |x| x[:yard_name] }.join(", ")
1626
+ print ", " if method_args.length > 0
1431
1627
  puts "**opts)"
1432
1628
 
1433
- puts "# #{description.capitalize}."
1629
+ puts "# #{introspect.description.capitalize}."
1630
+
1631
+ method_args.each do |details|
1632
+ yard_name = details[:yard_name]
1633
+ gtype = details[:gtype]
1634
+ blurb = details[:blurb]
1434
1635
 
1435
- required_input.each do |arg|
1436
- puts "# @param #{arg[:name]} [#{arg[:type_name]}] #{arg[:blurb]}"
1636
+ puts "# @param #{yard_name} [#{gtype_to_ruby(gtype)}] #{blurb}"
1437
1637
  end
1438
1638
 
1439
1639
  puts "# @param opts [Hash] Set of options"
1440
- optional_input.each do |arg|
1441
- puts "# @option opts [#{arg[:type_name]}] :#{arg[:name]} " +
1442
- "#{arg[:blurb]}"
1640
+ optional_input.each do |arg_name, details|
1641
+ yard_name = details[:yard_name]
1642
+ gtype = details[:gtype]
1643
+ blurb = details[:blurb]
1644
+
1645
+ puts "# @option opts [#{gtype_to_ruby(gtype)}] :#{yard_name} #{blurb}"
1443
1646
  end
1444
- optional_output.each do |arg|
1445
- print "# @option opts [#{arg[:type_name]}] :#{arg[:name]}"
1446
- puts " Output #{arg[:blurb]}"
1647
+ optional_output.each do |arg_name, details|
1648
+ yard_name = details[:yard_name]
1649
+ gtype = details[:gtype]
1650
+ blurb = details[:blurb]
1651
+
1652
+ print "# @option opts [#{gtype_to_ruby(gtype)}] :#{yard_name}"
1653
+ puts " Output #{blurb}"
1447
1654
  end
1448
1655
 
1449
1656
  print "# @return ["
1450
1657
  if required_output.length == 0
1451
1658
  print "nil"
1452
1659
  elsif required_output.length == 1
1453
- print required_output.first[:type_name]
1660
+ print gtype_to_ruby(required_output.first[:gtype])
1454
1661
  else
1455
1662
  print "Array<"
1456
- print required_output.map { |x| x[:type_name] }.join(", ")
1663
+ print required_output.map { |x| gtype_to_ruby(x[:gtype]) }.join(", ")
1457
1664
  print ">"
1458
1665
  end
1459
1666
  if optional_output.length > 0
@@ -1470,30 +1677,42 @@ module Vips
1470
1677
  puts ""
1471
1678
  end
1472
1679
 
1473
- generate_class = lambda do |gtype, _|
1474
- nickname = Vips::nickname_find gtype
1680
+ def self.generate
1681
+ alias_gtypes = {}
1682
+ ALIAS.each do |name|
1683
+ gtype = Vips.type_find "VipsOperation", name
1684
+ alias_gtypes[gtype] = name
1685
+ end
1475
1686
 
1476
- if nickname
1477
- begin
1478
- # can fail for abstract types
1479
- op = Vips::Operation.new nickname
1480
- rescue Vips::Error
1481
- nil
1687
+ generate_class = lambda do |gtype, _|
1688
+ name = if alias_gtypes.key? gtype
1689
+ alias_gtypes[gtype]
1690
+ else
1691
+ Vips.nickname_find gtype
1482
1692
  end
1483
1693
 
1484
- generate_operation.(gtype, nickname, op) if op
1485
- end
1694
+ if name
1695
+ begin
1696
+ # can fail for abstract types
1697
+ introspect = Vips::Introspect.get_yard name
1698
+ rescue Vips::Error
1699
+ nil
1700
+ end
1486
1701
 
1487
- Vips::vips_type_map gtype, generate_class, nil
1488
- end
1702
+ generate_operation(introspect) if introspect
1703
+ end
1489
1704
 
1490
- puts "module Vips"
1491
- puts " class Image"
1492
- puts ""
1705
+ Vips.vips_type_map gtype, generate_class, nil
1706
+ end
1707
+
1708
+ puts "module Vips"
1709
+ puts " class Image"
1710
+ puts ""
1493
1711
 
1494
- generate_class.(GObject::g_type_from_name("VipsOperation"), nil)
1712
+ generate_class.call(GObject.g_type_from_name("VipsOperation"), nil)
1495
1713
 
1496
- puts " end"
1497
- puts "end"
1714
+ puts " end"
1715
+ puts "end"
1716
+ end
1498
1717
  end
1499
1718
  end