vips 8.6.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (52) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +16 -0
  3. data/.travis.yml +47 -0
  4. data/.yardopts +2 -0
  5. data/Gemfile +4 -0
  6. data/README.md +64 -0
  7. data/Rakefile +28 -0
  8. data/example/annotate.rb +17 -0
  9. data/example/daltonize8.rb +75 -0
  10. data/example/example1.rb +12 -0
  11. data/example/example2.rb +34 -0
  12. data/example/example3.rb +19 -0
  13. data/example/example4.rb +18 -0
  14. data/example/example5.rb +31 -0
  15. data/example/inheritance_with_refcount.rb +286 -0
  16. data/example/thumb.rb +31 -0
  17. data/example/trim8.rb +41 -0
  18. data/example/watermark.rb +44 -0
  19. data/example/wobble.rb +36 -0
  20. data/ext/Rakefile +35 -0
  21. data/lib/vips.rb +597 -0
  22. data/lib/vips/access.rb +11 -0
  23. data/lib/vips/align.rb +11 -0
  24. data/lib/vips/angle.rb +12 -0
  25. data/lib/vips/angle45.rb +16 -0
  26. data/lib/vips/bandformat.rb +20 -0
  27. data/lib/vips/coding.rb +14 -0
  28. data/lib/vips/compass_direction.rb +17 -0
  29. data/lib/vips/direction.rb +11 -0
  30. data/lib/vips/extend.rb +17 -0
  31. data/lib/vips/gobject.rb +122 -0
  32. data/lib/vips/gvalue.rb +281 -0
  33. data/lib/vips/image.rb +1500 -0
  34. data/lib/vips/interesting.rb +14 -0
  35. data/lib/vips/interpolate.rb +62 -0
  36. data/lib/vips/interpretation.rb +28 -0
  37. data/lib/vips/kernel.rb +22 -0
  38. data/lib/vips/methods.rb +2145 -0
  39. data/lib/vips/object.rb +244 -0
  40. data/lib/vips/operation.rb +365 -0
  41. data/lib/vips/operationboolean.rb +14 -0
  42. data/lib/vips/operationcomplex.rb +12 -0
  43. data/lib/vips/operationcomplex2.rb +10 -0
  44. data/lib/vips/operationcomplexget.rb +11 -0
  45. data/lib/vips/operationmath.rb +18 -0
  46. data/lib/vips/operationmath2.rb +10 -0
  47. data/lib/vips/operationrelational.rb +15 -0
  48. data/lib/vips/operationround.rb +11 -0
  49. data/lib/vips/size.rb +13 -0
  50. data/lib/vips/version.rb +4 -0
  51. data/vips.gemspec +36 -0
  52. metadata +209 -0
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # batch-process a lot of files
4
+ #
5
+ # this should run in constant memory -- if it doesn't, something has broken
6
+
7
+ require 'vips'
8
+
9
+ # benchmark thumbnail via a memory buffer
10
+ def via_memory(filename, thumbnail_width)
11
+ data = IO.binread(filename)
12
+
13
+ thumb = Vips::Image.thumbnail_buffer data, thumbnail_width, crop: 'centre'
14
+
15
+ thumb.write_to_buffer '.jpg'
16
+ end
17
+
18
+ # benchmark thumbnail via files
19
+ def via_files(filename, thumbnail_width)
20
+ thumb = Vips::Image.thumbnail filename, thumbnail_width, crop: 'centre'
21
+
22
+ thumb.write_to_buffer '.jpg'
23
+ end
24
+
25
+ ARGV.each do |filename|
26
+ puts "processing #{filename} ..."
27
+ thumb = via_memory(filename, 500)
28
+ # thumb = via_files(filename, 500)
29
+ end
30
+
31
+
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/ruby
2
+
3
+ # An equivalent of ImageMagick's -trim in ruby-vips ... automatically remove
4
+ # "boring" image edges.
5
+
6
+ # We use .project to sum the rows and columns of a 0/255 mask image, the first
7
+ # non-zero row or column is the object edge. We make the mask image with an
8
+ # amount-different-from-background image plus a threshold.
9
+
10
+ require 'vips'
11
+
12
+ im = Vips::Image.new_from_file ARGV[0]
13
+
14
+ # find the value of the pixel at (0, 0) ... we will search for all pixels
15
+ # significantly different from this
16
+ background = im.getpoint(0, 0)
17
+
18
+ # we need to smooth the image, subtract the background from every pixel, take
19
+ # the absolute value of the difference, then threshold
20
+ mask = (im.median - background).abs > 10
21
+
22
+ # sum mask rows and columns, then search for the first non-zero sum in each
23
+ # direction
24
+ columns, rows = mask.project
25
+
26
+ first_column, first_row = columns.profile
27
+ left = first_row.min
28
+
29
+ first_column, first_row = columns.fliphor.profile
30
+ right = columns.width - first_row.min
31
+
32
+ first_column, first_row = rows.profile
33
+ top = first_column.min
34
+
35
+ first_column, first_row = rows.flipver.profile
36
+ bottom = rows.height - first_column.min
37
+
38
+ # and now crop the original image
39
+ im = im.crop left, top, right - left, bottom - top
40
+
41
+ im.write_to_file ARGV[1]
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'vips'
4
+
5
+ im = Vips::Image.new_from_file ARGV[0], :access => :sequential
6
+
7
+ text = Vips::Image.text ARGV[2], :width => 500, :dpi => 300
8
+ text = (text * 0.3).cast(:uchar)
9
+ text = text.embed 100, 100, text.width + 200, text.width + 200
10
+ text = text.replicate 1 + im.width / text.width, 1 + im.height / text.height
11
+ text = text.crop 0, 0, im.width, im.height
12
+
13
+ # we want to blend into the visible part of the image and leave any alpha
14
+ # channels untouched ... we need to split im into two parts
15
+
16
+ # guess how many bands from the start of im contain visible colour information
17
+ if im.bands >= 4 and im.interpretation == :cmyk
18
+ # cmyk image
19
+ n_visible_bands = 4
20
+ text_colour = [0, 255, 0, 0]
21
+ elsif im.bands >= 3
22
+ # rgb image
23
+ n_visible_bands = 3
24
+ text_colour = [255, 0, 0]
25
+ else
26
+ # mono image
27
+ n_visible_bands = 1
28
+ text_colour = 255
29
+ end
30
+
31
+ # split into image and alpha
32
+ if im.bands - n_visible_bands > 0
33
+ alpha = im.extract_band n_visible_bands, :n => im.bands - n_visible_bands
34
+ im = im.extract_band 0, :n => n_visible_bands
35
+ else
36
+ alpha = nil
37
+ end
38
+
39
+ marked = text.ifthenelse text_colour, im, :blend => true
40
+
41
+ # reattach alpha
42
+ marked = marked.bandjoin alpha if alpha
43
+
44
+ marked.write_to_file ARGV[1]
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'vips'
4
+
5
+ image = Vips::Image.new_from_file ARGV[0]
6
+
7
+ module Vips
8
+ class Image
9
+ def wobble
10
+ # this makes an image where pixel (0, 0) (at the top-left) has
11
+ # value [0, 0], and pixel (image.width - 1, image.height - 1) at the
12
+ # bottom-right has value [image.width - 1, image.height - 1]
13
+ index = Vips::Image.xyz width, height
14
+
15
+ # make a version with (0, 0) at the centre, negative values up
16
+ # and left, positive down and right
17
+ centre = index - [width / 2, height / 2]
18
+
19
+ # to polar space, so each pixel is now distance and angle in degrees
20
+ polar = centre.polar
21
+
22
+ # scale sin(distance) by 1/distance to make a wavey pattern
23
+ d = ((polar[0] * 3).sin * 10000) / (polar[0] + 1)
24
+
25
+ # and back to rectangular coordinates again to make a set of
26
+ # vectors we can apply to the original index image
27
+ index += d.bandjoin(polar[1]).rect
28
+
29
+ # finally, use our modified index image to distort!
30
+ mapim index
31
+ end
32
+ end
33
+ end
34
+
35
+ image = image.wobble
36
+ image.write_to_file ARGV[1]
@@ -0,0 +1,35 @@
1
+
2
+ require_relative '../lib/vips/version'
3
+
4
+ version = Vips::VERSION[/\d+\.\d+\.\d+/]
5
+ archive_path = "vips-#{version}.tar.gz"
6
+ source_path = "vips-#{version}"
7
+ prefix = ENV['PREFIX'] || File.dirname(__dir__)
8
+
9
+ task :fetch do
10
+ url = "https://github.com/jcupitt/libvips/releases/download/v#{version}/#{archive_path}"
11
+
12
+ unless File.exist? archive_path
13
+ sh "wget #{url}"
14
+ end
15
+ end
16
+
17
+ task :extract do
18
+ unless File.exist? source_path
19
+ sh "tar -xvf #{archive_path}"
20
+ end
21
+ end
22
+
23
+ task :build do
24
+ Dir.chdir source_path do
25
+ sh "./configure --prefix=#{prefix} --exec-prefix=#{prefix}"
26
+ sh "make install"
27
+ end
28
+ end
29
+
30
+ task :clean do
31
+ FileUtils.rm_rf archive_path
32
+ FileUtils.rm_rf source_path
33
+ end
34
+
35
+ task :default => [:fetch, :extract, :build]
@@ -0,0 +1,597 @@
1
+ # This module provides an interface to the vips image processing library
2
+ # via ruby-ffi.
3
+ #
4
+ # Author:: John Cupitt (mailto:jcupitt@gmail.com)
5
+ # License:: MIT
6
+
7
+ require 'ffi'
8
+ require 'logger'
9
+
10
+ # This module uses FFI to make a simple layer over the glib and gobject
11
+ # libraries.
12
+
13
+ module GLib
14
+ class << self
15
+ attr_accessor :logger
16
+ end
17
+ @logger = Logger.new(STDOUT)
18
+ @logger.level = Logger::WARN
19
+
20
+ extend FFI::Library
21
+
22
+ if FFI::Platform.windows?
23
+ glib_libname = 'libglib-2.0-0.dll'
24
+ else
25
+ glib_libname = 'glib-2.0'
26
+ end
27
+
28
+ ffi_lib glib_libname
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
+
36
+ callback :g_log_func, [:string, :int, :string, :pointer], :void
37
+ attach_function :g_log_set_handler,
38
+ [:string, :int, :g_log_func, :pointer], :int
39
+ attach_function :g_log_remove_handler, [:string, :int], :void
40
+
41
+ # log flags
42
+ LOG_FLAG_RECURSION = 1 << 0
43
+ LOG_FLAG_FATAL = 1 << 1
44
+
45
+ # GLib log levels
46
+ LOG_LEVEL_ERROR = 1 << 2 # always fatal
47
+ LOG_LEVEL_CRITICAL = 1 << 3
48
+ LOG_LEVEL_WARNING = 1 << 4
49
+ LOG_LEVEL_MESSAGE = 1 << 5
50
+ LOG_LEVEL_INFO = 1 << 6
51
+ LOG_LEVEL_DEBUG = 1 << 7
52
+
53
+ # map glib levels to Logger::Severity
54
+ GLIB_TO_SEVERITY = {
55
+ LOG_LEVEL_ERROR => Logger::ERROR,
56
+ LOG_LEVEL_CRITICAL => Logger::FATAL,
57
+ LOG_LEVEL_WARNING => Logger::WARN,
58
+ LOG_LEVEL_MESSAGE => Logger::UNKNOWN,
59
+ LOG_LEVEL_INFO => Logger::INFO,
60
+ LOG_LEVEL_DEBUG => Logger::DEBUG
61
+ }
62
+ GLIB_TO_SEVERITY.default = Logger::UNKNOWN
63
+
64
+ # nil being the default
65
+ @glib_log_domain = nil
66
+ @glib_log_handler_id = 0
67
+
68
+ # module-level, so it's not GCd away
69
+ LOG_HANDLER = Proc.new do |domain, level, message, user_data|
70
+ @logger.log(GLIB_TO_SEVERITY[level], message, domain)
71
+ end
72
+
73
+ def self.remove_log_handler
74
+ if @glib_log_handler_id != 0 && @glib_log_domain
75
+ g_log_remove_handler @glib_log_domain, @glib_log_handler_id
76
+ @glib_log_handler_id = nil
77
+ end
78
+ end
79
+
80
+ def self.set_log_domain domain
81
+ GLib::remove_log_handler
82
+
83
+ @glib_log_domain = domain
84
+
85
+ # forward all glib logging output from this domain to a Ruby logger
86
+ if @glib_log_domain
87
+ # disable this feature for now
88
+ #
89
+ # libvips background worker threads can issue warnings, and
90
+ # since the main thread is blocked waiting for libvips to come back
91
+ # from an ffi call, you get a deadlock on the GIL
92
+ #
93
+ # to fix this, we need a way for g_log() calls from libvips workers
94
+ # to be returned via the main thread
95
+ #
96
+
97
+ # @glib_log_handler_id = g_log_set_handler @glib_log_domain,
98
+ # LOG_LEVEL_DEBUG |
99
+ # LOG_LEVEL_INFO |
100
+ # LOG_LEVEL_MESSAGE |
101
+ # LOG_LEVEL_WARNING |
102
+ # LOG_LEVEL_ERROR |
103
+ # LOG_LEVEL_CRITICAL |
104
+ # LOG_FLAG_FATAL | LOG_FLAG_RECURSION,
105
+ # LOG_HANDLER, nil
106
+
107
+ # we must remove any handlers on exit, since libvips may log stuff
108
+ # on shutdown and we don't want LOG_HANDLER to be invoked
109
+ # after Ruby has gone
110
+ at_exit {
111
+ GLib::remove_log_handler
112
+ }
113
+ end
114
+
115
+ end
116
+
117
+ end
118
+
119
+ module GObject
120
+ extend FFI::Library
121
+
122
+ if FFI::Platform.windows?
123
+ gobject_libname = 'libgobject-2.0-0.dll'
124
+ else
125
+ gobject_libname = 'gobject-2.0'
126
+ end
127
+
128
+ ffi_lib gobject_libname
129
+
130
+ # we can't just use ulong, windows has different int sizing rules
131
+ if FFI::Platform::ADDRESS_SIZE == 64
132
+ typedef :uint64, :GType
133
+ else
134
+ typedef :uint32, :GType
135
+ end
136
+
137
+ attach_function :g_type_init, [], :void
138
+ attach_function :g_type_name, [:GType], :string
139
+ attach_function :g_type_from_name, [:string], :GType
140
+ attach_function :g_type_fundamental, [:GType], :GType
141
+
142
+ # glib before 2.36 needed this, does nothing in current glib
143
+ g_type_init
144
+
145
+ # look up some common gtypes
146
+ GBOOL_TYPE = g_type_from_name "gboolean"
147
+ GINT_TYPE = g_type_from_name "gint"
148
+ GUINT64_TYPE = g_type_from_name "guint64"
149
+ GDOUBLE_TYPE = g_type_from_name "gdouble"
150
+ GENUM_TYPE = g_type_from_name "GEnum"
151
+ GFLAGS_TYPE = g_type_from_name "GFlags"
152
+ GSTR_TYPE = g_type_from_name "gchararray"
153
+ GOBJECT_TYPE = g_type_from_name "GObject"
154
+
155
+ end
156
+
157
+ require 'vips/gobject'
158
+ require 'vips/gvalue'
159
+
160
+ # This module provides a binding for the [libvips image processing
161
+ # library](https://jcupitt.github.io/libvips/).
162
+ #
163
+ # # Example
164
+ #
165
+ # ```ruby
166
+ # require 'vips'
167
+ #
168
+ # if ARGV.length < 2
169
+ # raise "usage: #{$PROGRAM_NAME}: input-file output-file"
170
+ # end
171
+ #
172
+ # im = Vips::Image.new_from_file ARGV[0], access: :sequential
173
+ #
174
+ # im *= [1, 2, 1]
175
+ #
176
+ # mask = Vips::Image.new_from_array [
177
+ # [-1, -1, -1],
178
+ # [-1, 16, -1],
179
+ # [-1, -1, -1]
180
+ # ], 8
181
+ # im = im.conv mask, precision: :integer
182
+ #
183
+ # im.write_to_file ARGV[1]
184
+ # ```
185
+ #
186
+ # This example loads a file, boosts the green channel (I'm not sure why),
187
+ # sharpens the image, and saves it back to disc again.
188
+ #
189
+ # Reading this example line by line, we have:
190
+ #
191
+ # ```ruby
192
+ # im = Vips::Image.new_from_file ARGV[0], access: :sequential
193
+ # ```
194
+ #
195
+ # {Image.new_from_file} can load any image file supported by vips. In this
196
+ # example, we will be accessing pixels top-to-bottom as we sweep through the
197
+ # image reading and writing, so `:sequential` access mode is best for us. The
198
+ # default mode is `:random`: this allows for full random access to image pixels,
199
+ # but is slower and needs more memory. See {Access}
200
+ # for full details
201
+ # on the various modes available.
202
+ #
203
+ # You can also load formatted images from
204
+ # memory buffers, create images that wrap C-style memory arrays, or make images
205
+ # from constants.
206
+ #
207
+ # The next line:
208
+ #
209
+ # ```ruby
210
+ # im *= [1, 2, 1]
211
+ # ```
212
+ #
213
+ # Multiplying the image by an array constant uses one array element for each
214
+ # image band. This line assumes that the input image has three bands and will
215
+ # double the middle band. For RGB images, that's doubling green.
216
+ #
217
+ # Next we have:
218
+ #
219
+ # ```ruby
220
+ # mask = Vips::Image.new_from_array [
221
+ # [-1, -1, -1],
222
+ # [-1, 16, -1],
223
+ # [-1, -1, -1]
224
+ # ], 8
225
+ # im = im.conv mask, precision: :integer
226
+ # ```
227
+ #
228
+ # {Image.new_from_array} creates an image from an array constant. The 8 at
229
+ # the end sets the scale: the amount to divide the image by after
230
+ # integer convolution.
231
+ #
232
+ # See the libvips API docs for `vips_conv()` (the operation
233
+ # invoked by {Image#conv}) for details on the convolution operator. By default,
234
+ # it computes with a float mask, but `:integer` is fine for this case, and is
235
+ # much faster.
236
+ #
237
+ # Finally:
238
+ #
239
+ # ```ruby
240
+ # im.write_to_file ARGV[1]
241
+ # ```
242
+ #
243
+ # {Image#write_to_file} writes an image back to the filesystem. It can
244
+ # write any format supported by vips: the file type is set from the filename
245
+ # suffix. You can also write formatted images to memory buffers, or dump
246
+ # image data to a raw memory array.
247
+ #
248
+ # # How it works
249
+ #
250
+ # The binding uses [ruby-ffi](https://github.com/ffi/ffi) to open the libvips
251
+ # shared library. When you call a method on the image class, it uses libvips
252
+ # introspection system (based on GObject) to search the
253
+ # library for an operation of that name, transforms the arguments to a form
254
+ # libvips can digest, and runs the operation.
255
+ #
256
+ # This means ruby-vips always presents the API implemented by the libvips shared
257
+ # library. It should update itself as new features are added.
258
+ #
259
+ # # Automatic wrapping
260
+ #
261
+ # `ruby-vips` adds a {Image.method_missing} handler to {Image} and uses
262
+ # it to look up vips operations. For example, the libvips operation `add`, which
263
+ # appears in C as `vips_add()`, appears in Ruby as {Image#add}.
264
+ #
265
+ # The operation's list of required arguments is searched and the first input
266
+ # image is set to the value of `self`. Operations which do not take an input
267
+ # image, such as {Image.black}, appear as class methods. The remainder of
268
+ # the arguments you supply in the function call are used to set the other
269
+ # required input arguments. Any trailing keyword arguments are used to set
270
+ # options on the operation.
271
+ #
272
+ # The result is the required output
273
+ # argument if there is only one result, or an array of values if the operation
274
+ # produces several results. If the operation has optional output objects, they
275
+ # are returned as a final hash.
276
+ #
277
+ # For example, {Image#min}, the vips operation that searches an image for
278
+ # the minimum value, has a large number of optional arguments. You can use it to
279
+ # find the minimum value like this:
280
+ #
281
+ # ```ruby
282
+ # min_value = image.min
283
+ # ```
284
+ #
285
+ # You can ask it to return the position of the minimum with `:x` and `:y`.
286
+ #
287
+ # ```ruby
288
+ # min_value, opts = min x: true, y: true
289
+ # x_pos = opts['x']
290
+ # y_pos = opts['y']
291
+ # ```
292
+ #
293
+ # Now `x_pos` and `y_pos` will have the coordinates of the minimum value.
294
+ # There's actually a convenience method for this, {Image#minpos}.
295
+ #
296
+ # You can also ask for the top *n* minimum, for example:
297
+ #
298
+ # ```ruby
299
+ # min_value, opts = min size: 10, x_array: true, y_array: true
300
+ # x_pos = opts['x_array']
301
+ # y_pos = opts['y_array']
302
+ # ```
303
+ #
304
+ # Now `x_pos` and `y_pos` will be 10-element arrays.
305
+ #
306
+ # Because operations are member functions and return the result image, you can
307
+ # chain them. For example, you can write:
308
+ #
309
+ # ```ruby
310
+ # result_image = image.real.cos
311
+ # ```
312
+ #
313
+ # to calculate the cosine of the real part of a complex image.
314
+ # There are also a full set
315
+ # of arithmetic operator overloads, see below.
316
+ #
317
+ # libvips types are also automatically wrapped. The override looks at the type
318
+ # of argument required by the operation and converts the value you supply,
319
+ # when it can. For example, {Image#linear} takes a `VipsArrayDouble` as
320
+ # an argument
321
+ # for the set of constants to use for multiplication. You can supply this
322
+ # value as an integer, a float, or some kind of compound object and it
323
+ # will be converted for you. You can write:
324
+ #
325
+ # ```ruby
326
+ # result_image = image.linear 1, 3
327
+ # result_image = image.linear 12.4, 13.9
328
+ # result_image = image.linear [1, 2, 3], [4, 5, 6]
329
+ # result_image = image.linear 1, [4, 5, 6]
330
+ # ```
331
+ #
332
+ # And so on. A set of overloads are defined for {Image#linear}, see below.
333
+ #
334
+ # It does a couple of more ambitious conversions. It will automatically convert
335
+ # to and from the various vips types, like `VipsBlob` and `VipsArrayImage`. For
336
+ # example, you can read the ICC profile out of an image like this:
337
+ #
338
+ # ```ruby
339
+ # profile = im.get_value "icc-profile-data"
340
+ # ```
341
+ #
342
+ # and profile will be a byte array.
343
+ #
344
+ # If an operation takes several input images, you can use a constant for all but
345
+ # one of them and the wrapper will expand the constant to an image for you. For
346
+ # example, {Image#ifthenelse} uses a condition image to pick pixels
347
+ # between a then and an else image:
348
+ #
349
+ # ```ruby
350
+ # result_image = condition_image.ifthenelse then_image, else_image
351
+ # ```
352
+ #
353
+ # You can use a constant instead of either the then or the else parts and it
354
+ # will be expanded to an image for you. If you use a constant for both then and
355
+ # else, it will be expanded to match the condition image. For example:
356
+ #
357
+ # ```ruby
358
+ # result_image = condition_image.ifthenelse [0, 255, 0], [255, 0, 0]
359
+ # ```
360
+ #
361
+ # Will make an image where true pixels are green and false pixels are red.
362
+ #
363
+ # This is useful for {Image#bandjoin}, the thing to join two or more
364
+ # images up bandwise. You can write:
365
+ #
366
+ # ```ruby
367
+ # rgba = rgb.bandjoin 255
368
+ # ```
369
+ #
370
+ # to append a constant 255 band to an image, perhaps to add an alpha channel. Of
371
+ # course you can also write:
372
+ #
373
+ # ```ruby
374
+ # result_image = image1.bandjoin image2
375
+ # result_image = image1.bandjoin [image2, image3]
376
+ # result_image = Vips::Image.bandjoin [image1, image2, image3]
377
+ # result_image = image1.bandjoin [image2, 255]
378
+ # ```
379
+ #
380
+ # and so on.
381
+ #
382
+ # # Logging
383
+ #
384
+ # Libvips uses g_log() to log warning, debug, info and (some) error messages.
385
+ #
386
+ # https://developer.gnome.org/glib/stable/glib-Message-Logging.html
387
+ #
388
+ # You can disable wanrings by defining the `VIPS_WARNING` environment variable.
389
+ # You can enable info output by defining `VIPS_INFO`.
390
+ #
391
+ # # Exceptions
392
+ #
393
+ # The wrapper spots errors from vips operations and raises the {Vips::Error}
394
+ # exception. You can catch it in the usual way.
395
+ #
396
+ # # Automatic YARD documentation
397
+ #
398
+ # The bulk of these API docs are generated automatically by
399
+ # {Vips::generate_yard}. It examines
400
+ # libvips and writes a summary of each operation and the arguments and options
401
+ # that that operation expects.
402
+ #
403
+ # Use the [C API
404
+ # docs](https://jcupitt.github.io/libvips/API/current)
405
+ # for more detail.
406
+ #
407
+ # # Enums
408
+ #
409
+ # The libvips enums, such as `VipsBandFormat` appear in ruby-vips as Symbols
410
+ # like `:uchar`. They are documented as a set of classes for convenience, see
411
+ # the class list.
412
+ #
413
+ # # Draw operations
414
+ #
415
+ # Paint operations like {Image#draw_circle} and {Image#draw_line}
416
+ # modify their input image. This
417
+ # makes them hard to use with the rest of libvips: you need to be very careful
418
+ # about the order in which operations execute or you can get nasty crashes.
419
+ #
420
+ # The wrapper spots operations of this type and makes a private copy of the
421
+ # image in memory before calling the operation. This stops crashes, but it does
422
+ # make it inefficient. If you draw 100 lines on an image, for example, you'll
423
+ # copy the image 100 times. The wrapper does make sure that memory is recycled
424
+ # where possible, so you won't have 100 copies in memory.
425
+ #
426
+ # If you want to avoid the copies, you'll need to call drawing operations
427
+ # yourself.
428
+ #
429
+ # # Overloads
430
+ #
431
+ # The wrapper defines the usual set of arithmetic, boolean and relational
432
+ # overloads on image. You can mix images, constants and lists of constants
433
+ # (almost) freely. For example, you can write:
434
+ #
435
+ # ```ruby
436
+ # result_image = ((image * [1, 2, 3]).abs < 128) | 4
437
+ # ```
438
+ #
439
+ # # Expansions
440
+ #
441
+ # Some vips operators take an enum to select an action, for example
442
+ # {Image#math} can be used to calculate sine of every pixel like this:
443
+ #
444
+ # ```ruby
445
+ # result_image = image.math :sin
446
+ # ```
447
+ #
448
+ # This is annoying, so the wrapper expands all these enums into separate members
449
+ # named after the enum. So you can write:
450
+ #
451
+ # ```ruby
452
+ # result_image = image.sin
453
+ # ```
454
+ #
455
+ # # Convenience functions
456
+ #
457
+ # The wrapper defines a few extra useful utility functions:
458
+ # {Image#get_value}, {Image#set_value}, {Image#bandsplit},
459
+ # {Image#maxpos}, {Image#minpos},
460
+ # {Image#median}.
461
+
462
+ module Vips
463
+ extend FFI::Library
464
+
465
+ if FFI::Platform.windows?
466
+ vips_libname = 'libvips-42.dll'
467
+ else
468
+ vips_libname = File.expand_path('libvips.so', __dir__)
469
+ end
470
+
471
+ ffi_lib vips_libname
472
+
473
+ LOG_DOMAIN = "VIPS"
474
+ GLib::set_log_domain LOG_DOMAIN
475
+
476
+ typedef :ulong, :GType
477
+
478
+ attach_function :vips_error_buffer, [], :string
479
+ attach_function :vips_error_clear, [], :void
480
+
481
+ # The ruby-vips error class.
482
+ class Error < RuntimeError
483
+ # @param msg [String] The error message. If this is not supplied, grab
484
+ # and clear the vips error buffer and use that.
485
+ def initialize msg = nil
486
+ if msg
487
+ @details = msg
488
+ elsif Vips::vips_error_buffer != ""
489
+ @details = Vips::vips_error_buffer
490
+ Vips::vips_error_clear
491
+ else
492
+ @details = nil
493
+ end
494
+ end
495
+
496
+ # Pretty-print a {Vips::Error}.
497
+ #
498
+ # @return [String] The error message
499
+ def to_s
500
+ if @details != nil
501
+ @details
502
+ else
503
+ super.to_s
504
+ end
505
+ end
506
+ end
507
+
508
+ attach_function :vips_init, [:string], :int
509
+
510
+ if Vips::vips_init($0) != 0
511
+ throw Vips::get_error
512
+ end
513
+
514
+ # don't use at_exit to call vips_shutdown, it causes problems with fork, and
515
+ # in any case libvips does this for us
516
+
517
+ attach_function :vips_leak_set, [:int], :void
518
+ attach_function :vips_vector_set_enabled, [:int], :void
519
+ attach_function :vips_concurrency_set, [:int], :void
520
+
521
+ # Turn libvips leak testing on and off. Handy for debugging ruby-vips, not
522
+ # very useful for user code.
523
+ def self.leak_set leak
524
+ vips_leak_set (leak ? 1 : 0)
525
+ end
526
+
527
+ attach_function :vips_cache_set_max, [:int], :void
528
+ attach_function :vips_cache_set_max_mem, [:int], :void
529
+ attach_function :vips_cache_set_max_files, [:int], :void
530
+
531
+ # Set the maximum number of operations that libvips should cache. Set 0 to
532
+ # disable the operation cache. The default is 1000.
533
+ def self.cache_set_max size
534
+ vips_cache_set_max size
535
+ end
536
+
537
+ # Set the maximum amount of memory that libvips should use for the operation
538
+ # cache. Set 0 to disable the operation cache. The default is 100mb.
539
+ def self.cache_set_max_mem size
540
+ vips_cache_set_max_mem size
541
+ end
542
+
543
+ # Set the maximum number of files libvips should keep open in the
544
+ # operation cache. Set 0 to disable the operation cache. The default is
545
+ # 100.
546
+ def self.cache_set_max_files size
547
+ vips_cache_set_max_files size
548
+ end
549
+
550
+ # Set the size of the libvips worker pool. This defaults to the number of
551
+ # hardware threads on your computer. Set to 1 to disable threading.
552
+ def self.concurrency_set n
553
+ vips_concurrency_set n
554
+ end
555
+
556
+ # Enable or disable SIMD and the run-time compiler. This can give a nice
557
+ # speed-up, but can also be unstable on some systems or with some versions
558
+ # of the run-time compiler.
559
+ def self.vector_set enabled
560
+ vips_vector_set_enabled(enabled ? 1 : 0)
561
+ end
562
+
563
+ # Deprecated compatibility function.
564
+ #
565
+ # Don't use this, instead change GLib::logger.level.
566
+ def self.set_debug debug
567
+ if debug
568
+ GLib::logger.level = Logger::DEBUG
569
+ end
570
+ end
571
+
572
+ attach_function :version, :vips_version, [:int], :int
573
+ attach_function :version_string, :vips_version_string, [], :string
574
+
575
+ # True if this is at least libvips x.y
576
+ def self.at_least_libvips?(x, y)
577
+ major = version(0)
578
+ minor = version(1)
579
+
580
+ major > x || (major == x && minor >= y)
581
+ end
582
+
583
+ LIBRARY_VERSION = Vips::version_string
584
+
585
+ # libvips has this arbitrary number as a sanity-check upper bound on image
586
+ # size. It's sometimes useful for know whan calculating image ratios.
587
+ MAX_COORD = 10000000
588
+
589
+ end
590
+
591
+ require 'vips/object'
592
+ require 'vips/operation'
593
+ require 'vips/image'
594
+ require 'vips/interpolate'
595
+ require 'vips/version'
596
+
597
+