vips 8.8.3 → 8.11.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5b741c06a5dd87066e67be9371f529d73fe26f763bbf43925a0422d76dbbe857
4
- data.tar.gz: a6c5aea06cd1431cd769430b9b211179ae17649cfacd3c91108285965074562b
3
+ metadata.gz: 0d8cc116cc011d40275e97c4f71ed4de8c816986b0ea7f693569c1c8e1c389c6
4
+ data.tar.gz: b38e3424536c7c35da15394a1f79d29a1a70058280eaefb75a8e43372e50bddf
5
5
  SHA512:
6
- metadata.gz: 4fcc86880b97721f5c16b278cca4f71148e5216cb3c94c82b3a746fc1a635c5275edb2d6e3bdafc2e5597b12aef878157011351ea343b7bc7043eaba9dabcf21
7
- data.tar.gz: a2fb7855ba689e6040c3d51ee24d9cd56a34949f844da30cb7ef18354376c2e6067263df626892160bbd48170712c2e5ae845d37f86922bbf723b1d3afb4580c
6
+ metadata.gz: 8f9014f781138d33232a3f7bd88706a0cc3b6f494a9ea48def52d5f1e4db6d2fce07eca88782c9130121866cd6b9231d2f96dde5f5064a9739cdd9fc1074cb12
7
+ data.tar.gz: 60273f63fc6289240650c675141afe46037cc301926f691507dfd3a39971dd236cebd1ee964df090f4e911a17f33141bd614223de1492a74ba1f954c7ed816ad
data/.travis.yml CHANGED
@@ -41,6 +41,7 @@ matrix:
41
41
  - rvm: 2.6
42
42
  os: osx
43
43
  env: PKG_CONFIG_PATH="/usr/local/opt/libffi/lib/pkgconfig"
44
+ - rvm: 2.7
44
45
  - rvm: truffleruby
45
46
  - rvm: jruby-head
46
47
  - rvm: ruby-head
data/Gemfile CHANGED
@@ -2,3 +2,8 @@ source 'https://rubygems.org'
2
2
 
3
3
  # all gems are handled by .gemspec (since this repo is for a gem)
4
4
  gemspec
5
+
6
+ group :maintenance, optional: true do
7
+ gem "bake"
8
+ gem "bake-gem"
9
+ end
data/README.md CHANGED
@@ -1,10 +1,12 @@
1
1
  # Vips
2
2
 
3
+ Programs that use `vips` don't manipulate images directly, instead they create pipelines of image processing operations building on a source image. When the end of the pipe is connected to a destination, the whole pipeline executes at once, streaming the image in parallel from source to destination a section at a time. Because `ruby-vips` is parallel, it's quick, and because it doesn't need to keep entire images in memory, it's light.
4
+
3
5
  This gem is a backwards compatible fork of `ruby-vips` but also includes (and compiles) the [libvips] source code.
4
6
 
5
7
  [![Build Status](https://secure.travis-ci.org/ioquatix/vips.svg)](http://travis-ci.org/ioquatix/vips)
6
8
 
7
- [libvips]: https://jcupitt.github.io/libvips
9
+ [libvips]: https://libvips.github.io/libvips
8
10
 
9
11
  ## Installation
10
12
 
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'vips'
4
+
5
+ file = File.open ARGV[0], "rb"
6
+ source = Vips::SourceCustom.new
7
+ source.on_read { |length| file.read length }
8
+ # this method is optional
9
+ # source.on_seek { |offset, whence| file.seek(offset, whence) }
10
+
11
+ dest = File.open ARGV[1], "wb"
12
+ target = Vips::TargetCustom.new
13
+ target.on_write { |chunk| dest.write(chunk) }
14
+ target.on_finish { dest.close }
15
+
16
+ image = Vips::Image.new_from_source source, "", access: :sequential
17
+ image.write_to_target target, ".png"
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'vips'
4
+
5
+ image = Vips::Image.black 1, 100000
6
+ image.set_progress true
7
+
8
+ def progress_to_s(name, progress)
9
+ puts "#{name}:"
10
+ puts " progress.run = #{progress[:run]}"
11
+ puts " progress.eta = #{progress[:eta]}"
12
+ puts " progress.tpels = #{progress[:tpels]}"
13
+ puts " progress.npels = #{progress[:npels]}"
14
+ puts " progress.percent = #{progress[:percent]}"
15
+ end
16
+
17
+ image.signal_connect :preeval do |progress|
18
+ progress_to_s("preeval", progress)
19
+ end
20
+
21
+ image.signal_connect :eval do |progress|
22
+ progress_to_s("eval", progress)
23
+ image.set_kill(true) if progress[:percent] > 50
24
+ end
25
+
26
+ image.signal_connect :posteval do |progress|
27
+ progress_to_s("posteval", progress)
28
+ end
29
+
30
+ image.avg
data/ext/Rakefile CHANGED
@@ -8,9 +8,9 @@ prefix = ENV['PREFIX'] || File.dirname(__dir__)
8
8
 
9
9
  task :fetch do
10
10
  url = "https://github.com/libvips/libvips/releases/download/v#{version}/#{archive_path}"
11
-
11
+
12
12
  unless File.exist? archive_path
13
- sh "wget #{url}"
13
+ sh "wget #{url} -O #{archive_path}"
14
14
  end
15
15
  end
16
16
 
@@ -0,0 +1,46 @@
1
+ # This module provides an interface to the top level bits of libvips
2
+ # via ruby-ffi.
3
+ #
4
+ # Author:: John Cupitt (mailto:jcupitt@gmail.com)
5
+ # License:: MIT
6
+
7
+ require 'ffi'
8
+
9
+ module Vips
10
+ if Vips::at_least_libvips?(8, 9)
11
+ attach_function :vips_connection_filename, [:pointer], :string
12
+ attach_function :vips_connection_nick, [:pointer], :string
13
+ end
14
+
15
+ # Abstract base class for connections.
16
+ class Connection < Vips::Object
17
+ # The layout of the VipsRegion struct.
18
+ module ConnectionLayout
19
+ def self.included(base)
20
+ base.class_eval do
21
+ layout :parent, Vips::Object::Struct
22
+ # rest opaque
23
+ end
24
+ end
25
+ end
26
+
27
+ class Struct < Vips::Object::Struct
28
+ include ConnectionLayout
29
+ end
30
+
31
+ class ManagedStruct < Vips::Object::ManagedStruct
32
+ include ConnectionLayout
33
+ end
34
+
35
+ # Get any filename associated with a connection, or nil.
36
+ def filename
37
+ Vips::vips_connection_filename self
38
+ end
39
+
40
+ # Get a nickname (short description) of a connection that could be shown to
41
+ # the user.
42
+ def nick
43
+ Vips::vips_connection_nick self
44
+ end
45
+ end
46
+ end
data/lib/vips/gobject.rb CHANGED
@@ -73,6 +73,9 @@ module GObject
73
73
  def initialize ptr
74
74
  # GLib::logger.debug("GObject::GObject.initialize") {"ptr = #{ptr}"}
75
75
  @struct = ffi_managed_struct.new ptr
76
+
77
+ # sometimes we need to keep refs across C calls ... hide them here
78
+ @references = []
76
79
  end
77
80
 
78
81
  # access to the casting struct for this class
@@ -111,8 +114,13 @@ module GObject
111
114
  layout :value, GParamSpec.ptr
112
115
  end
113
116
 
114
- attach_function :g_param_spec_get_blurb, [GParamSpec.ptr], :string
117
+ attach_function :g_param_spec_get_blurb, [:pointer], :string
115
118
 
116
119
  attach_function :g_object_ref, [:pointer], :void
117
120
  attach_function :g_object_unref, [:pointer], :void
121
+
122
+ # we just use one gcallback type for every signal, hopefully this is OK
123
+ callback :gcallback, [:pointer], :void
124
+ attach_function :g_signal_connect_data,
125
+ [:pointer, :string, :gcallback, :pointer, :pointer, :int], :long
118
126
  end
data/lib/vips/gvalue.rb CHANGED
@@ -13,6 +13,8 @@ module GObject
13
13
  # gvalue.init GObject::GDOUBLE_TYPE
14
14
  # gvalue.set 3.1415
15
15
  # value = gvalue.get
16
+ # # optional -- drop any ref the gvalue had
17
+ # gvalue.unset
16
18
  # ```
17
19
  #
18
20
  # Lifetime is managed automatically. It doesn't know about all GType values,
@@ -27,7 +29,9 @@ module GObject
27
29
  value = value.to_s if value.is_a? Symbol
28
30
 
29
31
  if value.is_a? String
30
- value = Vips::vips_enum_from_nick "ruby-vips", gtype, value
32
+ # libvips expects "-" as a separator in enum names, but "_" is more
33
+ # convenient for ruby, eg. :b_w
34
+ value = Vips::vips_enum_from_nick "ruby-vips", gtype, value.tr("_", "-")
31
35
  if value == -1
32
36
  raise Vips::Error
33
37
  end
@@ -241,6 +245,14 @@ module GObject
241
245
 
242
246
  return result
243
247
  end
248
+
249
+ # Clear the thing held by a GValue.
250
+ #
251
+ # This happens automatically when a GValue is GCed, but this method can be
252
+ # handy if you need to drop a reference explicitly for some reason.
253
+ def unset
254
+ ::GObject::g_value_unset self
255
+ end
244
256
  end
245
257
 
246
258
  attach_function :g_value_init, [GValue.ptr, :GType], :void
data/lib/vips/image.rb CHANGED
@@ -14,6 +14,9 @@ module Vips
14
14
 
15
15
  attach_function :vips_image_copy_memory, [:pointer], :pointer
16
16
 
17
+ attach_function :vips_image_set_progress, [:pointer, :bool], :void
18
+ attach_function :vips_image_set_kill, [:pointer, :bool], :void
19
+
17
20
  attach_function :vips_filename_get_filename, [:string], :pointer
18
21
  attach_function :vips_filename_get_options, [:string], :pointer
19
22
 
@@ -22,6 +25,11 @@ module Vips
22
25
  attach_function :vips_foreign_find_load_buffer, [:pointer, :size_t], :string
23
26
  attach_function :vips_foreign_find_save_buffer, [:string], :string
24
27
 
28
+ if Vips::at_least_libvips?(8, 9)
29
+ attach_function :vips_foreign_find_load_source, [:pointer], :string
30
+ attach_function :vips_foreign_find_save_target, [:string], :string
31
+ end
32
+
25
33
  attach_function :vips_image_write_to_memory,
26
34
  [:pointer, SizeStruct.ptr], :pointer
27
35
 
@@ -29,20 +37,14 @@ module Vips
29
37
  attach_function :vips_image_get,
30
38
  [:pointer, :string, GObject::GValue.ptr], :int
31
39
 
32
- # vips_image_get_fields was added in libvips 8.5
33
- begin
40
+ if Vips::at_least_libvips?(8, 5)
34
41
  attach_function :vips_image_get_fields, [:pointer], :pointer
35
- rescue FFI::NotFoundError
36
- nil
42
+ attach_function :vips_image_hasalpha, [:pointer], :int
37
43
  end
38
44
 
39
- # vips_addalpha was added in libvips 8.6
40
45
  if Vips::at_least_libvips?(8, 6)
41
46
  attach_function :vips_addalpha, [:pointer, :pointer, :varargs], :int
42
47
  end
43
- if Vips::at_least_libvips?(8, 5)
44
- attach_function :vips_image_hasalpha, [:pointer], :int
45
- end
46
48
 
47
49
  attach_function :vips_image_set,
48
50
  [:pointer, :string, GObject::GValue.ptr], :void
@@ -53,6 +55,8 @@ module Vips
53
55
 
54
56
  attach_function :nickname_find, :vips_nickname_find, [:GType], :string
55
57
 
58
+ attach_function :vips_image_invalidate_all, [:pointer], :void
59
+
56
60
  # turn a raw pointer that must be freed into a self-freeing Ruby string
57
61
  def self.p2str(pointer)
58
62
  pointer = FFI::AutoPointer.new(pointer, GLib::G_FREE)
@@ -67,6 +71,10 @@ module Vips
67
71
  class Image < Vips::Object
68
72
  alias_method :parent_get_typeof, :get_typeof
69
73
 
74
+ def close
75
+ Vips.vips_image_invalidate_all(self)
76
+ end
77
+
70
78
  private
71
79
 
72
80
  # the layout of the VipsImage struct
@@ -115,7 +123,7 @@ module Vips
115
123
 
116
124
  unless Image::complex? image.format
117
125
  if image.bands % 2 != 0
118
- raise Error, "not an even number of bands"
126
+ raise Vips::Error, "not an even number of bands"
119
127
  end
120
128
 
121
129
  unless Image::float? image.format
@@ -145,34 +153,6 @@ module Vips
145
153
  end
146
154
  end
147
155
 
148
- # Write can fail due to no file descriptors and memory can fill if
149
- # large objects are not collected fairly soon. We can't try a
150
- # write and GC and retry on fail, since the write may take a
151
- # long time and may not be repeatable.
152
- #
153
- # GCing before every write would have a horrible effect on
154
- # performance, so as a compromise we GC every @@gc_interval writes.
155
- #
156
- # ruby2.1 introduced a generational GC which is fast enough to be
157
- # able to GC on every write.
158
-
159
- @@generational_gc = RUBY_ENGINE == "ruby" && RUBY_VERSION.to_f >= 2.1
160
-
161
- @@gc_interval = 100
162
- @@gc_countdown = @@gc_interval
163
-
164
- def write_gc
165
- if @@generational_gc
166
- GC.start full_mark: false
167
- else
168
- @@gc_countdown -= 1
169
- if @@gc_countdown < 0
170
- @@gc_countdown = @@gc_interval
171
- GC.start
172
- end
173
- end
174
- end
175
-
176
156
  public
177
157
 
178
158
  def inspect
@@ -219,13 +199,13 @@ module Vips
219
199
  # load options, for example:
220
200
  #
221
201
  # ```
222
- # image = Vips::new_from_file "fred.jpg[shrink=2]"
202
+ # image = Vips::Image.new_from_file "fred.jpg[shrink=2]"
223
203
  # ```
224
204
  #
225
205
  # You can also supply options as a hash, for example:
226
206
  #
227
207
  # ```
228
- # image = Vips::new_from_file "fred.jpg", shrink: 2
208
+ # image = Vips::Image.new_from_file "fred.jpg", shrink: 2
229
209
  # ```
230
210
  #
231
211
  # The full set of options available depend upon the load operation that
@@ -296,11 +276,50 @@ module Vips
296
276
  # @return [Image] the loaded image
297
277
  def self.new_from_buffer data, option_string, **opts
298
278
  loader = Vips::vips_foreign_find_load_buffer data, data.bytesize
299
- raise Vips::Error if loader == nil
279
+ raise Vips::Error if loader.nil?
300
280
 
301
281
  Vips::Operation.call loader, [data], opts, option_string
302
282
  end
303
283
 
284
+ # Create a new {Image} from a source. Load options may be passed as
285
+ # strings or appended as a hash. For example:
286
+ #
287
+ # ```
288
+ # source = Vips::Source.new_from_file("k2.jpg")
289
+ # image = Vips::Image.new_from_source source, "shrink=2"
290
+ # ```
291
+ #
292
+ # or alternatively:
293
+ #
294
+ # ```
295
+ # image = Vips::Image.new_from_source source, "", shrink: 2
296
+ # ```
297
+ #
298
+ # The options available depend on the file format. Try something like:
299
+ #
300
+ # ```
301
+ # $ vips jpegload_source
302
+ # ```
303
+ #
304
+ # at the command-line to see the available options. Not all loaders
305
+ # support load from source, but at least JPEG, PNG and
306
+ # TIFF images will work.
307
+ #
308
+ # 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
310
+ # needed.
311
+ #
312
+ # @param source [Vips::Source] the source to load from
313
+ # @param option_string [String] load options as a string
314
+ # @macro vips.loadopts
315
+ # @return [Image] the loaded image
316
+ def self.new_from_source source, option_string, **opts
317
+ loader = Vips::vips_foreign_find_load_source source
318
+ raise Vips::Error if loader.nil?
319
+
320
+ Vips::Operation.call loader, [source], opts, option_string
321
+ end
322
+
304
323
  def self.matrix_from_array width, height, array
305
324
  ptr = FFI::MemoryPointer.new :double, array.length
306
325
  ptr.write_array_of_double array
@@ -317,13 +336,13 @@ module Vips
317
336
  # For example:
318
337
  #
319
338
  # ```
320
- # image = Vips::new_from_array [1, 2, 3]
339
+ # image = Vips::Image.new_from_array [1, 2, 3]
321
340
  # ```
322
341
  #
323
342
  # or
324
343
  #
325
344
  # ```
326
- # image = Vips::new_from_array [
345
+ # image = Vips::Image.new_from_array [
327
346
  # [-1, -1, -1],
328
347
  # [-1, 16, -1],
329
348
  # [-1, -1, -1]], 8
@@ -426,8 +445,6 @@ module Vips
426
445
  end
427
446
 
428
447
  Vips::Operation.call saver, [self, filename], opts, option_string
429
-
430
- write_gc
431
448
  end
432
449
 
433
450
  # Write this image to a memory buffer. Save options may be encoded in
@@ -460,17 +477,52 @@ module Vips
460
477
  option_string = Vips::p2str(Vips::vips_filename_get_options format_string)
461
478
  saver = Vips::vips_foreign_find_save_buffer filename
462
479
  if saver == nil
463
- raise Vips::Error, "No known saver for '#{filename}'."
480
+ raise Vips::Error, "No known buffer saver for '#{filename}'."
464
481
  end
465
482
 
466
483
  buffer = Vips::Operation.call saver, [self], opts, option_string
467
484
  raise Vips::Error if buffer == nil
468
485
 
469
- write_gc
470
-
471
486
  return buffer
472
487
  end
473
488
 
489
+ # Write this image to a target. Save options may be encoded in
490
+ # the format_string or given as a hash. For example:
491
+ #
492
+ # ```ruby
493
+ # target = Vips::Target.new_to_file "k2.jpg"
494
+ # image.write_to_target target, ".jpg[Q=90]"
495
+ # ```
496
+ #
497
+ # or equivalently:
498
+ #
499
+ # ```ruby
500
+ # image.write_to_target target, ".jpg", Q: 90
501
+ # ```
502
+ #
503
+ # The full set of save options depend on the selected saver. Try
504
+ # something like:
505
+ #
506
+ # ```
507
+ # $ vips jpegsave_target
508
+ # ```
509
+ #
510
+ # to see all the available options for JPEG save.
511
+ #
512
+ # @param target [Vips::Target] the target to write to
513
+ # @param format_string [String] save format plus string options
514
+ # @macro vips.saveopts
515
+ 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
522
+
523
+ Vips::Operation.call saver, [self, target], opts, option_string
524
+ end
525
+
474
526
  # Write this image to a large memory buffer.
475
527
  #
476
528
  # @return [String] the pixels as a huge binary string
@@ -485,6 +537,28 @@ module Vips
485
537
  ptr.get_bytes 0, len[:value]
486
538
  end
487
539
 
540
+ # Turn progress signalling on and off.
541
+ #
542
+ # If this is on, the most-downstream image from this image will issue
543
+ # progress signals.
544
+ #
545
+ # @see Object#signal_connect
546
+ # @param state [Boolean] progress signalling state
547
+ def set_progress state
548
+ Vips::vips_image_set_progress self, state
549
+ end
550
+
551
+ # Kill computation of this time.
552
+ #
553
+ # Set true to stop computation of this image. You can call this from a
554
+ # progress handler, for example.
555
+ #
556
+ # @see Object#signal_connect
557
+ # @param kill [Boolean] stop computation
558
+ def set_kill kill
559
+ Vips::vips_image_set_kill self, kill
560
+ end
561
+
488
562
  # Get the `GType` of a metadata field. The result is 0 if no such field
489
563
  # exists.
490
564
  #
@@ -523,10 +597,11 @@ module Vips
523
597
  end
524
598
 
525
599
  gvalue = GObject::GValue.alloc
526
- result = Vips::vips_image_get self, name, gvalue
527
- raise Vips::Error if result != 0
600
+ raise Vips::Error if Vips::vips_image_get(self, name, gvalue) != 0
601
+ result = gvalue.get
602
+ gvalue.unset
528
603
 
529
- gvalue.get
604
+ result
530
605
  end
531
606
 
532
607
  # Get the names of all fields on an image. Use this to loop over all
@@ -571,6 +646,7 @@ module Vips
571
646
  gvalue.init gtype
572
647
  gvalue.set value
573
648
  Vips::vips_image_set self, name, gvalue
649
+ gvalue.unset
574
650
  end
575
651
 
576
652
  # Set the value of a metadata item on an image. The metadata item must
@@ -1059,7 +1135,7 @@ module Vips
1059
1135
  # @option opts [Vips::Interpretation] :compositing_space Composite images in this colour space
1060
1136
  # @option opts [Boolean] :premultiplied Images have premultiplied alpha
1061
1137
  # @return [Image] blended image
1062
- def composite overlay, mode, **opts
1138
+ def composite overlay, mode, **options
1063
1139
  unless overlay.is_a? Array
1064
1140
  overlay = [overlay]
1065
1141
  end
@@ -1071,7 +1147,7 @@ module Vips
1071
1147
  GObject::GValue.from_nick Vips::BLEND_MODE_TYPE, x
1072
1148
  end
1073
1149
 
1074
- Vips::Image.composite([self] + overlay, mode, opts)
1150
+ Vips::Image.composite([self] + overlay, mode, **options)
1075
1151
  end
1076
1152
 
1077
1153
  # Return the coordinates of the image maximum.
@@ -1320,30 +1396,27 @@ module Vips
1320
1396
  #
1321
1397
  # @param opts [Hash] Set of options
1322
1398
  # @return [Vips::Image] Output image
1323
- def scaleimage **opts
1324
- Vips::Image.scale self, opts
1399
+ def scaleimage **options
1400
+ Vips::Image.scale self, **options
1325
1401
  end
1326
1402
  end
1327
1403
  end
1328
1404
 
1329
1405
  module Vips
1330
- # This method generates yard comments for all the dynamically bound
1406
+ # This module generates yard comments for all the dynamically bound
1331
1407
  # vips operations.
1332
1408
  #
1333
1409
  # Regenerate with something like:
1334
1410
  #
1335
1411
  # ```
1336
1412
  # $ ruby > methods.rb
1337
- # require 'vips'; Vips::generate_yard
1413
+ # require 'vips'; Vips::Yard.generate
1338
1414
  # ^D
1339
1415
  # ```
1340
1416
 
1341
- def self.generate_yard
1342
- # these have hand-written methods, see above
1343
- no_generate = ["scale", "bandjoin", "composite", "ifthenelse"]
1344
-
1417
+ module Yard
1345
1418
  # map gobject's type names to Ruby
1346
- map_go_to_ruby = {
1419
+ MAP_GO_TO_RUBY = {
1347
1420
  "gboolean" => "Boolean",
1348
1421
  "gint" => "Integer",
1349
1422
  "gdouble" => "Float",
@@ -1351,116 +1424,99 @@ module Vips
1351
1424
  "gchararray" => "String",
1352
1425
  "VipsImage" => "Vips::Image",
1353
1426
  "VipsInterpolate" => "Vips::Interpolate",
1427
+ "VipsConnection" => "Vips::Connection",
1428
+ "VipsSource" => "Vips::Source",
1429
+ "VipsTarget" => "Vips::Target",
1430
+ "VipsSourceCustom" => "Vips::SourceCustom",
1431
+ "VipsTargetCustom" => "Vips::TargetCustom",
1354
1432
  "VipsArrayDouble" => "Array<Double>",
1355
1433
  "VipsArrayInt" => "Array<Integer>",
1356
1434
  "VipsArrayImage" => "Array<Image>",
1357
1435
  "VipsArrayString" => "Array<String>",
1358
1436
  }
1359
1437
 
1360
- generate_operation = lambda do |gtype, nickname, op|
1361
- op_flags = op.get_flags
1362
- return if (op_flags & OPERATION_DEPRECATED) != 0
1363
- return if no_generate.include? nickname
1364
-
1365
- description = Vips::vips_object_get_description op
1366
-
1367
- # find and classify all the arguments the operator can take
1368
- required_input = []
1369
- optional_input = []
1370
- required_output = []
1371
- optional_output = []
1372
- member_x = nil
1373
- op.argument_map do |pspec, argument_class, _argument_instance|
1374
- arg_flags = argument_class[:flags]
1375
- next if (arg_flags & ARGUMENT_CONSTRUCT) == 0
1376
- next if (arg_flags & ARGUMENT_DEPRECATED) != 0
1377
-
1378
- name = pspec[:name].tr("-", "_")
1379
- # 'in' as a param name confuses yard
1380
- name = "im" if name == "in"
1381
- gtype = pspec[:value_type]
1382
- fundamental = GObject::g_type_fundamental gtype
1383
- type_name = GObject::g_type_name gtype
1384
- if map_go_to_ruby.include? type_name
1385
- type_name = map_go_to_ruby[type_name]
1386
- end
1387
- if fundamental == GObject::GFLAGS_TYPE ||
1388
- fundamental == GObject::GENUM_TYPE
1389
- type_name = "Vips::" + type_name[/Vips(.*)/, 1]
1390
- end
1391
- blurb = GObject::g_param_spec_get_blurb pspec
1392
- value = {
1393
- name: name,
1394
- flags: arg_flags,
1395
- gtype: gtype,
1396
- type_name: type_name,
1397
- blurb: blurb
1398
- }
1399
-
1400
- if (arg_flags & ARGUMENT_INPUT) != 0
1401
- if (arg_flags & ARGUMENT_REQUIRED) != 0
1402
- # note the first required input image, if any ... we
1403
- # will be a method of this instance
1404
- if !member_x && gtype == Vips::IMAGE_TYPE
1405
- member_x = value
1406
- else
1407
- required_input << value
1408
- end
1409
- else
1410
- optional_input << value
1411
- end
1412
- end
1438
+ # these have hand-written methods, see above
1439
+ NO_GENERATE = ["scale", "bandjoin", "composite", "ifthenelse"]
1413
1440
 
1414
- # MODIFY INPUT args count as OUTPUT as well
1415
- if (arg_flags & ARGUMENT_OUTPUT) != 0 ||
1416
- ((arg_flags & ARGUMENT_INPUT) != 0 &&
1417
- (arg_flags & ARGUMENT_MODIFY) != 0)
1418
- if (arg_flags & ARGUMENT_REQUIRED) != 0
1419
- required_output << value
1420
- else
1421
- optional_output << value
1422
- end
1423
- end
1441
+ # these are aliased (appear under several names)
1442
+ ALIAS = ["crop"]
1443
+
1444
+ # turn a gtype into a ruby type name
1445
+ def self.gtype_to_ruby gtype
1446
+ fundamental = GObject::g_type_fundamental gtype
1447
+ type_name = GObject::g_type_name gtype
1448
+
1449
+ if MAP_GO_TO_RUBY.include? type_name
1450
+ type_name = MAP_GO_TO_RUBY[type_name]
1451
+ end
1452
+
1453
+ if fundamental == GObject::GFLAGS_TYPE ||
1454
+ fundamental == GObject::GENUM_TYPE
1455
+ type_name = "Vips::" + type_name[/Vips(.*)/, 1]
1424
1456
  end
1425
1457
 
1458
+ type_name
1459
+ end
1460
+
1461
+ def self.generate_operation introspect
1462
+ return if (introspect.flags & OPERATION_DEPRECATED) != 0
1463
+ return if NO_GENERATE.include? introspect.name
1464
+
1465
+ method_args = introspect.method_args
1466
+ required_output = introspect.required_output
1467
+ optional_input = introspect.optional_input
1468
+ optional_output = introspect.optional_output
1469
+
1426
1470
  print "# @!method "
1427
- print "self." unless member_x
1428
- print "#{nickname}("
1429
- print required_input.map { |x| x[:name] }.join(", ")
1430
- print ", " if required_input.length > 0
1471
+ print "self." unless introspect.member_x
1472
+ print "#{introspect.name}("
1473
+ print method_args.map{ |x| x[:yard_name] }.join(", ")
1474
+ print ", " if method_args.length > 0
1431
1475
  puts "**opts)"
1432
1476
 
1433
- puts "# #{description.capitalize}."
1477
+ puts "# #{introspect.description.capitalize}."
1478
+
1479
+ method_args.each do |details|
1480
+ yard_name = details[:yard_name]
1481
+ gtype = details[:gtype]
1482
+ blurb = details[:blurb]
1434
1483
 
1435
- required_input.each do |arg|
1436
- puts "# @param #{arg[:name]} [#{arg[:type_name]}] #{arg[:blurb]}"
1484
+ puts "# @param #{yard_name} [#{gtype_to_ruby(gtype)}] #{blurb}"
1437
1485
  end
1438
1486
 
1439
1487
  puts "# @param opts [Hash] Set of options"
1440
- optional_input.each do |arg|
1441
- puts "# @option opts [#{arg[:type_name]}] :#{arg[:name]} " +
1442
- "#{arg[:blurb]}"
1488
+ optional_input.each do |arg_name, details|
1489
+ yard_name = details[:yard_name]
1490
+ gtype = details[:gtype]
1491
+ blurb = details[:blurb]
1492
+
1493
+ puts "# @option opts [#{gtype_to_ruby(gtype)}] :#{yard_name} " +
1494
+ "#{blurb}"
1443
1495
  end
1444
- optional_output.each do |arg|
1445
- print "# @option opts [#{arg[:type_name]}] :#{arg[:name]}"
1446
- puts " Output #{arg[:blurb]}"
1496
+ optional_output.each do |arg_name, details|
1497
+ yard_name = details[:yard_name]
1498
+ gtype = details[:gtype]
1499
+ blurb = details[:blurb]
1500
+
1501
+ print "# @option opts [#{gtype_to_ruby(gtype)}] :#{yard_name}"
1502
+ puts " Output #{blurb}"
1447
1503
  end
1448
1504
 
1449
1505
  print "# @return ["
1450
1506
  if required_output.length == 0
1451
1507
  print "nil"
1452
1508
  elsif required_output.length == 1
1453
- print required_output.first[:type_name]
1509
+ print gtype_to_ruby(required_output.first[:gtype])
1454
1510
  else
1455
1511
  print "Array<"
1456
- print required_output.map { |x| x[:type_name] }.join(", ")
1512
+ print required_output.map{ |x| gtype_to_ruby(x[:gtype]) }.join(", ")
1457
1513
  print ">"
1458
1514
  end
1459
1515
  if optional_output.length > 0
1460
1516
  print ", Hash<Symbol => Object>"
1461
1517
  end
1462
1518
  print "] "
1463
- print required_output.map { |x| x[:blurb] }.join(", ")
1519
+ print required_output.map{ |x| x[:blurb] }.join(", ")
1464
1520
  if optional_output.length > 0
1465
1521
  print ", " if required_output.length > 0
1466
1522
  print "Hash of optional output items"
@@ -1470,30 +1526,42 @@ module Vips
1470
1526
  puts ""
1471
1527
  end
1472
1528
 
1473
- generate_class = lambda do |gtype, _|
1474
- nickname = Vips::nickname_find gtype
1529
+ def self.generate
1530
+ alias_gtypes = {}
1531
+ ALIAS.each do |name|
1532
+ gtype = Vips::type_find "VipsOperation", name
1533
+ alias_gtypes[gtype] = name
1534
+ end
1475
1535
 
1476
- if nickname
1477
- begin
1478
- # can fail for abstract types
1479
- op = Vips::Operation.new nickname
1480
- rescue Vips::Error
1481
- nil
1536
+ generate_class = lambda do |gtype, _|
1537
+ if alias_gtypes.key? gtype
1538
+ name = alias_gtypes[gtype]
1539
+ else
1540
+ name = Vips::nickname_find gtype
1482
1541
  end
1483
1542
 
1484
- generate_operation.(gtype, nickname, op) if op
1485
- end
1543
+ if name
1544
+ begin
1545
+ # can fail for abstract types
1546
+ introspect = Vips::Introspect.get_yard name
1547
+ rescue Vips::Error
1548
+ nil
1549
+ end
1486
1550
 
1487
- Vips::vips_type_map gtype, generate_class, nil
1488
- end
1551
+ generate_operation(introspect) if introspect
1552
+ end
1553
+
1554
+ Vips::vips_type_map gtype, generate_class, nil
1555
+ end
1489
1556
 
1490
- puts "module Vips"
1491
- puts " class Image"
1492
- puts ""
1557
+ puts "module Vips"
1558
+ puts " class Image"
1559
+ puts ""
1493
1560
 
1494
- generate_class.(GObject::g_type_from_name("VipsOperation"), nil)
1561
+ generate_class.(GObject::g_type_from_name("VipsOperation"), nil)
1495
1562
 
1496
- puts " end"
1497
- puts "end"
1563
+ puts " end"
1564
+ puts "end"
1565
+ end
1498
1566
  end
1499
1567
  end