ruby-vips 2.0.13 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/.github/ISSUE_TEMPLATE/bug_report.md +42 -0
  3. data/.github/workflows/test.yml +80 -0
  4. data/.standard.yml +17 -0
  5. data/.yardopts +0 -1
  6. data/CHANGELOG.md +44 -0
  7. data/Gemfile +3 -1
  8. data/README.md +45 -47
  9. data/Rakefile +13 -15
  10. data/TODO +19 -10
  11. data/VERSION +1 -1
  12. data/example/annotate.rb +7 -7
  13. data/example/connection.rb +26 -0
  14. data/example/daltonize8.rb +27 -29
  15. data/example/draw_lines.rb +30 -0
  16. data/example/example1.rb +5 -6
  17. data/example/example2.rb +11 -11
  18. data/example/example3.rb +9 -9
  19. data/example/example4.rb +8 -8
  20. data/example/example5.rb +8 -9
  21. data/example/inheritance_with_refcount.rb +203 -221
  22. data/example/progress.rb +30 -0
  23. data/example/thumb.rb +12 -14
  24. data/example/trim8.rb +7 -7
  25. data/example/watermark.rb +15 -36
  26. data/example/wobble.rb +25 -25
  27. data/lib/ruby-vips.rb +1 -1
  28. data/lib/vips.rb +473 -338
  29. data/lib/vips/access.rb +9 -9
  30. data/lib/vips/align.rb +7 -8
  31. data/lib/vips/angle.rb +8 -9
  32. data/lib/vips/angle45.rb +12 -13
  33. data/lib/vips/bandformat.rb +16 -18
  34. data/lib/vips/blend_mode.rb +36 -0
  35. data/lib/vips/coding.rb +11 -12
  36. data/lib/vips/compass_direction.rb +13 -14
  37. data/lib/vips/connection.rb +46 -0
  38. data/lib/vips/direction.rb +7 -8
  39. data/lib/vips/extend.rb +13 -14
  40. data/lib/vips/gobject.rb +111 -100
  41. data/lib/vips/gvalue.rb +243 -237
  42. data/lib/vips/image.rb +1501 -1338
  43. data/lib/vips/interesting.rb +10 -11
  44. data/lib/vips/interpolate.rb +50 -54
  45. data/lib/vips/interpretation.rb +25 -26
  46. data/lib/vips/kernel.rb +18 -19
  47. data/lib/vips/methods.rb +929 -309
  48. data/lib/vips/mutableimage.rb +154 -0
  49. data/lib/vips/object.rb +318 -208
  50. data/lib/vips/operation.rb +467 -320
  51. data/lib/vips/operationboolean.rb +10 -11
  52. data/lib/vips/operationcomplex.rb +8 -9
  53. data/lib/vips/operationcomplex2.rb +6 -7
  54. data/lib/vips/operationcomplexget.rb +7 -8
  55. data/lib/vips/operationmath.rb +14 -15
  56. data/lib/vips/operationmath2.rb +6 -7
  57. data/lib/vips/operationrelational.rb +11 -12
  58. data/lib/vips/operationround.rb +7 -8
  59. data/lib/vips/region.rb +73 -0
  60. data/lib/vips/size.rb +9 -10
  61. data/lib/vips/source.rb +88 -0
  62. data/lib/vips/sourcecustom.rb +89 -0
  63. data/lib/vips/target.rb +86 -0
  64. data/lib/vips/targetcustom.rb +77 -0
  65. data/lib/vips/version.rb +1 -2
  66. data/ruby-vips.gemspec +29 -20
  67. metadata +51 -40
  68. data/.travis.yml +0 -55
  69. data/install-vips.sh +0 -26
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require "vips"
4
+
5
+ image = Vips::Image.black 1, 100000
6
+ image.set_progress true
7
+
8
+ def progress_to_s(name, progress)
9
+ puts "#{name}:"
10
+ puts " progress.run = #{progress[:run]}"
11
+ puts " progress.eta = #{progress[:eta]}"
12
+ puts " progress.tpels = #{progress[:tpels]}"
13
+ puts " progress.npels = #{progress[:npels]}"
14
+ puts " progress.percent = #{progress[:percent]}"
15
+ end
16
+
17
+ image.signal_connect :preeval do |progress|
18
+ progress_to_s("preeval", progress)
19
+ end
20
+
21
+ image.signal_connect :eval do |progress|
22
+ progress_to_s("eval", progress)
23
+ image.set_kill(true) if progress[:percent] > 50
24
+ end
25
+
26
+ image.signal_connect :posteval do |progress|
27
+ progress_to_s("posteval", progress)
28
+ end
29
+
30
+ image.avg
data/example/thumb.rb CHANGED
@@ -1,31 +1,29 @@
1
- #!/usr/bin/env ruby
1
+ #!/usr/bin/ruby
2
2
 
3
3
  # batch-process a lot of files
4
4
  #
5
5
  # this should run in constant memory -- if it doesn't, something has broken
6
6
 
7
- require 'vips'
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
-
31
-
data/example/trim8.rb CHANGED
@@ -7,15 +7,15 @@
7
7
  # non-zero row or column is the object edge. We make the mask image with an
8
8
  # amount-different-from-background image plus a threshold.
9
9
 
10
- require 'vips'
10
+ 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
 
@@ -23,16 +23,16 @@ mask = (im.median - background).abs > 10
23
23
  # direction
24
24
  columns, rows = mask.project
25
25
 
26
- first_column, first_row = columns.profile
26
+ _first_column, first_row = columns.profile
27
27
  left = first_row.min
28
28
 
29
- first_column, first_row = columns.fliphor.profile
29
+ _first_column, first_row = columns.fliphor.profile
30
30
  right = columns.width - first_row.min
31
31
 
32
- first_column, first_row = rows.profile
32
+ first_column, _first_row = rows.profile
33
33
  top = first_column.min
34
34
 
35
- first_column, first_row = rows.flipver.profile
35
+ first_column, _first_row = rows.flipver.profile
36
36
  bottom = rows.height - first_column.min
37
37
 
38
38
  # and now crop the original image
data/example/watermark.rb CHANGED
@@ -1,44 +1,23 @@
1
1
  #!/usr/bin/ruby
2
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
3
+ require "vips"
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]
data/example/wobble.rb CHANGED
@@ -1,35 +1,35 @@
1
1
  #!/usr/bin/ruby
2
2
 
3
- require 'vips'
3
+ require "vips"
4
4
 
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
data/lib/ruby-vips.rb CHANGED
@@ -1 +1 @@
1
- require 'vips'
1
+ require "vips"
data/lib/vips.rb CHANGED
@@ -4,161 +4,169 @@
4
4
  # Author:: John Cupitt (mailto:jcupitt@gmail.com)
5
5
  # License:: MIT
6
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.
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
+ # Generate a library name for ffi.
14
+ #
15
+ # Platform notes:
16
+ # linux:
17
+ # Some distros allow "libvips.so", but only if the -dev headers have been
18
+ # installed. To work everywhere, you must include the ABI number.
19
+ # Confusingly, the file extension is not at the end. ffi adds the "lib"
20
+ # prefix.
21
+ # mac:
22
+ # As linux, but the extension is at the end and is added by ffi.
23
+ # windows:
24
+ # The ABI number must be included, but with a hyphen. ffi does not add a
25
+ # "lib" prefix or a ".dll" suffix.
26
+ def library_name(name, abi_number)
27
+ if FFI::Platform.windows?
28
+ "lib#{name}-#{abi_number}.dll"
29
+ elsif FFI::Platform.mac?
30
+ "#{name}.#{abi_number}"
31
+ else
32
+ "#{name}.so.#{abi_number}"
33
+ end
34
+ end
12
35
 
13
36
  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
37
+ class << self
38
+ attr_accessor :logger
39
+ end
40
+ @logger = Logger.new($stdout)
41
+ @logger.level = Logger::WARN
42
+
43
+ extend FFI::Library
44
+
45
+ ffi_lib library_name("glib-2.0", 0)
46
+
47
+ attach_function :g_malloc, [:size_t], :pointer
48
+
49
+ # save the FFI::Function that attach will return ... we can use it directly
50
+ # as a param for callbacks
51
+ G_FREE = attach_function :g_free, [:pointer], :void
52
+
53
+ callback :g_log_func, [:string, :int, :string, :pointer], :void
54
+ attach_function :g_log_set_handler,
55
+ [:string, :int, :g_log_func, :pointer], :int
56
+ attach_function :g_log_remove_handler, [:string, :int], :void
57
+
58
+ # log flags
59
+ LOG_FLAG_RECURSION = 1 << 0
60
+ LOG_FLAG_FATAL = 1 << 1
61
+
62
+ # GLib log levels
63
+ LOG_LEVEL_ERROR = 1 << 2 # always fatal
64
+ LOG_LEVEL_CRITICAL = 1 << 3
65
+ LOG_LEVEL_WARNING = 1 << 4
66
+ LOG_LEVEL_MESSAGE = 1 << 5
67
+ LOG_LEVEL_INFO = 1 << 6
68
+ LOG_LEVEL_DEBUG = 1 << 7
69
+
70
+ # map glib levels to Logger::Severity
71
+ GLIB_TO_SEVERITY = {
72
+ LOG_LEVEL_ERROR => Logger::ERROR,
73
+ LOG_LEVEL_CRITICAL => Logger::FATAL,
74
+ LOG_LEVEL_WARNING => Logger::WARN,
75
+ LOG_LEVEL_MESSAGE => Logger::UNKNOWN,
76
+ LOG_LEVEL_INFO => Logger::INFO,
77
+ LOG_LEVEL_DEBUG => Logger::DEBUG
78
+ }
79
+ GLIB_TO_SEVERITY.default = Logger::UNKNOWN
80
+
81
+ # nil being the default
82
+ @glib_log_domain = nil
83
+ @glib_log_handler_id = 0
84
+
85
+ # module-level, so it's not GCd away
86
+ LOG_HANDLER = proc { |domain, level, message, _user_data|
87
+ @logger.log(GLIB_TO_SEVERITY[level], message, domain)
88
+ }
89
+
90
+ def self.remove_log_handler
91
+ if @glib_log_handler_id != 0 && @glib_log_domain
92
+ g_log_remove_handler @glib_log_domain, @glib_log_handler_id
93
+ @glib_log_handler_id = nil
78
94
  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
-
95
+ end
96
+
97
+ def self.set_log_domain domain
98
+ GLib.remove_log_handler
99
+
100
+ @glib_log_domain = domain
101
+
102
+ # forward all glib logging output from this domain to a Ruby logger
103
+ if @glib_log_domain
104
+ # disable this feature for now
105
+ #
106
+ # libvips background worker threads can issue warnings, and
107
+ # since the main thread is blocked waiting for libvips to come back
108
+ # from an ffi call, you get a deadlock on the GIL
109
+ #
110
+ # to fix this, we need a way for g_log() calls from libvips workers
111
+ # to be returned via the main thread
112
+ #
113
+
114
+ # @glib_log_handler_id = g_log_set_handler @glib_log_domain,
115
+ # LOG_LEVEL_DEBUG |
116
+ # LOG_LEVEL_INFO |
117
+ # LOG_LEVEL_MESSAGE |
118
+ # LOG_LEVEL_WARNING |
119
+ # LOG_LEVEL_ERROR |
120
+ # LOG_LEVEL_CRITICAL |
121
+ # LOG_FLAG_FATAL | LOG_FLAG_RECURSION,
122
+ # LOG_HANDLER, nil
123
+
124
+ # we must remove any handlers on exit, since libvips may log stuff
125
+ # on shutdown and we don't want LOG_HANDLER to be invoked
126
+ # after Ruby has gone
127
+ at_exit {
128
+ GLib.remove_log_handler
129
+ }
115
130
  end
116
-
131
+ end
117
132
  end
118
133
 
119
134
  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
-
135
+ extend FFI::Library
136
+
137
+ ffi_lib library_name("gobject-2.0", 0)
138
+
139
+ # we can't just use ulong, windows has different int sizing rules
140
+ if FFI::Platform::ADDRESS_SIZE == 64
141
+ typedef :uint64, :GType
142
+ else
143
+ typedef :uint32, :GType
144
+ end
145
+
146
+ attach_function :g_type_init, [], :void
147
+ attach_function :g_type_name, [:GType], :string
148
+ attach_function :g_type_from_name, [:string], :GType
149
+ attach_function :g_type_fundamental, [:GType], :GType
150
+
151
+ # glib before 2.36 needed this, does nothing in current glib
152
+ g_type_init
153
+
154
+ # look up some common gtypes
155
+ GBOOL_TYPE = g_type_from_name "gboolean"
156
+ GINT_TYPE = g_type_from_name "gint"
157
+ GUINT64_TYPE = g_type_from_name "guint64"
158
+ GDOUBLE_TYPE = g_type_from_name "gdouble"
159
+ GENUM_TYPE = g_type_from_name "GEnum"
160
+ GFLAGS_TYPE = g_type_from_name "GFlags"
161
+ GSTR_TYPE = g_type_from_name "gchararray"
162
+ GOBJECT_TYPE = g_type_from_name "GObject"
155
163
  end
156
164
 
157
- require 'vips/gobject'
158
- require 'vips/gvalue'
165
+ require "vips/gobject"
166
+ require "vips/gvalue"
159
167
 
160
- # This module provides a binding for the [libvips image processing
161
- # library](https://jcupitt.github.io/libvips/).
168
+ # This module provides a binding for the [libvips image processing
169
+ # library](https://libvips.github.io/libvips/).
162
170
  #
163
171
  # # Example
164
172
  #
@@ -183,8 +191,8 @@ require 'vips/gvalue'
183
191
  # im.write_to_file ARGV[1]
184
192
  # ```
185
193
  #
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.
194
+ # This example loads a file, boosts the green channel (I'm not sure why),
195
+ # sharpens the image, and saves it back to disc again.
188
196
  #
189
197
  # Reading this example line by line, we have:
190
198
  #
@@ -198,11 +206,12 @@ require 'vips/gvalue'
198
206
  # default mode is `:random`: this allows for full random access to image pixels,
199
207
  # but is slower and needs more memory. See {Access}
200
208
  # for full details
201
- # on the various modes available.
209
+ # on the various modes available.
202
210
  #
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.
211
+ # You can also load formatted images from memory buffers, create images that
212
+ # wrap C-style memory arrays, or make images from constants. Use {Source}
213
+ # and {Image.new_from_source} to load images from any data source, for
214
+ # example URIs.
206
215
  #
207
216
  # The next line:
208
217
  #
@@ -226,13 +235,13 @@ require 'vips/gvalue'
226
235
  # ```
227
236
  #
228
237
  # {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.
238
+ # the end sets the scale: the amount to divide the image by after
239
+ # integer convolution.
231
240
  #
232
241
  # See the libvips API docs for `vips_conv()` (the operation
233
242
  # 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.
243
+ # it computes with a float mask, but `:integer` is fine for this case, and is
244
+ # much faster.
236
245
  #
237
246
  # Finally:
238
247
  #
@@ -240,10 +249,13 @@ require 'vips/gvalue'
240
249
  # im.write_to_file ARGV[1]
241
250
  # ```
242
251
  #
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.
252
+ # {Image#write_to_file} writes an image back to the filesystem. It can
253
+ # write any format supported by vips: the file type is set from the filename
254
+ # suffix. You can also write formatted images to memory buffers, or dump
255
+ # image data to a raw memory array.
256
+ #
257
+ # Use {Target} and {Image#write_to_target} to write formatted images to
258
+ # any data sink, for example URIs.
247
259
  #
248
260
  # # How it works
249
261
  #
@@ -251,30 +263,30 @@ require 'vips/gvalue'
251
263
  # shared library. When you call a method on the image class, it uses libvips
252
264
  # introspection system (based on GObject) to search the
253
265
  # library for an operation of that name, transforms the arguments to a form
254
- # libvips can digest, and runs the operation.
266
+ # libvips can digest, and runs the operation.
255
267
  #
256
268
  # This means ruby-vips always presents the API implemented by the libvips shared
257
- # library. It should update itself as new features are added.
269
+ # library. It should update itself as new features are added.
258
270
  #
259
271
  # # Automatic wrapping
260
272
  #
261
273
  # `ruby-vips` adds a {Image.method_missing} handler to {Image} and uses
262
274
  # 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}.
275
+ # appears in C as `vips_add()`, appears in Ruby as {Image#add}.
264
276
  #
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
277
+ # The operation's list of required arguments is searched and the first input
278
+ # image is set to the value of `self`. Operations which do not take an input
267
279
  # image, such as {Image.black}, appear as class methods. The remainder of
268
280
  # the arguments you supply in the function call are used to set the other
269
281
  # required input arguments. Any trailing keyword arguments are used to set
270
282
  # options on the operation.
271
- #
272
- # The result is the required output
283
+ #
284
+ # The result is the required output
273
285
  # argument if there is only one result, or an array of values if the operation
274
286
  # produces several results. If the operation has optional output objects, they
275
287
  # are returned as a final hash.
276
288
  #
277
- # For example, {Image#min}, the vips operation that searches an image for
289
+ # For example, {Image#min}, the vips operation that searches an image for
278
290
  # the minimum value, has a large number of optional arguments. You can use it to
279
291
  # find the minimum value like this:
280
292
  #
@@ -283,14 +295,14 @@ require 'vips/gvalue'
283
295
  # ```
284
296
  #
285
297
  # You can ask it to return the position of the minimum with `:x` and `:y`.
286
- #
298
+ #
287
299
  # ```ruby
288
300
  # min_value, opts = min x: true, y: true
289
301
  # x_pos = opts['x']
290
302
  # y_pos = opts['y']
291
303
  # ```
292
304
  #
293
- # Now `x_pos` and `y_pos` will have the coordinates of the minimum value.
305
+ # Now `x_pos` and `y_pos` will have the coordinates of the minimum value.
294
306
  # There's actually a convenience method for this, {Image#minpos}.
295
307
  #
296
308
  # You can also ask for the top *n* minimum, for example:
@@ -301,7 +313,7 @@ require 'vips/gvalue'
301
313
  # y_pos = opts['y_array']
302
314
  # ```
303
315
  #
304
- # Now `x_pos` and `y_pos` will be 10-element arrays.
316
+ # Now `x_pos` and `y_pos` will be 10-element arrays.
305
317
  #
306
318
  # Because operations are member functions and return the result image, you can
307
319
  # chain them. For example, you can write:
@@ -310,30 +322,30 @@ require 'vips/gvalue'
310
322
  # result_image = image.real.cos
311
323
  # ```
312
324
  #
313
- # to calculate the cosine of the real part of a complex image.
325
+ # to calculate the cosine of the real part of a complex image.
314
326
  # There are also a full set
315
327
  # of arithmetic operator overloads, see below.
316
328
  #
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
329
+ # libvips types are also automatically wrapped. The override looks at the type
330
+ # of argument required by the operation and converts the value you supply,
331
+ # when it can. For example, {Image#linear} takes a `VipsArrayDouble` as
332
+ # an argument
333
+ # for the set of constants to use for multiplication. You can supply this
334
+ # value as an integer, a float, or some kind of compound object and it
323
335
  # will be converted for you. You can write:
324
336
  #
325
337
  # ```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]
338
+ # result_image = image.linear 1, 3
339
+ # result_image = image.linear 12.4, 13.9
340
+ # result_image = image.linear [1, 2, 3], [4, 5, 6]
341
+ # result_image = image.linear 1, [4, 5, 6]
330
342
  # ```
331
343
  #
332
344
  # And so on. A set of overloads are defined for {Image#linear}, see below.
333
345
  #
334
346
  # It does a couple of more ambitious conversions. It will automatically convert
335
347
  # 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:
348
+ # example, you can read the ICC profile out of an image like this:
337
349
  #
338
350
  # ```ruby
339
351
  # profile = im.get_value "icc-profile-data"
@@ -343,7 +355,7 @@ require 'vips/gvalue'
343
355
  #
344
356
  # If an operation takes several input images, you can use a constant for all but
345
357
  # 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
358
+ # example, {Image#ifthenelse} uses a condition image to pick pixels
347
359
  # between a then and an else image:
348
360
  #
349
361
  # ```ruby
@@ -360,7 +372,7 @@ require 'vips/gvalue'
360
372
  #
361
373
  # Will make an image where true pixels are green and false pixels are red.
362
374
  #
363
- # This is useful for {Image#bandjoin}, the thing to join two or more
375
+ # This is useful for {Image#bandjoin}, the thing to join two or more
364
376
  # images up bandwise. You can write:
365
377
  #
366
378
  # ```ruby
@@ -377,54 +389,150 @@ require 'vips/gvalue'
377
389
  # result_image = image1.bandjoin [image2, 255]
378
390
  # ```
379
391
  #
380
- # and so on.
392
+ # and so on.
381
393
  #
382
394
  # # Logging
383
395
  #
384
- # Libvips uses g_log() to log warning, debug, info and (some) error messages.
396
+ # Libvips uses g_log() to log warning, debug, info and (some) error messages.
385
397
  #
386
398
  # https://developer.gnome.org/glib/stable/glib-Message-Logging.html
387
399
  #
388
- # You can disable wanrings by defining the `VIPS_WARNING` environment variable.
389
- # You can enable info output by defining `VIPS_INFO`.
400
+ # You can disable warnings by defining the `VIPS_WARNING` environment variable.
401
+ # You can enable info output by defining `VIPS_INFO`.
390
402
  #
391
403
  # # Exceptions
392
404
  #
393
405
  # The wrapper spots errors from vips operations and raises the {Vips::Error}
394
- # exception. You can catch it in the usual way.
406
+ # exception. You can catch it in the usual way.
395
407
  #
396
408
  # # Automatic YARD documentation
397
409
  #
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)
410
+ # The bulk of these API docs are generated automatically by {Yard#generate}.
411
+ # It examines libvips and writes a summary of each operation and the arguments
412
+ # and options that that operation expects.
413
+ #
414
+ # Use the [C API # docs](https://libvips.github.io/libvips/API/current)
405
415
  # for more detail.
406
416
  #
407
417
  # # Enums
408
418
  #
409
419
  # The libvips enums, such as `VipsBandFormat` appear in ruby-vips as Symbols
410
420
  # like `:uchar`. They are documented as a set of classes for convenience, see
411
- # the class list.
412
- #
421
+ # {Vips::BandFormat}, for example.
422
+ #
413
423
  # # Draw operations
414
424
  #
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.
425
+ # There are two ways of calling the libvips draw operations, like
426
+ # {Image#draw_circle} and {Image#draw_line}.
427
+ #
428
+ # First, you can use them like functions. For example:
429
+ #
430
+ # ```ruby
431
+ # y = x.draw_line 255, 0, 0, x.width, x.height
432
+ # ```
433
+ #
434
+ # This will make a new image, `y`, which is a copy of `x` but with a line
435
+ # drawn across it. `x` is unchanged.
436
+ #
437
+ # This is simple, but will be slow if you want to draw many lines, since
438
+ # ruby-vips will make a copy of the whole image each time.
439
+ #
440
+ # You can use {Image#mutate} to make a {MutableImage}. This is an image which
441
+ # is unshared and is only available inside the {Image#mutate} block. Within
442
+ # this block, you can use `!` versions of the draw operations to modify images
443
+ # and avoid the copy. For example:
444
+ #
445
+ # ```ruby
446
+ # image = image.mutate do |mutable|
447
+ # (0 ... 1).step(0.01) do |i|
448
+ # mutable.draw_line! 255, mutable.width * i, 0, 0, mutable.height * (1 - i)
449
+ # end
450
+ # end
451
+ # ```
452
+ #
453
+ # Now each {Image#draw_line} will directly modify the mutable image, saving
454
+ # the copy. This is much faster and needs much less memory.
455
+ #
456
+ # # Metadata read
457
+ #
458
+ # Use {Image#get_fields} to get a list of the metadata fields that an image
459
+ # supports. ICC profiles, for example, are in a field called
460
+ # `icc-profile-data`. Use `vipsheader -a something.jpg` at the command-line
461
+ # to see all the fields on an image.
462
+ #
463
+ # Use {Image#get_typeof} to get the type of a field. Types are integers, with
464
+ # 0 meaning "no such field". Constants like {GObject::GINT_TYPE} are useful for
465
+ # testing field types.
466
+ #
467
+ # You can read image metadata using {Image#get}. The field value is converted
468
+ # to a Ruby value in the obvious way.
469
+ #
470
+ # # Metadata write
471
+ #
472
+ # You can also set and remove image metadata fields. Images are immutable, so
473
+ # you must make any changes inside a {Image#mutate} block. For example:
474
+ #
475
+ # ```ruby
476
+ # image = image.mutate do |mutable|
477
+ # image.get_fields.each do |field|
478
+ # mutable.remove! field unless field == "icc-profile-data"
479
+ # end
480
+ # end
481
+ # ```
482
+ #
483
+ # To remove all metadata except the icc profile.
484
+ #
485
+ # You can use {MutableImage#set!} to change the value of an existing field,
486
+ # and {MutableImage#set_type!} to create a new field with a specified type.
487
+ #
488
+ # # Progress
489
+ #
490
+ # You can attach signal handlers to images to watch computation progress. For
491
+ # example:
492
+ #
493
+ # ```ruby
494
+ # image = Vips::Image.black 1, 100000
495
+ # image.set_progress true
496
+ #
497
+ # def progress_to_s(name, progress)
498
+ # puts "#{name}:"
499
+ # puts " run = #{progress[:run]}"
500
+ # puts " eta = #{progress[:eta]}"
501
+ # puts " tpels = #{progress[:tpels]}"
502
+ # puts " npels = #{progress[:npels]}"
503
+ # puts " percent = #{progress[:percent]}"
504
+ # end
505
+ #
506
+ # image.signal_connect :preeval do |progress|
507
+ # progress_to_s("preeval", progress)
508
+ # end
509
+ #
510
+ # image.signal_connect :eval do |progress|
511
+ # progress_to_s("eval", progress)
512
+ # image.set_kill(true) if progress[:percent] > 50
513
+ # end
514
+ #
515
+ # image.signal_connect :posteval do |progress|
516
+ # progress_to_s("posteval", progress)
517
+ # end
518
+ #
519
+ # image.avg
520
+ # ```
521
+ #
522
+ # The `:eval` signal will fire for every tile that is processed. You can stop
523
+ # progress with {Image#set_kill} and processing will end with an exception.
524
+ #
525
+ # User streams
419
526
  #
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.
527
+ # You can make your own input and output stream objects with {SourceCustom} and
528
+ # {TargetCustom}. For example:
425
529
  #
426
- # If you want to avoid the copies, you'll need to call drawing operations
427
- # yourself.
530
+ # ```ruby
531
+ # file = File.open "some/file", "rb"
532
+ # source = Vips::SourceCustom.new
533
+ # source.on_read { |length| file.read length }
534
+ # image = Vips::Image.new_from_source source, "", access: "sequential"
535
+ # ```
428
536
  #
429
537
  # # Overloads
430
538
  #
@@ -438,7 +546,7 @@ require 'vips/gvalue'
438
546
  #
439
547
  # # Expansions
440
548
  #
441
- # Some vips operators take an enum to select an action, for example
549
+ # Some vips operators take an enum to select an action, for example
442
550
  # {Image#math} can be used to calculate sine of every pixel like this:
443
551
  #
444
552
  # ```ruby
@@ -454,144 +562,171 @@ require 'vips/gvalue'
454
562
  #
455
563
  # # Convenience functions
456
564
  #
457
- # The wrapper defines a few extra useful utility functions:
458
- # {Image#get_value}, {Image#set_value}, {Image#bandsplit},
459
- # {Image#maxpos}, {Image#minpos},
565
+ # The wrapper defines a few extra useful utility functions:
566
+ # {Image#get_value}, {Image#set_value}, {Image#bandsplit},
567
+ # {Image#maxpos}, {Image#minpos},
460
568
  # {Image#median}.
461
569
 
462
570
  module Vips
463
- extend FFI::Library
464
-
465
- if FFI::Platform.windows?
466
- vips_libname = 'libvips-42.dll'
467
- else
468
- vips_libname = 'vips'
571
+ extend FFI::Library
572
+
573
+ ffi_lib library_name("vips", 42)
574
+
575
+ LOG_DOMAIN = "VIPS"
576
+ GLib.set_log_domain LOG_DOMAIN
577
+
578
+ typedef :ulong, :GType
579
+
580
+ attach_function :vips_error_buffer, [], :string
581
+ attach_function :vips_error_clear, [], :void
582
+
583
+ # The ruby-vips error class.
584
+ class Error < RuntimeError
585
+ # @param msg [String] The error message. If this is not supplied, grab
586
+ # and clear the vips error buffer and use that.
587
+ def initialize msg = nil
588
+ if msg
589
+ @details = msg
590
+ elsif Vips.vips_error_buffer != ""
591
+ @details = Vips.vips_error_buffer
592
+ Vips.vips_error_clear
593
+ else
594
+ @details = nil
595
+ end
469
596
  end
470
597
 
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.
598
+ # Pretty-print a {Vips::Error}.
564
599
  #
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
600
+ # @return [String] The error message
601
+ def to_s
602
+ if !@details.nil?
603
+ @details
604
+ else
605
+ super.to_s
606
+ end
570
607
  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)
608
+ end
609
+
610
+ attach_function :vips_init, [:string], :int
611
+
612
+ if Vips.vips_init($0) != 0
613
+ throw Vips.get_error
614
+ end
615
+
616
+ # don't use at_exit to call vips_shutdown, it causes problems with fork, and
617
+ # in any case libvips does this for us
618
+
619
+ attach_function :vips_leak_set, [:int], :void
620
+ attach_function :vips_vector_set_enabled, [:int], :void
621
+ attach_function :vips_concurrency_set, [:int], :void
622
+
623
+ # vips_foreign_get_suffixes was added in libvips 8.8
624
+ begin
625
+ attach_function :vips_foreign_get_suffixes, [], :pointer
626
+ rescue FFI::NotFoundError
627
+ nil
628
+ end
629
+
630
+ # Turn libvips leak testing on and off. Handy for debugging ruby-vips, not
631
+ # very useful for user code.
632
+ def self.leak_set leak
633
+ vips_leak_set((leak ? 1 : 0))
634
+ end
635
+
636
+ attach_function :vips_cache_set_max, [:int], :void
637
+ attach_function :vips_cache_set_max_mem, [:int], :void
638
+ attach_function :vips_cache_set_max_files, [:int], :void
639
+
640
+ # Set the maximum number of operations that libvips should cache. Set 0 to
641
+ # disable the operation cache. The default is 1000.
642
+ def self.cache_set_max size
643
+ vips_cache_set_max size
644
+ end
645
+
646
+ # Set the maximum amount of memory that libvips should use for the operation
647
+ # cache. Set 0 to disable the operation cache. The default is 100mb.
648
+ def self.cache_set_max_mem size
649
+ vips_cache_set_max_mem size
650
+ end
651
+
652
+ # Set the maximum number of files libvips should keep open in the
653
+ # operation cache. Set 0 to disable the operation cache. The default is
654
+ # 100.
655
+ def self.cache_set_max_files size
656
+ vips_cache_set_max_files size
657
+ end
658
+
659
+ # Set the size of the libvips worker pool. This defaults to the number of
660
+ # hardware threads on your computer. Set to 1 to disable threading.
661
+ def self.concurrency_set n
662
+ vips_concurrency_set n
663
+ end
664
+
665
+ # Enable or disable SIMD and the run-time compiler. This can give a nice
666
+ # speed-up, but can also be unstable on some systems or with some versions
667
+ # of the run-time compiler.
668
+ def self.vector_set enabled
669
+ vips_vector_set_enabled(enabled ? 1 : 0)
670
+ end
671
+
672
+ # Deprecated compatibility function.
673
+ #
674
+ # Don't use this, instead change GLib::logger.level.
675
+ def self.set_debug debug
676
+ if debug
677
+ GLib.logger.level = Logger::DEBUG
678
+ end
679
+ end
680
+
681
+ attach_function :version, :vips_version, [:int], :int
682
+ attach_function :version_string, :vips_version_string, [], :string
683
+
684
+ # True if this is at least libvips x.y
685
+ def self.at_least_libvips?(x, y)
686
+ major = version(0)
687
+ minor = version(1)
688
+
689
+ major > x || (major == x && minor >= y)
690
+ end
691
+
692
+ # Get a list of all supported file suffixes.
693
+ #
694
+ # @return [[String]] array of supported suffixes
695
+ def self.get_suffixes
696
+ # vips_foreign_get_suffixes() was added in libvips 8.8
697
+ return [] unless Vips.respond_to? :vips_foreign_get_suffixes
698
+
699
+ array = Vips.vips_foreign_get_suffixes
700
+
701
+ names = []
702
+ p = array
703
+ until (q = p.read_pointer).null?
704
+ suff = q.read_string
705
+ GLib.g_free q
706
+ names << suff unless names.include? suff
707
+ p += FFI::Type::POINTER.size
581
708
  end
709
+ GLib.g_free array
582
710
 
583
- LIBRARY_VERSION = Vips::version_string
711
+ names
712
+ end
584
713
 
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
714
+ LIBRARY_VERSION = Vips.version_string
588
715
 
716
+ # libvips has this arbitrary number as a sanity-check upper bound on image
717
+ # size. It's sometimes useful to know when calculating scale factors.
718
+ MAX_COORD = 10000000
589
719
  end
590
720
 
591
- require 'vips/object'
592
- require 'vips/operation'
593
- require 'vips/image'
594
- require 'vips/interpolate'
595
- require 'vips/version'
596
-
597
-
721
+ require "vips/object"
722
+ require "vips/operation"
723
+ require "vips/image"
724
+ require "vips/mutableimage"
725
+ require "vips/interpolate"
726
+ require "vips/region"
727
+ require "vips/version"
728
+ require "vips/connection"
729
+ require "vips/source"
730
+ require "vips/sourcecustom"
731
+ require "vips/target"
732
+ require "vips/targetcustom"