vips 8.10.5 → 8.12.2

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