ruby-vips 2.0.15 → 2.1.2

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