Skip to content
jcupitt edited this page Jun 29, 2012 · 10 revisions

Basic concepts

Sequential mode read

Many image formats only really support sequential reading. For example, libpng provides png_read_row(), a function which reads the next line of pixels from a file. You call it once for each line in the image to get every pixel.

However, many operations require random access to pixels. For example, a 90-degree rotate will need to read a column of pixels for every output line it writes. If it just used png_read_row() it would need to decompress the input image many, many times in order to create the output.

To prevent this libvips will first decompress the entire image to a large temporary area and then process from that. This temporary area is in memory for small files or on disc for large files.

Not all operations need random access to their source pixels. For example, thumbnailing, the process of shrinking images for display, can work strictly top-to-bottom. To help speed up operations of this type you can give a hint to read operations to indicate that you only need sequential access. For example:

a = Image.png filename, :sequential => true

libvips opens this image it will not decompress to a temporary buffer but, instead, stream pixels from the png decompressor directly through the operation. This saves first writing and then reading back the temporary area.

See the longer discussion on the libvips blog for more details and benchmarks.

Lookup tables

It's just an array you use to pre-calculate results.

For an 8-bit image, there are only 256 possible values for pixels. For example, you don't need to calculate pow() for every pixel, just calculate pow() for the values 0 - 255, then when you process the image just look up the correct result in the table rather than calculating it each time.

lut = Image.identity(1)

This makes a 1 band image 256 elements across and one element deep where elements have the values 0, 1, 2, 3, 4, 5, ... 255. It's called "identity" because it creates an identity function.

lut = lut.pow(0.5).lin(255 / 255 ** 0.5, 0)

This runs the pow() on the identity LUT. So element 123 (for example) will contain

123 ** 0.5 * 255 / 255 ** 0.5

ie. the result that every pixel with the value 123 out to be changed to.

Finally this:

im = im.maplut(lut)

loops over the large image looking up every pixel value in lut and replacing it with the pre-calculated result.

Clone this wiki locally