ruby-vips 2.0.17 → 2.1.3

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 +26 -0
  7. data/Gemfile +3 -1
  8. data/README.md +12 -11
  9. data/Rakefile +13 -21
  10. data/TODO +4 -8
  11. data/VERSION +1 -1
  12. data/example/annotate.rb +6 -6
  13. data/example/connection.rb +18 -9
  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 +46 -39
  22. data/example/progress.rb +3 -3
  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 +127 -76
  29. data/lib/vips/blend_mode.rb +29 -25
  30. data/lib/vips/connection.rb +4 -4
  31. data/lib/vips/gobject.rb +18 -11
  32. data/lib/vips/gvalue.rb +54 -54
  33. data/lib/vips/image.rb +289 -165
  34. data/lib/vips/interpolate.rb +3 -2
  35. data/lib/vips/methods.rb +484 -107
  36. data/lib/vips/mutableimage.rb +173 -0
  37. data/lib/vips/object.rb +86 -93
  38. data/lib/vips/operation.rb +161 -82
  39. data/lib/vips/region.rb +6 -6
  40. data/lib/vips/source.rb +11 -12
  41. data/lib/vips/sourcecustom.rb +7 -8
  42. data/lib/vips/target.rb +12 -13
  43. data/lib/vips/targetcustom.rb +9 -10
  44. data/lib/vips/version.rb +1 -1
  45. data/ruby-vips.gemspec +26 -22
  46. metadata +29 -49
  47. data/.rubocop.yml +0 -22
  48. data/.rubocop_todo.yml +0 -473
  49. data/.travis.yml +0 -57
  50. data/install-vips.sh +0 -26
data/lib/vips/image.rb CHANGED
@@ -4,13 +4,13 @@
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
 
@@ -25,29 +25,35 @@ module Vips
25
25
  attach_function :vips_foreign_find_load_buffer, [:pointer, :size_t], :string
26
26
  attach_function :vips_foreign_find_save_buffer, [:string], :string
27
27
 
28
- if Vips::at_least_libvips?(8, 9)
28
+ if Vips.at_least_libvips?(8, 9)
29
29
  attach_function :vips_foreign_find_load_source, [:pointer], :string
30
30
  attach_function :vips_foreign_find_save_target, [:string], :string
31
31
  end
32
32
 
33
33
  attach_function :vips_image_write_to_memory,
34
- [:pointer, SizeStruct.ptr], :pointer
34
+ [:pointer, SizeStruct.ptr], :pointer
35
35
 
36
36
  attach_function :vips_image_get_typeof, [:pointer, :string], :GType
37
37
  attach_function :vips_image_get,
38
- [:pointer, :string, GObject::GValue.ptr], :int
38
+ [:pointer, :string, GObject::GValue.ptr], :int
39
39
 
40
- if Vips::at_least_libvips?(8, 5)
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)
41
45
  attach_function :vips_image_get_fields, [:pointer], :pointer
42
46
  attach_function :vips_image_hasalpha, [:pointer], :int
43
47
  end
44
48
 
45
- if Vips::at_least_libvips?(8, 6)
49
+ if Vips.at_least_libvips?(8, 6)
46
50
  attach_function :vips_addalpha, [:pointer, :pointer, :varargs], :int
47
51
  end
48
52
 
53
+ # move these three lines to mutableimage when we finally remove set and
54
+ # remove in this class
49
55
  attach_function :vips_image_set,
50
- [:pointer, :string, GObject::GValue.ptr], :void
56
+ [:pointer, :string, GObject::GValue.ptr], :void
51
57
  attach_function :vips_image_remove, [:pointer, :string], :void
52
58
 
53
59
  attach_function :vips_band_format_iscomplex, [:int], :int
@@ -55,6 +61,9 @@ module Vips
55
61
 
56
62
  attach_function :nickname_find, :vips_nickname_find, [:GType], :string
57
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
+
58
67
  # turn a raw pointer that must be freed into a self-freeing Ruby string
59
68
  def self.p2str(pointer)
60
69
  pointer = FFI::AutoPointer.new(pointer, GLib::G_FREE)
@@ -69,6 +78,11 @@ module Vips
69
78
  class Image < Vips::Object
70
79
  alias_method :parent_get_typeof, :get_typeof
71
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
+
72
86
  private
73
87
 
74
88
  # the layout of the VipsImage struct
@@ -96,17 +110,17 @@ module Vips
96
110
  # handy for overloads ... want to be able to apply a function to an
97
111
  # array or to a scalar
98
112
  def self.smap x, &block
99
- 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)
100
114
  end
101
115
 
102
116
  def self.complex? format
103
117
  format_number = GObject::GValue.from_nick BAND_FORMAT_TYPE, format
104
- Vips::vips_band_format_iscomplex(format_number) != 0
118
+ Vips.vips_band_format_iscomplex(format_number) != 0
105
119
  end
106
120
 
107
121
  def self.float? format
108
122
  format_number = GObject::GValue.from_nick BAND_FORMAT_TYPE, format
109
- Vips::vips_band_format_isfloat(format_number) != 0
123
+ Vips.vips_band_format_isfloat(format_number) != 0
110
124
  end
111
125
 
112
126
  # run a complex operation on a complex image, or an image with an even
@@ -115,12 +129,12 @@ module Vips
115
129
  def self.run_cmplx image, &block
116
130
  original_format = image.format
117
131
 
118
- unless Image::complex? image.format
132
+ unless Image.complex? image.format
119
133
  if image.bands % 2 != 0
120
134
  raise Vips::Error, "not an even number of bands"
121
135
  end
122
136
 
123
- unless Image::float? image.format
137
+ unless Image.float? image.format
124
138
  image = image.cast :float
125
139
  end
126
140
 
@@ -128,9 +142,9 @@ module Vips
128
142
  image = image.copy format: new_format, bands: image.bands / 2
129
143
  end
130
144
 
131
- image = block.(image)
145
+ image = block.call(image)
132
146
 
133
- unless Image::complex? original_format
147
+ unless Image.complex? original_format
134
148
  new_format = image.format == :dpcomplex ? :double : :float
135
149
  image = image.copy format: new_format, bands: image.bands * 2
136
150
  end
@@ -189,15 +203,19 @@ module Vips
189
203
  # 36013-heads-up-ruby-implicitly-converts-a-hash-to-keyword-arguments
190
204
  return false if name == :to_hash
191
205
 
206
+ super
207
+ end
208
+
209
+ def respond_to_missing? name, include_all = false
192
210
  # respond to all vips operations by nickname
193
- return true if Vips::type_find("VipsOperation", name.to_s) != 0
211
+ return true if Vips.type_find("VipsOperation", name.to_s) != 0
194
212
 
195
213
  super
196
214
  end
197
215
 
198
- def self.respond_to? name, include_all = false
216
+ def self.respond_to_missing? name, include_all = false
199
217
  # respond to all vips operations by nickname
200
- return true if Vips::type_find("VipsOperation", name.to_s) != 0
218
+ return true if Vips.type_find("VipsOperation", name.to_s) != 0
201
219
 
202
220
  super
203
221
  end
@@ -255,18 +273,18 @@ module Vips
255
273
  def self.new_from_file name, **opts
256
274
  # very common, and Vips::vips_filename_get_filename will segv if we
257
275
  # pass this
258
- raise Vips::Error, "filename is nil" if name == nil
276
+ raise Vips::Error, "filename is nil" if name.nil?
259
277
 
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
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?
264
282
 
265
283
  Operation.call loader, [filename], opts, option_string
266
284
  end
267
285
 
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
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
270
288
  # strings or appended as a hash. For example:
271
289
  #
272
290
  # ```
@@ -297,12 +315,113 @@ module Vips
297
315
  # @macro vips.loadopts
298
316
  # @return [Image] the loaded image
299
317
  def self.new_from_buffer data, option_string, **opts
300
- loader = Vips::vips_foreign_find_load_buffer data, data.bytesize
318
+ loader = Vips.vips_foreign_find_load_buffer data, data.bytesize
301
319
  raise Vips::Error if loader.nil?
302
320
 
303
321
  Vips::Operation.call loader, [data], opts, option_string
304
322
  end
305
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
+
306
425
  # Create a new {Image} from a source. Load options may be passed as
307
426
  # strings or appended as a hash. For example:
308
427
  #
@@ -328,7 +447,7 @@ module Vips
328
447
  # TIFF images will work.
329
448
  #
330
449
  # Loading is fast: only enough data is read to be able to fill
331
- # out the header. Pixels will only be read and decompressed when they are
450
+ # out the header. Pixels will only be read and decompressed when they are
332
451
  # needed.
333
452
  #
334
453
  # @param source [Vips::Source] the source to load from
@@ -336,7 +455,7 @@ module Vips
336
455
  # @macro vips.loadopts
337
456
  # @return [Image] the loaded image
338
457
  def self.new_from_source source, option_string, **opts
339
- loader = Vips::vips_foreign_find_load_source source
458
+ loader = Vips.vips_foreign_find_load_source source
340
459
  raise Vips::Error if loader.nil?
341
460
 
342
461
  Vips::Operation.call loader, [source], opts, option_string
@@ -345,8 +464,8 @@ module Vips
345
464
  def self.matrix_from_array width, height, array
346
465
  ptr = FFI::MemoryPointer.new :double, array.length
347
466
  ptr.write_array_of_double array
348
- image = Vips::vips_image_new_matrix_from_array width, height,
349
- ptr, array.length
467
+ image = Vips.vips_image_new_matrix_from_array width, height,
468
+ ptr, array.length
350
469
  Vips::Image.new image
351
470
  end
352
471
 
@@ -399,18 +518,22 @@ module Vips
399
518
  width = array.length
400
519
  end
401
520
 
521
+ unless array.length == width * height
522
+ raise Vips::Error, "Bad array dimensions."
523
+ end
524
+
402
525
  unless array.all? { |x| x.is_a? Numeric }
403
526
  raise Vips::Error, "Not all array elements are Numeric."
404
527
  end
405
528
 
406
529
  image = Vips::Image.matrix_from_array width, height, array
407
- raise Vips::Error if image == nil
408
-
409
- # be careful to set them as double
410
- image.set_type GObject::GDOUBLE_TYPE, 'scale', scale.to_f
411
- image.set_type GObject::GDOUBLE_TYPE, 'offset', offset.to_f
530
+ raise Vips::Error if image.nil?
412
531
 
413
- 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
414
537
  end
415
538
 
416
539
  # A new image is created with the same width, height, format,
@@ -459,12 +582,12 @@ module Vips
459
582
  #
460
583
  # @param name [String] filename to write to
461
584
  def write_to_file name, **opts
462
- filename = Vips::p2str(Vips::vips_filename_get_filename name)
463
- option_string = Vips::p2str(Vips::vips_filename_get_options name)
464
- saver = Vips::vips_foreign_find_save filename
465
- if saver == nil
466
- raise Vips::Error, "No known saver for '#{filename}'."
467
- 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?
468
591
 
469
592
  Vips::Operation.call saver, [self, filename], opts, option_string
470
593
 
@@ -497,19 +620,18 @@ module Vips
497
620
  # @macro vips.saveopts
498
621
  # @return [String] the image saved in the specified format
499
622
  def write_to_buffer format_string, **opts
500
- filename = Vips::p2str(Vips::vips_filename_get_filename format_string)
501
- option_string = Vips::p2str(Vips::vips_filename_get_options format_string)
502
- saver = Vips::vips_foreign_find_save_buffer filename
503
- if saver == nil
504
- raise Vips::Error, "No known buffer saver for '#{filename}'."
505
- 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?
506
628
 
507
629
  buffer = Vips::Operation.call saver, [self], opts, option_string
508
- raise Vips::Error if buffer == nil
630
+ raise Vips::Error if buffer.nil?
509
631
 
510
632
  write_gc
511
633
 
512
- return buffer
634
+ buffer
513
635
  end
514
636
 
515
637
  # Write this image to a target. Save options may be encoded in
@@ -539,12 +661,11 @@ module Vips
539
661
  # @param format_string [String] save format plus string options
540
662
  # @macro vips.saveopts
541
663
  def write_to_target target, format_string, **opts
542
- filename = Vips::p2str(Vips::vips_filename_get_filename format_string)
543
- option_string = Vips::p2str(Vips::vips_filename_get_options format_string)
544
- saver = Vips::vips_foreign_find_save_target filename
545
- if saver == nil
546
- raise Vips::Error, "No known target saver for '#{filename}'."
547
- end
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?
548
669
 
549
670
  Vips::Operation.call saver, [self, target], opts, option_string
550
671
  write_gc
@@ -555,8 +676,8 @@ module Vips
555
676
  # @return [String] the pixels as a huge binary string
556
677
  def write_to_memory
557
678
  len = Vips::SizeStruct.new
558
- ptr = Vips::vips_image_write_to_memory self, len
559
- raise Vips::Error if ptr == nil
679
+ ptr = Vips.vips_image_write_to_memory self, len
680
+ raise Vips::Error if ptr.nil?
560
681
 
561
682
  # wrap up as an autopointer
562
683
  ptr = FFI::AutoPointer.new(ptr, GLib::G_FREE)
@@ -564,15 +685,15 @@ module Vips
564
685
  ptr.get_bytes 0, len[:value]
565
686
  end
566
687
 
567
- # Turn progress signalling on and off.
688
+ # Turn progress signalling on and off.
568
689
  #
569
690
  # If this is on, the most-downstream image from this image will issue
570
- # progress signals.
691
+ # progress signals.
571
692
  #
572
693
  # @see Object#signal_connect
573
694
  # @param state [Boolean] progress signalling state
574
695
  def set_progress state
575
- Vips::vips_image_set_progress self, state
696
+ Vips.vips_image_set_progress self, state
576
697
  end
577
698
 
578
699
  # Kill computation of this time.
@@ -583,7 +704,7 @@ module Vips
583
704
  # @see Object#signal_connect
584
705
  # @param kill [Boolean] stop computation
585
706
  def set_kill kill
586
- Vips::vips_image_set_kill self, kill
707
+ Vips.vips_image_set_kill self, kill
587
708
  end
588
709
 
589
710
  # Get the `GType` of a metadata field. The result is 0 if no such field
@@ -595,12 +716,12 @@ module Vips
595
716
  def get_typeof name
596
717
  # on libvips before 8.5, property types must be searched first,
597
718
  # since vips_image_get_typeof returned built-in enums as int
598
- unless Vips::at_least_libvips?(8, 5)
719
+ unless Vips.at_least_libvips?(8, 5)
599
720
  gtype = parent_get_typeof name
600
721
  return gtype if gtype != 0
601
722
  end
602
723
 
603
- Vips::vips_image_get_typeof self, name
724
+ Vips.vips_image_get_typeof self, name
604
725
  end
605
726
 
606
727
  # Get a metadata item from an image. Ruby types are constructed
@@ -619,12 +740,12 @@ module Vips
619
740
  def get name
620
741
  # with old libvips, we must fetch properties (as opposed to
621
742
  # metadata) via VipsObject
622
- unless Vips::at_least_libvips?(8, 5)
743
+ unless Vips.at_least_libvips?(8, 5)
623
744
  return super if parent_get_typeof(name) != 0
624
745
  end
625
746
 
626
747
  gvalue = GObject::GValue.alloc
627
- raise Vips::Error if Vips::vips_image_get(self, name, gvalue) != 0
748
+ raise Vips::Error if Vips.vips_image_get(self, name, gvalue) != 0
628
749
  result = gvalue.get
629
750
  gvalue.unset
630
751
 
@@ -639,67 +760,64 @@ module Vips
639
760
  # vips_image_get_fields() was added in libvips 8.5
640
761
  return [] unless Vips.respond_to? :vips_image_get_fields
641
762
 
642
- array = Vips::vips_image_get_fields self
763
+ array = Vips.vips_image_get_fields self
643
764
 
644
765
  names = []
645
766
  p = array
646
767
  until (q = p.read_pointer).null?
647
768
  names << q.read_string
648
- GLib::g_free q
769
+ GLib.g_free q
649
770
  p += FFI::Type::POINTER.size
650
771
  end
651
- GLib::g_free array
772
+ GLib.g_free array
652
773
 
653
774
  names
654
775
  end
655
776
 
656
- # Create a metadata item on an image of the specifed type. Ruby types
657
- # 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.
658
780
  #
659
- # For example, you can use this to set an image's ICC profile:
781
+ # For example:
660
782
  #
661
- # ```
662
- # 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
663
789
  # ```
664
790
  #
665
- # 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.
666
799
  #
667
- # @see set
668
- # @param gtype [Integer] GType of item
669
- # @param name [String] Metadata field to set
670
- # @param value [Object] Value to set
800
+ # Please use {MutableImage#set_type!} instead.
671
801
  def set_type gtype, name, value
672
802
  gvalue = GObject::GValue.alloc
673
803
  gvalue.init gtype
674
804
  gvalue.set value
675
- Vips::vips_image_set self, name, gvalue
805
+ Vips.vips_image_set self, name, gvalue
676
806
  gvalue.unset
677
807
  end
678
808
 
679
- # Set the value of a metadata item on an image. The metadata item must
680
- # already exist. Ruby types are automatically transformed into the
681
- # matching `GValue`, if possible.
682
- #
683
- # For example, you can use this to set an image's ICC profile:
684
- #
685
- # ```
686
- # x = y.set "icc-profile-data", profile
687
- # ```
688
- #
689
- # where `profile` is an ICC profile held as a binary string object.
809
+ # This method is deprecated.
690
810
  #
691
- # @see set_type
692
- # @param name [String] Metadata field to set
693
- # @param value [Object] Value to set
811
+ # Please use {MutableImage#set!} instead.
694
812
  def set name, value
695
813
  set_type get_typeof(name), name, value
696
814
  end
697
815
 
698
- # Remove a metadata item from an image.
816
+ # This method is deprecated.
699
817
  #
700
- # @param name [String] Metadata field to remove
818
+ # Please use {MutableImage#remove!} instead.
701
819
  def remove name
702
- Vips::vips_image_remove self, name
820
+ Vips.vips_image_remove self, name
703
821
  end
704
822
 
705
823
  # compatibility: old name for get
@@ -707,7 +825,9 @@ module Vips
707
825
  get name
708
826
  end
709
827
 
710
- # compatibility: old name for set
828
+ # This method is deprecated.
829
+ #
830
+ # Please use {MutableImage#set!} instead.
711
831
  def set_value name, value
712
832
  set name, value
713
833
  end
@@ -716,21 +836,21 @@ module Vips
716
836
  #
717
837
  # @return [Integer] image width, in pixels
718
838
  def width
719
- get "width"
839
+ Vips.vips_image_get_width self
720
840
  end
721
841
 
722
842
  # Get image height, in pixels.
723
843
  #
724
844
  # @return [Integer] image height, in pixels
725
845
  def height
726
- get "height"
846
+ Vips.vips_image_get_height self
727
847
  end
728
848
 
729
849
  # Get number of image bands.
730
850
  #
731
851
  # @return [Integer] number of image bands
732
852
  def bands
733
- get "bands"
853
+ Vips.vips_image_get_bands self
734
854
  end
735
855
 
736
856
  # Get image format.
@@ -814,23 +934,23 @@ module Vips
814
934
  [width, height]
815
935
  end
816
936
 
817
- if Vips::at_least_libvips?(8, 5)
937
+ if Vips.at_least_libvips?(8, 5)
818
938
  # Detect if image has an alpha channel
819
939
  #
820
940
  # @return [Boolean] true if image has an alpha channel.
821
941
  def has_alpha?
822
- return Vips::vips_image_hasalpha(self) != 0
942
+ Vips.vips_image_hasalpha(self) != 0
823
943
  end
824
944
  end
825
945
 
826
946
  # vips_addalpha was added in libvips 8.6
827
- if Vips::at_least_libvips?(8, 6)
947
+ if Vips.at_least_libvips?(8, 6)
828
948
  # Append an alpha channel to an image.
829
949
  #
830
950
  # @return [Image] new image
831
951
  def add_alpha
832
952
  ptr = GenericPtr.new
833
- result = Vips::vips_addalpha self, ptr
953
+ result = Vips.vips_addalpha self, ptr
834
954
  raise Vips::Error if result != 0
835
955
 
836
956
  Vips::Image.new ptr[:value]
@@ -845,7 +965,7 @@ module Vips
845
965
  #
846
966
  # @return [Image] new memory image
847
967
  def copy_memory
848
- new_image = Vips::vips_image_copy_memory self
968
+ new_image = Vips.vips_image_copy_memory self
849
969
  Vips::Image.new new_image
850
970
  end
851
971
 
@@ -855,7 +975,7 @@ module Vips
855
975
  #
856
976
  # @return [Image] modified image
857
977
  def draw_point ink, left, top, **opts
858
- draw_rect ink, left, top, 1, 1, opts
978
+ draw_rect ink, left, top, 1, 1, **opts
859
979
  end
860
980
 
861
981
  # Add an image, constant or array.
@@ -873,7 +993,7 @@ module Vips
873
993
  # @return [Image] result of subtraction
874
994
  def - other
875
995
  other.is_a?(Vips::Image) ?
876
- subtract(other) : linear(1, Image::smap(other) { |x| x * -1 })
996
+ subtract(other) : linear(1, Image.smap(other) { |x| x * -1 })
877
997
  end
878
998
 
879
999
  # Multiply an image, constant or array.
@@ -891,7 +1011,7 @@ module Vips
891
1011
  # @return [Image] result of division
892
1012
  def / other
893
1013
  other.is_a?(Vips::Image) ?
894
- divide(other) : linear(Image::smap(other) { |x| 1.0 / x }, 0)
1014
+ divide(other) : linear(Image.smap(other) { |x| 1.0 / x }, 0)
895
1015
  end
896
1016
 
897
1017
  # Remainder after integer division with an image, constant or array.
@@ -1017,7 +1137,7 @@ module Vips
1017
1137
  # @return [Image] result of equality
1018
1138
  def == other
1019
1139
  # for equality, we must allow tests against nil
1020
- if other == nil
1140
+ if other.nil?
1021
1141
  false
1022
1142
  else
1023
1143
  call_enum "relational", other, :equal
@@ -1030,7 +1150,7 @@ module Vips
1030
1150
  # @return [Image] result of inequality
1031
1151
  def != other
1032
1152
  # for equality, we must allow tests against nil
1033
- if other == nil
1153
+ if other.nil?
1034
1154
  true
1035
1155
  else
1036
1156
  call_enum "relational", other, :noteq
@@ -1052,38 +1172,40 @@ module Vips
1052
1172
  end
1053
1173
  end
1054
1174
 
1055
- # Convert to an Array. This will be slow for large images.
1175
+ # Convert to an Enumerator. Similar to `#to_a` but lazier.
1056
1176
  #
1057
- # @return [Array] array of Fixnum
1058
- def to_a
1059
- # we render the image to a big string, then unpack
1060
- # as a Ruby array of the correct type
1061
- memory = write_to_memory
1062
-
1177
+ # @return [Enumerator] Enumerator of Enumerators of Arrays of Numerics
1178
+ def to_enum
1063
1179
  # make the template for unpack
1064
1180
  template = {
1065
- char: 'c',
1066
- uchar: 'C',
1067
- short: 's_',
1068
- ushort: 'S_',
1069
- int: 'i_',
1070
- uint: 'I_',
1071
- float: 'f',
1072
- double: 'd',
1073
- complex: 'f',
1074
- dpcomplex: 'd'
1075
- }[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] + "*"
1076
1192
 
1077
- # and unpack into something like [1, 2, 3, 4 ..]
1078
- 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
1079
1196
 
1080
- # gather band elements together
1081
- pixel_array = array.each_slice(bands).to_a
1197
+ # gather bands of a pixel together
1198
+ pixel_array = array.each_slice bands
1082
1199
 
1083
- # build rows
1084
- row_array = pixel_array.each_slice(width).to_a
1200
+ # gather pixels of a row together
1201
+ pixel_array.each_slice width
1202
+ end
1085
1203
 
1086
- 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
1087
1209
  end
1088
1210
 
1089
1211
  # Return the largest integral value not greater than the argument.
@@ -1159,7 +1281,10 @@ module Vips
1159
1281
  # @param overlay [Image, Array<Image>] images to composite
1160
1282
  # @param mode [BlendMode, Array<BlendMode>] blend modes to use
1161
1283
  # @param opts [Hash] Set of options
1162
- # @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
1163
1288
  # @option opts [Boolean] :premultiplied Images have premultiplied alpha
1164
1289
  # @return [Image] blended image
1165
1290
  def composite overlay, mode, **opts
@@ -1183,9 +1308,9 @@ module Vips
1183
1308
  # coordinate of maximum
1184
1309
  def maxpos
1185
1310
  v, opts = max x: true, y: true
1186
- x = opts['x']
1187
- y = opts['y']
1188
- return v, x, y
1311
+ x = opts["x"]
1312
+ y = opts["y"]
1313
+ [v, x, y]
1189
1314
  end
1190
1315
 
1191
1316
  # Return the coordinates of the image minimum.
@@ -1194,9 +1319,9 @@ module Vips
1194
1319
  # coordinate of minimum
1195
1320
  def minpos
1196
1321
  v, opts = min x: true, y: true
1197
- x = opts['x']
1198
- y = opts['y']
1199
- return v, x, y
1322
+ x = opts["x"]
1323
+ y = opts["y"]
1324
+ [v, x, y]
1200
1325
  end
1201
1326
 
1202
1327
  # a median filter
@@ -1204,7 +1329,7 @@ module Vips
1204
1329
  # @param size [Integer] size of filter window
1205
1330
  # @return [Image] result of median filter
1206
1331
  def median size = 3
1207
- rank size, size, (size * size) / 2
1332
+ rank size, size, size**2 / 2
1208
1333
  end
1209
1334
 
1210
1335
  # Return the real part of a complex image.
@@ -1231,7 +1356,7 @@ module Vips
1231
1356
  # @see xyz
1232
1357
  # @return [Image] image converted to polar coordinates
1233
1358
  def polar
1234
- Image::run_cmplx(self) { |x| x.complex :polar }
1359
+ Image.run_cmplx(self) { |x| x.complex :polar }
1235
1360
  end
1236
1361
 
1237
1362
  # Return an image with polar pixels converted to rectangular.
@@ -1244,7 +1369,7 @@ module Vips
1244
1369
  # @see xyz
1245
1370
  # @return [Image] image converted to rectangular coordinates
1246
1371
  def rect
1247
- Image::run_cmplx(self) { |x| x.complex :rect }
1372
+ Image.run_cmplx(self) { |x| x.complex :rect }
1248
1373
  end
1249
1374
 
1250
1375
  # Return the complex conjugate of an image.
@@ -1256,7 +1381,7 @@ module Vips
1256
1381
  #
1257
1382
  # @return [Image] complex conjugate
1258
1383
  def conj
1259
- Image::run_cmplx(self) { |x| x.complex :conj }
1384
+ Image.run_cmplx(self) { |x| x.complex :conj }
1260
1385
  end
1261
1386
 
1262
1387
  # Calculate the cross phase of two images.
@@ -1437,7 +1562,7 @@ module Vips
1437
1562
  #
1438
1563
  # ```
1439
1564
  # $ ruby > methods.rb
1440
- # require 'vips'; Vips::Yard.generate
1565
+ # require "vips"; Vips::Yard.generate
1441
1566
  # ^D
1442
1567
  # ```
1443
1568
 
@@ -1459,7 +1584,7 @@ module Vips
1459
1584
  "VipsArrayDouble" => "Array<Double>",
1460
1585
  "VipsArrayInt" => "Array<Integer>",
1461
1586
  "VipsArrayImage" => "Array<Image>",
1462
- "VipsArrayString" => "Array<String>",
1587
+ "VipsArrayString" => "Array<String>"
1463
1588
  }
1464
1589
 
1465
1590
  # these have hand-written methods, see above
@@ -1470,15 +1595,15 @@ module Vips
1470
1595
 
1471
1596
  # turn a gtype into a ruby type name
1472
1597
  def self.gtype_to_ruby gtype
1473
- fundamental = GObject::g_type_fundamental gtype
1474
- type_name = GObject::g_type_name gtype
1598
+ fundamental = GObject.g_type_fundamental gtype
1599
+ type_name = GObject.g_type_name gtype
1475
1600
 
1476
1601
  if MAP_GO_TO_RUBY.include? type_name
1477
1602
  type_name = MAP_GO_TO_RUBY[type_name]
1478
1603
  end
1479
1604
 
1480
1605
  if fundamental == GObject::GFLAGS_TYPE ||
1481
- fundamental == GObject::GENUM_TYPE
1606
+ fundamental == GObject::GENUM_TYPE
1482
1607
  type_name = "Vips::" + type_name[/Vips(.*)/, 1]
1483
1608
  end
1484
1609
 
@@ -1497,7 +1622,7 @@ module Vips
1497
1622
  print "# @!method "
1498
1623
  print "self." unless introspect.member_x
1499
1624
  print "#{introspect.name}("
1500
- print method_args.map{ |x| x[:yard_name] }.join(", ")
1625
+ print method_args.map { |x| x[:yard_name] }.join(", ")
1501
1626
  print ", " if method_args.length > 0
1502
1627
  puts "**opts)"
1503
1628
 
@@ -1517,8 +1642,7 @@ module Vips
1517
1642
  gtype = details[:gtype]
1518
1643
  blurb = details[:blurb]
1519
1644
 
1520
- puts "# @option opts [#{gtype_to_ruby(gtype)}] :#{yard_name} " +
1521
- "#{blurb}"
1645
+ puts "# @option opts [#{gtype_to_ruby(gtype)}] :#{yard_name} #{blurb}"
1522
1646
  end
1523
1647
  optional_output.each do |arg_name, details|
1524
1648
  yard_name = details[:yard_name]
@@ -1536,14 +1660,14 @@ module Vips
1536
1660
  print gtype_to_ruby(required_output.first[:gtype])
1537
1661
  else
1538
1662
  print "Array<"
1539
- print required_output.map{ |x| gtype_to_ruby(x[:gtype]) }.join(", ")
1663
+ print required_output.map { |x| gtype_to_ruby(x[:gtype]) }.join(", ")
1540
1664
  print ">"
1541
1665
  end
1542
1666
  if optional_output.length > 0
1543
1667
  print ", Hash<Symbol => Object>"
1544
1668
  end
1545
1669
  print "] "
1546
- print required_output.map{ |x| x[:blurb] }.join(", ")
1670
+ print required_output.map { |x| x[:blurb] }.join(", ")
1547
1671
  if optional_output.length > 0
1548
1672
  print ", " if required_output.length > 0
1549
1673
  print "Hash of optional output items"
@@ -1555,16 +1679,16 @@ module Vips
1555
1679
 
1556
1680
  def self.generate
1557
1681
  alias_gtypes = {}
1558
- ALIAS.each do |name|
1559
- gtype = Vips::type_find "VipsOperation", name
1560
- alias_gtypes[gtype] = name
1682
+ ALIAS.each do |name|
1683
+ gtype = Vips.type_find "VipsOperation", name
1684
+ alias_gtypes[gtype] = name
1561
1685
  end
1562
1686
 
1563
1687
  generate_class = lambda do |gtype, _|
1564
- if alias_gtypes.key? gtype
1565
- name = alias_gtypes[gtype]
1688
+ name = if alias_gtypes.key? gtype
1689
+ alias_gtypes[gtype]
1566
1690
  else
1567
- name = Vips::nickname_find gtype
1691
+ Vips.nickname_find gtype
1568
1692
  end
1569
1693
 
1570
1694
  if name
@@ -1578,14 +1702,14 @@ module Vips
1578
1702
  generate_operation(introspect) if introspect
1579
1703
  end
1580
1704
 
1581
- Vips::vips_type_map gtype, generate_class, nil
1705
+ Vips.vips_type_map gtype, generate_class, nil
1582
1706
  end
1583
1707
 
1584
1708
  puts "module Vips"
1585
1709
  puts " class Image"
1586
1710
  puts ""
1587
1711
 
1588
- generate_class.(GObject::g_type_from_name("VipsOperation"), nil)
1712
+ generate_class.call(GObject.g_type_from_name("VipsOperation"), nil)
1589
1713
 
1590
1714
  puts " end"
1591
1715
  puts "end"