vips 8.6.3

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