ruby-vips 2.0.13 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
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"