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.
@@ -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
+