Module: Vips
- Defined in:
- lib/vips8/image.rb,
lib/vips8.rb,
lib/vips8/call.rb,
lib/vips8/align.rb,
lib/vips8/angle.rb,
lib/vips8/error.rb,
lib/vips8/access.rb,
lib/vips8/coding.rb,
lib/vips8/extend.rb,
lib/vips8/angle45.rb,
lib/vips8/methods.rb,
lib/vips8/argument.rb,
lib/vips8/direction.rb,
lib/vips8/operation.rb,
lib/vips8/bandformat.rb,
lib/vips8/demandstyle.rb,
lib/vips8/interpolate.rb,
lib/vips8/foreignflags.rb,
lib/vips8/interpretation.rb more...
Overview
This module provides a set of overrides for the vips image processing library used via the gobject-introspection gem.
It needs vips-8.2 or later to be installed,
and Vips-8.0.typelib
, the vips typelib, needs to be on your
GI_TYPELIB_PATH
.
Example
require 'vips8'
if ARGV.length < 2
raise "usage: #{$PROGRAM_NAME}: input-file output-file"
end
im = Vips::Image.new_from_file ARGV[0], :access => :sequential
im *= [1, 2, 1]
mask = Vips::Image.new_from_array [
[-1, -1, -1],
[-1, 16, -1],
[-1, -1, -1]], 8
im = im.conv mask
im.write_to_file ARGV[1]
This example loads a file, boosts the green channel (I'm not sure why), sharpens the image, and saves it back to disc again.
Reading this example line by line, we have:
im = Vips::Image.new_from_file ARGV[0], :access => :sequential
Image.new_from_file can load any image file supported by vips. In this
example, we will be accessing pixels top-to-bottom as we sweep through the
image reading and writing, so :sequential
access mode is best for us. The
default mode is :random
, this allows for full random access to image pixels,
but is slower and needs more memory. See Access
for full details
on the various modes available. You can also load formatted images from
memory buffers or create images that wrap C-style memory arrays.
The next line:
im *= [1, 2, 1]
Multiplying the image by an array constant uses one array element for each image band. This line assumes that the input image has three bands and will double the middle band. For RGB images, that's doubling green.
Next we have:
mask = Vips::Image.new_from_array [
[-1, -1, -1],
[-1, 16, -1],
[-1, -1, -1]], 8
im = im.conv mask
Image.new_from_array creates an image from an array constant. The 8 at
the end sets the scale: the amount to divide the image by after
integer convolution. See the libvips API docs for vips_conv()
(the operation
invoked by Image#conv) for details on the convolution operator.
Finally:
im.write_to_file ARGV[1]
Image#write_to_file writes an image back to the filesystem. It can write any format supported by vips: the file type is set from the filename suffix. You can also write formatted images to memory buffers, or dump image data to a raw memory array.
How it works
The C sources to libvips include a set of specially formatted
comments which describe its interfaces. When you compile the library,
gobject-introspection generates Vips-8.0.typelib
, a file
describing how to use libvips.
The gobject-introspection
gem loads this typelib and uses it to let you
call
functions in libvips directly from Ruby. However, the interface you get
from raw gobject-introspection is rather ugly, so the ruby-vips8
gem
adds a set
of overrides which try to make it nicer to use.
The API you end up with is a Ruby-ish version of the VIPS C API. Full documentation on the operations and what they do is there, you can use it directly. This document explains the extra features of the Ruby API and lists the available operations very briefly.
Automatic wrapping
ruby-vips8
adds a Image.method_missing handler to Image and uses
it to look up vips operations. For example, the libvips operation add
, which
appears in C as vips_add()
, appears in Ruby as Image#add.
The operation's list of required arguments is searched and the first input
image is set to the value of self
. Operations which do not take an input
image, such as Image.black, appear as class methods. The remainder of
the arguments you supply in the function call are used to set the other
required input arguments. If the final supplied argument is a hash, it is used
to set any optional input arguments. The result is the required output
argument if there is only one result, or an array of values if the operation
produces several results. If the operation has optional output objects, they
are returned as a final hash.
For example, Image#min, the vips operation that searches an image for the minimum value, has a large number of optional arguments. You can use it to find the minimum value like this:
min_value = image.min
You can ask it to return the position of the minimum with :x
and :y
.
min_value, opts = min :x => true, :y => true
x_pos = opts['x']
y_pos = opts['y']
Now x_pos
and y_pos
will have the coordinates of the minimum value.
There's actually a convenience function for this, Image#minpos.
You can also ask for the top n minimum, for example:
min_value, opts = min :size => 10, :x_array => true, :y_array => true
x_pos = opts['x_array']
y_pos = opts['y_array']
Now x_pos
and y_pos
will be 10-element arrays.
Because operations are member functions and return the result image, you can chain them. For example, you can write:
result_image = image.real.cos
to calculate the cosine of the real part of a complex image. There are also a full set of arithmetic operator overloads, see below.
libvips types are also automatically wrapped. The override looks at the type
of argument required by the operation and converts the value you supply,
when it can. For example, Image#linear takes a VipsArrayDouble
as
an argument
for the set of constants to use for multiplication. You can supply this
value as an integer, a float, or some kind of compound object and it
will be converted for you. You can write:
result_image = image.linear 1, 3
result_image = image.linear 12.4, 13.9
result_image = image.linear [1, 2, 3], [4, 5, 6]
result_image = image.linear 1, [4, 5, 6]
And so on. A set of overloads are defined for Image#linear, see below.
It does a couple of more ambitious conversions. It will automatically convert
to and from the various vips types, like VipsBlob
and VipsArrayImage
. For
example, you can read the ICC profile out of an image like this:
profile = im.get_value "icc-profile-data"
and profile will be a byte array.
If an operation takes several input images, you can use a constant for all but one of them and the wrapper will expand the constant to an image for you. For example, Image#ifthenelse uses a condition image to pick pixels between a then and an else image:
result_image = condition_image.ifthenelse then_image, else_image
You can use a constant instead of either the then or the else parts and it will be expanded to an image for you. If you use a constant for both then and else, it will be expanded to match the condition image. For example:
result_image = condition_image.ifthenelse [0, 255, 0], [255, 0, 0]
Will make an image where true pixels are green and false pixels are red.
This is useful for Image#bandjoin, the thing to join two or more images up bandwise. You can write:
rgba = rgb.bandjoin 255
to append a constant 255 band to an image, perhaps to add an alpha channel. Of course you can also write:
result_image = image1.bandjoin image2
result_image = image1.bandjoin [image2, image3]
result_image = Vips::Image.bandjoin [image1, image2, image3]
result_image = image1.bandjoin [image2, 255]
and so on.
Automatic YARD documentation
The bulk of these API docs are generated automatically by generate_yard. It examines libvips and writes a summary of each operation and the arguments and options that operation expects.
Use the C API docs for more detail.
Exceptions
The wrapper spots errors from vips operations and raises the Error exception. You can catch it in the usual way.
Draw operations
Paint operations like Image#draw_circle and Image#draw_line modify their input image. This makes them hard to use with the rest of libvips: you need to be very careful about the order in which operations execute or you can get nasty crashes.
The wrapper spots operations of this type and makes a private copy of the image in memory before calling the operation. This stops crashes, but it does make it inefficient. If you draw 100 lines on an image, for example, you'll copy the image 100 times. The wrapper does make sure that memory is recycled where possible, so you won't have 100 copies in memory.
If you want to avoid the copies, you'll need to call drawing operations yourself.
Overloads
The wrapper defines the usual set of arithmetic, boolean and relational overloads on image. You can mix images, constants and lists of constants (almost) freely. For example, you can write:
result_image = ((image * [1, 2, 3]).abs < 128) | 4
Expansions
Some vips operators take an enum to select an action, for example Image#math can be used to calculate sine of every pixel like this:
result_image = image.math :sin
This is annoying, so the wrapper expands all these enums into separate members named after the enum. So you can write:
result_image = image.sin
Convenience functions
The wrapper defines a few extra useful utility functions: Image#get_value, Image#set_value, Image#bandsplit, Image#maxpos, Image#minpos, Image#median.
Defined Under Namespace
Classes: Access, Align, Angle, Angle45, BandFormat, Coding, DemandStyle, Direction, Error, Extend, ForeignFlags, Image, Interpolate, Interpretation
Class Method Summary collapse
-
.call(name, *args) ⇒ Object
This is the public entry point for the vips8 binding.
-
.generate_yard ⇒ Object
This method generates yard comments for all the dynamically bound vips operations.
-
.set_debug(dbg) ⇒ Object
Turn debug logging on and off.
Class Method Details
permalink .call(name, *args) ⇒ Object
This is the public entry point for the vips8 binding. call will run any vips operation, for example:
out = Vips::call "black", 100, 100, :bands => 12
will call the C function
vips_black( &out, 100, 100, "bands", 12, NULL );
There are Vips::Image#method_missing hooks which will run call for you on Image for undefined instance or class methods. So you can also write:
out = Vips::Image.black 100, 100, :bands => 12
Or perhaps:
x = Vips::Image.black 100, 100
y = x.invert
to run the vips_invert()
operator.
There are also a set of operator overloads and some convenience functions, see Image.
If the operator needs a vector constant, call will turn a scalar into a
vector for you. So for x.linear(a, b)
, which calculates
x * a + b
where a
and b
are vector constants, you can write:
x = Vips::Image.black 100, 100, :bands => 3
y = x.linear(1, 2)
y = x.linear([1], 4)
y = x.linear([1, 2, 3], 4)
or any other combination. The operator overloads use this facility to support all the variations on:
x = Vips::Image.black 100, 100, :bands => 3
y = x * 2
y = x + [1,2,3]
y = x % [1]
Similarly, whereever an image is required, you can use a constant. The constant will be expanded to an image matching the first input image argument. For example, you can write:
x = Vips::Image.black 100, 100, :bands => 3
y = x.bandjoin(255)
to add an extra band to the image where each pixel in the new band has the constant value 255.
298 299 300 |
# File 'lib/vips8/call.rb', line 298 def self.call(name, *args) Vips::call_base name, nil, "", args end |
permalink .generate_yard ⇒ Object
This method generates yard comments for all the dynamically bound vips operations.
Regenerate with something like:
ruby > methods.rb require 'vips8'; Vips::generate_yard ^D
1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 |
# File 'lib/vips8/image.rb', line 1249 def self.generate_yard # these have hand-written methods, see above no_generate = ["bandjoin", "ifthenelse"] generate_operation = lambda do |op| flags = op.flags return if (flags & :deprecated) != 0 nickname = Vips::nickname_find op.gtype return if no_generate.include? nickname all_args = op.get_args.select {|arg| not arg.isset} # separate args into various categories required_input = all_args.select do |arg| (arg.flags & :input) != 0 and (arg.flags & :required) != 0 end optional_input = all_args.select do |arg| (arg.flags & :input) != 0 and (arg.flags & :required) == 0 end required_output = all_args.select do |arg| (arg.flags & :output) != 0 and (arg.flags & :required) != 0 end # required input args with :modify are copied and appended to # output modified_required_input = required_input.select do |arg| (arg.flags & :modify) != 0 end required_output += modified_required_input optional_output = all_args.select do |arg| (arg.flags & :output) != 0 and (arg.flags & :required) == 0 end # optional input args with :modify are copied and appended to # output modified_optional_input = optional_input.select do |arg| (arg.flags & :modify) != 0 end optional_output += modified_optional_input # find the first input image, if any ... we will be a method of this # instance member_x = required_input.find do |x| x.gtype.type_is_a? GLib::Type["VipsImage"] end if member_x != nil required_input.delete member_x end print "# @!method " print "self." if not member_x print "#{nickname}(" print required_input.map(&:name).join(", ") puts ", opts = {})" puts "# #{op.description.capitalize}." required_input.each do |arg| puts "# @param #{arg.name} [#{arg.type}] #{arg.blurb}" end puts "# @param [Hash] opts Set of options" optional_input.each do |arg| puts "# @option opts [#{arg.type}] :#{arg.name} #{arg.blurb}" end optional_output.each do |arg| print "# @option opts [#{arg.type}] :#{arg.name}" puts " Output #{arg.blurb}" end print "# @return [" if required_output.length == 0 print "nil" elsif required_output.length == 1 print required_output[0].type elsif print "Array<" print required_output.map(&:type).join(", ") print ">" end if optional_output.length > 0 print ", Hash<Symbol => Object>" end print "] " print required_output.map(&:blurb).join(", ") if optional_output.length > 0 print ", " if required_output.length > 0 print "Hash of optional output items" end puts "" puts "" end generate_class = lambda do |gtype| begin # can fail for abstract types # can't find a way to get to #abstract? from a gtype op = Vips::Operation.new gtype.name rescue op = nil end generate_operation.(op) if op gtype.children.each do |x| generate_class.(x) end end puts "module Vips" puts " class Image" puts "" # gobject-introspection 3.0.7 crashes a lot if it GCs while doing # something GC.disable generate_class.(GLib::Type["VipsOperation"]) puts " end" puts "end" end |
permalink .set_debug(dbg) ⇒ Object
Turn debug logging on and off.
38 39 40 |
# File 'lib/vips8.rb', line 38 def self.set_debug dbg $vips_debug = dbg end |