vips 8.6.3
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 +7 -0
- data/.gitignore +16 -0
- data/.travis.yml +47 -0
- data/.yardopts +2 -0
- data/Gemfile +4 -0
- data/README.md +64 -0
- data/Rakefile +28 -0
- data/example/annotate.rb +17 -0
- data/example/daltonize8.rb +75 -0
- data/example/example1.rb +12 -0
- data/example/example2.rb +34 -0
- data/example/example3.rb +19 -0
- data/example/example4.rb +18 -0
- data/example/example5.rb +31 -0
- data/example/inheritance_with_refcount.rb +286 -0
- data/example/thumb.rb +31 -0
- data/example/trim8.rb +41 -0
- data/example/watermark.rb +44 -0
- data/example/wobble.rb +36 -0
- data/ext/Rakefile +35 -0
- data/lib/vips.rb +597 -0
- data/lib/vips/access.rb +11 -0
- data/lib/vips/align.rb +11 -0
- data/lib/vips/angle.rb +12 -0
- data/lib/vips/angle45.rb +16 -0
- data/lib/vips/bandformat.rb +20 -0
- data/lib/vips/coding.rb +14 -0
- data/lib/vips/compass_direction.rb +17 -0
- data/lib/vips/direction.rb +11 -0
- data/lib/vips/extend.rb +17 -0
- data/lib/vips/gobject.rb +122 -0
- data/lib/vips/gvalue.rb +281 -0
- data/lib/vips/image.rb +1500 -0
- data/lib/vips/interesting.rb +14 -0
- data/lib/vips/interpolate.rb +62 -0
- data/lib/vips/interpretation.rb +28 -0
- data/lib/vips/kernel.rb +22 -0
- data/lib/vips/methods.rb +2145 -0
- data/lib/vips/object.rb +244 -0
- data/lib/vips/operation.rb +365 -0
- data/lib/vips/operationboolean.rb +14 -0
- data/lib/vips/operationcomplex.rb +12 -0
- data/lib/vips/operationcomplex2.rb +10 -0
- data/lib/vips/operationcomplexget.rb +11 -0
- data/lib/vips/operationmath.rb +18 -0
- data/lib/vips/operationmath2.rb +10 -0
- data/lib/vips/operationrelational.rb +15 -0
- data/lib/vips/operationround.rb +11 -0
- data/lib/vips/size.rb +13 -0
- data/lib/vips/version.rb +4 -0
- data/vips.gemspec +36 -0
- metadata +209 -0
data/example/thumb.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# batch-process a lot of files
|
4
|
+
#
|
5
|
+
# this should run in constant memory -- if it doesn't, something has broken
|
6
|
+
|
7
|
+
require 'vips'
|
8
|
+
|
9
|
+
# benchmark thumbnail via a memory buffer
|
10
|
+
def via_memory(filename, thumbnail_width)
|
11
|
+
data = IO.binread(filename)
|
12
|
+
|
13
|
+
thumb = Vips::Image.thumbnail_buffer data, thumbnail_width, crop: 'centre'
|
14
|
+
|
15
|
+
thumb.write_to_buffer '.jpg'
|
16
|
+
end
|
17
|
+
|
18
|
+
# benchmark thumbnail via files
|
19
|
+
def via_files(filename, thumbnail_width)
|
20
|
+
thumb = Vips::Image.thumbnail filename, thumbnail_width, crop: 'centre'
|
21
|
+
|
22
|
+
thumb.write_to_buffer '.jpg'
|
23
|
+
end
|
24
|
+
|
25
|
+
ARGV.each do |filename|
|
26
|
+
puts "processing #{filename} ..."
|
27
|
+
thumb = via_memory(filename, 500)
|
28
|
+
# thumb = via_files(filename, 500)
|
29
|
+
end
|
30
|
+
|
31
|
+
|
data/example/trim8.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
# An equivalent of ImageMagick's -trim in ruby-vips ... automatically remove
|
4
|
+
# "boring" image edges.
|
5
|
+
|
6
|
+
# We use .project to sum the rows and columns of a 0/255 mask image, the first
|
7
|
+
# non-zero row or column is the object edge. We make the mask image with an
|
8
|
+
# amount-different-from-background image plus a threshold.
|
9
|
+
|
10
|
+
require 'vips'
|
11
|
+
|
12
|
+
im = Vips::Image.new_from_file ARGV[0]
|
13
|
+
|
14
|
+
# find the value of the pixel at (0, 0) ... we will search for all pixels
|
15
|
+
# significantly different from this
|
16
|
+
background = im.getpoint(0, 0)
|
17
|
+
|
18
|
+
# we need to smooth the image, subtract the background from every pixel, take
|
19
|
+
# the absolute value of the difference, then threshold
|
20
|
+
mask = (im.median - background).abs > 10
|
21
|
+
|
22
|
+
# sum mask rows and columns, then search for the first non-zero sum in each
|
23
|
+
# direction
|
24
|
+
columns, rows = mask.project
|
25
|
+
|
26
|
+
first_column, first_row = columns.profile
|
27
|
+
left = first_row.min
|
28
|
+
|
29
|
+
first_column, first_row = columns.fliphor.profile
|
30
|
+
right = columns.width - first_row.min
|
31
|
+
|
32
|
+
first_column, first_row = rows.profile
|
33
|
+
top = first_column.min
|
34
|
+
|
35
|
+
first_column, first_row = rows.flipver.profile
|
36
|
+
bottom = rows.height - first_column.min
|
37
|
+
|
38
|
+
# and now crop the original image
|
39
|
+
im = im.crop left, top, right - left, bottom - top
|
40
|
+
|
41
|
+
im.write_to_file ARGV[1]
|
@@ -0,0 +1,44 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require 'vips'
|
4
|
+
|
5
|
+
im = Vips::Image.new_from_file ARGV[0], :access => :sequential
|
6
|
+
|
7
|
+
text = Vips::Image.text ARGV[2], :width => 500, :dpi => 300
|
8
|
+
text = (text * 0.3).cast(:uchar)
|
9
|
+
text = text.embed 100, 100, text.width + 200, text.width + 200
|
10
|
+
text = text.replicate 1 + im.width / text.width, 1 + im.height / text.height
|
11
|
+
text = text.crop 0, 0, im.width, im.height
|
12
|
+
|
13
|
+
# we want to blend into the visible part of the image and leave any alpha
|
14
|
+
# channels untouched ... we need to split im into two parts
|
15
|
+
|
16
|
+
# guess how many bands from the start of im contain visible colour information
|
17
|
+
if im.bands >= 4 and im.interpretation == :cmyk
|
18
|
+
# cmyk image
|
19
|
+
n_visible_bands = 4
|
20
|
+
text_colour = [0, 255, 0, 0]
|
21
|
+
elsif im.bands >= 3
|
22
|
+
# rgb image
|
23
|
+
n_visible_bands = 3
|
24
|
+
text_colour = [255, 0, 0]
|
25
|
+
else
|
26
|
+
# mono image
|
27
|
+
n_visible_bands = 1
|
28
|
+
text_colour = 255
|
29
|
+
end
|
30
|
+
|
31
|
+
# split into image and alpha
|
32
|
+
if im.bands - n_visible_bands > 0
|
33
|
+
alpha = im.extract_band n_visible_bands, :n => im.bands - n_visible_bands
|
34
|
+
im = im.extract_band 0, :n => n_visible_bands
|
35
|
+
else
|
36
|
+
alpha = nil
|
37
|
+
end
|
38
|
+
|
39
|
+
marked = text.ifthenelse text_colour, im, :blend => true
|
40
|
+
|
41
|
+
# reattach alpha
|
42
|
+
marked = marked.bandjoin alpha if alpha
|
43
|
+
|
44
|
+
marked.write_to_file ARGV[1]
|
data/example/wobble.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
require 'vips'
|
4
|
+
|
5
|
+
image = Vips::Image.new_from_file ARGV[0]
|
6
|
+
|
7
|
+
module Vips
|
8
|
+
class Image
|
9
|
+
def wobble
|
10
|
+
# this makes an image where pixel (0, 0) (at the top-left) has
|
11
|
+
# value [0, 0], and pixel (image.width - 1, image.height - 1) at the
|
12
|
+
# bottom-right has value [image.width - 1, image.height - 1]
|
13
|
+
index = Vips::Image.xyz width, height
|
14
|
+
|
15
|
+
# make a version with (0, 0) at the centre, negative values up
|
16
|
+
# and left, positive down and right
|
17
|
+
centre = index - [width / 2, height / 2]
|
18
|
+
|
19
|
+
# to polar space, so each pixel is now distance and angle in degrees
|
20
|
+
polar = centre.polar
|
21
|
+
|
22
|
+
# scale sin(distance) by 1/distance to make a wavey pattern
|
23
|
+
d = ((polar[0] * 3).sin * 10000) / (polar[0] + 1)
|
24
|
+
|
25
|
+
# and back to rectangular coordinates again to make a set of
|
26
|
+
# vectors we can apply to the original index image
|
27
|
+
index += d.bandjoin(polar[1]).rect
|
28
|
+
|
29
|
+
# finally, use our modified index image to distort!
|
30
|
+
mapim index
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
image = image.wobble
|
36
|
+
image.write_to_file ARGV[1]
|
data/ext/Rakefile
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
|
2
|
+
require_relative '../lib/vips/version'
|
3
|
+
|
4
|
+
version = Vips::VERSION[/\d+\.\d+\.\d+/]
|
5
|
+
archive_path = "vips-#{version}.tar.gz"
|
6
|
+
source_path = "vips-#{version}"
|
7
|
+
prefix = ENV['PREFIX'] || File.dirname(__dir__)
|
8
|
+
|
9
|
+
task :fetch do
|
10
|
+
url = "https://github.com/jcupitt/libvips/releases/download/v#{version}/#{archive_path}"
|
11
|
+
|
12
|
+
unless File.exist? archive_path
|
13
|
+
sh "wget #{url}"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
task :extract do
|
18
|
+
unless File.exist? source_path
|
19
|
+
sh "tar -xvf #{archive_path}"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
task :build do
|
24
|
+
Dir.chdir source_path do
|
25
|
+
sh "./configure --prefix=#{prefix} --exec-prefix=#{prefix}"
|
26
|
+
sh "make install"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
task :clean do
|
31
|
+
FileUtils.rm_rf archive_path
|
32
|
+
FileUtils.rm_rf source_path
|
33
|
+
end
|
34
|
+
|
35
|
+
task :default => [:fetch, :extract, :build]
|
data/lib/vips.rb
ADDED
@@ -0,0 +1,597 @@
|
|
1
|
+
# This module provides an interface to the vips image processing library
|
2
|
+
# via ruby-ffi.
|
3
|
+
#
|
4
|
+
# Author:: John Cupitt (mailto:jcupitt@gmail.com)
|
5
|
+
# License:: MIT
|
6
|
+
|
7
|
+
require 'ffi'
|
8
|
+
require 'logger'
|
9
|
+
|
10
|
+
# This module uses FFI to make a simple layer over the glib and gobject
|
11
|
+
# libraries.
|
12
|
+
|
13
|
+
module GLib
|
14
|
+
class << self
|
15
|
+
attr_accessor :logger
|
16
|
+
end
|
17
|
+
@logger = Logger.new(STDOUT)
|
18
|
+
@logger.level = Logger::WARN
|
19
|
+
|
20
|
+
extend FFI::Library
|
21
|
+
|
22
|
+
if FFI::Platform.windows?
|
23
|
+
glib_libname = 'libglib-2.0-0.dll'
|
24
|
+
else
|
25
|
+
glib_libname = 'glib-2.0'
|
26
|
+
end
|
27
|
+
|
28
|
+
ffi_lib glib_libname
|
29
|
+
|
30
|
+
attach_function :g_malloc, [:size_t], :pointer
|
31
|
+
|
32
|
+
# save the FFI::Function that attach will return ... we can use it directly
|
33
|
+
# as a param for callbacks
|
34
|
+
G_FREE = attach_function :g_free, [:pointer], :void
|
35
|
+
|
36
|
+
callback :g_log_func, [:string, :int, :string, :pointer], :void
|
37
|
+
attach_function :g_log_set_handler,
|
38
|
+
[:string, :int, :g_log_func, :pointer], :int
|
39
|
+
attach_function :g_log_remove_handler, [:string, :int], :void
|
40
|
+
|
41
|
+
# log flags
|
42
|
+
LOG_FLAG_RECURSION = 1 << 0
|
43
|
+
LOG_FLAG_FATAL = 1 << 1
|
44
|
+
|
45
|
+
# GLib log levels
|
46
|
+
LOG_LEVEL_ERROR = 1 << 2 # always fatal
|
47
|
+
LOG_LEVEL_CRITICAL = 1 << 3
|
48
|
+
LOG_LEVEL_WARNING = 1 << 4
|
49
|
+
LOG_LEVEL_MESSAGE = 1 << 5
|
50
|
+
LOG_LEVEL_INFO = 1 << 6
|
51
|
+
LOG_LEVEL_DEBUG = 1 << 7
|
52
|
+
|
53
|
+
# map glib levels to Logger::Severity
|
54
|
+
GLIB_TO_SEVERITY = {
|
55
|
+
LOG_LEVEL_ERROR => Logger::ERROR,
|
56
|
+
LOG_LEVEL_CRITICAL => Logger::FATAL,
|
57
|
+
LOG_LEVEL_WARNING => Logger::WARN,
|
58
|
+
LOG_LEVEL_MESSAGE => Logger::UNKNOWN,
|
59
|
+
LOG_LEVEL_INFO => Logger::INFO,
|
60
|
+
LOG_LEVEL_DEBUG => Logger::DEBUG
|
61
|
+
}
|
62
|
+
GLIB_TO_SEVERITY.default = Logger::UNKNOWN
|
63
|
+
|
64
|
+
# nil being the default
|
65
|
+
@glib_log_domain = nil
|
66
|
+
@glib_log_handler_id = 0
|
67
|
+
|
68
|
+
# module-level, so it's not GCd away
|
69
|
+
LOG_HANDLER = Proc.new do |domain, level, message, user_data|
|
70
|
+
@logger.log(GLIB_TO_SEVERITY[level], message, domain)
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.remove_log_handler
|
74
|
+
if @glib_log_handler_id != 0 && @glib_log_domain
|
75
|
+
g_log_remove_handler @glib_log_domain, @glib_log_handler_id
|
76
|
+
@glib_log_handler_id = nil
|
77
|
+
end
|
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 {
|
111
|
+
GLib::remove_log_handler
|
112
|
+
}
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
module GObject
|
120
|
+
extend FFI::Library
|
121
|
+
|
122
|
+
if FFI::Platform.windows?
|
123
|
+
gobject_libname = 'libgobject-2.0-0.dll'
|
124
|
+
else
|
125
|
+
gobject_libname = 'gobject-2.0'
|
126
|
+
end
|
127
|
+
|
128
|
+
ffi_lib gobject_libname
|
129
|
+
|
130
|
+
# we can't just use ulong, windows has different int sizing rules
|
131
|
+
if FFI::Platform::ADDRESS_SIZE == 64
|
132
|
+
typedef :uint64, :GType
|
133
|
+
else
|
134
|
+
typedef :uint32, :GType
|
135
|
+
end
|
136
|
+
|
137
|
+
attach_function :g_type_init, [], :void
|
138
|
+
attach_function :g_type_name, [:GType], :string
|
139
|
+
attach_function :g_type_from_name, [:string], :GType
|
140
|
+
attach_function :g_type_fundamental, [:GType], :GType
|
141
|
+
|
142
|
+
# glib before 2.36 needed this, does nothing in current glib
|
143
|
+
g_type_init
|
144
|
+
|
145
|
+
# look up some common gtypes
|
146
|
+
GBOOL_TYPE = g_type_from_name "gboolean"
|
147
|
+
GINT_TYPE = g_type_from_name "gint"
|
148
|
+
GUINT64_TYPE = g_type_from_name "guint64"
|
149
|
+
GDOUBLE_TYPE = g_type_from_name "gdouble"
|
150
|
+
GENUM_TYPE = g_type_from_name "GEnum"
|
151
|
+
GFLAGS_TYPE = g_type_from_name "GFlags"
|
152
|
+
GSTR_TYPE = g_type_from_name "gchararray"
|
153
|
+
GOBJECT_TYPE = g_type_from_name "GObject"
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
require 'vips/gobject'
|
158
|
+
require 'vips/gvalue'
|
159
|
+
|
160
|
+
# This module provides a binding for the [libvips image processing
|
161
|
+
# library](https://jcupitt.github.io/libvips/).
|
162
|
+
#
|
163
|
+
# # Example
|
164
|
+
#
|
165
|
+
# ```ruby
|
166
|
+
# require 'vips'
|
167
|
+
#
|
168
|
+
# if ARGV.length < 2
|
169
|
+
# raise "usage: #{$PROGRAM_NAME}: input-file output-file"
|
170
|
+
# end
|
171
|
+
#
|
172
|
+
# im = Vips::Image.new_from_file ARGV[0], access: :sequential
|
173
|
+
#
|
174
|
+
# im *= [1, 2, 1]
|
175
|
+
#
|
176
|
+
# mask = Vips::Image.new_from_array [
|
177
|
+
# [-1, -1, -1],
|
178
|
+
# [-1, 16, -1],
|
179
|
+
# [-1, -1, -1]
|
180
|
+
# ], 8
|
181
|
+
# im = im.conv mask, precision: :integer
|
182
|
+
#
|
183
|
+
# im.write_to_file ARGV[1]
|
184
|
+
# ```
|
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.
|
188
|
+
#
|
189
|
+
# Reading this example line by line, we have:
|
190
|
+
#
|
191
|
+
# ```ruby
|
192
|
+
# im = Vips::Image.new_from_file ARGV[0], access: :sequential
|
193
|
+
# ```
|
194
|
+
#
|
195
|
+
# {Image.new_from_file} can load any image file supported by vips. In this
|
196
|
+
# example, we will be accessing pixels top-to-bottom as we sweep through the
|
197
|
+
# image reading and writing, so `:sequential` access mode is best for us. The
|
198
|
+
# default mode is `:random`: this allows for full random access to image pixels,
|
199
|
+
# but is slower and needs more memory. See {Access}
|
200
|
+
# for full details
|
201
|
+
# on the various modes available.
|
202
|
+
#
|
203
|
+
# You can also load formatted images from
|
204
|
+
# memory buffers, create images that wrap C-style memory arrays, or make images
|
205
|
+
# from constants.
|
206
|
+
#
|
207
|
+
# The next line:
|
208
|
+
#
|
209
|
+
# ```ruby
|
210
|
+
# im *= [1, 2, 1]
|
211
|
+
# ```
|
212
|
+
#
|
213
|
+
# Multiplying the image by an array constant uses one array element for each
|
214
|
+
# image band. This line assumes that the input image has three bands and will
|
215
|
+
# double the middle band. For RGB images, that's doubling green.
|
216
|
+
#
|
217
|
+
# Next we have:
|
218
|
+
#
|
219
|
+
# ```ruby
|
220
|
+
# mask = Vips::Image.new_from_array [
|
221
|
+
# [-1, -1, -1],
|
222
|
+
# [-1, 16, -1],
|
223
|
+
# [-1, -1, -1]
|
224
|
+
# ], 8
|
225
|
+
# im = im.conv mask, precision: :integer
|
226
|
+
# ```
|
227
|
+
#
|
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.
|
231
|
+
#
|
232
|
+
# See the libvips API docs for `vips_conv()` (the operation
|
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.
|
236
|
+
#
|
237
|
+
# Finally:
|
238
|
+
#
|
239
|
+
# ```ruby
|
240
|
+
# im.write_to_file ARGV[1]
|
241
|
+
# ```
|
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.
|
247
|
+
#
|
248
|
+
# # How it works
|
249
|
+
#
|
250
|
+
# The binding uses [ruby-ffi](https://github.com/ffi/ffi) to open the libvips
|
251
|
+
# shared library. When you call a method on the image class, it uses libvips
|
252
|
+
# introspection system (based on GObject) to search the
|
253
|
+
# library for an operation of that name, transforms the arguments to a form
|
254
|
+
# libvips can digest, and runs the operation.
|
255
|
+
#
|
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.
|
258
|
+
#
|
259
|
+
# # Automatic wrapping
|
260
|
+
#
|
261
|
+
# `ruby-vips` adds a {Image.method_missing} handler to {Image} and uses
|
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}.
|
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
|
267
|
+
# image, such as {Image.black}, appear as class methods. The remainder of
|
268
|
+
# the arguments you supply in the function call are used to set the other
|
269
|
+
# required input arguments. Any trailing keyword arguments are used to set
|
270
|
+
# options on the operation.
|
271
|
+
#
|
272
|
+
# The result is the required output
|
273
|
+
# argument if there is only one result, or an array of values if the operation
|
274
|
+
# produces several results. If the operation has optional output objects, they
|
275
|
+
# are returned as a final hash.
|
276
|
+
#
|
277
|
+
# For example, {Image#min}, the vips operation that searches an image for
|
278
|
+
# the minimum value, has a large number of optional arguments. You can use it to
|
279
|
+
# find the minimum value like this:
|
280
|
+
#
|
281
|
+
# ```ruby
|
282
|
+
# min_value = image.min
|
283
|
+
# ```
|
284
|
+
#
|
285
|
+
# You can ask it to return the position of the minimum with `:x` and `:y`.
|
286
|
+
#
|
287
|
+
# ```ruby
|
288
|
+
# min_value, opts = min x: true, y: true
|
289
|
+
# x_pos = opts['x']
|
290
|
+
# y_pos = opts['y']
|
291
|
+
# ```
|
292
|
+
#
|
293
|
+
# Now `x_pos` and `y_pos` will have the coordinates of the minimum value.
|
294
|
+
# There's actually a convenience method for this, {Image#minpos}.
|
295
|
+
#
|
296
|
+
# You can also ask for the top *n* minimum, for example:
|
297
|
+
#
|
298
|
+
# ```ruby
|
299
|
+
# min_value, opts = min size: 10, x_array: true, y_array: true
|
300
|
+
# x_pos = opts['x_array']
|
301
|
+
# y_pos = opts['y_array']
|
302
|
+
# ```
|
303
|
+
#
|
304
|
+
# Now `x_pos` and `y_pos` will be 10-element arrays.
|
305
|
+
#
|
306
|
+
# Because operations are member functions and return the result image, you can
|
307
|
+
# chain them. For example, you can write:
|
308
|
+
#
|
309
|
+
# ```ruby
|
310
|
+
# result_image = image.real.cos
|
311
|
+
# ```
|
312
|
+
#
|
313
|
+
# to calculate the cosine of the real part of a complex image.
|
314
|
+
# There are also a full set
|
315
|
+
# of arithmetic operator overloads, see below.
|
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
|
323
|
+
# will be converted for you. You can write:
|
324
|
+
#
|
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]
|
330
|
+
# ```
|
331
|
+
#
|
332
|
+
# And so on. A set of overloads are defined for {Image#linear}, see below.
|
333
|
+
#
|
334
|
+
# It does a couple of more ambitious conversions. It will automatically convert
|
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:
|
337
|
+
#
|
338
|
+
# ```ruby
|
339
|
+
# profile = im.get_value "icc-profile-data"
|
340
|
+
# ```
|
341
|
+
#
|
342
|
+
# and profile will be a byte array.
|
343
|
+
#
|
344
|
+
# If an operation takes several input images, you can use a constant for all but
|
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
|
347
|
+
# between a then and an else image:
|
348
|
+
#
|
349
|
+
# ```ruby
|
350
|
+
# result_image = condition_image.ifthenelse then_image, else_image
|
351
|
+
# ```
|
352
|
+
#
|
353
|
+
# You can use a constant instead of either the then or the else parts and it
|
354
|
+
# will be expanded to an image for you. If you use a constant for both then and
|
355
|
+
# else, it will be expanded to match the condition image. For example:
|
356
|
+
#
|
357
|
+
# ```ruby
|
358
|
+
# result_image = condition_image.ifthenelse [0, 255, 0], [255, 0, 0]
|
359
|
+
# ```
|
360
|
+
#
|
361
|
+
# Will make an image where true pixels are green and false pixels are red.
|
362
|
+
#
|
363
|
+
# This is useful for {Image#bandjoin}, the thing to join two or more
|
364
|
+
# images up bandwise. You can write:
|
365
|
+
#
|
366
|
+
# ```ruby
|
367
|
+
# rgba = rgb.bandjoin 255
|
368
|
+
# ```
|
369
|
+
#
|
370
|
+
# to append a constant 255 band to an image, perhaps to add an alpha channel. Of
|
371
|
+
# course you can also write:
|
372
|
+
#
|
373
|
+
# ```ruby
|
374
|
+
# result_image = image1.bandjoin image2
|
375
|
+
# result_image = image1.bandjoin [image2, image3]
|
376
|
+
# result_image = Vips::Image.bandjoin [image1, image2, image3]
|
377
|
+
# result_image = image1.bandjoin [image2, 255]
|
378
|
+
# ```
|
379
|
+
#
|
380
|
+
# and so on.
|
381
|
+
#
|
382
|
+
# # Logging
|
383
|
+
#
|
384
|
+
# Libvips uses g_log() to log warning, debug, info and (some) error messages.
|
385
|
+
#
|
386
|
+
# https://developer.gnome.org/glib/stable/glib-Message-Logging.html
|
387
|
+
#
|
388
|
+
# You can disable wanrings by defining the `VIPS_WARNING` environment variable.
|
389
|
+
# You can enable info output by defining `VIPS_INFO`.
|
390
|
+
#
|
391
|
+
# # Exceptions
|
392
|
+
#
|
393
|
+
# The wrapper spots errors from vips operations and raises the {Vips::Error}
|
394
|
+
# exception. You can catch it in the usual way.
|
395
|
+
#
|
396
|
+
# # Automatic YARD documentation
|
397
|
+
#
|
398
|
+
# The bulk of these API docs are generated automatically by
|
399
|
+
# {Vips::generate_yard}. It examines
|
400
|
+
# libvips and writes a summary of each operation and the arguments and options
|
401
|
+
# that that operation expects.
|
402
|
+
#
|
403
|
+
# Use the [C API
|
404
|
+
# docs](https://jcupitt.github.io/libvips/API/current)
|
405
|
+
# for more detail.
|
406
|
+
#
|
407
|
+
# # Enums
|
408
|
+
#
|
409
|
+
# The libvips enums, such as `VipsBandFormat` appear in ruby-vips as Symbols
|
410
|
+
# like `:uchar`. They are documented as a set of classes for convenience, see
|
411
|
+
# the class list.
|
412
|
+
#
|
413
|
+
# # Draw operations
|
414
|
+
#
|
415
|
+
# Paint operations like {Image#draw_circle} and {Image#draw_line}
|
416
|
+
# modify their input image. This
|
417
|
+
# makes them hard to use with the rest of libvips: you need to be very careful
|
418
|
+
# about the order in which operations execute or you can get nasty crashes.
|
419
|
+
#
|
420
|
+
# The wrapper spots operations of this type and makes a private copy of the
|
421
|
+
# image in memory before calling the operation. This stops crashes, but it does
|
422
|
+
# make it inefficient. If you draw 100 lines on an image, for example, you'll
|
423
|
+
# copy the image 100 times. The wrapper does make sure that memory is recycled
|
424
|
+
# where possible, so you won't have 100 copies in memory.
|
425
|
+
#
|
426
|
+
# If you want to avoid the copies, you'll need to call drawing operations
|
427
|
+
# yourself.
|
428
|
+
#
|
429
|
+
# # Overloads
|
430
|
+
#
|
431
|
+
# The wrapper defines the usual set of arithmetic, boolean and relational
|
432
|
+
# overloads on image. You can mix images, constants and lists of constants
|
433
|
+
# (almost) freely. For example, you can write:
|
434
|
+
#
|
435
|
+
# ```ruby
|
436
|
+
# result_image = ((image * [1, 2, 3]).abs < 128) | 4
|
437
|
+
# ```
|
438
|
+
#
|
439
|
+
# # Expansions
|
440
|
+
#
|
441
|
+
# Some vips operators take an enum to select an action, for example
|
442
|
+
# {Image#math} can be used to calculate sine of every pixel like this:
|
443
|
+
#
|
444
|
+
# ```ruby
|
445
|
+
# result_image = image.math :sin
|
446
|
+
# ```
|
447
|
+
#
|
448
|
+
# This is annoying, so the wrapper expands all these enums into separate members
|
449
|
+
# named after the enum. So you can write:
|
450
|
+
#
|
451
|
+
# ```ruby
|
452
|
+
# result_image = image.sin
|
453
|
+
# ```
|
454
|
+
#
|
455
|
+
# # Convenience functions
|
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},
|
460
|
+
# {Image#median}.
|
461
|
+
|
462
|
+
module Vips
|
463
|
+
extend FFI::Library
|
464
|
+
|
465
|
+
if FFI::Platform.windows?
|
466
|
+
vips_libname = 'libvips-42.dll'
|
467
|
+
else
|
468
|
+
vips_libname = File.expand_path('libvips.so', __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
|
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.
|
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
|
582
|
+
|
583
|
+
LIBRARY_VERSION = Vips::version_string
|
584
|
+
|
585
|
+
# libvips has this arbitrary number as a sanity-check upper bound on image
|
586
|
+
# size. It's sometimes useful for know whan calculating image ratios.
|
587
|
+
MAX_COORD = 10000000
|
588
|
+
|
589
|
+
end
|
590
|
+
|
591
|
+
require 'vips/object'
|
592
|
+
require 'vips/operation'
|
593
|
+
require 'vips/image'
|
594
|
+
require 'vips/interpolate'
|
595
|
+
require 'vips/version'
|
596
|
+
|
597
|
+
|