ruby-vips 2.0.13 → 2.0.14
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.
- checksums.yaml +4 -4
- data/.rubocop.yml +10 -0
- data/.rubocop_todo.yml +730 -0
- data/.travis.yml +13 -6
- data/CHANGELOG.md +8 -0
- data/README.md +5 -8
- data/Rakefile +6 -0
- data/VERSION +1 -1
- data/example/annotate.rb +2 -2
- data/example/daltonize8.rb +14 -14
- data/example/example2.rb +6 -6
- data/example/example3.rb +5 -5
- data/example/example4.rb +4 -4
- data/example/example5.rb +2 -2
- data/example/inheritance_with_refcount.rb +207 -207
- data/example/thumb.rb +10 -10
- data/example/trim8.rb +2 -2
- data/example/watermark.rb +14 -35
- data/example/wobble.rb +24 -24
- data/install-vips.sh +1 -1
- data/lib/vips.rb +335 -306
- data/lib/vips/access.rb +9 -9
- data/lib/vips/align.rb +7 -7
- data/lib/vips/angle.rb +8 -8
- data/lib/vips/angle45.rb +12 -12
- data/lib/vips/bandformat.rb +16 -16
- data/lib/vips/blend_mode.rb +34 -0
- data/lib/vips/coding.rb +11 -11
- data/lib/vips/compass_direction.rb +13 -13
- data/lib/vips/direction.rb +7 -7
- data/lib/vips/extend.rb +13 -13
- data/lib/vips/gobject.rb +94 -94
- data/lib/vips/gvalue.rb +232 -232
- data/lib/vips/image.rb +1329 -1335
- data/lib/vips/interesting.rb +10 -10
- data/lib/vips/interpolate.rb +51 -51
- data/lib/vips/interpretation.rb +25 -25
- data/lib/vips/kernel.rb +18 -18
- data/lib/vips/methods.rb +463 -283
- data/lib/vips/object.rb +208 -208
- data/lib/vips/operation.rb +323 -323
- data/lib/vips/operationboolean.rb +10 -10
- data/lib/vips/operationcomplex.rb +8 -8
- data/lib/vips/operationcomplex2.rb +6 -6
- data/lib/vips/operationcomplexget.rb +7 -7
- data/lib/vips/operationmath.rb +14 -14
- data/lib/vips/operationmath2.rb +6 -6
- data/lib/vips/operationrelational.rb +11 -11
- data/lib/vips/operationround.rb +7 -7
- data/lib/vips/size.rb +9 -9
- data/lib/vips/version.rb +1 -1
- data/ruby-vips.gemspec +6 -2
- metadata +29 -6
data/example/thumb.rb
CHANGED
@@ -7,25 +7,25 @@
|
|
7
7
|
require 'vips'
|
8
8
|
|
9
9
|
# benchmark thumbnail via a memory buffer
|
10
|
-
def via_memory(filename, thumbnail_width)
|
11
|
-
|
10
|
+
def via_memory(filename, thumbnail_width)
|
11
|
+
data = IO.binread(filename)
|
12
12
|
|
13
|
-
|
13
|
+
thumb = Vips::Image.thumbnail_buffer data, thumbnail_width, crop: 'centre'
|
14
14
|
|
15
|
-
|
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
|
-
|
19
|
+
def via_files(filename, thumbnail_width)
|
20
|
+
thumb = Vips::Image.thumbnail filename, thumbnail_width, crop: 'centre'
|
21
21
|
|
22
|
-
|
22
|
+
thumb.write_to_buffer '.jpg'
|
23
23
|
end
|
24
24
|
|
25
25
|
ARGV.each do |filename|
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
puts "processing #{filename} ..."
|
27
|
+
thumb = via_memory(filename, 500)
|
28
|
+
# thumb = via_files(filename, 500)
|
29
29
|
end
|
30
30
|
|
31
31
|
|
data/example/trim8.rb
CHANGED
@@ -11,11 +11,11 @@ require 'vips'
|
|
11
11
|
|
12
12
|
im = Vips::Image.new_from_file ARGV[0]
|
13
13
|
|
14
|
-
# find the value of the pixel at (0, 0) ... we will search for all pixels
|
14
|
+
# find the value of the pixel at (0, 0) ... we will search for all pixels
|
15
15
|
# significantly different from this
|
16
16
|
background = im.getpoint(0, 0)
|
17
17
|
|
18
|
-
# we need to smooth the image, subtract the background from every pixel, take
|
18
|
+
# we need to smooth the image, subtract the background from every pixel, take
|
19
19
|
# the absolute value of the difference, then threshold
|
20
20
|
mask = (im.median - background).abs > 10
|
21
21
|
|
data/example/watermark.rb
CHANGED
@@ -1,44 +1,23 @@
|
|
1
1
|
#!/usr/bin/ruby
|
2
2
|
|
3
3
|
require 'vips'
|
4
|
-
|
5
|
-
im = Vips::Image.new_from_file ARGV[0], :
|
6
|
-
|
7
|
-
|
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.
|
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
|
14
|
-
|
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
|
-
|
20
|
+
# overlay the text
|
21
|
+
im = im.composite overlay, :over
|
40
22
|
|
41
|
-
|
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
@@ -5,31 +5,31 @@ require 'vips'
|
|
5
5
|
image = Vips::Image.new_from_file ARGV[0]
|
6
6
|
|
7
7
|
module Vips
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
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/install-vips.sh
CHANGED
data/lib/vips.rb
CHANGED
@@ -7,157 +7,157 @@
|
|
7
7
|
require 'ffi'
|
8
8
|
require 'logger'
|
9
9
|
|
10
|
-
# This module uses FFI to make a simple layer over the glib and gobject
|
11
|
-
# libraries.
|
10
|
+
# This module uses FFI to make a simple layer over the glib and gobject
|
11
|
+
# libraries.
|
12
12
|
|
13
13
|
module GLib
|
14
|
-
|
15
|
-
|
14
|
+
class << self
|
15
|
+
attr_accessor :logger
|
16
|
+
end
|
17
|
+
@logger = Logger.new(STDOUT)
|
18
|
+
@logger.level = Logger::WARN
|
19
|
+
|
20
|
+
extend FFI::Library
|
21
|
+
|
22
|
+
if FFI::Platform.windows?
|
23
|
+
glib_libname = 'libglib-2.0-0.dll'
|
24
|
+
else
|
25
|
+
glib_libname = 'glib-2.0'
|
26
|
+
end
|
27
|
+
|
28
|
+
ffi_lib glib_libname
|
29
|
+
|
30
|
+
attach_function :g_malloc, [:size_t], :pointer
|
31
|
+
|
32
|
+
# save the FFI::Function that attach will return ... we can use it directly
|
33
|
+
# as a param for callbacks
|
34
|
+
G_FREE = attach_function :g_free, [:pointer], :void
|
35
|
+
|
36
|
+
callback :g_log_func, [:string, :int, :string, :pointer], :void
|
37
|
+
attach_function :g_log_set_handler,
|
38
|
+
[:string, :int, :g_log_func, :pointer], :int
|
39
|
+
attach_function :g_log_remove_handler, [:string, :int], :void
|
40
|
+
|
41
|
+
# log flags
|
42
|
+
LOG_FLAG_RECURSION = 1 << 0
|
43
|
+
LOG_FLAG_FATAL = 1 << 1
|
44
|
+
|
45
|
+
# GLib log levels
|
46
|
+
LOG_LEVEL_ERROR = 1 << 2 # always fatal
|
47
|
+
LOG_LEVEL_CRITICAL = 1 << 3
|
48
|
+
LOG_LEVEL_WARNING = 1 << 4
|
49
|
+
LOG_LEVEL_MESSAGE = 1 << 5
|
50
|
+
LOG_LEVEL_INFO = 1 << 6
|
51
|
+
LOG_LEVEL_DEBUG = 1 << 7
|
52
|
+
|
53
|
+
# map glib levels to Logger::Severity
|
54
|
+
GLIB_TO_SEVERITY = {
|
55
|
+
LOG_LEVEL_ERROR => Logger::ERROR,
|
56
|
+
LOG_LEVEL_CRITICAL => Logger::FATAL,
|
57
|
+
LOG_LEVEL_WARNING => Logger::WARN,
|
58
|
+
LOG_LEVEL_MESSAGE => Logger::UNKNOWN,
|
59
|
+
LOG_LEVEL_INFO => Logger::INFO,
|
60
|
+
LOG_LEVEL_DEBUG => Logger::DEBUG
|
61
|
+
}
|
62
|
+
GLIB_TO_SEVERITY.default = Logger::UNKNOWN
|
63
|
+
|
64
|
+
# nil being the default
|
65
|
+
@glib_log_domain = nil
|
66
|
+
@glib_log_handler_id = 0
|
67
|
+
|
68
|
+
# module-level, so it's not GCd away
|
69
|
+
LOG_HANDLER = Proc.new do |domain, level, message, user_data|
|
70
|
+
@logger.log(GLIB_TO_SEVERITY[level], message, domain)
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.remove_log_handler
|
74
|
+
if @glib_log_handler_id != 0 && @glib_log_domain
|
75
|
+
g_log_remove_handler @glib_log_domain, @glib_log_handler_id
|
76
|
+
@glib_log_handler_id = nil
|
16
77
|
end
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
LOG_LEVEL_INFO = 1 << 6
|
51
|
-
LOG_LEVEL_DEBUG = 1 << 7
|
52
|
-
|
53
|
-
# map glib levels to Logger::Severity
|
54
|
-
GLIB_TO_SEVERITY = {
|
55
|
-
LOG_LEVEL_ERROR => Logger::ERROR,
|
56
|
-
LOG_LEVEL_CRITICAL => Logger::FATAL,
|
57
|
-
LOG_LEVEL_WARNING => Logger::WARN,
|
58
|
-
LOG_LEVEL_MESSAGE => Logger::UNKNOWN,
|
59
|
-
LOG_LEVEL_INFO => Logger::INFO,
|
60
|
-
LOG_LEVEL_DEBUG => Logger::DEBUG
|
61
|
-
}
|
62
|
-
GLIB_TO_SEVERITY.default = Logger::UNKNOWN
|
63
|
-
|
64
|
-
# nil being the default
|
65
|
-
@glib_log_domain = nil
|
66
|
-
@glib_log_handler_id = 0
|
67
|
-
|
68
|
-
# module-level, so it's not GCd away
|
69
|
-
LOG_HANDLER = Proc.new do |domain, level, message, user_data|
|
70
|
-
@logger.log(GLIB_TO_SEVERITY[level], message, domain)
|
71
|
-
end
|
72
|
-
|
73
|
-
def self.remove_log_handler
|
74
|
-
if @glib_log_handler_id != 0 && @glib_log_domain
|
75
|
-
g_log_remove_handler @glib_log_domain, @glib_log_handler_id
|
76
|
-
@glib_log_handler_id = nil
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def self.set_log_domain domain
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.set_log_domain domain
|
81
|
+
GLib::remove_log_handler
|
82
|
+
|
83
|
+
@glib_log_domain = domain
|
84
|
+
|
85
|
+
# forward all glib logging output from this domain to a Ruby logger
|
86
|
+
if @glib_log_domain
|
87
|
+
# disable this feature for now
|
88
|
+
#
|
89
|
+
# libvips background worker threads can issue warnings, and
|
90
|
+
# since the main thread is blocked waiting for libvips to come back
|
91
|
+
# from an ffi call, you get a deadlock on the GIL
|
92
|
+
#
|
93
|
+
# to fix this, we need a way for g_log() calls from libvips workers
|
94
|
+
# to be returned via the main thread
|
95
|
+
#
|
96
|
+
|
97
|
+
# @glib_log_handler_id = g_log_set_handler @glib_log_domain,
|
98
|
+
# LOG_LEVEL_DEBUG |
|
99
|
+
# LOG_LEVEL_INFO |
|
100
|
+
# LOG_LEVEL_MESSAGE |
|
101
|
+
# LOG_LEVEL_WARNING |
|
102
|
+
# LOG_LEVEL_ERROR |
|
103
|
+
# LOG_LEVEL_CRITICAL |
|
104
|
+
# LOG_FLAG_FATAL | LOG_FLAG_RECURSION,
|
105
|
+
# LOG_HANDLER, nil
|
106
|
+
|
107
|
+
# we must remove any handlers on exit, since libvips may log stuff
|
108
|
+
# on shutdown and we don't want LOG_HANDLER to be invoked
|
109
|
+
# after Ruby has gone
|
110
|
+
at_exit {
|
81
111
|
GLib::remove_log_handler
|
82
|
-
|
83
|
-
@glib_log_domain = domain
|
84
|
-
|
85
|
-
# forward all glib logging output from this domain to a Ruby logger
|
86
|
-
if @glib_log_domain
|
87
|
-
# disable this feature for now
|
88
|
-
#
|
89
|
-
# libvips background worker threads can issue warnings, and
|
90
|
-
# since the main thread is blocked waiting for libvips to come back
|
91
|
-
# from an ffi call, you get a deadlock on the GIL
|
92
|
-
#
|
93
|
-
# to fix this, we need a way for g_log() calls from libvips workers
|
94
|
-
# to be returned via the main thread
|
95
|
-
#
|
96
|
-
|
97
|
-
# @glib_log_handler_id = g_log_set_handler @glib_log_domain,
|
98
|
-
# LOG_LEVEL_DEBUG |
|
99
|
-
# LOG_LEVEL_INFO |
|
100
|
-
# LOG_LEVEL_MESSAGE |
|
101
|
-
# LOG_LEVEL_WARNING |
|
102
|
-
# LOG_LEVEL_ERROR |
|
103
|
-
# LOG_LEVEL_CRITICAL |
|
104
|
-
# LOG_FLAG_FATAL | LOG_FLAG_RECURSION,
|
105
|
-
# LOG_HANDLER, nil
|
106
|
-
|
107
|
-
# we must remove any handlers on exit, since libvips may log stuff
|
108
|
-
# on shutdown and we don't want LOG_HANDLER to be invoked
|
109
|
-
# after Ruby has gone
|
110
|
-
at_exit {
|
111
|
-
GLib::remove_log_handler
|
112
|
-
}
|
113
|
-
end
|
114
|
-
|
112
|
+
}
|
115
113
|
end
|
116
114
|
|
115
|
+
end
|
116
|
+
|
117
117
|
end
|
118
118
|
|
119
119
|
module GObject
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
120
|
+
extend FFI::Library
|
121
|
+
|
122
|
+
if FFI::Platform.windows?
|
123
|
+
gobject_libname = 'libgobject-2.0-0.dll'
|
124
|
+
else
|
125
|
+
gobject_libname = 'gobject-2.0'
|
126
|
+
end
|
127
|
+
|
128
|
+
ffi_lib gobject_libname
|
129
|
+
|
130
|
+
# we can't just use ulong, windows has different int sizing rules
|
131
|
+
if FFI::Platform::ADDRESS_SIZE == 64
|
132
|
+
typedef :uint64, :GType
|
133
|
+
else
|
134
|
+
typedef :uint32, :GType
|
135
|
+
end
|
136
|
+
|
137
|
+
attach_function :g_type_init, [], :void
|
138
|
+
attach_function :g_type_name, [:GType], :string
|
139
|
+
attach_function :g_type_from_name, [:string], :GType
|
140
|
+
attach_function :g_type_fundamental, [:GType], :GType
|
141
|
+
|
142
|
+
# glib before 2.36 needed this, does nothing in current glib
|
143
|
+
g_type_init
|
144
|
+
|
145
|
+
# look up some common gtypes
|
146
|
+
GBOOL_TYPE = g_type_from_name "gboolean"
|
147
|
+
GINT_TYPE = g_type_from_name "gint"
|
148
|
+
GUINT64_TYPE = g_type_from_name "guint64"
|
149
|
+
GDOUBLE_TYPE = g_type_from_name "gdouble"
|
150
|
+
GENUM_TYPE = g_type_from_name "GEnum"
|
151
|
+
GFLAGS_TYPE = g_type_from_name "GFlags"
|
152
|
+
GSTR_TYPE = g_type_from_name "gchararray"
|
153
|
+
GOBJECT_TYPE = g_type_from_name "GObject"
|
154
154
|
|
155
155
|
end
|
156
156
|
|
157
157
|
require 'vips/gobject'
|
158
158
|
require 'vips/gvalue'
|
159
159
|
|
160
|
-
# This module provides a binding for the [libvips image processing
|
160
|
+
# This module provides a binding for the [libvips image processing
|
161
161
|
# library](https://jcupitt.github.io/libvips/).
|
162
162
|
#
|
163
163
|
# # Example
|
@@ -183,8 +183,8 @@ require 'vips/gvalue'
|
|
183
183
|
# im.write_to_file ARGV[1]
|
184
184
|
# ```
|
185
185
|
#
|
186
|
-
# This example loads a file, boosts the green channel (I'm not sure why),
|
187
|
-
# sharpens the image, and saves it back to disc again.
|
186
|
+
# This example loads a file, boosts the green channel (I'm not sure why),
|
187
|
+
# sharpens the image, and saves it back to disc again.
|
188
188
|
#
|
189
189
|
# Reading this example line by line, we have:
|
190
190
|
#
|
@@ -198,9 +198,9 @@ require 'vips/gvalue'
|
|
198
198
|
# default mode is `:random`: this allows for full random access to image pixels,
|
199
199
|
# but is slower and needs more memory. See {Access}
|
200
200
|
# for full details
|
201
|
-
# on the various modes available.
|
201
|
+
# on the various modes available.
|
202
202
|
#
|
203
|
-
# You can also load formatted images from
|
203
|
+
# You can also load formatted images from
|
204
204
|
# memory buffers, create images that wrap C-style memory arrays, or make images
|
205
205
|
# from constants.
|
206
206
|
#
|
@@ -226,13 +226,13 @@ require 'vips/gvalue'
|
|
226
226
|
# ```
|
227
227
|
#
|
228
228
|
# {Image.new_from_array} creates an image from an array constant. The 8 at
|
229
|
-
# the end sets the scale: the amount to divide the image by after
|
230
|
-
# integer convolution.
|
229
|
+
# the end sets the scale: the amount to divide the image by after
|
230
|
+
# integer convolution.
|
231
231
|
#
|
232
232
|
# See the libvips API docs for `vips_conv()` (the operation
|
233
233
|
# invoked by {Image#conv}) for details on the convolution operator. By default,
|
234
|
-
# it computes with a float mask, but `:integer` is fine for this case, and is
|
235
|
-
# much faster.
|
234
|
+
# it computes with a float mask, but `:integer` is fine for this case, and is
|
235
|
+
# much faster.
|
236
236
|
#
|
237
237
|
# Finally:
|
238
238
|
#
|
@@ -240,10 +240,10 @@ require 'vips/gvalue'
|
|
240
240
|
# im.write_to_file ARGV[1]
|
241
241
|
# ```
|
242
242
|
#
|
243
|
-
# {Image#write_to_file} writes an image back to the filesystem. It can
|
244
|
-
# write any format supported by vips: the file type is set from the filename
|
245
|
-
# suffix. You can also write formatted images to memory buffers, or dump
|
246
|
-
# image data to a raw memory array.
|
243
|
+
# {Image#write_to_file} writes an image back to the filesystem. It can
|
244
|
+
# write any format supported by vips: the file type is set from the filename
|
245
|
+
# suffix. You can also write formatted images to memory buffers, or dump
|
246
|
+
# image data to a raw memory array.
|
247
247
|
#
|
248
248
|
# # How it works
|
249
249
|
#
|
@@ -251,30 +251,30 @@ require 'vips/gvalue'
|
|
251
251
|
# shared library. When you call a method on the image class, it uses libvips
|
252
252
|
# introspection system (based on GObject) to search the
|
253
253
|
# library for an operation of that name, transforms the arguments to a form
|
254
|
-
# libvips can digest, and runs the operation.
|
254
|
+
# libvips can digest, and runs the operation.
|
255
255
|
#
|
256
256
|
# This means ruby-vips always presents the API implemented by the libvips shared
|
257
|
-
# library. It should update itself as new features are added.
|
257
|
+
# library. It should update itself as new features are added.
|
258
258
|
#
|
259
259
|
# # Automatic wrapping
|
260
260
|
#
|
261
261
|
# `ruby-vips` adds a {Image.method_missing} handler to {Image} and uses
|
262
262
|
# it to look up vips operations. For example, the libvips operation `add`, which
|
263
|
-
# appears in C as `vips_add()`, appears in Ruby as {Image#add}.
|
263
|
+
# appears in C as `vips_add()`, appears in Ruby as {Image#add}.
|
264
264
|
#
|
265
|
-
# The operation's list of required arguments is searched and the first input
|
266
|
-
# image is set to the value of `self`. Operations which do not take an input
|
265
|
+
# The operation's list of required arguments is searched and the first input
|
266
|
+
# image is set to the value of `self`. Operations which do not take an input
|
267
267
|
# image, such as {Image.black}, appear as class methods. The remainder of
|
268
268
|
# the arguments you supply in the function call are used to set the other
|
269
269
|
# required input arguments. Any trailing keyword arguments are used to set
|
270
270
|
# options on the operation.
|
271
|
-
#
|
272
|
-
# The result is the required output
|
271
|
+
#
|
272
|
+
# The result is the required output
|
273
273
|
# argument if there is only one result, or an array of values if the operation
|
274
274
|
# produces several results. If the operation has optional output objects, they
|
275
275
|
# are returned as a final hash.
|
276
276
|
#
|
277
|
-
# For example, {Image#min}, the vips operation that searches an image for
|
277
|
+
# For example, {Image#min}, the vips operation that searches an image for
|
278
278
|
# the minimum value, has a large number of optional arguments. You can use it to
|
279
279
|
# find the minimum value like this:
|
280
280
|
#
|
@@ -283,14 +283,14 @@ require 'vips/gvalue'
|
|
283
283
|
# ```
|
284
284
|
#
|
285
285
|
# You can ask it to return the position of the minimum with `:x` and `:y`.
|
286
|
-
#
|
286
|
+
#
|
287
287
|
# ```ruby
|
288
288
|
# min_value, opts = min x: true, y: true
|
289
289
|
# x_pos = opts['x']
|
290
290
|
# y_pos = opts['y']
|
291
291
|
# ```
|
292
292
|
#
|
293
|
-
# Now `x_pos` and `y_pos` will have the coordinates of the minimum value.
|
293
|
+
# Now `x_pos` and `y_pos` will have the coordinates of the minimum value.
|
294
294
|
# There's actually a convenience method for this, {Image#minpos}.
|
295
295
|
#
|
296
296
|
# You can also ask for the top *n* minimum, for example:
|
@@ -301,7 +301,7 @@ require 'vips/gvalue'
|
|
301
301
|
# y_pos = opts['y_array']
|
302
302
|
# ```
|
303
303
|
#
|
304
|
-
# Now `x_pos` and `y_pos` will be 10-element arrays.
|
304
|
+
# Now `x_pos` and `y_pos` will be 10-element arrays.
|
305
305
|
#
|
306
306
|
# Because operations are member functions and return the result image, you can
|
307
307
|
# chain them. For example, you can write:
|
@@ -310,30 +310,30 @@ require 'vips/gvalue'
|
|
310
310
|
# result_image = image.real.cos
|
311
311
|
# ```
|
312
312
|
#
|
313
|
-
# to calculate the cosine of the real part of a complex image.
|
313
|
+
# to calculate the cosine of the real part of a complex image.
|
314
314
|
# There are also a full set
|
315
315
|
# of arithmetic operator overloads, see below.
|
316
316
|
#
|
317
|
-
# libvips types are also automatically wrapped. The override looks at the type
|
318
|
-
# of argument required by the operation and converts the value you supply,
|
319
|
-
# when it can. For example, {Image#linear} takes a `VipsArrayDouble` as
|
320
|
-
# an argument
|
321
|
-
# for the set of constants to use for multiplication. You can supply this
|
322
|
-
# value as an integer, a float, or some kind of compound object and it
|
317
|
+
# libvips types are also automatically wrapped. The override looks at the type
|
318
|
+
# of argument required by the operation and converts the value you supply,
|
319
|
+
# when it can. For example, {Image#linear} takes a `VipsArrayDouble` as
|
320
|
+
# an argument
|
321
|
+
# for the set of constants to use for multiplication. You can supply this
|
322
|
+
# value as an integer, a float, or some kind of compound object and it
|
323
323
|
# will be converted for you. You can write:
|
324
324
|
#
|
325
325
|
# ```ruby
|
326
|
-
# result_image = image.linear 1, 3
|
327
|
-
# result_image = image.linear 12.4, 13.9
|
328
|
-
# result_image = image.linear [1, 2, 3], [4, 5, 6]
|
329
|
-
# result_image = image.linear 1, [4, 5, 6]
|
326
|
+
# result_image = image.linear 1, 3
|
327
|
+
# result_image = image.linear 12.4, 13.9
|
328
|
+
# result_image = image.linear [1, 2, 3], [4, 5, 6]
|
329
|
+
# result_image = image.linear 1, [4, 5, 6]
|
330
330
|
# ```
|
331
331
|
#
|
332
332
|
# And so on. A set of overloads are defined for {Image#linear}, see below.
|
333
333
|
#
|
334
334
|
# It does a couple of more ambitious conversions. It will automatically convert
|
335
335
|
# to and from the various vips types, like `VipsBlob` and `VipsArrayImage`. For
|
336
|
-
# example, you can read the ICC profile out of an image like this:
|
336
|
+
# example, you can read the ICC profile out of an image like this:
|
337
337
|
#
|
338
338
|
# ```ruby
|
339
339
|
# profile = im.get_value "icc-profile-data"
|
@@ -343,7 +343,7 @@ require 'vips/gvalue'
|
|
343
343
|
#
|
344
344
|
# If an operation takes several input images, you can use a constant for all but
|
345
345
|
# one of them and the wrapper will expand the constant to an image for you. For
|
346
|
-
# example, {Image#ifthenelse} uses a condition image to pick pixels
|
346
|
+
# example, {Image#ifthenelse} uses a condition image to pick pixels
|
347
347
|
# between a then and an else image:
|
348
348
|
#
|
349
349
|
# ```ruby
|
@@ -360,7 +360,7 @@ require 'vips/gvalue'
|
|
360
360
|
#
|
361
361
|
# Will make an image where true pixels are green and false pixels are red.
|
362
362
|
#
|
363
|
-
# This is useful for {Image#bandjoin}, the thing to join two or more
|
363
|
+
# This is useful for {Image#bandjoin}, the thing to join two or more
|
364
364
|
# images up bandwise. You can write:
|
365
365
|
#
|
366
366
|
# ```ruby
|
@@ -377,39 +377,39 @@ require 'vips/gvalue'
|
|
377
377
|
# result_image = image1.bandjoin [image2, 255]
|
378
378
|
# ```
|
379
379
|
#
|
380
|
-
# and so on.
|
380
|
+
# and so on.
|
381
381
|
#
|
382
382
|
# # Logging
|
383
383
|
#
|
384
|
-
# Libvips uses g_log() to log warning, debug, info and (some) error messages.
|
384
|
+
# Libvips uses g_log() to log warning, debug, info and (some) error messages.
|
385
385
|
#
|
386
386
|
# https://developer.gnome.org/glib/stable/glib-Message-Logging.html
|
387
387
|
#
|
388
388
|
# You can disable wanrings by defining the `VIPS_WARNING` environment variable.
|
389
|
-
# You can enable info output by defining `VIPS_INFO`.
|
389
|
+
# You can enable info output by defining `VIPS_INFO`.
|
390
390
|
#
|
391
391
|
# # Exceptions
|
392
392
|
#
|
393
393
|
# The wrapper spots errors from vips operations and raises the {Vips::Error}
|
394
|
-
# exception. You can catch it in the usual way.
|
394
|
+
# exception. You can catch it in the usual way.
|
395
395
|
#
|
396
396
|
# # Automatic YARD documentation
|
397
397
|
#
|
398
|
-
# The bulk of these API docs are generated automatically by
|
398
|
+
# The bulk of these API docs are generated automatically by
|
399
399
|
# {Vips::generate_yard}. It examines
|
400
400
|
# libvips and writes a summary of each operation and the arguments and options
|
401
|
-
# that that operation expects.
|
402
|
-
#
|
403
|
-
# Use the [C API
|
404
|
-
# docs](https://jcupitt.github.io/libvips/API/current)
|
401
|
+
# that that operation expects.
|
402
|
+
#
|
403
|
+
# Use the [C API
|
404
|
+
# docs](https://jcupitt.github.io/libvips/API/current)
|
405
405
|
# for more detail.
|
406
406
|
#
|
407
407
|
# # Enums
|
408
408
|
#
|
409
409
|
# The libvips enums, such as `VipsBandFormat` appear in ruby-vips as Symbols
|
410
410
|
# like `:uchar`. They are documented as a set of classes for convenience, see
|
411
|
-
# the class list.
|
412
|
-
#
|
411
|
+
# the class list.
|
412
|
+
#
|
413
413
|
# # Draw operations
|
414
414
|
#
|
415
415
|
# Paint operations like {Image#draw_circle} and {Image#draw_line}
|
@@ -421,7 +421,7 @@ require 'vips/gvalue'
|
|
421
421
|
# image in memory before calling the operation. This stops crashes, but it does
|
422
422
|
# make it inefficient. If you draw 100 lines on an image, for example, you'll
|
423
423
|
# copy the image 100 times. The wrapper does make sure that memory is recycled
|
424
|
-
# where possible, so you won't have 100 copies in memory.
|
424
|
+
# where possible, so you won't have 100 copies in memory.
|
425
425
|
#
|
426
426
|
# If you want to avoid the copies, you'll need to call drawing operations
|
427
427
|
# yourself.
|
@@ -438,7 +438,7 @@ require 'vips/gvalue'
|
|
438
438
|
#
|
439
439
|
# # Expansions
|
440
440
|
#
|
441
|
-
# Some vips operators take an enum to select an action, for example
|
441
|
+
# Some vips operators take an enum to select an action, for example
|
442
442
|
# {Image#math} can be used to calculate sine of every pixel like this:
|
443
443
|
#
|
444
444
|
# ```ruby
|
@@ -454,137 +454,166 @@ require 'vips/gvalue'
|
|
454
454
|
#
|
455
455
|
# # Convenience functions
|
456
456
|
#
|
457
|
-
# The wrapper defines a few extra useful utility functions:
|
458
|
-
# {Image#get_value}, {Image#set_value}, {Image#bandsplit},
|
459
|
-
# {Image#maxpos}, {Image#minpos},
|
457
|
+
# The wrapper defines a few extra useful utility functions:
|
458
|
+
# {Image#get_value}, {Image#set_value}, {Image#bandsplit},
|
459
|
+
# {Image#maxpos}, {Image#minpos},
|
460
460
|
# {Image#median}.
|
461
461
|
|
462
462
|
module Vips
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
463
|
+
extend FFI::Library
|
464
|
+
|
465
|
+
if FFI::Platform.windows?
|
466
|
+
vips_libname = 'libvips-42.dll'
|
467
|
+
else
|
468
|
+
vips_libname = 'vips'
|
469
|
+
end
|
470
|
+
|
471
|
+
ffi_lib vips_libname
|
472
|
+
|
473
|
+
LOG_DOMAIN = "VIPS"
|
474
|
+
GLib::set_log_domain LOG_DOMAIN
|
475
|
+
|
476
|
+
typedef :ulong, :GType
|
477
|
+
|
478
|
+
attach_function :vips_error_buffer, [], :string
|
479
|
+
attach_function :vips_error_clear, [], :void
|
480
|
+
|
481
|
+
# The ruby-vips error class.
|
482
|
+
class Error < RuntimeError
|
483
|
+
# @param msg [String] The error message. If this is not supplied, grab
|
484
|
+
# and clear the vips error buffer and use that.
|
485
|
+
def initialize msg = nil
|
486
|
+
if msg
|
487
|
+
@details = msg
|
488
|
+
elsif Vips::vips_error_buffer != ""
|
489
|
+
@details = Vips::vips_error_buffer
|
490
|
+
Vips::vips_error_clear
|
491
|
+
else
|
492
|
+
@details = nil
|
493
|
+
end
|
469
494
|
end
|
470
495
|
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
# The ruby-vips error class.
|
482
|
-
class Error < RuntimeError
|
483
|
-
# @param msg [String] The error message. If this is not supplied, grab
|
484
|
-
# and clear the vips error buffer and use that.
|
485
|
-
def initialize msg = nil
|
486
|
-
if msg
|
487
|
-
@details = msg
|
488
|
-
elsif Vips::vips_error_buffer != ""
|
489
|
-
@details = Vips::vips_error_buffer
|
490
|
-
Vips::vips_error_clear
|
491
|
-
else
|
492
|
-
@details = nil
|
493
|
-
end
|
494
|
-
end
|
495
|
-
|
496
|
-
# Pretty-print a {Vips::Error}.
|
497
|
-
#
|
498
|
-
# @return [String] The error message
|
499
|
-
def to_s
|
500
|
-
if @details != nil
|
501
|
-
@details
|
502
|
-
else
|
503
|
-
super.to_s
|
504
|
-
end
|
505
|
-
end
|
506
|
-
end
|
507
|
-
|
508
|
-
attach_function :vips_init, [:string], :int
|
509
|
-
|
510
|
-
if Vips::vips_init($0) != 0
|
511
|
-
throw Vips::get_error
|
512
|
-
end
|
513
|
-
|
514
|
-
# don't use at_exit to call vips_shutdown, it causes problems with fork, and
|
515
|
-
# in any case libvips does this for us
|
516
|
-
|
517
|
-
attach_function :vips_leak_set, [:int], :void
|
518
|
-
attach_function :vips_vector_set_enabled, [:int], :void
|
519
|
-
attach_function :vips_concurrency_set, [:int], :void
|
520
|
-
|
521
|
-
# Turn libvips leak testing on and off. Handy for debugging ruby-vips, not
|
522
|
-
# very useful for user code.
|
523
|
-
def self.leak_set leak
|
524
|
-
vips_leak_set (leak ? 1 : 0)
|
525
|
-
end
|
526
|
-
|
527
|
-
attach_function :vips_cache_set_max, [:int], :void
|
528
|
-
attach_function :vips_cache_set_max_mem, [:int], :void
|
529
|
-
attach_function :vips_cache_set_max_files, [:int], :void
|
530
|
-
|
531
|
-
# Set the maximum number of operations that libvips should cache. Set 0 to
|
532
|
-
# disable the operation cache. The default is 1000.
|
533
|
-
def self.cache_set_max size
|
534
|
-
vips_cache_set_max size
|
535
|
-
end
|
536
|
-
|
537
|
-
# Set the maximum amount of memory that libvips should use for the operation
|
538
|
-
# cache. Set 0 to disable the operation cache. The default is 100mb.
|
539
|
-
def self.cache_set_max_mem size
|
540
|
-
vips_cache_set_max_mem size
|
541
|
-
end
|
542
|
-
|
543
|
-
# Set the maximum number of files libvips should keep open in the
|
544
|
-
# operation cache. Set 0 to disable the operation cache. The default is
|
545
|
-
# 100.
|
546
|
-
def self.cache_set_max_files size
|
547
|
-
vips_cache_set_max_files size
|
496
|
+
# Pretty-print a {Vips::Error}.
|
497
|
+
#
|
498
|
+
# @return [String] The error message
|
499
|
+
def to_s
|
500
|
+
if @details != nil
|
501
|
+
@details
|
502
|
+
else
|
503
|
+
super.to_s
|
504
|
+
end
|
548
505
|
end
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
506
|
+
end
|
507
|
+
|
508
|
+
attach_function :vips_init, [:string], :int
|
509
|
+
|
510
|
+
if Vips::vips_init($0) != 0
|
511
|
+
throw Vips::get_error
|
512
|
+
end
|
513
|
+
|
514
|
+
# don't use at_exit to call vips_shutdown, it causes problems with fork, and
|
515
|
+
# in any case libvips does this for us
|
516
|
+
|
517
|
+
attach_function :vips_leak_set, [:int], :void
|
518
|
+
attach_function :vips_vector_set_enabled, [:int], :void
|
519
|
+
attach_function :vips_concurrency_set, [:int], :void
|
520
|
+
|
521
|
+
# vips_foreign_get_suffixes was added in libvips 8.8
|
522
|
+
begin
|
523
|
+
attach_function :vips_foreign_get_suffixes, [], :pointer
|
524
|
+
rescue FFI::NotFoundError
|
525
|
+
nil
|
526
|
+
end
|
527
|
+
|
528
|
+
# Turn libvips leak testing on and off. Handy for debugging ruby-vips, not
|
529
|
+
# very useful for user code.
|
530
|
+
def self.leak_set leak
|
531
|
+
vips_leak_set (leak ? 1 : 0)
|
532
|
+
end
|
533
|
+
|
534
|
+
attach_function :vips_cache_set_max, [:int], :void
|
535
|
+
attach_function :vips_cache_set_max_mem, [:int], :void
|
536
|
+
attach_function :vips_cache_set_max_files, [:int], :void
|
537
|
+
|
538
|
+
# Set the maximum number of operations that libvips should cache. Set 0 to
|
539
|
+
# disable the operation cache. The default is 1000.
|
540
|
+
def self.cache_set_max size
|
541
|
+
vips_cache_set_max size
|
542
|
+
end
|
543
|
+
|
544
|
+
# Set the maximum amount of memory that libvips should use for the operation
|
545
|
+
# cache. Set 0 to disable the operation cache. The default is 100mb.
|
546
|
+
def self.cache_set_max_mem size
|
547
|
+
vips_cache_set_max_mem size
|
548
|
+
end
|
549
|
+
|
550
|
+
# Set the maximum number of files libvips should keep open in the
|
551
|
+
# operation cache. Set 0 to disable the operation cache. The default is
|
552
|
+
# 100.
|
553
|
+
def self.cache_set_max_files size
|
554
|
+
vips_cache_set_max_files size
|
555
|
+
end
|
556
|
+
|
557
|
+
# Set the size of the libvips worker pool. This defaults to the number of
|
558
|
+
# hardware threads on your computer. Set to 1 to disable threading.
|
559
|
+
def self.concurrency_set n
|
560
|
+
vips_concurrency_set n
|
561
|
+
end
|
562
|
+
|
563
|
+
# Enable or disable SIMD and the run-time compiler. This can give a nice
|
564
|
+
# speed-up, but can also be unstable on some systems or with some versions
|
565
|
+
# of the run-time compiler.
|
566
|
+
def self.vector_set enabled
|
567
|
+
vips_vector_set_enabled(enabled ? 1 : 0)
|
568
|
+
end
|
569
|
+
|
570
|
+
# Deprecated compatibility function.
|
571
|
+
#
|
572
|
+
# Don't use this, instead change GLib::logger.level.
|
573
|
+
def self.set_debug debug
|
574
|
+
if debug
|
575
|
+
GLib::logger.level = Logger::DEBUG
|
554
576
|
end
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
577
|
+
end
|
578
|
+
|
579
|
+
attach_function :version, :vips_version, [:int], :int
|
580
|
+
attach_function :version_string, :vips_version_string, [], :string
|
581
|
+
|
582
|
+
# True if this is at least libvips x.y
|
583
|
+
def self.at_least_libvips?(x, y)
|
584
|
+
major = version(0)
|
585
|
+
minor = version(1)
|
586
|
+
|
587
|
+
major > x || (major == x && minor >= y)
|
588
|
+
end
|
589
|
+
|
590
|
+
# Get a list of all supported file suffixes.
|
591
|
+
#
|
592
|
+
# @return [[String]] array of supported suffixes
|
593
|
+
def self.get_suffixes
|
594
|
+
# vips_foreign_get_suffixes() was added in libvips 8.8
|
595
|
+
return [] unless Vips.respond_to? :vips_foreign_get_suffixes
|
596
|
+
|
597
|
+
array = Vips::vips_foreign_get_suffixes
|
598
|
+
|
599
|
+
names = []
|
600
|
+
p = array
|
601
|
+
until (q = p.read_pointer).null?
|
602
|
+
suff = q.read_string
|
603
|
+
GLib::g_free q
|
604
|
+
names << suff unless names.include? suff
|
605
|
+
p += FFI::Type::POINTER.size
|
561
606
|
end
|
607
|
+
GLib::g_free array
|
562
608
|
|
563
|
-
|
564
|
-
|
565
|
-
# Don't use this, instead change GLib::logger.level.
|
566
|
-
def self.set_debug debug
|
567
|
-
if debug
|
568
|
-
GLib::logger.level = Logger::DEBUG
|
569
|
-
end
|
570
|
-
end
|
571
|
-
|
572
|
-
attach_function :version, :vips_version, [:int], :int
|
573
|
-
attach_function :version_string, :vips_version_string, [], :string
|
574
|
-
|
575
|
-
# True if this is at least libvips x.y
|
576
|
-
def self.at_least_libvips?(x, y)
|
577
|
-
major = version(0)
|
578
|
-
minor = version(1)
|
579
|
-
|
580
|
-
major > x || (major == x && minor >= y)
|
581
|
-
end
|
609
|
+
names
|
610
|
+
end
|
582
611
|
|
583
|
-
|
612
|
+
LIBRARY_VERSION = Vips::version_string
|
584
613
|
|
585
|
-
|
586
|
-
|
587
|
-
|
614
|
+
# libvips has this arbitrary number as a sanity-check upper bound on image
|
615
|
+
# size. It's sometimes useful for know whan calculating image ratios.
|
616
|
+
MAX_COORD = 10000000
|
588
617
|
|
589
618
|
end
|
590
619
|
|