vips 8.10.5 → 8.12.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.
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
@@ -57,6 +63,9 @@ module Vips
57
63
 
58
64
  attach_function :vips_image_invalidate_all, [:pointer], :void
59
65
 
66
+ attach_function :vips_image_new_from_memory, [:pointer, :size_t, :int, :int, :int, :int], :pointer
67
+ attach_function :vips_image_new_from_memory_copy, [:pointer, :size_t, :int, :int, :int, :int], :pointer
68
+
60
69
  # turn a raw pointer that must be freed into a self-freeing Ruby string
61
70
  def self.p2str(pointer)
62
71
  pointer = FFI::AutoPointer.new(pointer, GLib::G_FREE)
@@ -75,6 +84,11 @@ module Vips
75
84
  Vips.vips_image_invalidate_all(self)
76
85
  end
77
86
 
87
+ # FFI sets a pointer's size to this magic value if the size of the memory
88
+ # chunk the pointer points to is unknown to FFI.
89
+ UNKNOWN_POINTER_SIZE = FFI::Pointer.new(1).size
90
+ private_constant :UNKNOWN_POINTER_SIZE
91
+
78
92
  private
79
93
 
80
94
  # the layout of the VipsImage struct
@@ -102,17 +116,17 @@ module Vips
102
116
  # handy for overloads ... want to be able to apply a function to an
103
117
  # array or to a scalar
104
118
  def self.smap x, &block
105
- x.is_a?(Array) ? x.map { |y| smap(y, &block) } : block.(x)
119
+ x.is_a?(Array) ? x.map { |y| smap(y, &block) } : block.call(x)
106
120
  end
107
121
 
108
122
  def self.complex? format
109
123
  format_number = GObject::GValue.from_nick BAND_FORMAT_TYPE, format
110
- Vips::vips_band_format_iscomplex(format_number) != 0
124
+ Vips.vips_band_format_iscomplex(format_number) != 0
111
125
  end
112
126
 
113
127
  def self.float? format
114
128
  format_number = GObject::GValue.from_nick BAND_FORMAT_TYPE, format
115
- Vips::vips_band_format_isfloat(format_number) != 0
129
+ Vips.vips_band_format_isfloat(format_number) != 0
116
130
  end
117
131
 
118
132
  # run a complex operation on a complex image, or an image with an even
@@ -121,12 +135,12 @@ module Vips
121
135
  def self.run_cmplx image, &block
122
136
  original_format = image.format
123
137
 
124
- unless Image::complex? image.format
138
+ unless Image.complex? image.format
125
139
  if image.bands % 2 != 0
126
140
  raise Vips::Error, "not an even number of bands"
127
141
  end
128
142
 
129
- unless Image::float? image.format
143
+ unless Image.float? image.format
130
144
  image = image.cast :float
131
145
  end
132
146
 
@@ -134,9 +148,9 @@ module Vips
134
148
  image = image.copy format: new_format, bands: image.bands / 2
135
149
  end
136
150
 
137
- image = block.(image)
151
+ image = block.call(image)
138
152
 
139
- unless Image::complex? original_format
153
+ unless Image.complex? original_format
140
154
  new_format = image.format == :dpcomplex ? :double : :float
141
155
  image = image.copy format: new_format, bands: image.bands * 2
142
156
  end
@@ -167,15 +181,19 @@ module Vips
167
181
  # 36013-heads-up-ruby-implicitly-converts-a-hash-to-keyword-arguments
168
182
  return false if name == :to_hash
169
183
 
184
+ super
185
+ end
186
+
187
+ def respond_to_missing? name, include_all = false
170
188
  # respond to all vips operations by nickname
171
- return true if Vips::type_find("VipsOperation", name.to_s) != 0
189
+ return true if Vips.type_find("VipsOperation", name.to_s) != 0
172
190
 
173
191
  super
174
192
  end
175
193
 
176
- def self.respond_to? name, include_all = false
194
+ def self.respond_to_missing? name, include_all = false
177
195
  # respond to all vips operations by nickname
178
- return true if Vips::type_find("VipsOperation", name.to_s) != 0
196
+ return true if Vips.type_find("VipsOperation", name.to_s) != 0
179
197
 
180
198
  super
181
199
  end
@@ -233,18 +251,18 @@ module Vips
233
251
  def self.new_from_file name, **opts
234
252
  # very common, and Vips::vips_filename_get_filename will segv if we
235
253
  # pass this
236
- raise Vips::Error, "filename is nil" if name == nil
254
+ raise Vips::Error, "filename is nil" if name.nil?
237
255
 
238
- filename = Vips::p2str(Vips::vips_filename_get_filename name)
239
- option_string = Vips::p2str(Vips::vips_filename_get_options name)
240
- loader = Vips::vips_foreign_find_load filename
241
- raise Vips::Error if loader == nil
256
+ filename = Vips.p2str(Vips.vips_filename_get_filename(name))
257
+ option_string = Vips.p2str(Vips.vips_filename_get_options(name))
258
+ loader = Vips.vips_foreign_find_load filename
259
+ raise Vips::Error if loader.nil?
242
260
 
243
261
  Operation.call loader, [filename], opts, option_string
244
262
  end
245
263
 
246
- # Create a new {Image} for an image encoded, in a format such as
247
- # JPEG, in a binary string. Load options may be passed as
264
+ # Create a new {Image} for an image encoded in a format such as
265
+ # JPEG in a binary string. Load options may be passed as
248
266
  # strings or appended as a hash. For example:
249
267
  #
250
268
  # ```
@@ -275,12 +293,113 @@ module Vips
275
293
  # @macro vips.loadopts
276
294
  # @return [Image] the loaded image
277
295
  def self.new_from_buffer data, option_string, **opts
278
- loader = Vips::vips_foreign_find_load_buffer data, data.bytesize
296
+ loader = Vips.vips_foreign_find_load_buffer data, data.bytesize
279
297
  raise Vips::Error if loader.nil?
280
298
 
281
299
  Vips::Operation.call loader, [data], opts, option_string
282
300
  end
283
301
 
302
+ # Create a new {Image} from a C-style array held in memory. For example:
303
+ #
304
+ # ```
305
+ # image = Vips::Image.black(16, 16) + 128
306
+ # data = image.write_to_memory
307
+ #
308
+ # x = Vips::Image.new_from_memory data,
309
+ # image.width, image.height, image.bands, image.format
310
+ # ```
311
+ #
312
+ # Creating a new image from a memory pointer:
313
+ #
314
+ # ```
315
+ # ptr = FFI::MemoryPointer.new(:uchar, 10*10)
316
+ # # => #<FFI::MemoryPointer address=0x00007fc236db31d0 size=100>
317
+ # x = Vips::Image.new_from_memory(ptr, 10, 10, 1, :uchar)
318
+ # ```
319
+ #
320
+ # Creating a new image from an address only pointer:
321
+ #
322
+ # ```
323
+ # ptr = call_to_external_c_library(w: 10, h: 10)
324
+ # # => #<FFI::Pointer address=0x00007f9780813a00>
325
+ # ptr_slice = ptr.slice(0, 10*10)
326
+ # # => #<FFI::Pointer address=0x00007f9780813a00 size=100>
327
+ # x = Vips::Image.new_from_memory(ptr_slice, 10, 10, 1, :uchar)
328
+ # ```
329
+ #
330
+ # {new_from_memory} keeps a reference to the array of pixels you pass in
331
+ # to try to prevent that memory from being freed by the Ruby GC while it
332
+ # is being used.
333
+ #
334
+ # See {new_from_memory_copy} for a version of this method which does not
335
+ # keep a reference.
336
+ #
337
+ # @param data [String, FFI::Pointer] the data to load from
338
+ # @param width [Integer] width in pixels
339
+ # @param height [Integer] height in pixels
340
+ # @param bands [Integer] number of bands
341
+ # @param format [Symbol] band format
342
+ # @return [Image] the loaded image
343
+ def self.new_from_memory data, width, height, bands, format
344
+ # prevent data from being freed with JRuby FFI
345
+ if defined?(JRUBY_VERSION) && !data.is_a?(FFI::Pointer)
346
+ data = ::FFI::MemoryPointer.new(:char, data.bytesize).write_bytes data
347
+ end
348
+
349
+ if data.is_a?(FFI::Pointer)
350
+ # A pointer needs to know about the size of the memory it points to.
351
+ # If you have an address-only pointer, use the .slice method to wrap
352
+ # the pointer in a size aware pointer.
353
+ if data.size == UNKNOWN_POINTER_SIZE
354
+ raise Vips::Error, "size of memory is unknown"
355
+ end
356
+ size = data.size
357
+ else
358
+ size = data.bytesize
359
+ end
360
+
361
+ format_number = GObject::GValue.from_nick BAND_FORMAT_TYPE, format
362
+ vi = Vips.vips_image_new_from_memory data, size,
363
+ width, height, bands, format_number
364
+ raise Vips::Error if vi.null?
365
+ image = new(vi)
366
+
367
+ # keep a secret ref to the underlying object .. this reference will be
368
+ # inherited by things that in turn depend on us, so the memory we are
369
+ # using will not be freed
370
+ image.references << data
371
+
372
+ image
373
+ end
374
+
375
+ # Create a new {Image} from memory and copies the memory area. See
376
+ # {new_from_memory} for a version of this method which does not copy the
377
+ # memory area.
378
+ #
379
+ # @param data [String, FFI::Pointer] the data to load from
380
+ # @param width [Integer] width in pixels
381
+ # @param height [Integer] height in pixels
382
+ # @param bands [Integer] number of bands
383
+ # @param format [Symbol] band format
384
+ # @return [Image] the loaded image
385
+ def self.new_from_memory_copy data, width, height, bands, format
386
+ format_number = GObject::GValue.from_nick BAND_FORMAT_TYPE, format
387
+
388
+ if data.is_a?(FFI::Pointer)
389
+ if data.size == UNKNOWN_POINTER_SIZE
390
+ raise Vips::Error, "size of memory is unknown"
391
+ end
392
+ size = data.size
393
+ else
394
+ size = data.bytesize
395
+ end
396
+
397
+ vi = Vips.vips_image_new_from_memory_copy data, size,
398
+ width, height, bands, format_number
399
+ raise Vips::Error if vi.null?
400
+ new(vi)
401
+ end
402
+
284
403
  # Create a new {Image} from a source. Load options may be passed as
285
404
  # strings or appended as a hash. For example:
286
405
  #
@@ -306,7 +425,7 @@ module Vips
306
425
  # TIFF images will work.
307
426
  #
308
427
  # Loading is fast: only enough data is read to be able to fill
309
- # out the header. Pixels will only be read and decompressed when they are
428
+ # out the header. Pixels will only be read and decompressed when they are
310
429
  # needed.
311
430
  #
312
431
  # @param source [Vips::Source] the source to load from
@@ -314,7 +433,7 @@ module Vips
314
433
  # @macro vips.loadopts
315
434
  # @return [Image] the loaded image
316
435
  def self.new_from_source source, option_string, **opts
317
- loader = Vips::vips_foreign_find_load_source source
436
+ loader = Vips.vips_foreign_find_load_source source
318
437
  raise Vips::Error if loader.nil?
319
438
 
320
439
  Vips::Operation.call loader, [source], opts, option_string
@@ -323,8 +442,8 @@ module Vips
323
442
  def self.matrix_from_array width, height, array
324
443
  ptr = FFI::MemoryPointer.new :double, array.length
325
444
  ptr.write_array_of_double array
326
- image = Vips::vips_image_new_matrix_from_array width, height,
327
- ptr, array.length
445
+ image = Vips.vips_image_new_matrix_from_array width, height,
446
+ ptr, array.length
328
447
  Vips::Image.new image
329
448
  end
330
449
 
@@ -377,18 +496,22 @@ module Vips
377
496
  width = array.length
378
497
  end
379
498
 
499
+ unless array.length == width * height
500
+ raise Vips::Error, "Bad array dimensions."
501
+ end
502
+
380
503
  unless array.all? { |x| x.is_a? Numeric }
381
504
  raise Vips::Error, "Not all array elements are Numeric."
382
505
  end
383
506
 
384
507
  image = Vips::Image.matrix_from_array width, height, array
385
- raise Vips::Error if image == nil
386
-
387
- # be careful to set them as double
388
- image.set_type GObject::GDOUBLE_TYPE, 'scale', scale.to_f
389
- image.set_type GObject::GDOUBLE_TYPE, 'offset', offset.to_f
508
+ raise Vips::Error if image.nil?
390
509
 
391
- return image
510
+ image.mutate do |mutable|
511
+ # be careful to set them as double
512
+ mutable.set_type! GObject::GDOUBLE_TYPE, "scale", scale.to_f
513
+ mutable.set_type! GObject::GDOUBLE_TYPE, "offset", offset.to_f
514
+ end
392
515
  end
393
516
 
394
517
  # A new image is created with the same width, height, format,
@@ -437,14 +560,16 @@ module Vips
437
560
  #
438
561
  # @param name [String] filename to write to
439
562
  def write_to_file name, **opts
440
- filename = Vips::p2str(Vips::vips_filename_get_filename name)
441
- option_string = Vips::p2str(Vips::vips_filename_get_options name)
442
- saver = Vips::vips_foreign_find_save filename
443
- if saver == nil
444
- raise Vips::Error, "No known saver for '#{filename}'."
445
- end
563
+ raise Vips::Error, "filename is nil" if name.nil?
564
+
565
+ filename = Vips.p2str(Vips.vips_filename_get_filename(name))
566
+ option_string = Vips.p2str(Vips.vips_filename_get_options(name))
567
+ saver = Vips.vips_foreign_find_save filename
568
+ raise Vips::Error if saver.nil?
446
569
 
447
570
  Vips::Operation.call saver, [self, filename], opts, option_string
571
+
572
+ GC.start(full_mark: false)
448
573
  end
449
574
 
450
575
  # Write this image to a memory buffer. Save options may be encoded in
@@ -473,15 +598,32 @@ module Vips
473
598
  # @macro vips.saveopts
474
599
  # @return [String] the image saved in the specified format
475
600
  def write_to_buffer format_string, **opts
476
- filename = Vips::p2str(Vips::vips_filename_get_filename format_string)
477
- option_string = Vips::p2str(Vips::vips_filename_get_options format_string)
478
- saver = Vips::vips_foreign_find_save_buffer filename
479
- if saver == nil
480
- raise Vips::Error, "No known buffer saver for '#{filename}'."
601
+ raise Vips::Error, "filename is nil" if format_string.nil?
602
+ filename = Vips.p2str(Vips.vips_filename_get_filename(format_string))
603
+ option_string = Vips.p2str(Vips.vips_filename_get_options(format_string))
604
+
605
+ # try to save with the new target API first, only fall back to the old
606
+ # buffer API if there's no target save for this filetype
607
+ saver = nil
608
+ if Vips.at_least_libvips?(8, 9)
609
+ Vips.vips_error_freeze
610
+ saver = Vips.vips_foreign_find_save_target filename
611
+ Vips.vips_error_thaw
481
612
  end
482
613
 
483
- buffer = Vips::Operation.call saver, [self], opts, option_string
484
- raise Vips::Error if buffer == nil
614
+ if !saver.nil?
615
+ target = Vips::Target.new_to_memory
616
+ Vips::Operation.call saver, [self, target], opts, option_string
617
+ buffer = target.get("blob")
618
+ else
619
+ saver = Vips.vips_foreign_find_save_buffer filename
620
+ raise Vips::Error if saver.nil?
621
+
622
+ buffer = Vips::Operation.call saver, [self], opts, option_string
623
+ raise Vips::Error if buffer.nil?
624
+ end
625
+
626
+ GC.start(full_mark: false)
485
627
 
486
628
  return buffer
487
629
  end
@@ -513,14 +655,15 @@ module Vips
513
655
  # @param format_string [String] save format plus string options
514
656
  # @macro vips.saveopts
515
657
  def write_to_target target, format_string, **opts
516
- filename = Vips::p2str(Vips::vips_filename_get_filename format_string)
517
- option_string = Vips::p2str(Vips::vips_filename_get_options format_string)
518
- saver = Vips::vips_foreign_find_save_target filename
519
- if saver == nil
520
- raise Vips::Error, "No known target saver for '#{filename}'."
521
- end
658
+ raise Vips::Error, "filename is nil" if format_string.nil?
659
+ filename = Vips.p2str(Vips.vips_filename_get_filename(format_string))
660
+ option_string = Vips.p2str(Vips.vips_filename_get_options(format_string))
661
+ saver = Vips.vips_foreign_find_save_target filename
662
+ raise Vips::Error if saver.nil?
522
663
 
523
664
  Vips::Operation.call saver, [self, target], opts, option_string
665
+
666
+ GC.start(full_mark: false)
524
667
  end
525
668
 
526
669
  # Write this image to a large memory buffer.
@@ -528,24 +671,28 @@ module Vips
528
671
  # @return [String] the pixels as a huge binary string
529
672
  def write_to_memory
530
673
  len = Vips::SizeStruct.new
531
- ptr = Vips::vips_image_write_to_memory self, len
532
- raise Vips::Error if ptr == nil
674
+ ptr = Vips.vips_image_write_to_memory self, len
675
+ raise Vips::Error if ptr.nil?
533
676
 
534
677
  # wrap up as an autopointer
535
678
  ptr = FFI::AutoPointer.new(ptr, GLib::G_FREE)
536
679
 
537
- ptr.get_bytes 0, len[:value]
680
+ data = ptr.get_bytes 0, len[:value]
681
+
682
+ GC.start(full_mark: false)
683
+
684
+ return data
538
685
  end
539
686
 
540
- # Turn progress signalling on and off.
687
+ # Turn progress signalling on and off.
541
688
  #
542
689
  # If this is on, the most-downstream image from this image will issue
543
- # progress signals.
690
+ # progress signals.
544
691
  #
545
692
  # @see Object#signal_connect
546
693
  # @param state [Boolean] progress signalling state
547
694
  def set_progress state
548
- Vips::vips_image_set_progress self, state
695
+ Vips.vips_image_set_progress self, state
549
696
  end
550
697
 
551
698
  # Kill computation of this time.
@@ -556,7 +703,7 @@ module Vips
556
703
  # @see Object#signal_connect
557
704
  # @param kill [Boolean] stop computation
558
705
  def set_kill kill
559
- Vips::vips_image_set_kill self, kill
706
+ Vips.vips_image_set_kill self, kill
560
707
  end
561
708
 
562
709
  # Get the `GType` of a metadata field. The result is 0 if no such field
@@ -568,12 +715,12 @@ module Vips
568
715
  def get_typeof name
569
716
  # on libvips before 8.5, property types must be searched first,
570
717
  # since vips_image_get_typeof returned built-in enums as int
571
- unless Vips::at_least_libvips?(8, 5)
718
+ unless Vips.at_least_libvips?(8, 5)
572
719
  gtype = parent_get_typeof name
573
720
  return gtype if gtype != 0
574
721
  end
575
722
 
576
- Vips::vips_image_get_typeof self, name
723
+ Vips.vips_image_get_typeof self, name
577
724
  end
578
725
 
579
726
  # Get a metadata item from an image. Ruby types are constructed
@@ -592,12 +739,12 @@ module Vips
592
739
  def get name
593
740
  # with old libvips, we must fetch properties (as opposed to
594
741
  # metadata) via VipsObject
595
- unless Vips::at_least_libvips?(8, 5)
742
+ unless Vips.at_least_libvips?(8, 5)
596
743
  return super if parent_get_typeof(name) != 0
597
744
  end
598
745
 
599
746
  gvalue = GObject::GValue.alloc
600
- raise Vips::Error if Vips::vips_image_get(self, name, gvalue) != 0
747
+ raise Vips::Error if Vips.vips_image_get(self, name, gvalue) != 0
601
748
  result = gvalue.get
602
749
  gvalue.unset
603
750
 
@@ -612,67 +759,64 @@ module Vips
612
759
  # vips_image_get_fields() was added in libvips 8.5
613
760
  return [] unless Vips.respond_to? :vips_image_get_fields
614
761
 
615
- array = Vips::vips_image_get_fields self
762
+ array = Vips.vips_image_get_fields self
616
763
 
617
764
  names = []
618
765
  p = array
619
766
  until (q = p.read_pointer).null?
620
767
  names << q.read_string
621
- GLib::g_free q
768
+ GLib.g_free q
622
769
  p += FFI::Type::POINTER.size
623
770
  end
624
- GLib::g_free array
771
+ GLib.g_free array
625
772
 
626
773
  names
627
774
  end
628
775
 
629
- # Create a metadata item on an image of the specifed type. Ruby types
630
- # are automatically transformed into the matching `GType`, if possible.
776
+ # Mutate an image with a block. Inside the block, you can call methods
777
+ # which modify the image, such as setting or removing metadata, or
778
+ # modifying pixels.
631
779
  #
632
- # For example, you can use this to set an image's ICC profile:
780
+ # For example:
633
781
  #
634
- # ```
635
- # x = y.set_type Vips::BLOB_TYPE, "icc-profile-data", profile
782
+ # ```ruby
783
+ # image = image.mutate do |x|
784
+ # (0 ... 1).step(0.01) do |i|
785
+ # x.draw_line! 255, x.width * i, 0, 0, x.height * (1 - i)
786
+ # end
787
+ # end
636
788
  # ```
637
789
  #
638
- # where `profile` is an ICC profile held as a binary string object.
790
+ # See {MutableImage}.
791
+ def mutate
792
+ mutable = Vips::MutableImage.new self
793
+ yield mutable
794
+ mutable.image
795
+ end
796
+
797
+ # This method is deprecated.
639
798
  #
640
- # @see set
641
- # @param gtype [Integer] GType of item
642
- # @param name [String] Metadata field to set
643
- # @param value [Object] Value to set
799
+ # Please use {MutableImage#set_type!} instead.
644
800
  def set_type gtype, name, value
645
801
  gvalue = GObject::GValue.alloc
646
802
  gvalue.init gtype
647
803
  gvalue.set value
648
- Vips::vips_image_set self, name, gvalue
804
+ Vips.vips_image_set self, name, gvalue
649
805
  gvalue.unset
650
806
  end
651
807
 
652
- # Set the value of a metadata item on an image. The metadata item must
653
- # already exist. Ruby types are automatically transformed into the
654
- # matching `GValue`, if possible.
655
- #
656
- # For example, you can use this to set an image's ICC profile:
808
+ # This method is deprecated.
657
809
  #
658
- # ```
659
- # x = y.set "icc-profile-data", profile
660
- # ```
661
- #
662
- # where `profile` is an ICC profile held as a binary string object.
663
- #
664
- # @see set_type
665
- # @param name [String] Metadata field to set
666
- # @param value [Object] Value to set
810
+ # Please use {MutableImage#set!} instead.
667
811
  def set name, value
668
812
  set_type get_typeof(name), name, value
669
813
  end
670
814
 
671
- # Remove a metadata item from an image.
815
+ # This method is deprecated.
672
816
  #
673
- # @param name [String] Metadata field to remove
817
+ # Please use {MutableImage#remove!} instead.
674
818
  def remove name
675
- Vips::vips_image_remove self, name
819
+ Vips.vips_image_remove self, name
676
820
  end
677
821
 
678
822
  # compatibility: old name for get
@@ -680,7 +824,9 @@ module Vips
680
824
  get name
681
825
  end
682
826
 
683
- # compatibility: old name for set
827
+ # This method is deprecated.
828
+ #
829
+ # Please use {MutableImage#set!} instead.
684
830
  def set_value name, value
685
831
  set name, value
686
832
  end
@@ -689,21 +835,21 @@ module Vips
689
835
  #
690
836
  # @return [Integer] image width, in pixels
691
837
  def width
692
- get "width"
838
+ Vips.vips_image_get_width self
693
839
  end
694
840
 
695
841
  # Get image height, in pixels.
696
842
  #
697
843
  # @return [Integer] image height, in pixels
698
844
  def height
699
- get "height"
845
+ Vips.vips_image_get_height self
700
846
  end
701
847
 
702
848
  # Get number of image bands.
703
849
  #
704
850
  # @return [Integer] number of image bands
705
851
  def bands
706
- get "bands"
852
+ Vips.vips_image_get_bands self
707
853
  end
708
854
 
709
855
  # Get image format.
@@ -787,23 +933,23 @@ module Vips
787
933
  [width, height]
788
934
  end
789
935
 
790
- if Vips::at_least_libvips?(8, 5)
936
+ if Vips.at_least_libvips?(8, 5)
791
937
  # Detect if image has an alpha channel
792
938
  #
793
939
  # @return [Boolean] true if image has an alpha channel.
794
940
  def has_alpha?
795
- return Vips::vips_image_hasalpha(self) != 0
941
+ Vips.vips_image_hasalpha(self) != 0
796
942
  end
797
943
  end
798
944
 
799
945
  # vips_addalpha was added in libvips 8.6
800
- if Vips::at_least_libvips?(8, 6)
946
+ if Vips.at_least_libvips?(8, 6)
801
947
  # Append an alpha channel to an image.
802
948
  #
803
949
  # @return [Image] new image
804
950
  def add_alpha
805
951
  ptr = GenericPtr.new
806
- result = Vips::vips_addalpha self, ptr
952
+ result = Vips.vips_addalpha self, ptr
807
953
  raise Vips::Error if result != 0
808
954
 
809
955
  Vips::Image.new ptr[:value]
@@ -818,7 +964,7 @@ module Vips
818
964
  #
819
965
  # @return [Image] new memory image
820
966
  def copy_memory
821
- new_image = Vips::vips_image_copy_memory self
967
+ new_image = Vips.vips_image_copy_memory self
822
968
  Vips::Image.new new_image
823
969
  end
824
970
 
@@ -828,7 +974,7 @@ module Vips
828
974
  #
829
975
  # @return [Image] modified image
830
976
  def draw_point ink, left, top, **opts
831
- draw_rect ink, left, top, 1, 1, opts
977
+ draw_rect ink, left, top, 1, 1, **opts
832
978
  end
833
979
 
834
980
  # Add an image, constant or array.
@@ -846,7 +992,7 @@ module Vips
846
992
  # @return [Image] result of subtraction
847
993
  def - other
848
994
  other.is_a?(Vips::Image) ?
849
- subtract(other) : linear(1, Image::smap(other) { |x| x * -1 })
995
+ subtract(other) : linear(1, Image.smap(other) { |x| x * -1 })
850
996
  end
851
997
 
852
998
  # Multiply an image, constant or array.
@@ -864,7 +1010,7 @@ module Vips
864
1010
  # @return [Image] result of division
865
1011
  def / other
866
1012
  other.is_a?(Vips::Image) ?
867
- divide(other) : linear(Image::smap(other) { |x| 1.0 / x }, 0)
1013
+ divide(other) : linear(Image.smap(other) { |x| 1.0 / x }, 0)
868
1014
  end
869
1015
 
870
1016
  # Remainder after integer division with an image, constant or array.
@@ -990,7 +1136,7 @@ module Vips
990
1136
  # @return [Image] result of equality
991
1137
  def == other
992
1138
  # for equality, we must allow tests against nil
993
- if other == nil
1139
+ if other.nil?
994
1140
  false
995
1141
  else
996
1142
  call_enum "relational", other, :equal
@@ -1003,7 +1149,7 @@ module Vips
1003
1149
  # @return [Image] result of inequality
1004
1150
  def != other
1005
1151
  # for equality, we must allow tests against nil
1006
- if other == nil
1152
+ if other.nil?
1007
1153
  true
1008
1154
  else
1009
1155
  call_enum "relational", other, :noteq
@@ -1025,38 +1171,40 @@ module Vips
1025
1171
  end
1026
1172
  end
1027
1173
 
1028
- # Convert to an Array. This will be slow for large images.
1174
+ # Convert to an Enumerator. Similar to `#to_a` but lazier.
1029
1175
  #
1030
- # @return [Array] array of Fixnum
1031
- def to_a
1032
- # we render the image to a big string, then unpack
1033
- # as a Ruby array of the correct type
1034
- memory = write_to_memory
1035
-
1176
+ # @return [Enumerator] Enumerator of Enumerators of Arrays of Numerics
1177
+ def to_enum
1036
1178
  # make the template for unpack
1037
1179
  template = {
1038
- char: 'c',
1039
- uchar: 'C',
1040
- short: 's_',
1041
- ushort: 'S_',
1042
- int: 'i_',
1043
- uint: 'I_',
1044
- float: 'f',
1045
- double: 'd',
1046
- complex: 'f',
1047
- dpcomplex: 'd'
1048
- }[format] + '*'
1180
+ char: "c",
1181
+ uchar: "C",
1182
+ short: "s_",
1183
+ ushort: "S_",
1184
+ int: "i_",
1185
+ uint: "I_",
1186
+ float: "f",
1187
+ double: "d",
1188
+ complex: "f",
1189
+ dpcomplex: "d"
1190
+ }[format] + "*"
1049
1191
 
1050
- # and unpack into something like [1, 2, 3, 4 ..]
1051
- array = memory.unpack(template)
1192
+ # we render the image to a big string, then unpack into
1193
+ # one-dimensional array as a Ruby array of the correct type
1194
+ array = write_to_memory.unpack template
1052
1195
 
1053
- # gather band elements together
1054
- pixel_array = array.each_slice(bands).to_a
1196
+ # gather bands of a pixel together
1197
+ pixel_array = array.each_slice bands
1055
1198
 
1056
- # build rows
1057
- row_array = pixel_array.each_slice(width).to_a
1199
+ # gather pixels of a row together
1200
+ pixel_array.each_slice width
1201
+ end
1058
1202
 
1059
- return row_array
1203
+ # Convert to an Array. This will be slow for large images.
1204
+ #
1205
+ # @return [Array] Array of Arrays of Arrays of Numerics
1206
+ def to_a
1207
+ to_enum.to_a
1060
1208
  end
1061
1209
 
1062
1210
  # Return the largest integral value not greater than the argument.
@@ -1132,7 +1280,10 @@ module Vips
1132
1280
  # @param overlay [Image, Array<Image>] images to composite
1133
1281
  # @param mode [BlendMode, Array<BlendMode>] blend modes to use
1134
1282
  # @param opts [Hash] Set of options
1135
- # @option opts [Vips::Interpretation] :compositing_space Composite images in this colour space
1283
+ # @option opts [Array<Integer>] :x x positions of overlay
1284
+ # @option opts [Array<Integer>] :y y positions of overlay
1285
+ # @option opts [Vips::Interpretation] :compositing_space Composite images
1286
+ # in this colour space
1136
1287
  # @option opts [Boolean] :premultiplied Images have premultiplied alpha
1137
1288
  # @return [Image] blended image
1138
1289
  def composite overlay, mode, **options
@@ -1156,9 +1307,9 @@ module Vips
1156
1307
  # coordinate of maximum
1157
1308
  def maxpos
1158
1309
  v, opts = max x: true, y: true
1159
- x = opts['x']
1160
- y = opts['y']
1161
- return v, x, y
1310
+ x = opts["x"]
1311
+ y = opts["y"]
1312
+ [v, x, y]
1162
1313
  end
1163
1314
 
1164
1315
  # Return the coordinates of the image minimum.
@@ -1167,9 +1318,9 @@ module Vips
1167
1318
  # coordinate of minimum
1168
1319
  def minpos
1169
1320
  v, opts = min x: true, y: true
1170
- x = opts['x']
1171
- y = opts['y']
1172
- return v, x, y
1321
+ x = opts["x"]
1322
+ y = opts["y"]
1323
+ [v, x, y]
1173
1324
  end
1174
1325
 
1175
1326
  # a median filter
@@ -1177,7 +1328,7 @@ module Vips
1177
1328
  # @param size [Integer] size of filter window
1178
1329
  # @return [Image] result of median filter
1179
1330
  def median size = 3
1180
- rank size, size, (size * size) / 2
1331
+ rank size, size, size**2 / 2
1181
1332
  end
1182
1333
 
1183
1334
  # Return the real part of a complex image.
@@ -1204,7 +1355,7 @@ module Vips
1204
1355
  # @see xyz
1205
1356
  # @return [Image] image converted to polar coordinates
1206
1357
  def polar
1207
- Image::run_cmplx(self) { |x| x.complex :polar }
1358
+ Image.run_cmplx(self) { |x| x.complex :polar }
1208
1359
  end
1209
1360
 
1210
1361
  # Return an image with polar pixels converted to rectangular.
@@ -1217,7 +1368,7 @@ module Vips
1217
1368
  # @see xyz
1218
1369
  # @return [Image] image converted to rectangular coordinates
1219
1370
  def rect
1220
- Image::run_cmplx(self) { |x| x.complex :rect }
1371
+ Image.run_cmplx(self) { |x| x.complex :rect }
1221
1372
  end
1222
1373
 
1223
1374
  # Return the complex conjugate of an image.
@@ -1229,7 +1380,7 @@ module Vips
1229
1380
  #
1230
1381
  # @return [Image] complex conjugate
1231
1382
  def conj
1232
- Image::run_cmplx(self) { |x| x.complex :conj }
1383
+ Image.run_cmplx(self) { |x| x.complex :conj }
1233
1384
  end
1234
1385
 
1235
1386
  # Calculate the cross phase of two images.
@@ -1282,6 +1433,48 @@ module Vips
1282
1433
  math :atan
1283
1434
  end
1284
1435
 
1436
+ # Return the hyperbolic sine of an image in radians.
1437
+ #
1438
+ # @return [Image] sine of each pixel
1439
+ def sinh
1440
+ math :sinh
1441
+ end
1442
+
1443
+ # Return the hyperbolic cosine of an image in radians.
1444
+ #
1445
+ # @return [Image] cosine of each pixel
1446
+ def cosh
1447
+ math :cosh
1448
+ end
1449
+
1450
+ # Return the hyperbolic tangent of an image in radians.
1451
+ #
1452
+ # @return [Image] tangent of each pixel
1453
+ def tanh
1454
+ math :tanh
1455
+ end
1456
+
1457
+ # Return the inverse hyperbolic sine of an image in radians.
1458
+ #
1459
+ # @return [Image] inverse sine of each pixel
1460
+ def asinh
1461
+ math :asinh
1462
+ end
1463
+
1464
+ # Return the inverse hyperbolic cosine of an image in radians.
1465
+ #
1466
+ # @return [Image] inverse cosine of each pixel
1467
+ def acosh
1468
+ math :acosh
1469
+ end
1470
+
1471
+ # Return the inverse hyperbolic tangent of an image in radians.
1472
+ #
1473
+ # @return [Image] inverse tangent of each pixel
1474
+ def atanh
1475
+ math :atanh
1476
+ end
1477
+
1285
1478
  # Return the natural log of an image.
1286
1479
  #
1287
1480
  # @return [Image] natural log of each pixel
@@ -1410,7 +1603,7 @@ module Vips
1410
1603
  #
1411
1604
  # ```
1412
1605
  # $ ruby > methods.rb
1413
- # require 'vips'; Vips::Yard.generate
1606
+ # require "vips"; Vips::Yard.generate
1414
1607
  # ^D
1415
1608
  # ```
1416
1609
 
@@ -1432,7 +1625,7 @@ module Vips
1432
1625
  "VipsArrayDouble" => "Array<Double>",
1433
1626
  "VipsArrayInt" => "Array<Integer>",
1434
1627
  "VipsArrayImage" => "Array<Image>",
1435
- "VipsArrayString" => "Array<String>",
1628
+ "VipsArrayString" => "Array<String>"
1436
1629
  }
1437
1630
 
1438
1631
  # these have hand-written methods, see above
@@ -1443,15 +1636,15 @@ module Vips
1443
1636
 
1444
1637
  # turn a gtype into a ruby type name
1445
1638
  def self.gtype_to_ruby gtype
1446
- fundamental = GObject::g_type_fundamental gtype
1447
- type_name = GObject::g_type_name gtype
1639
+ fundamental = GObject.g_type_fundamental gtype
1640
+ type_name = GObject.g_type_name gtype
1448
1641
 
1449
1642
  if MAP_GO_TO_RUBY.include? type_name
1450
1643
  type_name = MAP_GO_TO_RUBY[type_name]
1451
1644
  end
1452
1645
 
1453
1646
  if fundamental == GObject::GFLAGS_TYPE ||
1454
- fundamental == GObject::GENUM_TYPE
1647
+ fundamental == GObject::GENUM_TYPE
1455
1648
  type_name = "Vips::" + type_name[/Vips(.*)/, 1]
1456
1649
  end
1457
1650
 
@@ -1464,13 +1657,13 @@ module Vips
1464
1657
 
1465
1658
  method_args = introspect.method_args
1466
1659
  required_output = introspect.required_output
1467
- optional_input = introspect.optional_input
1468
- optional_output = introspect.optional_output
1660
+ optional_input = introspect.doc_optional_input
1661
+ optional_output = introspect.doc_optional_output
1469
1662
 
1470
1663
  print "# @!method "
1471
1664
  print "self." unless introspect.member_x
1472
1665
  print "#{introspect.name}("
1473
- print method_args.map{ |x| x[:yard_name] }.join(", ")
1666
+ print method_args.map { |x| x[:yard_name] }.join(", ")
1474
1667
  print ", " if method_args.length > 0
1475
1668
  puts "**opts)"
1476
1669
 
@@ -1488,18 +1681,18 @@ module Vips
1488
1681
  optional_input.each do |arg_name, details|
1489
1682
  yard_name = details[:yard_name]
1490
1683
  gtype = details[:gtype]
1684
+ rtype = gtype_to_ruby gtype
1491
1685
  blurb = details[:blurb]
1492
1686
 
1493
- puts "# @option opts [#{gtype_to_ruby(gtype)}] :#{yard_name} " +
1494
- "#{blurb}"
1687
+ puts "# @option opts [#{rtype}] :#{yard_name} #{blurb}"
1495
1688
  end
1496
1689
  optional_output.each do |arg_name, details|
1497
1690
  yard_name = details[:yard_name]
1498
1691
  gtype = details[:gtype]
1692
+ rtype = gtype_to_ruby gtype
1499
1693
  blurb = details[:blurb]
1500
1694
 
1501
- print "# @option opts [#{gtype_to_ruby(gtype)}] :#{yard_name}"
1502
- puts " Output #{blurb}"
1695
+ puts "# @option opts [#{rtype}] :#{yard_name} Output #{blurb}"
1503
1696
  end
1504
1697
 
1505
1698
  print "# @return ["
@@ -1509,14 +1702,14 @@ module Vips
1509
1702
  print gtype_to_ruby(required_output.first[:gtype])
1510
1703
  else
1511
1704
  print "Array<"
1512
- print required_output.map{ |x| gtype_to_ruby(x[:gtype]) }.join(", ")
1705
+ print required_output.map { |x| gtype_to_ruby(x[:gtype]) }.join(", ")
1513
1706
  print ">"
1514
1707
  end
1515
1708
  if optional_output.length > 0
1516
1709
  print ", Hash<Symbol => Object>"
1517
1710
  end
1518
1711
  print "] "
1519
- print required_output.map{ |x| x[:blurb] }.join(", ")
1712
+ print required_output.map { |x| x[:blurb] }.join(", ")
1520
1713
  if optional_output.length > 0
1521
1714
  print ", " if required_output.length > 0
1522
1715
  print "Hash of optional output items"
@@ -1528,16 +1721,16 @@ module Vips
1528
1721
 
1529
1722
  def self.generate
1530
1723
  alias_gtypes = {}
1531
- ALIAS.each do |name|
1532
- gtype = Vips::type_find "VipsOperation", name
1533
- alias_gtypes[gtype] = name
1724
+ ALIAS.each do |name|
1725
+ gtype = Vips.type_find "VipsOperation", name
1726
+ alias_gtypes[gtype] = name
1534
1727
  end
1535
1728
 
1536
1729
  generate_class = lambda do |gtype, _|
1537
- if alias_gtypes.key? gtype
1538
- name = alias_gtypes[gtype]
1730
+ name = if alias_gtypes.key? gtype
1731
+ alias_gtypes[gtype]
1539
1732
  else
1540
- name = Vips::nickname_find gtype
1733
+ Vips.nickname_find gtype
1541
1734
  end
1542
1735
 
1543
1736
  if name
@@ -1551,14 +1744,14 @@ module Vips
1551
1744
  generate_operation(introspect) if introspect
1552
1745
  end
1553
1746
 
1554
- Vips::vips_type_map gtype, generate_class, nil
1747
+ Vips.vips_type_map gtype, generate_class, nil
1555
1748
  end
1556
1749
 
1557
1750
  puts "module Vips"
1558
1751
  puts " class Image"
1559
1752
  puts ""
1560
1753
 
1561
- generate_class.(GObject::g_type_from_name("VipsOperation"), nil)
1754
+ generate_class.call(GObject.g_type_from_name("VipsOperation"), nil)
1562
1755
 
1563
1756
  puts " end"
1564
1757
  puts "end"