|
1 |
| -# wrapper for libvips |
| 1 | +""" |
| 2 | +This module wraps the libvips image processing library. |
| 3 | +
|
| 4 | +It needs vips-8.2 or later to be installed, and it uses cffi to call into the |
| 5 | +library, so you need to have the compiled library on your library search path. |
| 6 | +
|
| 7 | +See https://jcupitt.github.io/libvips for an introduction to the underlying |
| 8 | +library. These notes introduce the Python binding. |
| 9 | +
|
| 10 | +Example |
| 11 | +======= |
| 12 | +
|
| 13 | +This example loads a file, boosts the green channel (I'm not sure why), |
| 14 | +sharpens the image, and saves it back to disc again:: |
| 15 | +
|
| 16 | + import pyvips |
| 17 | +
|
| 18 | + image = pyvips.Image.new_from_file('some-image.jpg', access = 'sequential') |
| 19 | + image *= [1, 2, 1] |
| 20 | + mask = pyvips.Image.new_from_array([ |
| 21 | + [-1, -1, -1], |
| 22 | + [-1, 16, -1], |
| 23 | + [-1, -1, -1] |
| 24 | + ], scale = 8) |
| 25 | + image = image.conv(mask, precision = 'integer') |
| 26 | + image.write_to_file('x.jpg') |
| 27 | +
|
| 28 | +Reading this example line by line, we have:: |
| 29 | +
|
| 30 | + image = pyvips.Image.new_from_file('some-image.jpg', access = 'sequential') |
| 31 | +
|
| 32 | +`Image.new_from_file` can load any image file supported by vips. In this |
| 33 | +example, we will be accessing pixels top-to-bottom as we sweep through the |
| 34 | +image reading and writing, so `sequential` access mode is best for us. |
| 35 | +
|
| 36 | +The default mode is `random` which allows for full random access to image |
| 37 | +pixels, but is slower and needs more memory. See `Access` for full details |
| 38 | +on the various modes available. |
| 39 | +
|
| 40 | +You can also load formatted images from |
| 41 | +memory buffers, create images that wrap C-style memory arrays, or make images |
| 42 | +from constants. |
| 43 | +
|
| 44 | +The next line:: |
| 45 | +
|
| 46 | + image *= [1, 2, 1] |
| 47 | +
|
| 48 | +Multiplying the image by an array constant uses one array element for each |
| 49 | +image band. This line assumes that the input image has three bands and will |
| 50 | +double the middle band. For RGB images, that's doubling green. |
| 51 | +
|
| 52 | +There are the usual range of arithmetic operator overloads. |
| 53 | +
|
| 54 | +Next we have:: |
| 55 | +
|
| 56 | + mask = pyvips.Image.new_from_array([ |
| 57 | + [-1, -1, -1], |
| 58 | + [-1, 16, -1], |
| 59 | + [-1, -1, -1] |
| 60 | + ], scale = 8) |
| 61 | + image = image.conv(mask, precision = 'integer') |
| 62 | +
|
| 63 | +`Image.new_from_array` creates an image from an array constant. The scale is |
| 64 | +the amount to divide the image by after integer convolution. |
| 65 | +
|
| 66 | +See the libvips API docs for `vips_conv()` (the operation |
| 67 | +invoked by `Image.conv`) for details on the convolution operator. By default, |
| 68 | +it computes with a float mask, but `integer` is fine for this case, and is |
| 69 | +much faster. |
| 70 | +
|
| 71 | +Finally:: |
| 72 | +
|
| 73 | + image.write_to_file('x.jpg') |
| 74 | +
|
| 75 | +`Image.write_to_file` writes an image back to the filesystem. It can |
| 76 | +write any format supported by vips: the file type is set from the filename |
| 77 | +suffix. You can also write formatted images to memory buffers, or dump |
| 78 | +image data to a raw memory array. |
| 79 | +
|
| 80 | +How it works |
| 81 | +============ |
| 82 | +
|
| 83 | +The binding uses [ruby-ffi](https://github.com/ffi/ffi) to open the libvips |
| 84 | +shared library. When you call a method on the image class, it uses libvips |
| 85 | +introspection system (based on GObject) to search the |
| 86 | +library for an operation of that name, transforms the arguments to a form |
| 87 | +libvips can digest, and runs the operation. |
| 88 | +
|
| 89 | +This means ruby-vips always presents the API implemented by the libvips shared |
| 90 | +library. It should update itself as new features are added. |
| 91 | +
|
| 92 | + Automatic wrapping |
| 93 | +
|
| 94 | +`ruby-vips` adds a {Image.method_missing} handler to {Image} and uses |
| 95 | +it to look up vips operations. For example, the libvips operation `add`, which |
| 96 | +appears in C as `vips_add()`, appears in Ruby as {Image#add}. |
| 97 | +
|
| 98 | +The operation's list of required arguments is searched and the first input |
| 99 | +image is set to the value of `self`. Operations which do not take an input |
| 100 | +image, such as {Image.black}, appear as class methods. The remainder of |
| 101 | +the arguments you supply in the function call are used to set the other |
| 102 | +required input arguments. Any trailing keyword arguments are used to set |
| 103 | +options on the operation. |
| 104 | +
|
| 105 | +The result is the required output |
| 106 | +argument if there is only one result, or an array of values if the operation |
| 107 | +produces several results. If the operation has optional output objects, they |
| 108 | +are returned as a final hash. |
| 109 | +
|
| 110 | +For example, {Image#min}, the vips operation that searches an image for |
| 111 | +the minimum value, has a large number of optional arguments. You can use it to |
| 112 | +find the minimum value like this: |
| 113 | +
|
| 114 | +```ruby |
| 115 | +min_value = image.min |
| 116 | +``` |
| 117 | +
|
| 118 | +You can ask it to return the position of the minimum with `:x` and `:y`. |
| 119 | + |
| 120 | +```ruby |
| 121 | +min_value, opts = min x: true, y: true |
| 122 | +x_pos = opts['x'] |
| 123 | +y_pos = opts['y'] |
| 124 | +``` |
| 125 | +
|
| 126 | +Now `x_pos` and `y_pos` will have the coordinates of the minimum value. |
| 127 | +There's actually a convenience method for this, {Image#minpos}. |
| 128 | +
|
| 129 | +You can also ask for the top *n* minimum, for example: |
| 130 | +
|
| 131 | +```ruby |
| 132 | +min_value, opts = min size: 10, x_array: true, y_array: true |
| 133 | +x_pos = opts['x_array'] |
| 134 | +y_pos = opts['y_array'] |
| 135 | +``` |
| 136 | +
|
| 137 | +Now `x_pos` and `y_pos` will be 10-element arrays. |
| 138 | +
|
| 139 | +Because operations are member functions and return the result image, you can |
| 140 | +chain them. For example, you can write: |
| 141 | +
|
| 142 | +```ruby |
| 143 | +result_image = image.real.cos |
| 144 | +``` |
| 145 | +
|
| 146 | +to calculate the cosine of the real part of a complex image. |
| 147 | +There are also a full set |
| 148 | +of arithmetic operator overloads, see below. |
| 149 | +
|
| 150 | +libvips types are also automatically wrapped. The override looks at the type |
| 151 | +of argument required by the operation and converts the value you supply, |
| 152 | +when it can. For example, {Image#linear} takes a `VipsArrayDouble` as |
| 153 | +an argument |
| 154 | +for the set of constants to use for multiplication. You can supply this |
| 155 | +value as an integer, a float, or some kind of compound object and it |
| 156 | +will be converted for you. You can write: |
| 157 | +
|
| 158 | +```ruby |
| 159 | +result_image = image.linear 1, 3 |
| 160 | +result_image = image.linear 12.4, 13.9 |
| 161 | +result_image = image.linear [1, 2, 3], [4, 5, 6] |
| 162 | +result_image = image.linear 1, [4, 5, 6] |
| 163 | +``` |
| 164 | +
|
| 165 | +And so on. A set of overloads are defined for {Image#linear}, see below. |
| 166 | +
|
| 167 | +It does a couple of more ambitious conversions. It will automatically convert |
| 168 | +to and from the various vips types, like `VipsBlob` and `VipsArrayImage`. For |
| 169 | +example, you can read the ICC profile out of an image like this: |
| 170 | +
|
| 171 | +```ruby |
| 172 | +profile = im.get_value "icc-profile-data" |
| 173 | +``` |
| 174 | +
|
| 175 | +and profile will be a byte array. |
| 176 | +
|
| 177 | +If an operation takes several input images, you can use a constant for all but |
| 178 | +one of them and the wrapper will expand the constant to an image for you. For |
| 179 | +example, {Image#ifthenelse} uses a condition image to pick pixels |
| 180 | +between a then and an else image: |
| 181 | +
|
| 182 | +```ruby |
| 183 | +result_image = condition_image.ifthenelse then_image, else_image |
| 184 | +``` |
| 185 | +
|
| 186 | +You can use a constant instead of either the then or the else parts and it |
| 187 | +will be expanded to an image for you. If you use a constant for both then and |
| 188 | +else, it will be expanded to match the condition image. For example: |
| 189 | +
|
| 190 | +```ruby |
| 191 | +result_image = condition_image.ifthenelse [0, 255, 0], [255, 0, 0] |
| 192 | +``` |
| 193 | +
|
| 194 | +Will make an image where true pixels are green and false pixels are red. |
| 195 | +
|
| 196 | +This is useful for {Image#bandjoin}, the thing to join two or more |
| 197 | +images up bandwise. You can write: |
| 198 | +
|
| 199 | +```ruby |
| 200 | +rgba = rgb.bandjoin 255 |
| 201 | +``` |
| 202 | +
|
| 203 | +to append a constant 255 band to an image, perhaps to add an alpha channel. Of |
| 204 | +course you can also write: |
| 205 | +
|
| 206 | +```ruby |
| 207 | +result_image = image1.bandjoin image2 |
| 208 | +result_image = image1.bandjoin [image2, image3] |
| 209 | +result_image = Vips::Image.bandjoin [image1, image2, image3] |
| 210 | +result_image = image1.bandjoin [image2, 255] |
| 211 | +``` |
| 212 | +
|
| 213 | +and so on. |
| 214 | +
|
| 215 | + Automatic YARD documentation |
| 216 | +
|
| 217 | +The bulk of these API docs are generated automatically by |
| 218 | +{Vips::generate_yard}. It examines |
| 219 | +libvips and writes a summary of each operation and the arguments and options |
| 220 | +that that operation expects. |
| 221 | +
|
| 222 | +Use the [C API |
| 223 | +docs](https://jcupitt.github.io/libvips/API/current) |
| 224 | +for more detail. |
| 225 | +
|
| 226 | + Exceptions |
| 227 | +
|
| 228 | +The wrapper spots errors from vips operations and raises the {Vips::Error} |
| 229 | +exception. You can catch it in the usual way. |
| 230 | +
|
| 231 | + Enums |
| 232 | +
|
| 233 | +The libvips enums, such as `VipsBandFormat` appear in ruby-vips as Symbols |
| 234 | +like `:uchar`. They are documented as a set of classes for convenience, see |
| 235 | +the class list. |
| 236 | +
|
| 237 | + Draw operations |
| 238 | +
|
| 239 | +Paint operations like {Image#draw_circle} and {Image#draw_line} |
| 240 | +modify their input image. This |
| 241 | +makes them hard to use with the rest of libvips: you need to be very careful |
| 242 | +about the order in which operations execute or you can get nasty crashes. |
| 243 | +
|
| 244 | +The wrapper spots operations of this type and makes a private copy of the |
| 245 | +image in memory before calling the operation. This stops crashes, but it does |
| 246 | +make it inefficient. If you draw 100 lines on an image, for example, you'll |
| 247 | +copy the image 100 times. The wrapper does make sure that memory is recycled |
| 248 | +where possible, so you won't have 100 copies in memory. |
| 249 | +
|
| 250 | +If you want to avoid the copies, you'll need to call drawing operations |
| 251 | +yourself. |
| 252 | +
|
| 253 | + Overloads |
| 254 | +
|
| 255 | +The wrapper defines the usual set of arithmetic, boolean and relational |
| 256 | +overloads on image. You can mix images, constants and lists of constants |
| 257 | +(almost) freely. For example, you can write: |
| 258 | +
|
| 259 | +```ruby |
| 260 | +result_image = ((image * [1, 2, 3]).abs < 128) | 4 |
| 261 | +``` |
| 262 | +
|
| 263 | + Expansions |
| 264 | +
|
| 265 | +Some vips operators take an enum to select an action, for example |
| 266 | +{Image#math} can be used to calculate sine of every pixel like this: |
| 267 | +
|
| 268 | +```ruby |
| 269 | +result_image = image.math :sin |
| 270 | +``` |
| 271 | +
|
| 272 | +This is annoying, so the wrapper expands all these enums into separate members |
| 273 | +named after the enum. So you can write: |
| 274 | +
|
| 275 | +```ruby |
| 276 | +result_image = image.sin |
| 277 | +``` |
| 278 | +
|
| 279 | + Convenience functions |
| 280 | +
|
| 281 | +The wrapper defines a few extra useful utility functions: |
| 282 | +{Image#get_value}, {Image#set_value}, {Image#bandsplit}, |
| 283 | +{Image#maxpos}, {Image#minpos}, |
| 284 | +{Image#median}. |
| 285 | +
|
| 286 | +
|
| 287 | +""" |
2 | 288 |
|
3 | 289 | # Our classes need to refer to each other ... make them go via this
|
4 | 290 | # package-level global which we update at the end with references to the real
|
|
0 commit comments