vips 8.7.0.1 → 8.8.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +25 -22
- data/CHANGELOG.md +266 -0
- 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/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 -1327
- 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 +2226 -2139
- data/lib/vips/object.rb +208 -208
- data/lib/vips/operation.rb +323 -321
- 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/vips.gemspec +1 -1
- metadata +9 -8
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/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 = File.expand_path(FFI::map_library_name('vips'), __dir__)
|
469
|
+
end
|
470
|
+
|
471
|
+
ffi_lib vips_libname
|
472
|
+
|
473
|
+
LOG_DOMAIN = "VIPS"
|
474
|
+
GLib::set_log_domain LOG_DOMAIN
|
475
|
+
|
476
|
+
typedef :ulong, :GType
|
477
|
+
|
478
|
+
attach_function :vips_error_buffer, [], :string
|
479
|
+
attach_function :vips_error_clear, [], :void
|
480
|
+
|
481
|
+
# The ruby-vips error class.
|
482
|
+
class Error < RuntimeError
|
483
|
+
# @param msg [String] The error message. If this is not supplied, grab
|
484
|
+
# and clear the vips error buffer and use that.
|
485
|
+
def initialize msg = nil
|
486
|
+
if msg
|
487
|
+
@details = msg
|
488
|
+
elsif Vips::vips_error_buffer != ""
|
489
|
+
@details = Vips::vips_error_buffer
|
490
|
+
Vips::vips_error_clear
|
491
|
+
else
|
492
|
+
@details = nil
|
493
|
+
end
|
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
|
|