ruby-vips 1.0.6 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ require 'vips'
@@ -1,133 +1,465 @@
1
- # This module provides a set of overrides for the vips image processing library
2
- # used via the gobject-introspection gem.
1
+ # This module provides an interface to the vips image processing library
2
+ # via ruby-ffi.
3
3
  #
4
4
  # Author:: John Cupitt (mailto:jcupitt@gmail.com)
5
5
  # License:: MIT
6
6
 
7
- # @private
8
- def log str
9
- if $vips_debug
10
- puts str
7
+ require 'ffi'
8
+
9
+ # This module uses FFI to make a simple layer over the glib and gobject
10
+ # libraries.
11
+
12
+ module GLib
13
+ extend FFI::Library
14
+
15
+ if FFI::Platform.windows?
16
+ glib_libname = 'libglib-2.0-0.dll'
17
+ else
18
+ glib_libname = 'glib-2.0'
19
+ end
20
+
21
+ ffi_lib glib_libname
22
+
23
+ # nil being the default
24
+ glib_log_domain = nil
25
+
26
+ def self.set_log_domain domain
27
+ glib_log_domain = domain
11
28
  end
29
+
30
+ attach_function :g_malloc, [:size_t], :pointer
31
+
32
+ # save the FFI::Function that attach will return ... we can use it directly
33
+ # as a param for callbacks
34
+ G_FREE = attach_function :g_free, [:pointer], :void
35
+
12
36
  end
13
37
 
14
- # copied from ruby-gnome2/gstreamer/lib/gst.rb without much understanding
38
+ module GObject
39
+ extend FFI::Library
40
+
41
+ if FFI::Platform.windows?
42
+ gobject_libname = 'libgobject-2.0-0.dll'
43
+ else
44
+ gobject_libname = 'gobject-2.0'
45
+ end
46
+
47
+ ffi_lib gobject_libname
48
+
49
+ # we can't just use ulong, windows has different int sizing rules
50
+ if FFI::Platform::ADDRESS_SIZE == 64
51
+ typedef :uint64, :GType
52
+ else
53
+ typedef :uint32, :GType
54
+ end
15
55
 
16
- require 'pathname'
17
- require 'gobject-introspection'
56
+ attach_function :g_type_name, [:GType], :string
57
+ attach_function :g_type_from_name, [:string], :GType
58
+ attach_function :g_type_fundamental, [:GType], :GType
18
59
 
19
- # pick up a local girepository/lib in preference to the system one
20
- base_dir = Pathname.new(__FILE__).dirname.dirname.expand_path
21
- vendor_dir = base_dir + "vendor" + "local"
22
- vendor_bin_dir = vendor_dir + "bin"
23
- GLib.prepend_dll_path(vendor_bin_dir)
24
- vendor_girepository_dir = vendor_dir + "lib" + "girepository-1.0"
25
- GObjectIntrospection.prepend_typelib_path(vendor_girepository_dir)
60
+ # look up some common gtypes
61
+ GBOOL_TYPE = g_type_from_name "gboolean"
62
+ GINT_TYPE = g_type_from_name "gint"
63
+ GDOUBLE_TYPE = g_type_from_name "gdouble"
64
+ GENUM_TYPE = g_type_from_name "GEnum"
65
+ GFLAGS_TYPE = g_type_from_name "GFlags"
66
+ GSTR_TYPE = g_type_from_name "gchararray"
67
+ GOBJECT_TYPE = g_type_from_name "GObject"
68
+
69
+ end
70
+
71
+ require 'vips/gobject'
72
+ require 'vips/gvalue'
73
+
74
+ # This module provides a binding for the [libvips image processing
75
+ # library](https://jcupitt.github.io/libvips/).
76
+ #
77
+ # # Example
78
+ #
79
+ # ```ruby
80
+ # require 'vips'
81
+ #
82
+ # if ARGV.length < 2
83
+ # raise "usage: #{$PROGRAM_NAME}: input-file output-file"
84
+ # end
85
+ #
86
+ # im = Vips::Image.new_from_file ARGV[0], access: :sequential
87
+ #
88
+ # im *= [1, 2, 1]
89
+ #
90
+ # mask = Vips::Image.new_from_array [
91
+ # [-1, -1, -1],
92
+ # [-1, 16, -1],
93
+ # [-1, -1, -1]
94
+ # ], 8
95
+ # im = im.conv mask, precision: :integer
96
+ #
97
+ # im.write_to_file ARGV[1]
98
+ # ```
99
+ #
100
+ # This example loads a file, boosts the green channel (I'm not sure why),
101
+ # sharpens the image, and saves it back to disc again.
102
+ #
103
+ # Reading this example line by line, we have:
104
+ #
105
+ # ```ruby
106
+ # im = Vips::Image.new_from_file ARGV[0], access: :sequential
107
+ # ```
108
+ #
109
+ # {Image.new_from_file} can load any image file supported by vips. In this
110
+ # example, we will be accessing pixels top-to-bottom as we sweep through the
111
+ # image reading and writing, so `:sequential` access mode is best for us. The
112
+ # default mode is `:random`: this allows for full random access to image pixels,
113
+ # but is slower and needs more memory. See {Access}
114
+ # for full details
115
+ # on the various modes available.
116
+ #
117
+ # You can also load formatted images from
118
+ # memory buffers, create images that wrap C-style memory arrays, or make images
119
+ # from constants.
120
+ #
121
+ # The next line:
122
+ #
123
+ # ```ruby
124
+ # im *= [1, 2, 1]
125
+ # ```
126
+ #
127
+ # Multiplying the image by an array constant uses one array element for each
128
+ # image band. This line assumes that the input image has three bands and will
129
+ # double the middle band. For RGB images, that's doubling green.
130
+ #
131
+ # Next we have:
132
+ #
133
+ # ```ruby
134
+ # mask = Vips::Image.new_from_array [
135
+ # [-1, -1, -1],
136
+ # [-1, 16, -1],
137
+ # [-1, -1, -1]
138
+ # ], 8
139
+ # im = im.conv mask, precision: :integer
140
+ # ```
141
+ #
142
+ # {Image.new_from_array} creates an image from an array constant. The 8 at
143
+ # the end sets the scale: the amount to divide the image by after
144
+ # integer convolution.
145
+ #
146
+ # See the libvips API docs for `vips_conv()` (the operation
147
+ # invoked by {Image#conv}) for details on the convolution operator. By default,
148
+ # it computes with a float mask, but `:integer` is fine for this case, and is
149
+ # much faster.
150
+ #
151
+ # Finally:
152
+ #
153
+ # ```ruby
154
+ # im.write_to_file ARGV[1]
155
+ # ```
156
+ #
157
+ # {Image#write_to_file} writes an image back to the filesystem. It can
158
+ # write any format supported by vips: the file type is set from the filename
159
+ # suffix. You can also write formatted images to memory buffers, or dump
160
+ # image data to a raw memory array.
161
+ #
162
+ # # How it works
163
+ #
164
+ # The binding uses [ruby-ffi](https://github.com/ffi/ffi) to open the libvips
165
+ # shared library. When you call a method on the image class, it uses libvips
166
+ # introspection system (based on GObject) to search the
167
+ # library for an operation of that name, transforms the arguments to a form
168
+ # libvips can digest, and runs the operation.
169
+ #
170
+ # This means ruby-vips always presents the API implemented by the libvips shared
171
+ # library. It should update itself as new features are added.
172
+ #
173
+ # # Automatic wrapping
174
+ #
175
+ # `ruby-vips` adds a {Image.method_missing} handler to {Image} and uses
176
+ # it to look up vips operations. For example, the libvips operation `add`, which
177
+ # appears in C as `vips_add()`, appears in Ruby as {Image#add}.
178
+ #
179
+ # The operation's list of required arguments is searched and the first input
180
+ # image is set to the value of `self`. Operations which do not take an input
181
+ # image, such as {Image.black}, appear as class methods. The remainder of
182
+ # the arguments you supply in the function call are used to set the other
183
+ # required input arguments. Any trailing keyword arguments are used to set
184
+ # options on the operation.
185
+ #
186
+ # The result is the required output
187
+ # argument if there is only one result, or an array of values if the operation
188
+ # produces several results. If the operation has optional output objects, they
189
+ # are returned as a final hash.
190
+ #
191
+ # For example, {Image#min}, the vips operation that searches an image for
192
+ # the minimum value, has a large number of optional arguments. You can use it to
193
+ # find the minimum value like this:
194
+ #
195
+ # ```ruby
196
+ # min_value = image.min
197
+ # ```
198
+ #
199
+ # You can ask it to return the position of the minimum with `:x` and `:y`.
200
+ #
201
+ # ```ruby
202
+ # min_value, opts = min x: true, y: true
203
+ # x_pos = opts['x']
204
+ # y_pos = opts['y']
205
+ # ```
206
+ #
207
+ # Now `x_pos` and `y_pos` will have the coordinates of the minimum value.
208
+ # There's actually a convenience method for this, {Image#minpos}.
209
+ #
210
+ # You can also ask for the top *n* minimum, for example:
211
+ #
212
+ # ```ruby
213
+ # min_value, opts = min size: 10, x_array: true, y_array: true
214
+ # x_pos = opts['x_array']
215
+ # y_pos = opts['y_array']
216
+ # ```
217
+ #
218
+ # Now `x_pos` and `y_pos` will be 10-element arrays.
219
+ #
220
+ # Because operations are member functions and return the result image, you can
221
+ # chain them. For example, you can write:
222
+ #
223
+ # ```ruby
224
+ # result_image = image.real.cos
225
+ # ```
226
+ #
227
+ # to calculate the cosine of the real part of a complex image.
228
+ # There are also a full set
229
+ # of arithmetic operator overloads, see below.
230
+ #
231
+ # libvips types are also automatically wrapped. The override looks at the type
232
+ # of argument required by the operation and converts the value you supply,
233
+ # when it can. For example, {Image#linear} takes a `VipsArrayDouble` as
234
+ # an argument
235
+ # for the set of constants to use for multiplication. You can supply this
236
+ # value as an integer, a float, or some kind of compound object and it
237
+ # will be converted for you. You can write:
238
+ #
239
+ # ```ruby
240
+ # result_image = image.linear 1, 3
241
+ # result_image = image.linear 12.4, 13.9
242
+ # result_image = image.linear [1, 2, 3], [4, 5, 6]
243
+ # result_image = image.linear 1, [4, 5, 6]
244
+ # ```
245
+ #
246
+ # And so on. A set of overloads are defined for {Image#linear}, see below.
247
+ #
248
+ # It does a couple of more ambitious conversions. It will automatically convert
249
+ # to and from the various vips types, like `VipsBlob` and `VipsArrayImage`. For
250
+ # example, you can read the ICC profile out of an image like this:
251
+ #
252
+ # ```ruby
253
+ # profile = im.get_value "icc-profile-data"
254
+ # ```
255
+ #
256
+ # and profile will be a byte array.
257
+ #
258
+ # If an operation takes several input images, you can use a constant for all but
259
+ # one of them and the wrapper will expand the constant to an image for you. For
260
+ # example, {Image#ifthenelse} uses a condition image to pick pixels
261
+ # between a then and an else image:
262
+ #
263
+ # ```ruby
264
+ # result_image = condition_image.ifthenelse then_image, else_image
265
+ # ```
266
+ #
267
+ # You can use a constant instead of either the then or the else parts and it
268
+ # will be expanded to an image for you. If you use a constant for both then and
269
+ # else, it will be expanded to match the condition image. For example:
270
+ #
271
+ # ```ruby
272
+ # result_image = condition_image.ifthenelse [0, 255, 0], [255, 0, 0]
273
+ # ```
274
+ #
275
+ # Will make an image where true pixels are green and false pixels are red.
276
+ #
277
+ # This is useful for {Image#bandjoin}, the thing to join two or more
278
+ # images up bandwise. You can write:
279
+ #
280
+ # ```ruby
281
+ # rgba = rgb.bandjoin 255
282
+ # ```
283
+ #
284
+ # to append a constant 255 band to an image, perhaps to add an alpha channel. Of
285
+ # course you can also write:
286
+ #
287
+ # ```ruby
288
+ # result_image = image1.bandjoin image2
289
+ # result_image = image1.bandjoin [image2, image3]
290
+ # result_image = Vips::Image.bandjoin [image1, image2, image3]
291
+ # result_image = image1.bandjoin [image2, 255]
292
+ # ```
293
+ #
294
+ # and so on.
295
+ #
296
+ # # Automatic YARD documentation
297
+ #
298
+ # The bulk of these API docs are generated automatically by
299
+ # {Vips::generate_yard}. It examines
300
+ # libvips and writes a summary of each operation and the arguments and options
301
+ # that that operation expects.
302
+ #
303
+ # Use the [C API
304
+ # docs](https://jcupitt.github.io/libvips/API/current)
305
+ # for more detail.
306
+ #
307
+ # # Exceptions
308
+ #
309
+ # The wrapper spots errors from vips operations and raises the {Vips::Error}
310
+ # exception. You can catch it in the usual way.
311
+ #
312
+ # # Enums
313
+ #
314
+ # The libvips enums, such as `VipsBandFormat` appear in ruby-vips as Symbols
315
+ # like `:uchar`. They are documented as a set of classes for convenience, see
316
+ # the class list.
317
+ #
318
+ # # Draw operations
319
+ #
320
+ # Paint operations like {Image#draw_circle} and {Image#draw_line}
321
+ # modify their input image. This
322
+ # makes them hard to use with the rest of libvips: you need to be very careful
323
+ # about the order in which operations execute or you can get nasty crashes.
324
+ #
325
+ # The wrapper spots operations of this type and makes a private copy of the
326
+ # image in memory before calling the operation. This stops crashes, but it does
327
+ # make it inefficient. If you draw 100 lines on an image, for example, you'll
328
+ # copy the image 100 times. The wrapper does make sure that memory is recycled
329
+ # where possible, so you won't have 100 copies in memory.
330
+ #
331
+ # If you want to avoid the copies, you'll need to call drawing operations
332
+ # yourself.
333
+ #
334
+ # # Overloads
335
+ #
336
+ # The wrapper defines the usual set of arithmetic, boolean and relational
337
+ # overloads on image. You can mix images, constants and lists of constants
338
+ # (almost) freely. For example, you can write:
339
+ #
340
+ # ```ruby
341
+ # result_image = ((image * [1, 2, 3]).abs < 128) | 4
342
+ # ```
343
+ #
344
+ # # Expansions
345
+ #
346
+ # Some vips operators take an enum to select an action, for example
347
+ # {Image#math} can be used to calculate sine of every pixel like this:
348
+ #
349
+ # ```ruby
350
+ # result_image = image.math :sin
351
+ # ```
352
+ #
353
+ # This is annoying, so the wrapper expands all these enums into separate members
354
+ # named after the enum. So you can write:
355
+ #
356
+ # ```ruby
357
+ # result_image = image.sin
358
+ # ```
359
+ #
360
+ # # Convenience functions
361
+ #
362
+ # The wrapper defines a few extra useful utility functions:
363
+ # {Image#get_value}, {Image#set_value}, {Image#bandsplit},
364
+ # {Image#maxpos}, {Image#minpos},
365
+ # {Image#median}.
26
366
 
27
367
  module Vips
28
- # @private
29
- LOG_DOMAIN = "VIPS"
30
- GLib::Log.set_log_domain(LOG_DOMAIN)
368
+ extend FFI::Library
369
+
370
+ if FFI::Platform.windows?
371
+ vips_libname = 'libvips-42.dll'
372
+ else
373
+ vips_libname = 'vips'
374
+ end
375
+
376
+ ffi_lib vips_libname
31
377
 
32
- # about as crude as you could get
33
- $vips_debug = false
378
+ LOG_DOMAIN = "VIPS"
379
+ GLib::set_log_domain LOG_DOMAIN
34
380
 
35
- # allow to skip GI autoload
36
- $vips_skip_autoload ||= false
381
+ @@debug = false
37
382
 
38
383
  # Turn debug logging on and off.
39
384
  #
40
385
  # @param dbg [Boolean] Set true to print debug log messages
41
386
  def self.set_debug dbg
42
- $vips_debug = dbg
387
+ @@debug = dbg
43
388
  end
44
389
 
45
- class << self
46
- # @private
47
- def load_gi_module(*argv)
48
- log "Vips::load_gi_module: #{argv}"
49
-
50
- loader = Loader.new(self, argv)
51
- begin
52
- loader.load("Vips")
53
- rescue
54
- puts "Unable to load Vips"
55
- puts " Check that the vips library has been installed and is"
56
- puts " on your library path."
57
- puts " Check that the typelib `Vips-8.0.typelib` has been "
58
- puts " installed, and that it is on your GI_TYPELIB_PATH."
59
- raise
60
- end
61
-
62
- require 'vips/error'
63
- require 'vips/argument'
64
- require 'vips/operation'
65
- require 'vips/call'
66
- require 'vips/image'
67
- require 'vips/version'
68
-
69
- # Make sure we only get called once.
70
- def self.load_gi_module; false; end
71
-
72
- true
390
+ # Print a log message to the output. See {Vips::set_debug}.
391
+ def self.log str
392
+ if @@debug
393
+ puts str
73
394
  end
74
395
  end
75
396
 
76
- # @private
77
- class Loader < GObjectIntrospection::Loader
78
- def initialize(base_module, init_arguments)
79
- log "Vips::Loader.initialize: #{base_module}, #{init_arguments}"
397
+ typedef :ulong, :GType
80
398
 
81
- super(base_module)
82
- @init_arguments = init_arguments
83
- end
84
-
85
- private
86
- def pre_load(repository, namespace)
87
- log "Vips::Loader.pre_load: #{repository}, #{namespace}"
399
+ attach_function :vips_error_buffer, [], :string
400
+ attach_function :vips_error_clear, [], :void
88
401
 
89
- call_init_function(repository, namespace)
90
- define_value_modules
402
+ # The ruby-vips error class.
403
+ class Error < RuntimeError
404
+ # @param msg [String] The error message. If this is not supplied, grab
405
+ # and clear the vips error buffer and use that.
406
+ def initialize msg = nil
407
+ if msg
408
+ @details = msg
409
+ elsif Vips::vips_error_buffer != ""
410
+ @details = Vips::vips_error_buffer
411
+ Vips::vips_error_clear
412
+ else
413
+ @details = nil
414
+ end
91
415
  end
92
416
 
93
- def call_init_function(repository, namespace)
94
- log "Vips::Loader.call_init_function: #{repository}, #{namespace}"
417
+ # Pretty-print a {Vips::Error}.
418
+ #
419
+ # @return [String] The error message
420
+ def to_s
421
+ if @details != nil
422
+ @details
423
+ else
424
+ super.to_s
425
+ end
426
+ end
427
+ end
95
428
 
96
- # call Vips::init
97
- init = repository.find(namespace, "init")
98
- succeeded, argv, error = init.invoke([$PROGRAM_NAME])
429
+ attach_function :vips_init, [:string], :int
99
430
 
100
- # TODO get the vips error buffer
101
- raise error unless succeeded
431
+ if Vips::vips_init($0) != 0
432
+ throw Vips::get_error
433
+ end
102
434
 
103
- log "Vips::Loader.call_init_function: argv = #{argv}"
104
- end
435
+ # don't use at_exit to call vips_shutdown, it causes problems with fork, and
436
+ # in any case libvips does this for us
105
437
 
106
- def define_value_modules
107
- @value_functions_module = Module.new
108
- @value_methods_module = Module.new
109
- @base_module.const_set("ValueFunctions", @value_functions_module)
110
- @base_module.const_set("ValueMethods", @value_methods_module)
111
- end
438
+ attach_function :vips_object_print_all, [], :void
439
+ attach_function :vips_leak_set, [:int], :void
112
440
 
113
- def post_load(repository, namespace)
114
- log "Vips::Loader.post_load:"
441
+ def self.showall
442
+ if @@debug
443
+ GC.start
444
+ vips_object_print_all
115
445
  end
446
+ end
116
447
 
448
+ if @@debug
449
+ vips_leak_set 1
117
450
  end
118
- end
119
451
 
120
- # this makes vips keep a list of all active objects which we can print out
121
- Vips::leak_set true if $vips_debug
452
+ attach_function :version, :vips_version, [:int], :int
453
+ attach_function :version_string, :vips_version_string, [], :string
122
454
 
123
- # Initialize GI
124
- Vips::load_gi_module unless $vips_skip_autoload
455
+ LIBRARY_VERSION = Vips::version_string
125
456
 
126
- # @private
127
- def showall
128
- if $vips_debug
129
- GC.start
130
- Vips::Object::print_all
131
- end
132
457
  end
133
458
 
459
+ require 'vips/object'
460
+ require 'vips/operation'
461
+ require 'vips/image'
462
+ require 'vips/interpolate'
463
+ require 'vips/version'
464
+
465
+