ruby-vips 1.0.6 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,362 +1,127 @@
1
- # This module provides a set of overrides for the [vips image processing
2
- # library](https://jcupitt.github.io/libvips/)
3
- # used via the [gobject-introspection
4
- # gem](https://rubygems.org/gems/gobject-introspection).
1
+ # This module provides an interface to the vips image processing library
2
+ # via ruby-ffi.
5
3
  #
6
- # It needs vips-8.2 or later to be installed,
7
- # and `Vips-8.0.typelib`, the vips typelib, needs to be on your
8
- # `GI_TYPELIB_PATH`.
9
- #
10
- # # Example
11
- #
12
- # ```ruby
13
- # require 'vips'
14
- #
15
- # if ARGV.length < 2
16
- # raise "usage: #{$PROGRAM_NAME}: input-file output-file"
17
- # end
18
- #
19
- # im = Vips::Image.new_from_file ARGV[0], :access => :sequential
20
- #
21
- # im *= [1, 2, 1]
22
- #
23
- # mask = Vips::Image.new_from_array [
24
- # [-1, -1, -1],
25
- # [-1, 16, -1],
26
- # [-1, -1, -1]], 8
27
- # im = im.conv mask
28
- #
29
- # im.write_to_file ARGV[1]
30
- # ```
31
- #
32
- # This example loads a file, boosts the green channel (I'm not sure why),
33
- # sharpens the image, and saves it back to disc again.
34
- #
35
- # Reading this example line by line, we have:
36
- #
37
- # ```ruby
38
- # im = Vips::Image.new_from_file ARGV[0], :access => :sequential
39
- # ```
40
- #
41
- # {Image.new_from_file} can load any image file supported by vips. In this
42
- # example, we will be accessing pixels top-to-bottom as we sweep through the
43
- # image reading and writing, so `:sequential` access mode is best for us. The
44
- # default mode is `:random`, this allows for full random access to image pixels,
45
- # but is slower and needs more memory. See {Access}
46
- # for full details
47
- # on the various modes available. You can also load formatted images from
48
- # memory buffers, create images that wrap C-style memory arrays, or make images
49
- # from constants.
50
- #
51
- # The next line:
52
- #
53
- # ```ruby
54
- # im *= [1, 2, 1]
55
- # ```
56
- #
57
- # Multiplying the image by an array constant uses one array element for each
58
- # image band. This line assumes that the input image has three bands and will
59
- # double the middle band. For RGB images, that's doubling green.
60
- #
61
- # Next we have:
62
- #
63
- # ```ruby
64
- # mask = Vips::Image.new_from_array [
65
- # [-1, -1, -1],
66
- # [-1, 16, -1],
67
- # [-1, -1, -1]], 8
68
- # im = im.conv mask
69
- # ```
70
- #
71
- # {Image.new_from_array} creates an image from an array constant. The 8 at
72
- # the end sets the scale: the amount to divide the image by after
73
- # integer convolution. See the libvips API docs for `vips_conv()` (the operation
74
- # invoked by {Image#conv}) for details on the convolution operator.
75
- #
76
- # Finally:
77
- #
78
- # ```ruby
79
- # im.write_to_file ARGV[1]
80
- # ```
81
- #
82
- # {Image#write_to_file} writes an image back to the filesystem. It can
83
- # write any format supported by vips: the file type is set from the filename
84
- # suffix. You can also write formatted images to memory buffers, or dump
85
- # image data to a raw memory array.
86
- #
87
- # # How it works
88
- #
89
- # The C sources to libvips include a set of specially formatted
90
- # comments which describe its interfaces. When you compile the library,
91
- # gobject-introspection generates `Vips-8.0.typelib`, a file
92
- # describing how to use libvips.
93
- #
94
- # The `gobject-introspection` gem loads this typelib and uses it to let you
95
- # call
96
- # functions in libvips directly from Ruby. However, the interface you get
97
- # from raw gobject-introspection is rather ugly, so the `ruby-vips` gem
98
- # adds a set
99
- # of overrides which try to make it nicer to use.
100
- #
101
- # The API you end up with is a Ruby-ish version of the [VIPS C
102
- # API](https://jcupitt.github.io/libvips/API/current).
103
- # Full documentation
104
- # on the operations and what they do is there, you can use it directly. This
105
- # document explains the extra features of the Ruby API and lists the available
106
- # operations very briefly.
107
- #
108
- # # Automatic wrapping
109
- #
110
- # `ruby-vips` adds a {Image.method_missing} handler to {Image} and uses
111
- # it to look up vips operations. For example, the libvips operation `add`, which
112
- # appears in C as `vips_add()`, appears in Ruby as {Image#add}.
113
- #
114
- # The operation's list of required arguments is searched and the first input
115
- # image is set to the value of `self`. Operations which do not take an input
116
- # image, such as {Image.black}, appear as class methods. The remainder of
117
- # the arguments you supply in the function call are used to set the other
118
- # required input arguments. If the final supplied argument is a hash, it is used
119
- # to set any optional input arguments. The result is the required output
120
- # argument if there is only one result, or an array of values if the operation
121
- # produces several results. If the operation has optional output objects, they
122
- # are returned as a final hash.
123
- #
124
- # For example, {Image#min}, the vips operation that searches an image for
125
- # the minimum value, has a large number of optional arguments. You can use it to
126
- # find the minimum value like this:
127
- #
128
- # ```ruby
129
- # min_value = image.min
130
- # ```
131
- #
132
- # You can ask it to return the position of the minimum with `:x` and `:y`.
133
- #
134
- # ```ruby
135
- # min_value, opts = min :x => true, :y => true
136
- # x_pos = opts['x']
137
- # y_pos = opts['y']
138
- # ```
139
- #
140
- # Now `x_pos` and `y_pos` will have the coordinates of the minimum value.
141
- # There's actually a convenience function for this, {Image#minpos}.
142
- #
143
- # You can also ask for the top *n* minimum, for example:
144
- #
145
- # ```ruby
146
- # min_value, opts = min :size => 10, :x_array => true, :y_array => true
147
- # x_pos = opts['x_array']
148
- # y_pos = opts['y_array']
149
- # ```
150
- #
151
- # Now `x_pos` and `y_pos` will be 10-element arrays.
152
- #
153
- # Because operations are member functions and return the result image, you can
154
- # chain them. For example, you can write:
155
- #
156
- # ```ruby
157
- # result_image = image.real.cos
158
- # ```
159
- #
160
- # to calculate the cosine of the real part of a complex image.
161
- # There are also a full set
162
- # of arithmetic operator overloads, see below.
163
- #
164
- # libvips types are also automatically wrapped. The override looks at the type
165
- # of argument required by the operation and converts the value you supply,
166
- # when it can. For example, {Image#linear} takes a `VipsArrayDouble` as
167
- # an argument
168
- # for the set of constants to use for multiplication. You can supply this
169
- # value as an integer, a float, or some kind of compound object and it
170
- # will be converted for you. You can write:
171
- #
172
- # ```ruby
173
- # result_image = image.linear 1, 3
174
- # result_image = image.linear 12.4, 13.9
175
- # result_image = image.linear [1, 2, 3], [4, 5, 6]
176
- # result_image = image.linear 1, [4, 5, 6]
177
- # ```
178
- #
179
- # And so on. A set of overloads are defined for {Image#linear}, see below.
180
- #
181
- # It does a couple of more ambitious conversions. It will automatically convert
182
- # to and from the various vips types, like `VipsBlob` and `VipsArrayImage`. For
183
- # example, you can read the ICC profile out of an image like this:
184
- #
185
- # ```ruby
186
- # profile = im.get_value "icc-profile-data"
187
- # ```
188
- #
189
- # and profile will be a byte array.
190
- #
191
- # If an operation takes several input images, you can use a constant for all but
192
- # one of them and the wrapper will expand the constant to an image for you. For
193
- # example, {Image#ifthenelse} uses a condition image to pick pixels
194
- # between a then and an else image:
195
- #
196
- # ```ruby
197
- # result_image = condition_image.ifthenelse then_image, else_image
198
- # ```
199
- #
200
- # You can use a constant instead of either the then or the else parts and it
201
- # will be expanded to an image for you. If you use a constant for both then and
202
- # else, it will be expanded to match the condition image. For example:
203
- #
204
- # ```ruby
205
- # result_image = condition_image.ifthenelse [0, 255, 0], [255, 0, 0]
206
- # ```
207
- #
208
- # Will make an image where true pixels are green and false pixels are red.
209
- #
210
- # This is useful for {Image#bandjoin}, the thing to join two or more
211
- # images up bandwise. You can write:
212
- #
213
- # ```ruby
214
- # rgba = rgb.bandjoin 255
215
- # ```
216
- #
217
- # to append a constant 255 band to an image, perhaps to add an alpha channel. Of
218
- # course you can also write:
219
- #
220
- # ```ruby
221
- # result_image = image1.bandjoin image2
222
- # result_image = image1.bandjoin [image2, image3]
223
- # result_image = Vips::Image.bandjoin [image1, image2, image3]
224
- # result_image = image1.bandjoin [image2, 255]
225
- # ```
226
- #
227
- # and so on.
228
- #
229
- # # Automatic YARD documentation
230
- #
231
- # The bulk of these API docs are generated automatically by
232
- # {Vips::generate_yard}. It examines
233
- # libvips and writes a summary of each operation and the arguments and options
234
- # that that operation expects.
235
- #
236
- # Use the [C API
237
- # docs](https://jcupitt.github.io/libvips/API/current)
238
- # for more detail.
239
- #
240
- # # Exceptions
241
- #
242
- # The wrapper spots errors from vips operations and raises the {Vips::Error}
243
- # exception. You can catch it in the usual way.
244
- #
245
- # # Enums
246
- #
247
- # The libvips enums, such as `VipsBandFormat` appear in ruby-vips as classes
248
- # like {Vips::BandFormat}. Overloads let you manipulate them in the obvious
249
- # way. For example:
250
- #
251
- # ```ruby
252
- # irb(main):002:0> im = Vips::Image.new_from_file "IMG_1867.JPG"
253
- # => #<Vips::Image:0x13e9760 ptr=0x1a88010>
254
- # irb(main):003:0> im.format
255
- # => #<Vips::BandFormat uchar>
256
- # irb(main):004:0> im.format == :uchar
257
- # => true
258
- # irb(main):005:0> im.format == "uchar"
259
- # => true
260
- # irb(main):007:0> im.format == 0
261
- # => true
262
- # ```
263
- #
264
- # The `0` is the C value of the enum.
265
- #
266
- # # Draw operations
267
- #
268
- # Paint operations like {Image#draw_circle} and {Image#draw_line}
269
- # modify their input image. This
270
- # makes them hard to use with the rest of libvips: you need to be very careful
271
- # about the order in which operations execute or you can get nasty crashes.
272
- #
273
- # The wrapper spots operations of this type and makes a private copy of the
274
- # image in memory before calling the operation. This stops crashes, but it does
275
- # make it inefficient. If you draw 100 lines on an image, for example, you'll
276
- # copy the image 100 times. The wrapper does make sure that memory is recycled
277
- # where possible, so you won't have 100 copies in memory.
278
- #
279
- # If you want to avoid the copies, you'll need to call drawing operations
280
- # yourself.
281
- #
282
- # # Overloads
283
- #
284
- # The wrapper defines the usual set of arithmetic, boolean and relational
285
- # overloads on image. You can mix images, constants and lists of constants
286
- # (almost) freely. For example, you can write:
287
- #
288
- # ```ruby
289
- # result_image = ((image * [1, 2, 3]).abs < 128) | 4
290
- # ```
291
- #
292
- # # Expansions
293
- #
294
- # Some vips operators take an enum to select an action, for example
295
- # {Image#math} can be used to calculate sine of every pixel like this:
296
- #
297
- # ```ruby
298
- # result_image = image.math :sin
299
- # ```
300
- #
301
- # This is annoying, so the wrapper expands all these enums into separate members
302
- # named after the enum. So you can write:
303
- #
304
- # ```ruby
305
- # result_image = image.sin
306
- # ```
307
- #
308
- # # Convenience functions
309
- #
310
- # The wrapper defines a few extra useful utility functions:
311
- # {Image#get_value}, {Image#set_value}, {Image#bandsplit},
312
- # {Image#maxpos}, {Image#minpos},
313
- # {Image#median}.
4
+ # Author:: John Cupitt (mailto:jcupitt@gmail.com)
5
+ # License:: MIT
6
+
7
+ require 'ffi'
314
8
 
315
9
  module Vips
10
+ private
11
+
12
+ attach_function :vips_image_new_matrix_from_array,
13
+ [:int, :int, :pointer, :int], :pointer
14
+
15
+ attach_function :vips_image_copy_memory, [:pointer], :pointer
16
+
17
+ attach_function :vips_filename_get_filename, [:string], :string
18
+ attach_function :vips_filename_get_options, [:string], :string
19
+ attach_function :vips_filename_get_options, [:string], :string
20
+
21
+ attach_function :vips_foreign_find_load, [:string], :string
22
+ attach_function :vips_foreign_find_save, [:string], :string
23
+ attach_function :vips_foreign_find_load_buffer, [:pointer, :size_t], :string
24
+ attach_function :vips_foreign_find_save_buffer, [:string], :string
25
+
26
+ attach_function :vips_image_write_to_memory,
27
+ [:pointer, SizeStruct.ptr], :pointer
28
+
29
+ attach_function :vips_image_get_typeof, [:pointer, :string], :GType
30
+ attach_function :vips_image_get,
31
+ [:pointer, :string, GObject::GValue.ptr], :int
32
+ attach_function :vips_image_set,
33
+ [:pointer, :string, GObject::GValue.ptr], :void
34
+ attach_function :vips_image_remove, [:pointer, :string], :void
35
+
36
+ attach_function :vips_band_format_iscomplex, [:int], :int
37
+ attach_function :vips_band_format_isfloat, [:int], :int
38
+
39
+ attach_function :nickname_find, :vips_nickname_find, [:GType], :string
40
+
41
+ public
316
42
 
317
43
  # This class represents a libvips image. See the {Vips} module documentation
318
- # for an introduction to using this module.
44
+ # for an introduction to using this class.
319
45
 
320
- class Image
46
+ class Image < Vips::Object
321
47
  private
322
48
 
49
+ # the layout of the VipsImage struct
50
+ module ImageLayout
51
+ def self.included base
52
+ base.class_eval do
53
+ layout :parent, Vips::Object::Struct
54
+ # rest opaque
55
+ end
56
+ end
57
+ end
58
+
59
+ class Struct < Vips::Object::Struct
60
+ include ImageLayout
61
+
62
+ end
63
+
64
+ class ManagedStruct < Vips::Object::ManagedStruct
65
+ include ImageLayout
66
+
67
+ end
68
+
323
69
  # handy for overloads ... want to be able to apply a function to an
324
70
  # array or to a scalar
325
- def self.smap(x, &block)
71
+ def self.smap x, &block
326
72
  x.is_a?(Array) ? x.map {|y| smap(y, &block)} : block.(x)
327
73
  end
328
74
 
75
+ def self.complex? format
76
+ format_number = Vips::vips_enum_from_nick "complex?",
77
+ BAND_FORMAT_TYPE, format.to_s
78
+ Vips::vips_band_format_iscomplex(format_number) != 0
79
+ end
80
+
81
+ def self.float? format
82
+ format_number = Vips::vips_enum_from_nick "float?",
83
+ BAND_FORMAT_TYPE, format.to_s
84
+ Vips::vips_band_format_isfloat(format_number) != 0
85
+ end
86
+
329
87
  # run a complex operation on a complex image, or an image with an even
330
88
  # number of bands ... handy for things like running .polar on .index
331
89
  # images
332
- def self.run_cmplx(image, &block)
90
+ def self.run_cmplx image, &block
333
91
  original_format = image.format
334
92
 
335
- if not Vips::band_format_iscomplex image.format
93
+ if not Image::complex? image.format
336
94
  if image.bands % 2 != 0
337
95
  raise Error, "not an even number of bands"
338
96
  end
339
97
 
340
- if not Vips::band_format_isfloat image.format
98
+ if not Image::float? image.format
341
99
  image = image.cast :float
342
100
  end
343
101
 
344
102
  new_format = image.format == :double ? :dpcomplex : :complex
345
- image = image.copy :format => new_format,
346
- :bands => image.bands / 2
103
+ image = image.copy format: new_format, bands: image.bands / 2
347
104
  end
348
105
 
349
106
  image = block.(image)
350
107
 
351
- if not Vips::band_format_iscomplex original_format
108
+ if not Image::complex? original_format
352
109
  new_format = image.format == :dpcomplex ? :double : :float
353
- image = image.copy :format => new_format,
354
- :bands => image.bands * 2
110
+ image = image.copy format: new_format, bands: image.bands * 2
355
111
  end
356
112
 
357
113
  image
358
114
  end
359
115
 
116
+ # handy for expanding enum operations
117
+ def call_enum(name, other, enum)
118
+ if other.is_a?(Vips::Image)
119
+ Vips::Operation.call name.to_s, [self, other, enum]
120
+ else
121
+ Vips::Operation.call name.to_s + "_const", [self, enum, other]
122
+ end
123
+ end
124
+
360
125
  # Write can fail due to no file descriptors and memory can fill if
361
126
  # large objects are not collected fairly soon. We can't try a
362
127
  # write and GC and retry on fail, since the write may take a
@@ -385,38 +150,45 @@ module Vips
385
150
  end
386
151
  end
387
152
 
388
- # libvips 8.4 and earlier had a bug which swapped the args to the _const
389
- # enum operations
390
- def swap_const_args
391
- Vips::version(0) < 8 or
392
- (Vips::version(0) == 8 and Vips::version(1) <= 4)
153
+ public
154
+
155
+ def inspect
156
+ "#<Image #{width}x#{height} #{format}, #{bands} bands, " +
157
+ "#{interpretation}>"
393
158
  end
394
159
 
395
- # handy for expanding enum operations
396
- def call_enum(name, other, enum)
397
- if other.is_a?(Vips::Image)
398
- Vips::call_base name.to_s, self, "", [other, enum]
399
- else
400
- args = swap_const_args ? [other, enum] : [enum, other]
160
+ def respond_to? name, include_all = false
161
+ # To support keyword args, we need to tell Ruby that final image
162
+ # arguments cannot be hashes of keywords.
163
+ #
164
+ # https://makandracards.com/makandra/36013-heads-up-ruby-implicitly-converts-a-hash-to-keyword-arguments
165
+ return false if name == :to_hash
401
166
 
402
- Vips::call_base name.to_s + "_const", self, "", args
403
- end
167
+ # respond to all vips operations by nickname
168
+ return true if Vips::type_find("VipsOperation", name.to_s) != 0
169
+
170
+ super
404
171
  end
405
172
 
406
- public
173
+ def self.respond_to? name, include_all = false
174
+ # respond to all vips operations by nickname
175
+ return true if Vips::type_find("VipsOperation", name.to_s) != 0
407
176
 
408
- # Invoke a vips operation with {call}, using self as the first
409
- # input image argument.
177
+ super
178
+ end
179
+
180
+ # Invoke a vips operation with {Vips::Operation.call}, using self as
181
+ # the first input argument.
410
182
  #
411
183
  # @param name [String] vips operation to call
412
184
  # @return result of vips operation
413
- def method_missing(name, *args)
414
- Vips::call_base name.to_s, self, "", args
185
+ def method_missing name, *args, **options
186
+ Vips::Operation.call name.to_s, [self, *args], options
415
187
  end
416
188
 
417
- # Invoke a vips operation with {call}.
418
- def self.method_missing(name, *args)
419
- Vips::call_base name.to_s, nil, "", args
189
+ # Invoke a vips operation with {Vips::Operation.call}.
190
+ def self.method_missing name, *args, **options
191
+ Vips::Operation.call name.to_s, args, options
420
192
  end
421
193
 
422
194
  # Return a new {Image} for a file on disc. This method can load
@@ -430,7 +202,7 @@ module Vips
430
202
  # You can also supply options as a hash, for example:
431
203
  #
432
204
  # ```
433
- # image = Vips::new_from_file "fred.jpg", :shrink => 2
205
+ # image = Vips::new_from_file "fred.jpg", shrink: 2
434
206
  # ```
435
207
  #
436
208
  # The full set of options available depend upon the load operation that
@@ -447,7 +219,7 @@ module Vips
447
219
  # out the header. Pixels will only be decompressed when they are needed.
448
220
  #
449
221
  # @!macro [new] vips.loadopts
450
- # @param [Hash] opts set of options
222
+ # @param opts [Hash] set of options
451
223
  # @option opts [Boolean] :disc (true) Open large images via a
452
224
  # temporary disc file
453
225
  # @option opts [Vips::Access] :access (:random) Access mode for file
@@ -455,25 +227,22 @@ module Vips
455
227
  # @param name [String] the filename to load from
456
228
  # @macro vips.loadopts
457
229
  # @return [Image] the loaded image
458
- def self.new_from_file(name, opts = {})
459
- # very common, and Vips::filename_get_filename will segv if we pass
460
- # this
461
- if name == nil
462
- raise Error, "filename is nil"
463
- end
464
- filename = Vips::filename_get_filename name
465
- option_string = Vips::filename_get_options name
466
- loader = Vips::Foreign.find_load filename
467
- if loader == nil
468
- raise Vips::Error
469
- end
230
+ def self.new_from_file name, opts = {}
231
+ # very common, and Vips::vips_filename_get_filename will segv if we
232
+ # pass this
233
+ raise Vips::Error, "filename is nil" if name == nil
470
234
 
471
- Vips::call_base loader, nil, option_string, [filename, opts]
235
+ filename = Vips::vips_filename_get_filename name
236
+ option_string = Vips::vips_filename_get_options name
237
+ loader = Vips::vips_foreign_find_load filename
238
+ raise Vips::Error if loader == nil
239
+
240
+ Operation.call loader, [filename], opts, option_string
472
241
  end
473
242
 
474
243
  # Create a new {Image} for an image encoded, in a format such as
475
244
  # JPEG, in a memory string. Load options may be passed as
476
- # strings, or appended as a hash. For example:
245
+ # strings or appended as a hash. For example:
477
246
  #
478
247
  # ```
479
248
  # image = Vips::new_from_from_buffer memory_buffer, "shrink=2"
@@ -482,7 +251,7 @@ module Vips
482
251
  # or alternatively:
483
252
  #
484
253
  # ```
485
- # image = Vips::new_from_from_buffer memory_buffer, "", :shrink => 2
254
+ # image = Vips::new_from_from_buffer memory_buffer, "", shrink: 2
486
255
  # ```
487
256
  #
488
257
  # The options available depend on the file format. Try something like:
@@ -502,13 +271,19 @@ module Vips
502
271
  # @param option_string [String] load options as a string
503
272
  # @macro vips.loadopts
504
273
  # @return [Image] the loaded image
505
- def self.new_from_buffer(data, option_string, opts = {})
506
- loader = Vips::Foreign.find_load_buffer data
507
- if loader == nil
508
- raise Vips::Error
509
- end
274
+ def self.new_from_buffer data, option_string, opts = {}
275
+ loader = Vips::vips_foreign_find_load_buffer data, data.length
276
+ raise Vips::Error if loader == nil
277
+
278
+ Vips::Operation.call loader, [data], opts, option_string
279
+ end
510
280
 
511
- Vips::call_base loader, nil, option_string, [data, opts]
281
+ def self.matrix_from_array width, height, array
282
+ ptr = FFI::MemoryPointer.new :double, array.length
283
+ ptr.write_array_of_double array
284
+ image = Vips::vips_image_new_matrix_from_array width, height,
285
+ ptr, array.length
286
+ Vips::Image.new image
512
287
  end
513
288
 
514
289
  # Create a new Image from a 1D or 2D array. A 1D array becomes an
@@ -537,7 +312,7 @@ module Vips
537
312
  # @param scale [Real] the convolution scale
538
313
  # @param offset [Real] the convolution offset
539
314
  # @return [Image] the image
540
- def self.new_from_array(array, scale = 1, offset = 0)
315
+ def self.new_from_array array, scale = 1, offset = 0
541
316
  # we accept a 1D array and assume height == 1, or a 2D array
542
317
  # and check all lines are the same length
543
318
  if not array.is_a? Array
@@ -564,13 +339,11 @@ module Vips
564
339
  end
565
340
 
566
341
  image = Vips::Image.matrix_from_array width, height, array
567
- if image == nil
568
- raise Vips::Error
569
- end
342
+ raise Vips::Error if image == nil
570
343
 
571
344
  # be careful to set them as double
572
- image.set_double 'scale', scale.to_f
573
- image.set_double 'offset', offset.to_f
345
+ image.set_type GObject::GDOUBLE_TYPE, 'scale', scale.to_f
346
+ image.set_type GObject::GDOUBLE_TYPE, 'offset', offset.to_f
574
347
 
575
348
  return image
576
349
  end
@@ -582,14 +355,13 @@ module Vips
582
355
  # You can pass an array to make a many-band image, or a single value to
583
356
  # make a one-band image.
584
357
  #
585
- # @param pixel [Real, Array<Real>] value to put in each pixel
358
+ # @param value [Real, Array<Real>] value to put in each pixel
586
359
  # @return [Image] constant image
587
- def new_from_image(value)
360
+ def new_from_image value
588
361
  pixel = (Vips::Image.black(1, 1) + value).cast(format)
589
- image = pixel.embed(0, 0, width, height, :extend => :copy)
590
- image.copy :interpretation => interpretation,
591
- :xres => xres, :yres => yres,
592
- :xoffset => xoffset, :yoffset => yoffset
362
+ image = pixel.embed 0, 0, width, height, extend: :copy
363
+ image.copy interpretation: interpretation,
364
+ xres: xres, yres: yres, xoffset: xoffset, yoffset: yoffset
593
365
  end
594
366
 
595
367
  # Write this image to a file. Save options may be encoded in the
@@ -602,7 +374,7 @@ module Vips
602
374
  # or equivalently:
603
375
  #
604
376
  # ```
605
- # image.write_to_file "fred.jpg", :Q => 90
377
+ # image.write_to_file "fred.jpg", Q: 90
606
378
  # ```
607
379
  #
608
380
  # The full set of save options depend on the selected saver. Try
@@ -615,21 +387,21 @@ module Vips
615
387
  # to see all the available options for JPEG save.
616
388
  #
617
389
  # @!macro [new] vips.saveopts
618
- # @param [Hash] opts set of options
390
+ # @param opts [Hash] set of options
619
391
  # @option opts [Boolean] :strip (false) Strip all metadata from image
620
392
  # @option opts [Array<Float>] :background (0) Background colour to
621
393
  # flatten alpha against, if necessary
622
394
  #
623
395
  # @param name [String] filename to write to
624
- def write_to_file(name, opts = {})
625
- filename = Vips::filename_get_filename name
626
- option_string = Vips::filename_get_options name
627
- saver = Vips::Foreign.find_save filename
396
+ def write_to_file name, opts = {}
397
+ filename = Vips::vips_filename_get_filename name
398
+ option_string = Vips::vips_filename_get_options name
399
+ saver = Vips::vips_foreign_find_save filename
628
400
  if saver == nil
629
401
  raise Vips::Error, "No known saver for '#{filename}'."
630
402
  end
631
403
 
632
- Vips::call_base saver, self, option_string, [filename, opts]
404
+ Vips::Operation.call saver, [self, filename], opts, option_string
633
405
 
634
406
  write_gc
635
407
  end
@@ -644,7 +416,7 @@ module Vips
644
416
  # or equivalently:
645
417
  #
646
418
  # ```
647
- # image.write_to_buffer ".jpg", :Q => 90
419
+ # image.write_to_buffer ".jpg", Q: 90
648
420
  # ```
649
421
  #
650
422
  # The full set of save options depend on the selected saver. Try
@@ -659,63 +431,43 @@ module Vips
659
431
  # @param format_string [String] save format plus options
660
432
  # @macro vips.saveopts
661
433
  # @return [String] the image saved in the specified format
662
- def write_to_buffer(format_string, opts = {})
663
- filename = Vips::filename_get_filename format_string
664
- option_string = Vips::filename_get_options format_string
665
- saver = Vips::Foreign.find_save_buffer filename
434
+ def write_to_buffer format_string, opts = {}
435
+ filename = Vips::vips_filename_get_filename format_string
436
+ option_string = Vips::vips_filename_get_options format_string
437
+ saver = Vips::vips_foreign_find_save_buffer filename
666
438
  if saver == nil
667
439
  raise Vips::Error, "No known saver for '#{filename}'."
668
440
  end
669
441
 
670
- buffer = Vips::call_base saver, self, option_string, [opts]
442
+ buffer = Vips::Operation.call saver, [self], opts, option_string
443
+ raise Vips::Error if buffer == nil
671
444
 
672
445
  write_gc
673
446
 
674
447
  return buffer
675
448
  end
676
449
 
677
- # @!attribute [r] width
678
- # @return [Integer] image width, in pixels
679
- # @!attribute [r] height
680
- # @return [Integer] image height, in pixels
681
- # @!attribute [r] bands
682
- # @return [Integer] image bands
683
- # @!attribute [r] format
684
- # @return [Vips::BandFormat] image format
685
- # @!attribute [r] interpretation
686
- # @return [Vips::Interpretation] image interpretation
687
- # @!attribute [r] coding
688
- # @return [Vips::Coding] image coding
689
- # @!attribute [r] filename
690
- # @return [String] image filename
691
- # @!attribute [r] xres
692
- # @return [Float] horizontal image resolution, in pixels per mm
693
- # @!attribute [r] yres
694
- # @return [Float] vertical image resolution, in pixels per mm
450
+ # Write this image to a large memory buffer.
451
+ #
452
+ # @return [String] the pixels as a huge binary string
453
+ def write_to_memory
454
+ len = Vips::SizeStruct.new
455
+ ptr = Vips::vips_image_write_to_memory self, len
456
+
457
+ # wrap up as an autopointer
458
+ ptr = FFI::AutoPointer.new(ptr, GLib::G_FREE)
459
+
460
+ ptr.get_bytes 0, len[:value]
461
+ end
695
462
 
696
463
  # Fetch a `GType` from an image. `GType` will be 0 for no such field.
697
464
  #
698
465
  # @see get
699
- # @see get_value
700
- # @!method get_typeof(name)
701
466
  # @param name [String] Metadata field to fetch
702
467
  # @return [Integer] GType
703
-
704
- # Fetch a `GValue` from an image. The return status is 0 for success, -1
705
- # for failure.
706
- #
707
- # @see get_value
708
- # @see get_typeof
709
- # @!method get(name)
710
- # @param name [String] Metadata field to fetch
711
- # @return [Integer, GValue] Return status, GValue from image
712
-
713
- # Set a `GValue` on an image
714
- #
715
- # @see set_value
716
- # @!method set(name, value)
717
- # @param name [String] Metadata field to set
718
- # @param value [GValue] GValue to set
468
+ def get_typeof name
469
+ Vips::vips_image_get_typeof self, name
470
+ end
719
471
 
720
472
  # Get a metadata item from an image. Ruby types are constructed
721
473
  # automatically from the `GValue`, if possible.
@@ -723,63 +475,177 @@ module Vips
723
475
  # For example, you can read the ICC profile from an image like this:
724
476
  #
725
477
  # ```
726
- # profile = image.get_value "icc-profile-data"
478
+ # profile = image.get "icc-profile-data"
727
479
  # ```
728
480
  #
729
481
  # and profile will be an array containing the profile.
730
482
  #
731
- # @see get
732
- # @param name [String] Metadata field to set
483
+ # @param name [String] Metadata field to get
733
484
  # @return [Object] Value of field
734
- def get_value(name)
735
- ret, gval = get name
736
- if ret != 0
737
- raise Vips::Error, "Field #{name} not found."
485
+ def get name
486
+ gvalue = GObject::GValue.alloc
487
+ result = Vips::vips_image_get self, name, gvalue
488
+ if result != 0
489
+ raise Vips::Error
738
490
  end
739
- value = gval.value
740
491
 
741
- Argument::unwrap(value)
492
+ return gvalue.get
742
493
  end
743
494
 
744
- # Set a metadata item on an image. Ruby types are automatically
745
- # transformed into the matching `GValue`, if possible.
495
+ # Create a metadata item on an image, of the specifed type. Ruby types
496
+ # are automatically
497
+ # transformed into the matching `GType`, if possible.
746
498
  #
747
499
  # For example, you can use this to set an image's ICC profile:
748
500
  #
749
501
  # ```
750
- # x = y.set_value "icc-profile-data", profile
502
+ # x = y.set Vips::BLOB_TYPE, "icc-profile-data", profile
751
503
  # ```
752
504
  #
753
505
  # where `profile` is an ICC profile held as a binary string object.
754
506
  #
755
507
  # @see set
508
+ # @param gtype [Integer] GType of item
756
509
  # @param name [String] Metadata field to set
757
510
  # @param value [Object] Value to set
758
- def set_value(name, value)
759
- gtype = get_typeof name
760
- if gtype != 0
761
- # array-ize
762
- value = Argument::arrayize gtype, value
763
-
764
- # blob-ize
765
- if gtype.type_is_a? GLib::Type["VipsBlob"]
766
- if not value.is_a? Vips::Blob
767
- value = Vips::Blob.copy value
768
- end
769
- end
511
+ def set_type gtype, name, value
512
+ gvalue = GObject::GValue.alloc
513
+ gvalue.init gtype
514
+ gvalue.set value
515
+ Vips::vips_image_set self, name, gvalue
516
+ end
770
517
 
771
- # image-ize
772
- if gtype.type_is_a? GLib::Type["VipsImage"]
773
- if not value.is_a? Vips::Image
774
- value = imageize match_image, value
775
- end
776
- end
518
+ # Set the value of a metadata item on an image. The metadata item must
519
+ # already exist. Ruby types are automatically
520
+ # transformed into the matching `GValue`, if possible.
521
+ #
522
+ # For example, you can use this to set an image's ICC profile:
523
+ #
524
+ # ```
525
+ # x = y.set "icc-profile-data", profile
526
+ # ```
527
+ #
528
+ # where `profile` is an ICC profile held as a binary string object.
529
+ #
530
+ # @see set_type
531
+ # @param name [String] Metadata field to set
532
+ # @param value [Object] Value to set
533
+ def set name, value
534
+ set_type get_typeof(name), name, value
535
+ end
777
536
 
778
- end
537
+ # Remove a metadata item from an image.
538
+ #
539
+ # @param name [String] Metadata field to remove
540
+ def remove name
541
+ Vips::vips_image_remove self, name
542
+ end
779
543
 
544
+ # compatibility: old name for get
545
+ def get_value name
546
+ get name
547
+ end
548
+
549
+ # compatibility: old name for set
550
+ def set_value name, value
780
551
  set name, value
781
552
  end
782
553
 
554
+ # Get image width, in pixels.
555
+ #
556
+ # @return [Integer] image width, in pixels
557
+ def width
558
+ get "width"
559
+ end
560
+
561
+ # Get image height, in pixels.
562
+ #
563
+ # @return [Integer] image height, in pixels
564
+ def height
565
+ get "height"
566
+ end
567
+
568
+ # Get number of image bands.
569
+ #
570
+ # @return [Integer] number of image bands
571
+ def bands
572
+ get "bands"
573
+ end
574
+
575
+ # Get image format.
576
+ #
577
+ # @return [Symbol] image format
578
+ def format
579
+ get "format"
580
+ end
581
+
582
+ # Get image interpretation.
583
+ #
584
+ # @return [Symbol] image interpretation
585
+ def interpretation
586
+ get "interpretation"
587
+ end
588
+
589
+ # Get image coding.
590
+ #
591
+ # @return [Symbol] image coding
592
+ def coding
593
+ get "coding"
594
+ end
595
+
596
+ # Get image filename, if any.
597
+ #
598
+ # @return [String] image filename
599
+ def filename
600
+ get "filename"
601
+ end
602
+
603
+ # Get image xoffset.
604
+ #
605
+ # @return [Integer] image xoffset
606
+ def xoffset
607
+ get "xoffset"
608
+ end
609
+
610
+ # Get image yoffset.
611
+ #
612
+ # @return [Integer] image yoffset
613
+ def yoffset
614
+ get "yoffset"
615
+ end
616
+
617
+ # Get image x resolution.
618
+ #
619
+ # @return [Float] image x resolution
620
+ def xres
621
+ get "xres"
622
+ end
623
+
624
+ # Get image y resolution.
625
+ #
626
+ # @return [Float] image y resolution
627
+ def yres
628
+ get "yres"
629
+ end
630
+
631
+ # Get scale metadata.
632
+ #
633
+ # @return [Float] image scale
634
+ def scale
635
+ return 1 if get_typeof("scale") == 0
636
+
637
+ get "scale"
638
+ end
639
+
640
+ # Get offset metadata.
641
+ #
642
+ # @return [Float] image offset
643
+ def offset
644
+ return 0 if get_typeof("offset") == 0
645
+
646
+ get "offset"
647
+ end
648
+
783
649
  # Get the image size.
784
650
  #
785
651
  # @return [Integer, Integer] image width and height
@@ -787,11 +653,16 @@ module Vips
787
653
  [width, height]
788
654
  end
789
655
 
656
+ def copy_memory
657
+ new_image = Vips::vips_image_copy_memory self
658
+ Vips::Image.new new_image
659
+ end
660
+
790
661
  # Add an image, constant or array.
791
662
  #
792
663
  # @param other [Image, Real, Array<Real>] Thing to add to self
793
664
  # @return [Image] result of addition
794
- def +(other)
665
+ def + other
795
666
  other.is_a?(Vips::Image) ?
796
667
  add(other) : linear(1, other)
797
668
  end
@@ -800,7 +671,7 @@ module Vips
800
671
  #
801
672
  # @param other [Image, Real, Array<Real>] Thing to subtract from self
802
673
  # @return [Image] result of subtraction
803
- def -(other)
674
+ def - other
804
675
  other.is_a?(Vips::Image) ?
805
676
  subtract(other) : linear(1, Image::smap(other) {|x| x * -1})
806
677
  end
@@ -809,7 +680,7 @@ module Vips
809
680
  #
810
681
  # @param other [Image, Real, Array<Real>] Thing to multiply by self
811
682
  # @return [Image] result of multiplication
812
- def *(other)
683
+ def * other
813
684
  other.is_a?(Vips::Image) ?
814
685
  multiply(other) : linear(other, 0)
815
686
  end
@@ -818,7 +689,7 @@ module Vips
818
689
  #
819
690
  # @param other [Image, Real, Array<Real>] Thing to divide self by
820
691
  # @return [Image] result of division
821
- def /(other)
692
+ def / other
822
693
  other.is_a?(Vips::Image) ?
823
694
  divide(other) : linear(Image::smap(other) {|x| 1.0 / x}, 0)
824
695
  end
@@ -827,7 +698,7 @@ module Vips
827
698
  #
828
699
  # @param other [Image, Real, Array<Real>] self modulo this
829
700
  # @return [Image] result of modulo
830
- def %(other)
701
+ def % other
831
702
  other.is_a?(Vips::Image) ?
832
703
  remainder(other) : remainder_const(other)
833
704
  end
@@ -836,48 +707,48 @@ module Vips
836
707
  #
837
708
  # @param other [Image, Real, Array<Real>] self to the power of this
838
709
  # @return [Image] result of power
839
- def **(other)
840
- call_enum("math2", other, :pow)
710
+ def ** other
711
+ call_enum "math2", other, :pow
841
712
  end
842
713
 
843
714
  # Integer left shift with an image, constant or array.
844
715
  #
845
716
  # @param other [Image, Real, Array<Real>] shift left by this much
846
717
  # @return [Image] result of left shift
847
- def <<(other)
848
- call_enum("boolean", other, :lshift)
718
+ def << other
719
+ call_enum "boolean", other, :lshift
849
720
  end
850
721
 
851
722
  # Integer right shift with an image, constant or array.
852
723
  #
853
724
  # @param other [Image, Real, Array<Real>] shift right by this much
854
725
  # @return [Image] result of right shift
855
- def >>(other)
856
- call_enum("boolean", other, :rshift)
726
+ def >> other
727
+ call_enum "boolean", other, :rshift
857
728
  end
858
729
 
859
730
  # Integer bitwise OR with an image, constant or array.
860
731
  #
861
732
  # @param other [Image, Real, Array<Real>] bitwise OR with this
862
733
  # @return [Image] result of bitwise OR
863
- def |(other)
864
- call_enum("boolean", other, :or)
734
+ def | other
735
+ call_enum "boolean", other, :or
865
736
  end
866
737
 
867
738
  # Integer bitwise AND with an image, constant or array.
868
739
  #
869
740
  # @param other [Image, Real, Array<Real>] bitwise AND with this
870
741
  # @return [Image] result of bitwise AND
871
- def &(other)
872
- call_enum("boolean", other, :and)
742
+ def & other
743
+ call_enum "boolean", other, :and
873
744
  end
874
745
 
875
746
  # Integer bitwise EOR with an image, constant or array.
876
747
  #
877
748
  # @param other [Image, Real, Array<Real>] bitwise EOR with this
878
749
  # @return [Image] result of bitwise EOR
879
- def ^(other)
880
- call_enum("boolean", other, :eor)
750
+ def ^ other
751
+ call_enum "boolean", other, :eor
881
752
  end
882
753
 
883
754
  # Equivalent to image ^ -1
@@ -910,8 +781,8 @@ module Vips
910
781
  #
911
782
  # @param other [Image, Real, Array<Real>] relational less than with this
912
783
  # @return [Image] result of less than
913
- def <(other)
914
- call_enum("relational", other, :less)
784
+ def < other
785
+ call_enum "relational", other, :less
915
786
  end
916
787
 
917
788
  # Relational less than or equal to with an image, constant or array.
@@ -919,16 +790,16 @@ module Vips
919
790
  # @param other [Image, Real, Array<Real>] relational less than or
920
791
  # equal to with this
921
792
  # @return [Image] result of less than or equal to
922
- def <=(other)
923
- call_enum("relational", other, :lesseq)
793
+ def <= other
794
+ call_enum "relational", other, :lesseq
924
795
  end
925
796
 
926
797
  # Relational more than with an image, constant or array.
927
798
  #
928
799
  # @param other [Image, Real, Array<Real>] relational more than with this
929
800
  # @return [Image] result of more than
930
- def >(other)
931
- call_enum("relational", other, :more)
801
+ def > other
802
+ call_enum "relational", other, :more
932
803
  end
933
804
 
934
805
  # Relational more than or equal to with an image, constant or array.
@@ -936,20 +807,20 @@ module Vips
936
807
  # @param other [Image, Real, Array<Real>] relational more than or
937
808
  # equal to with this
938
809
  # @return [Image] result of more than or equal to
939
- def >=(other)
940
- call_enum("relational", other, :moreeq)
810
+ def >= other
811
+ call_enum "relational", other, :moreeq
941
812
  end
942
813
 
943
814
  # Compare equality to nil, an image, constant or array.
944
815
  #
945
816
  # @param other [nil, Image, Real, Array<Real>] test equality to this
946
817
  # @return [Image] result of equality
947
- def ==(other)
818
+ def == other
948
819
  # for equality, we must allow tests against nil
949
820
  if other == nil
950
821
  false
951
822
  else
952
- call_enum("relational", other, :equal)
823
+ call_enum "relational", other, :equal
953
824
  end
954
825
  end
955
826
 
@@ -957,12 +828,12 @@ module Vips
957
828
  #
958
829
  # @param other [nil, Image, Real, Array<Real>] test inequality to this
959
830
  # @return [Image] result of inequality
960
- def !=(other)
831
+ def != other
961
832
  # for equality, we must allow tests against nil
962
833
  if other == nil
963
834
  true
964
835
  else
965
- call_enum("relational", other, :noteq)
836
+ call_enum "relational", other, :noteq
966
837
  end
967
838
  end
968
839
 
@@ -970,11 +841,11 @@ module Vips
970
841
  #
971
842
  # @param index [Numeric, Range] extract these band(s)
972
843
  # @return [Image] extracted band(s)
973
- def [](index)
844
+ def [] index
974
845
  if index.is_a? Range
975
846
  n = index.end - index.begin
976
847
  n += 1 if not index.exclude_end?
977
- extract_band index.begin, :n => n
848
+ extract_band index.begin, n: n
978
849
  elsif index.is_a? Numeric
979
850
  extract_band index
980
851
  else
@@ -988,7 +859,7 @@ module Vips
988
859
  def to_a
989
860
  # we render the image to a big string, then unpack
990
861
  # as a Ruby array of the correct type
991
- memory = write_to_memory.pack('c*')
862
+ memory = write_to_memory
992
863
 
993
864
  # make the template for unpack
994
865
  template = {
@@ -1002,7 +873,7 @@ module Vips
1002
873
  :double => 'd',
1003
874
  :complex => 'f',
1004
875
  :dpcomplex => 'd'
1005
- }[format.nick.to_sym] + '*'
876
+ }[format] + '*'
1006
877
 
1007
878
  # and unpack into something like [1, 2, 3, 4 ..]
1008
879
  array = memory.unpack(template)
@@ -1071,7 +942,7 @@ module Vips
1071
942
  #
1072
943
  # @param other [Image, Array<Image>, Real, Array<Real>] bands to append
1073
944
  # @return [Image] many band image
1074
- def bandjoin(other)
945
+ def bandjoin other
1075
946
  if not other.is_a? Array
1076
947
  other = [other]
1077
948
  end
@@ -1091,7 +962,7 @@ module Vips
1091
962
  # @return [Real, Real, Real] maximum value, x coordinate of maximum, y
1092
963
  # coordinate of maximum
1093
964
  def maxpos
1094
- v, opts = max :x => true, :y => true
965
+ v, opts = max x: true, y: true
1095
966
  x = opts['x']
1096
967
  y = opts['y']
1097
968
  return v, x, y
@@ -1102,7 +973,7 @@ module Vips
1102
973
  # @return [Real, Real, Real] minimum value, x coordinate of minimum, y
1103
974
  # coordinate of minimum
1104
975
  def minpos
1105
- v, opts = min :x => true, :y => true
976
+ v, opts = min x: true, y: true
1106
977
  x = opts['x']
1107
978
  y = opts['y']
1108
979
  return v, x, y
@@ -1113,7 +984,7 @@ module Vips
1113
984
  # @param x [Integer] x coordinate to sample
1114
985
  # @param y [Integer] y coordinate to sample
1115
986
  # @return [Array<Float>] the pixel values as an array
1116
- def getpoint(x, y)
987
+ def getpoint x, y
1117
988
  # vips has an operation that does this, but we can't call it via
1118
989
  # gobject-introspection 3.1 since it's missing array double
1119
990
  # get
@@ -1126,8 +997,8 @@ module Vips
1126
997
  #
1127
998
  # @param size [Integer] size of filter window
1128
999
  # @return [Image] result of median filter
1129
- def median(size = 3)
1130
- rank(size, size, (size * size) / 2)
1000
+ def median size = 3
1001
+ rank size, size, (size * size) / 2
1131
1002
  end
1132
1003
 
1133
1004
  # Return the real part of a complex image.
@@ -1182,6 +1053,14 @@ module Vips
1182
1053
  Image::run_cmplx(self) {|x| x.complex :conj}
1183
1054
  end
1184
1055
 
1056
+ # Calculate the cross phase of two images.
1057
+ #
1058
+ # @param other [Image, Real, Array<Real>] cross phase with this
1059
+ # @return [Image] cross phase
1060
+ def cross_phase other
1061
+ complex2 other, :cross_phase
1062
+ end
1063
+
1185
1064
  # Return the sine of an image in degrees.
1186
1065
  #
1187
1066
  # @return [Image] sine of each pixel
@@ -1274,7 +1153,7 @@ module Vips
1274
1153
  # @param mask [Image, Array<Real>, Array<Array<Real>>] structuring
1275
1154
  # element
1276
1155
  # @return [Image] eroded image
1277
- def erode(mask)
1156
+ def erode mask
1278
1157
  morph mask, :erode
1279
1158
  end
1280
1159
 
@@ -1286,7 +1165,7 @@ module Vips
1286
1165
  # @param mask [Image, Array<Real>, Array<Array<Real>>] structuring
1287
1166
  # element
1288
1167
  # @return [Image] dilated image
1289
- def dilate(mask)
1168
+ def dilate mask
1290
1169
  morph mask, :dilate
1291
1170
  end
1292
1171
 
@@ -1317,28 +1196,28 @@ module Vips
1317
1196
  #
1318
1197
  # @param th [Image, Real, Array<Real>] true values
1319
1198
  # @param el [Image, Real, Array<Real>] false values
1320
- # @param [Hash] opts set of options
1199
+ # @param opts [Hash] set of options
1321
1200
  # @option opts [Boolean] :blend (false) Blend smoothly between th and el
1322
1201
  # @return [Image] merged image
1323
1202
  def ifthenelse(th, el, opts = {})
1324
1203
  match_image = [th, el, self].find {|x| x.is_a? Vips::Image}
1325
1204
 
1326
1205
  if not th.is_a? Vips::Image
1327
- th = Argument::imageize match_image, th
1206
+ th = Operation.imageize match_image, th
1328
1207
  end
1329
1208
  if not el.is_a? Vips::Image
1330
- el = Argument::imageize match_image, el
1209
+ el = Operation.imageize match_image, el
1331
1210
  end
1332
1211
 
1333
- Vips::call_base "ifthenelse", self, "", [th, el, opts]
1212
+ Vips::Operation.call "ifthenelse", [self, th, el], opts
1334
1213
  end
1335
1214
 
1336
1215
  # Scale an image to uchar. This is the vips `scale` operation, but
1337
1216
  # renamed to avoid a clash with the `.scale` property.
1338
1217
  #
1339
- # @param [Hash] opts Set of options
1218
+ # @param opts [Hash] Set of options
1340
1219
  # @return [Vips::Image] Output image
1341
- def scaleimage(opts = {})
1220
+ def scaleimage opts = {}
1342
1221
  Vips::Image.scale self, opts
1343
1222
  end
1344
1223
 
@@ -1359,97 +1238,125 @@ module Vips
1359
1238
  # these have hand-written methods, see above
1360
1239
  no_generate = ["scale", "bandjoin", "ifthenelse"]
1361
1240
 
1362
- generate_operation = lambda do |op|
1363
- flags = op.flags
1364
- return if (flags & :deprecated) != 0
1365
- nickname = Vips::nickname_find op.gtype
1366
-
1241
+ # map gobject's type names to Ruby
1242
+ map_go_to_ruby = {
1243
+ "gboolean" => "Boolean",
1244
+ "gint" => "Integer",
1245
+ "gdouble" => "Float",
1246
+ "gfloat" => "Float",
1247
+ "gchararray" => "String",
1248
+ "VipsImage" => "Vips::Image",
1249
+ "VipsInterpolate" => "Vips::Interpolate",
1250
+ "VipsArrayDouble" => "Array<Double>",
1251
+ "VipsArrayInt" => "Array<Integer>",
1252
+ "VipsArrayImage" => "Array<Image>",
1253
+ "VipsArrayString" => "Array<String>",
1254
+ }
1255
+
1256
+ generate_operation = lambda do |gtype, nickname, op|
1257
+ op_flags = op.get_flags
1258
+ return if (op_flags & OPERATION_DEPRECATED) != 0
1367
1259
  return if no_generate.include? nickname
1260
+ description = Vips::vips_object_get_description op
1261
+
1262
+ # find and classify all the arguments the operator can take
1263
+ required_input = []
1264
+ optional_input = []
1265
+ required_output = []
1266
+ optional_output = []
1267
+ member_x = nil
1268
+ op.argument_map do |pspec, argument_class, argument_instance|
1269
+ arg_flags = argument_class[:flags]
1270
+ next if (arg_flags & ARGUMENT_CONSTRUCT) == 0
1271
+ next if (arg_flags & ARGUMENT_DEPRECATED) != 0
1272
+
1273
+ name = pspec[:name].gsub("-", "_")
1274
+ # 'in' as a param name confuses yard
1275
+ name = "im" if name == "in"
1276
+ gtype = pspec[:value_type]
1277
+ fundamental = GObject::g_type_fundamental gtype
1278
+ type_name = GObject::g_type_name gtype
1279
+ if map_go_to_ruby.include? type_name
1280
+ type_name = map_go_to_ruby[type_name]
1281
+ end
1282
+ if fundamental == GObject::GFLAGS_TYPE or
1283
+ fundamental == GObject::GENUM_TYPE
1284
+ type_name =~ /Vips(.*)/
1285
+ type_name = "Vips::" + $~[1]
1286
+ end
1287
+ blurb = GObject::g_param_spec_get_blurb pspec
1288
+ value = {:name => name,
1289
+ :flags => arg_flags,
1290
+ :gtype => gtype,
1291
+ :type_name => type_name,
1292
+ :blurb => blurb}
1293
+
1294
+ if (arg_flags & ARGUMENT_INPUT) != 0
1295
+ if (arg_flags & ARGUMENT_REQUIRED) != 0
1296
+ # note the first required input image, if any ... we
1297
+ # will be a method of this instance
1298
+ if not member_x and gtype == Vips::IMAGE_TYPE
1299
+ member_x = value
1300
+ else
1301
+ required_input << value
1302
+ end
1303
+ else
1304
+ optional_input << value
1305
+ end
1306
+ end
1368
1307
 
1369
- all_args = op.get_args.select {|arg| not arg.isset}
1370
-
1371
- # separate args into various categories
1372
-
1373
- required_input = all_args.select do |arg|
1374
- (arg.flags & :input) != 0 and
1375
- (arg.flags & :required) != 0
1376
- end
1377
-
1378
- optional_input = all_args.select do |arg|
1379
- (arg.flags & :input) != 0 and
1380
- (arg.flags & :required) == 0
1381
- end
1382
-
1383
- required_output = all_args.select do |arg|
1384
- (arg.flags & :output) != 0 and
1385
- (arg.flags & :required) != 0
1386
- end
1387
-
1388
- # required input args with :modify are copied and appended to
1389
- # output
1390
- modified_required_input = required_input.select do |arg|
1391
- (arg.flags & :modify) != 0
1392
- end
1393
- required_output += modified_required_input
1394
-
1395
- optional_output = all_args.select do |arg|
1396
- (arg.flags & :output) != 0 and
1397
- (arg.flags & :required) == 0
1398
- end
1399
-
1400
- # optional input args with :modify are copied and appended to
1401
- # output
1402
- modified_optional_input = optional_input.select do |arg|
1403
- (arg.flags & :modify) != 0
1404
- end
1405
- optional_output += modified_optional_input
1308
+ # MODIFY INPUT args count as OUTPUT as well
1309
+ if (arg_flags & ARGUMENT_OUTPUT) != 0 or
1310
+ ((arg_flags & ARGUMENT_INPUT) != 0 and
1311
+ (arg_flags & ARGUMENT_MODIFY) != 0)
1312
+ if (arg_flags & ARGUMENT_REQUIRED) != 0 and
1313
+ required_output << value
1314
+ else
1315
+ optional_output << value
1316
+ end
1317
+ end
1406
1318
 
1407
- # find the first input image, if any ... we will be a method of this
1408
- # instance
1409
- member_x = required_input.find do |x|
1410
- x.gtype.type_is_a? GLib::Type["VipsImage"]
1411
- end
1412
- if member_x != nil
1413
- required_input.delete member_x
1414
1319
  end
1415
1320
 
1416
1321
  print "# @!method "
1417
1322
  print "self." if not member_x
1418
1323
  print "#{nickname}("
1419
- print required_input.map(&:name).join(", ")
1324
+ print required_input.map{|x| x[:name]}.join(", ")
1420
1325
  print ", " if required_input.length > 0
1421
1326
  puts "opts = {})"
1422
1327
 
1423
- puts "# #{op.description.capitalize}."
1328
+ puts "# #{description.capitalize}."
1424
1329
 
1425
- required_input.each do |arg|
1426
- puts "# @param #{arg.name} [#{arg.type}] #{arg.blurb}"
1330
+ required_input.each do |arg|
1331
+ puts "# @param #{arg[:name]} [#{arg[:type_name]}] " +
1332
+ "#{arg[:blurb]}"
1427
1333
  end
1428
1334
 
1429
- puts "# @param [Hash] opts Set of options"
1430
- optional_input.each do |arg|
1431
- puts "# @option opts [#{arg.type}] :#{arg.name} #{arg.blurb}"
1335
+ puts "# @param opts [Hash] Set of options"
1336
+ optional_input.each do |arg|
1337
+ puts "# @option opts [#{arg[:type_name]}] :#{arg[:name]} " +
1338
+ "#{arg[:blurb]}"
1432
1339
  end
1433
- optional_output.each do |arg|
1434
- print "# @option opts [#{arg.type}] :#{arg.name}"
1435
- puts " Output #{arg.blurb}"
1340
+ optional_output.each do |arg|
1341
+ print "# @option opts [#{arg[:type_name]}] :#{arg[:name]}"
1342
+ puts " Output #{arg[:blurb]}"
1436
1343
  end
1437
1344
 
1438
1345
  print "# @return ["
1439
1346
  if required_output.length == 0
1440
1347
  print "nil"
1441
1348
  elsif required_output.length == 1
1442
- print required_output[0].type
1349
+ print required_output.first[:type_name]
1443
1350
  elsif
1444
1351
  print "Array<"
1445
- print required_output.map(&:type).join(", ")
1352
+ print required_output.map{|x| x[:type_name]}.join(", ")
1446
1353
  print ">"
1447
1354
  end
1448
1355
  if optional_output.length > 0
1449
1356
  print ", Hash<Symbol => Object>"
1450
1357
  end
1451
1358
  print "] "
1452
- print required_output.map(&:blurb).join(", ")
1359
+ print required_output.map{|x| x[:blurb]}.join(", ")
1453
1360
  if optional_output.length > 0
1454
1361
  print ", " if required_output.length > 0
1455
1362
  print "Hash of optional output items"
@@ -1459,35 +1366,30 @@ module Vips
1459
1366
  puts ""
1460
1367
  end
1461
1368
 
1462
- generate_class = lambda do |gtype|
1463
- begin
1464
- # can fail for abstract types
1465
- # can't find a way to get to #abstract? from a gtype
1466
- op = Vips::Operation.new gtype.name
1467
- rescue
1468
- op = nil
1469
- end
1369
+ generate_class = lambda do |gtype, a|
1370
+ nickname = Vips::nickname_find gtype
1470
1371
 
1471
- generate_operation.(op) if op
1372
+ if nickname
1373
+ begin
1374
+ # can fail for abstract types
1375
+ op = Vips::Operation.new nickname
1376
+ rescue
1377
+ end
1472
1378
 
1473
- gtype.children.each do |x|
1474
- generate_class.(x)
1379
+ generate_operation.(gtype, nickname, op) if op
1475
1380
  end
1381
+
1382
+ Vips::vips_type_map gtype, generate_class, nil
1476
1383
  end
1477
1384
 
1478
1385
  puts "module Vips"
1479
1386
  puts " class Image"
1480
1387
  puts ""
1481
1388
 
1482
- # gobject-introspection 3.0.7 crashes a lot if it GCs while doing
1483
- # something
1484
- GC.disable
1485
-
1486
- generate_class.(GLib::Type["VipsOperation"])
1389
+ generate_class.(GObject::g_type_from_name("VipsOperation"), nil)
1487
1390
 
1488
1391
  puts " end"
1489
1392
  puts "end"
1490
1393
  end
1491
1394
 
1492
1395
  end
1493
-