ruby-vips 2.0.13 → 2.0.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +10 -0
  3. data/.rubocop_todo.yml +730 -0
  4. data/.travis.yml +13 -6
  5. data/CHANGELOG.md +8 -0
  6. data/README.md +5 -8
  7. data/Rakefile +6 -0
  8. data/VERSION +1 -1
  9. data/example/annotate.rb +2 -2
  10. data/example/daltonize8.rb +14 -14
  11. data/example/example2.rb +6 -6
  12. data/example/example3.rb +5 -5
  13. data/example/example4.rb +4 -4
  14. data/example/example5.rb +2 -2
  15. data/example/inheritance_with_refcount.rb +207 -207
  16. data/example/thumb.rb +10 -10
  17. data/example/trim8.rb +2 -2
  18. data/example/watermark.rb +14 -35
  19. data/example/wobble.rb +24 -24
  20. data/install-vips.sh +1 -1
  21. data/lib/vips.rb +335 -306
  22. data/lib/vips/access.rb +9 -9
  23. data/lib/vips/align.rb +7 -7
  24. data/lib/vips/angle.rb +8 -8
  25. data/lib/vips/angle45.rb +12 -12
  26. data/lib/vips/bandformat.rb +16 -16
  27. data/lib/vips/blend_mode.rb +34 -0
  28. data/lib/vips/coding.rb +11 -11
  29. data/lib/vips/compass_direction.rb +13 -13
  30. data/lib/vips/direction.rb +7 -7
  31. data/lib/vips/extend.rb +13 -13
  32. data/lib/vips/gobject.rb +94 -94
  33. data/lib/vips/gvalue.rb +232 -232
  34. data/lib/vips/image.rb +1329 -1335
  35. data/lib/vips/interesting.rb +10 -10
  36. data/lib/vips/interpolate.rb +51 -51
  37. data/lib/vips/interpretation.rb +25 -25
  38. data/lib/vips/kernel.rb +18 -18
  39. data/lib/vips/methods.rb +463 -283
  40. data/lib/vips/object.rb +208 -208
  41. data/lib/vips/operation.rb +323 -323
  42. data/lib/vips/operationboolean.rb +10 -10
  43. data/lib/vips/operationcomplex.rb +8 -8
  44. data/lib/vips/operationcomplex2.rb +6 -6
  45. data/lib/vips/operationcomplexget.rb +7 -7
  46. data/lib/vips/operationmath.rb +14 -14
  47. data/lib/vips/operationmath2.rb +6 -6
  48. data/lib/vips/operationrelational.rb +11 -11
  49. data/lib/vips/operationround.rb +7 -7
  50. data/lib/vips/size.rb +9 -9
  51. data/lib/vips/version.rb +1 -1
  52. data/ruby-vips.gemspec +6 -2
  53. metadata +29 -6
@@ -7,25 +7,25 @@
7
7
  require 'vips'
8
8
 
9
9
  # benchmark thumbnail via a memory buffer
10
- def via_memory(filename, thumbnail_width)
11
- data = IO.binread(filename)
10
+ def via_memory(filename, thumbnail_width)
11
+ data = IO.binread(filename)
12
12
 
13
- thumb = Vips::Image.thumbnail_buffer data, thumbnail_width, crop: 'centre'
13
+ thumb = Vips::Image.thumbnail_buffer data, thumbnail_width, crop: 'centre'
14
14
 
15
- thumb.write_to_buffer '.jpg'
15
+ thumb.write_to_buffer '.jpg'
16
16
  end
17
17
 
18
18
  # benchmark thumbnail via files
19
- def via_files(filename, thumbnail_width)
20
- thumb = Vips::Image.thumbnail filename, thumbnail_width, crop: 'centre'
19
+ def via_files(filename, thumbnail_width)
20
+ thumb = Vips::Image.thumbnail filename, thumbnail_width, crop: 'centre'
21
21
 
22
- thumb.write_to_buffer '.jpg'
22
+ thumb.write_to_buffer '.jpg'
23
23
  end
24
24
 
25
25
  ARGV.each do |filename|
26
- puts "processing #{filename} ..."
27
- thumb = via_memory(filename, 500)
28
- # thumb = via_files(filename, 500)
26
+ puts "processing #{filename} ..."
27
+ thumb = via_memory(filename, 500)
28
+ # thumb = via_files(filename, 500)
29
29
  end
30
30
 
31
31
 
@@ -11,11 +11,11 @@ require 'vips'
11
11
 
12
12
  im = Vips::Image.new_from_file ARGV[0]
13
13
 
14
- # find the value of the pixel at (0, 0) ... we will search for all pixels
14
+ # find the value of the pixel at (0, 0) ... we will search for all pixels
15
15
  # significantly different from this
16
16
  background = im.getpoint(0, 0)
17
17
 
18
- # we need to smooth the image, subtract the background from every pixel, take
18
+ # we need to smooth the image, subtract the background from every pixel, take
19
19
  # the absolute value of the difference, then threshold
20
20
  mask = (im.median - background).abs > 10
21
21
 
@@ -1,44 +1,23 @@
1
1
  #!/usr/bin/ruby
2
2
 
3
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
4
+
5
+ im = Vips::Image.new_from_file ARGV[0], access: :sequential
6
+
7
+ # make the text mask
8
+ text = Vips::Image.text ARGV[2], width: 200, dpi: 200, font: 'sans bold'
9
+ text = text.rotate(-45)
10
+ # make the text transparent
8
11
  text = (text * 0.3).cast(:uchar)
9
- text = text.embed 100, 100, text.width + 200, text.width + 200
12
+ text = text.gravity :centre, 200, 200
10
13
  text = text.replicate 1 + im.width / text.width, 1 + im.height / text.height
11
14
  text = text.crop 0, 0, im.width, im.height
12
15
 
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
16
+ # we make a constant colour image and attach the text mask as the alpha
17
+ overlay = (text.new_from_image [255, 128, 128]).copy interpretation: :srgb
18
+ overlay = overlay.bandjoin text
38
19
 
39
- marked = text.ifthenelse text_colour, im, :blend => true
20
+ # overlay the text
21
+ im = im.composite overlay, :over
40
22
 
41
- # reattach alpha
42
- marked = marked.bandjoin alpha if alpha
43
-
44
- marked.write_to_file ARGV[1]
23
+ im.write_to_file ARGV[1]
@@ -5,31 +5,31 @@ require 'vips'
5
5
  image = Vips::Image.new_from_file ARGV[0]
6
6
 
7
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
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
32
31
  end
32
+ end
33
33
  end
34
34
 
35
35
  image = image.wobble
@@ -1,6 +1,6 @@
1
1
  #!/bin/bash
2
2
 
3
- vips_site=https://github.com/jcupitt/libvips/releases/download
3
+ vips_site=https://github.com/libvips/libvips/releases/download
4
4
  version=$VIPS_VERSION_MAJOR.$VIPS_VERSION_MINOR.$VIPS_VERSION_MICRO
5
5
 
6
6
  set -e
@@ -7,157 +7,157 @@
7
7
  require 'ffi'
8
8
  require 'logger'
9
9
 
10
- # This module uses FFI to make a simple layer over the glib and gobject
11
- # libraries.
10
+ # This module uses FFI to make a simple layer over the glib and gobject
11
+ # libraries.
12
12
 
13
13
  module GLib
14
- class << self
15
- attr_accessor :logger
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
16
77
  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
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 {
81
111
  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
-
112
+ }
115
113
  end
116
114
 
115
+ end
116
+
117
117
  end
118
118
 
119
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"
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
154
 
155
155
  end
156
156
 
157
157
  require 'vips/gobject'
158
158
  require 'vips/gvalue'
159
159
 
160
- # This module provides a binding for the [libvips image processing
160
+ # This module provides a binding for the [libvips image processing
161
161
  # library](https://jcupitt.github.io/libvips/).
162
162
  #
163
163
  # # Example
@@ -183,8 +183,8 @@ require 'vips/gvalue'
183
183
  # im.write_to_file ARGV[1]
184
184
  # ```
185
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.
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
188
  #
189
189
  # Reading this example line by line, we have:
190
190
  #
@@ -198,9 +198,9 @@ require 'vips/gvalue'
198
198
  # default mode is `:random`: this allows for full random access to image pixels,
199
199
  # but is slower and needs more memory. See {Access}
200
200
  # for full details
201
- # on the various modes available.
201
+ # on the various modes available.
202
202
  #
203
- # You can also load formatted images from
203
+ # You can also load formatted images from
204
204
  # memory buffers, create images that wrap C-style memory arrays, or make images
205
205
  # from constants.
206
206
  #
@@ -226,13 +226,13 @@ require 'vips/gvalue'
226
226
  # ```
227
227
  #
228
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.
229
+ # the end sets the scale: the amount to divide the image by after
230
+ # integer convolution.
231
231
  #
232
232
  # See the libvips API docs for `vips_conv()` (the operation
233
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.
234
+ # it computes with a float mask, but `:integer` is fine for this case, and is
235
+ # much faster.
236
236
  #
237
237
  # Finally:
238
238
  #
@@ -240,10 +240,10 @@ require 'vips/gvalue'
240
240
  # im.write_to_file ARGV[1]
241
241
  # ```
242
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.
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
247
  #
248
248
  # # How it works
249
249
  #
@@ -251,30 +251,30 @@ require 'vips/gvalue'
251
251
  # shared library. When you call a method on the image class, it uses libvips
252
252
  # introspection system (based on GObject) to search the
253
253
  # library for an operation of that name, transforms the arguments to a form
254
- # libvips can digest, and runs the operation.
254
+ # libvips can digest, and runs the operation.
255
255
  #
256
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.
257
+ # library. It should update itself as new features are added.
258
258
  #
259
259
  # # Automatic wrapping
260
260
  #
261
261
  # `ruby-vips` adds a {Image.method_missing} handler to {Image} and uses
262
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}.
263
+ # appears in C as `vips_add()`, appears in Ruby as {Image#add}.
264
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
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
267
  # image, such as {Image.black}, appear as class methods. The remainder of
268
268
  # the arguments you supply in the function call are used to set the other
269
269
  # required input arguments. Any trailing keyword arguments are used to set
270
270
  # options on the operation.
271
- #
272
- # The result is the required output
271
+ #
272
+ # The result is the required output
273
273
  # argument if there is only one result, or an array of values if the operation
274
274
  # produces several results. If the operation has optional output objects, they
275
275
  # are returned as a final hash.
276
276
  #
277
- # For example, {Image#min}, the vips operation that searches an image for
277
+ # For example, {Image#min}, the vips operation that searches an image for
278
278
  # the minimum value, has a large number of optional arguments. You can use it to
279
279
  # find the minimum value like this:
280
280
  #
@@ -283,14 +283,14 @@ require 'vips/gvalue'
283
283
  # ```
284
284
  #
285
285
  # You can ask it to return the position of the minimum with `:x` and `:y`.
286
- #
286
+ #
287
287
  # ```ruby
288
288
  # min_value, opts = min x: true, y: true
289
289
  # x_pos = opts['x']
290
290
  # y_pos = opts['y']
291
291
  # ```
292
292
  #
293
- # Now `x_pos` and `y_pos` will have the coordinates of the minimum value.
293
+ # Now `x_pos` and `y_pos` will have the coordinates of the minimum value.
294
294
  # There's actually a convenience method for this, {Image#minpos}.
295
295
  #
296
296
  # You can also ask for the top *n* minimum, for example:
@@ -301,7 +301,7 @@ require 'vips/gvalue'
301
301
  # y_pos = opts['y_array']
302
302
  # ```
303
303
  #
304
- # Now `x_pos` and `y_pos` will be 10-element arrays.
304
+ # Now `x_pos` and `y_pos` will be 10-element arrays.
305
305
  #
306
306
  # Because operations are member functions and return the result image, you can
307
307
  # chain them. For example, you can write:
@@ -310,30 +310,30 @@ require 'vips/gvalue'
310
310
  # result_image = image.real.cos
311
311
  # ```
312
312
  #
313
- # to calculate the cosine of the real part of a complex image.
313
+ # to calculate the cosine of the real part of a complex image.
314
314
  # There are also a full set
315
315
  # of arithmetic operator overloads, see below.
316
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
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
323
  # will be converted for you. You can write:
324
324
  #
325
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]
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
330
  # ```
331
331
  #
332
332
  # And so on. A set of overloads are defined for {Image#linear}, see below.
333
333
  #
334
334
  # It does a couple of more ambitious conversions. It will automatically convert
335
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:
336
+ # example, you can read the ICC profile out of an image like this:
337
337
  #
338
338
  # ```ruby
339
339
  # profile = im.get_value "icc-profile-data"
@@ -343,7 +343,7 @@ require 'vips/gvalue'
343
343
  #
344
344
  # If an operation takes several input images, you can use a constant for all but
345
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
346
+ # example, {Image#ifthenelse} uses a condition image to pick pixels
347
347
  # between a then and an else image:
348
348
  #
349
349
  # ```ruby
@@ -360,7 +360,7 @@ require 'vips/gvalue'
360
360
  #
361
361
  # Will make an image where true pixels are green and false pixels are red.
362
362
  #
363
- # This is useful for {Image#bandjoin}, the thing to join two or more
363
+ # This is useful for {Image#bandjoin}, the thing to join two or more
364
364
  # images up bandwise. You can write:
365
365
  #
366
366
  # ```ruby
@@ -377,39 +377,39 @@ require 'vips/gvalue'
377
377
  # result_image = image1.bandjoin [image2, 255]
378
378
  # ```
379
379
  #
380
- # and so on.
380
+ # and so on.
381
381
  #
382
382
  # # Logging
383
383
  #
384
- # Libvips uses g_log() to log warning, debug, info and (some) error messages.
384
+ # Libvips uses g_log() to log warning, debug, info and (some) error messages.
385
385
  #
386
386
  # https://developer.gnome.org/glib/stable/glib-Message-Logging.html
387
387
  #
388
388
  # You can disable wanrings by defining the `VIPS_WARNING` environment variable.
389
- # You can enable info output by defining `VIPS_INFO`.
389
+ # You can enable info output by defining `VIPS_INFO`.
390
390
  #
391
391
  # # Exceptions
392
392
  #
393
393
  # The wrapper spots errors from vips operations and raises the {Vips::Error}
394
- # exception. You can catch it in the usual way.
394
+ # exception. You can catch it in the usual way.
395
395
  #
396
396
  # # Automatic YARD documentation
397
397
  #
398
- # The bulk of these API docs are generated automatically by
398
+ # The bulk of these API docs are generated automatically by
399
399
  # {Vips::generate_yard}. It examines
400
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)
401
+ # that that operation expects.
402
+ #
403
+ # Use the [C API
404
+ # docs](https://jcupitt.github.io/libvips/API/current)
405
405
  # for more detail.
406
406
  #
407
407
  # # Enums
408
408
  #
409
409
  # The libvips enums, such as `VipsBandFormat` appear in ruby-vips as Symbols
410
410
  # like `:uchar`. They are documented as a set of classes for convenience, see
411
- # the class list.
412
- #
411
+ # the class list.
412
+ #
413
413
  # # Draw operations
414
414
  #
415
415
  # Paint operations like {Image#draw_circle} and {Image#draw_line}
@@ -421,7 +421,7 @@ require 'vips/gvalue'
421
421
  # image in memory before calling the operation. This stops crashes, but it does
422
422
  # make it inefficient. If you draw 100 lines on an image, for example, you'll
423
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.
424
+ # where possible, so you won't have 100 copies in memory.
425
425
  #
426
426
  # If you want to avoid the copies, you'll need to call drawing operations
427
427
  # yourself.
@@ -438,7 +438,7 @@ require 'vips/gvalue'
438
438
  #
439
439
  # # Expansions
440
440
  #
441
- # Some vips operators take an enum to select an action, for example
441
+ # Some vips operators take an enum to select an action, for example
442
442
  # {Image#math} can be used to calculate sine of every pixel like this:
443
443
  #
444
444
  # ```ruby
@@ -454,137 +454,166 @@ require 'vips/gvalue'
454
454
  #
455
455
  # # Convenience functions
456
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},
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
460
  # {Image#median}.
461
461
 
462
462
  module Vips
463
- extend FFI::Library
464
-
465
- if FFI::Platform.windows?
466
- vips_libname = 'libvips-42.dll'
467
- else
468
- vips_libname = 'vips'
463
+ extend FFI::Library
464
+
465
+ if FFI::Platform.windows?
466
+ vips_libname = 'libvips-42.dll'
467
+ else
468
+ vips_libname = 'vips'
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
469
494
  end
470
495
 
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
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
548
505
  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
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
+ # vips_foreign_get_suffixes was added in libvips 8.8
522
+ begin
523
+ attach_function :vips_foreign_get_suffixes, [], :pointer
524
+ rescue FFI::NotFoundError
525
+ nil
526
+ end
527
+
528
+ # Turn libvips leak testing on and off. Handy for debugging ruby-vips, not
529
+ # very useful for user code.
530
+ def self.leak_set leak
531
+ vips_leak_set (leak ? 1 : 0)
532
+ end
533
+
534
+ attach_function :vips_cache_set_max, [:int], :void
535
+ attach_function :vips_cache_set_max_mem, [:int], :void
536
+ attach_function :vips_cache_set_max_files, [:int], :void
537
+
538
+ # Set the maximum number of operations that libvips should cache. Set 0 to
539
+ # disable the operation cache. The default is 1000.
540
+ def self.cache_set_max size
541
+ vips_cache_set_max size
542
+ end
543
+
544
+ # Set the maximum amount of memory that libvips should use for the operation
545
+ # cache. Set 0 to disable the operation cache. The default is 100mb.
546
+ def self.cache_set_max_mem size
547
+ vips_cache_set_max_mem size
548
+ end
549
+
550
+ # Set the maximum number of files libvips should keep open in the
551
+ # operation cache. Set 0 to disable the operation cache. The default is
552
+ # 100.
553
+ def self.cache_set_max_files size
554
+ vips_cache_set_max_files size
555
+ end
556
+
557
+ # Set the size of the libvips worker pool. This defaults to the number of
558
+ # hardware threads on your computer. Set to 1 to disable threading.
559
+ def self.concurrency_set n
560
+ vips_concurrency_set n
561
+ end
562
+
563
+ # Enable or disable SIMD and the run-time compiler. This can give a nice
564
+ # speed-up, but can also be unstable on some systems or with some versions
565
+ # of the run-time compiler.
566
+ def self.vector_set enabled
567
+ vips_vector_set_enabled(enabled ? 1 : 0)
568
+ end
569
+
570
+ # Deprecated compatibility function.
571
+ #
572
+ # Don't use this, instead change GLib::logger.level.
573
+ def self.set_debug debug
574
+ if debug
575
+ GLib::logger.level = Logger::DEBUG
554
576
  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)
577
+ end
578
+
579
+ attach_function :version, :vips_version, [:int], :int
580
+ attach_function :version_string, :vips_version_string, [], :string
581
+
582
+ # True if this is at least libvips x.y
583
+ def self.at_least_libvips?(x, y)
584
+ major = version(0)
585
+ minor = version(1)
586
+
587
+ major > x || (major == x && minor >= y)
588
+ end
589
+
590
+ # Get a list of all supported file suffixes.
591
+ #
592
+ # @return [[String]] array of supported suffixes
593
+ def self.get_suffixes
594
+ # vips_foreign_get_suffixes() was added in libvips 8.8
595
+ return [] unless Vips.respond_to? :vips_foreign_get_suffixes
596
+
597
+ array = Vips::vips_foreign_get_suffixes
598
+
599
+ names = []
600
+ p = array
601
+ until (q = p.read_pointer).null?
602
+ suff = q.read_string
603
+ GLib::g_free q
604
+ names << suff unless names.include? suff
605
+ p += FFI::Type::POINTER.size
561
606
  end
607
+ GLib::g_free array
562
608
 
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
609
+ names
610
+ end
582
611
 
583
- LIBRARY_VERSION = Vips::version_string
612
+ LIBRARY_VERSION = Vips::version_string
584
613
 
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
614
+ # libvips has this arbitrary number as a sanity-check upper bound on image
615
+ # size. It's sometimes useful for know whan calculating image ratios.
616
+ MAX_COORD = 10000000
588
617
 
589
618
  end
590
619