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