Merge branch 'add-markdown-docs' into 8.5

This commit is contained in:
John Cupitt 2017-04-06 11:51:36 +01:00
commit a5b04091ee
28 changed files with 2270 additions and 32 deletions

View File

@ -1,6 +1,8 @@
25/3/17 started 8.5.2
- better behaviour for truncated PNG files, thanks Yury
- missing proto for vips_tiffsave_buffer(), thanks greut
- move some docs from the wiki and blog into core libvips docs
- add support for markdown in docs
25/3/17 started 8.5.1
- init more classes earlier, thanks David

2
TODO
View File

@ -1,3 +1,5 @@
- add analytics tags to docs output
- not sure about utf8 error messages on win
- strange:

View File

@ -27,6 +27,8 @@ find doc -depth \( \
-o -path 'doc/images/*' \
-o -name '*.xml' ! -name libvips-docs.xml ! -path 'doc/xml/*' \
-o -name '*.py' \
-o -name '*.md' \
-o -name '*.docbook' \
\) -prune -or \( \
-type f \
-o -type d -empty \

326
doc/Examples.md Normal file
View File

@ -0,0 +1,326 @@
<refmeta>
<refentrytitle>Examples</refentrytitle>
<manvolnum>3</manvolnum>
<refmiscinfo>libvips</refmiscinfo>
</refmeta>
<refnamediv>
<refname>libvips examples</refname>
<refpurpose>A few example Python programs using libvips</refpurpose>
</refnamediv>
This page shows a few libvips examples using Python. They will work with small syntax
changes in any language with a libvips binding.
The libvips test suite is written in Python and exercises every operation in the API.
It's also a useful source of examples.
# Average a region of interest box on an image
``` python
#!/usr/bin/env python
import sys
import gi
gi.require_version('Vips', '8.0')
from gi.repository import Vips
left = 10
top = 10
width = 64
height = 64
image = Vips.Image.new_from_file(sys.argv[1])
roi = image.crop(left, top, width, height)
print 'average:', roi.avg()
```
# libvips and numpy
You can use `Vips.Image.new_from_memory_copy()` to make a vips image from an area of
memory. The memory array needs to be laid out band-interleaved, as a set of scanlines,
with no padding between lines.
This example moves an image from numpy to vips, but it's simple to move the other way
(use `Vips.Image.write_to_memory()`) to to move images into or out of PIL.
```python
#!/usr/bin/python
import numpy
import scipy.ndimage
import gi
gi.require_version('Vips', '8.0')
from gi.repository import Vips
def np_dtype_to_vips_format(np_dtype):
'''
Map numpy data types to VIPS data formats.
Parameters
----------
np_dtype: numpy.dtype
Returns
-------
gi.overrides.Vips.BandFormat
'''
lookup = {
numpy.dtype('int8'): Vips.BandFormat.CHAR,
numpy.dtype('uint8'): Vips.BandFormat.UCHAR,
numpy.dtype('int16'): Vips.BandFormat.SHORT,
numpy.dtype('uint16'): Vips.BandFormat.USHORT,
numpy.dtype('int32'): Vips.BandFormat.INT,
numpy.dtype('float32'): Vips.BandFormat.FLOAT,
numpy.dtype('float64'): Vips.BandFormat.DOUBLE
}
return lookup[np_dtype]
def np_array_to_vips_image(array):
'''
Convert a `numpy` array to a `Vips` image object.
Parameters
----------
nparray: numpy.ndarray
Returns
-------
gi.overrides.Vips.image
'''
# Look up what VIPS format corresponds to the type of this np array
vips_format = np_dtype_to_vips_format(array.dtype)
dims = array.shape
height = dims[0]
width = 1
bands = 1
if len(dims) > 1:
width = dims[1]
if len(dims) > 2:
bands = dims[2]
img = Vips.Image.new_from_memory_copy(array.data,
width, height, bands, vips_format)
return img
array = numpy.random.random((10,10))
vips_image = np_array_to_vips_image(array)
print 'avg =', vips_image.avg()
array = scipy.ndimage.imread("test.jpg")
vips_image = np_array_to_vips_image(array)
print 'avg =', vips_image.avg()
vips_image.write_to_file("test2.jpg")
```
# Watermarking
This example renders a simple watermark on an image. Use it like this:
```
./watermark.py somefile.png output.jpg "hello <i>world</i>"
```
The text is rendered in transparent red pixels all over the image. It knows about
transparency, CMYK, and 16-bit images.
```python
#!/usr/bin/python
import sys
import gi
gi.require_version('Vips', '8.0')
from gi.repository import Vips
im = Vips.Image.new_from_file(sys.argv[1], access = Vips.Access.SEQUENTIAL)
text = Vips.Image.text(sys.argv[3], width = 500, dpi = 300)
text = (text * 0.3).cast("uchar")
text = text.embed(100, 100, text.width + 200, text.width + 200)
text = text.replicate(1 + im.width / text.width, 1 + im.height / text.height)
text = text.crop(0, 0, im.width, im.height)
# we want to blend into the visible part of the image and leave any alpha
# channels untouched ... we need to split im into two parts
# 16-bit images have 65535 as white
if im.format == Vips.BandFormat.USHORT:
white = 65535
else:
white = 255
# guess how many bands from the start of im contain visible colour information
if im.bands >= 4 and im.interpretation == Vips.Interpretation.CMYK:
# cmyk image ... put the white into the magenta channel
n_visible_bands = 4
text_colour = [0, white, 0, 0]
elif im.bands >= 3:
# colour image ... put the white into the red channel
n_visible_bands = 3
text_colour = [white, 0, 0]
else:
# mono image
n_visible_bands = 1
text_colour = white
# split into image and alpha
if im.bands - n_visible_bands > 0:
alpha = im.extract_band(n_visible_bands, n = im.bands - n_visible_bands)
im = im.extract_band(0, n = n_visible_bands)
else:
alpha = None
# blend means do a smooth fade using the 0 - 255 values in the condition channel
# (test in this case) ... this will render the anit-aliasing
im = text.ifthenelse(text_colour, im, blend = True)
# reattach alpha
if alpha:
im = im.bandjoin(alpha)
im.write_to_file(sys.argv[2])
```
# Build huge image mosaic
This makes a 100,000 x 100,000 black image, then inserts all the images you pass on the
command-line into it at random positions. libvips is able to run this program in
sequential mode: it'll open all the input images at the same time, and stream pixels from
them as it needs them to generate the output.
To test it, first make a large 1-bit image. This command will take the green channel and
write as a 1-bit fax image. `wtc.jpg` is a test 10,000 x 10,000 jpeg:
```
$ vips extract_band wtc.jpg x.tif[squash,compression=ccittfax4,strip] 1
```
Now make 1,000 copies of that image in a subdirectory:
```
$ mkdir test
$ for i in {1..1000}; do cp x.tif test/$i.tif; done
```
And run this Python program on them:
```
$ time ./try255.py x.tif[squash,compression=ccittfax4,strip,bigtif] test/*
real 1m59.924s
user 4m5.388s
sys 0m8.936s
```
It completes in just under two minutes on this laptop, and needs about
7gb of RAM to run. It would need about the same amount of memory for a
full-colour RGB image, I was just keen to keep disc usage down.
If you wanted to handle transparency, or if you wanted mixed CMYK and RGB images, you'd
need to do some more work to convert them all into the same colourspace before
inserting them.
``` python
#!/usr/bin/env python
import sys
import random
import gi
gi.require_version('Vips', '8.0')
from gi.repository import Vips
# turn on progress reporting
Vips.progress_set(True)
# this makes a 8-bit, mono image of 100,000 x 100,000 pixels, each pixel zero
im = Vips.Image.black(100000, 100000)
for filename in sys.argv[2:]:
tile = Vips.Image.new_from_file(filename, access = Vips.Access.SEQUENTIAL)
im = im.insert(tile,
random.randint(0, im.width - tile.width),
random.randint(0, im.height - tile.height))
im.write_to_file(sys.argv[1])
```
# Rename DICOM images using header fields
DICOM images commonly come in an awful directory hierarchy named as something
like `images/a/b/e/z04`. There can be thousands of files and it can be very
hard to find the one you want.
This utility copies files to a single flat directory, naming them using
fields from the DICOM header. You can actually find stuff! Useful.
```python
#!/usr/bin/env python
import sys
import re
import os
import shutil
import gi
gi.require_version('Vips', '8.0')
from gi.repository import Vips
if len(sys.argv) != 3:
print 'rename DICOM files using tags from the header'
sys.exit(1)
srcdir = sys.argv[1]
destdir = sys.argv[2]
if not os.access(destdir, os.F_OK | os.R_OK | os.W_OK | os.X_OK):
os.mkdir(destdir)
def get_field(vim, field):
result = vim.get_value(field)
# remove any \n etc.
result = re.sub("\n", "", result)
# remove any leading or trailing spaces
result = re.sub(" $", "", result)
result = re.sub("^ ", "", result)
return result
modality_name = "magick-dcm:Modality"
series_name = "magick-dcm:SeriesNumber"
instance_name = "magick-dcm:Instance(formerlyImage)Number"
date_name = "magick-dcm:ImageDate"
for(dirpath, dirnames, filenames) in os.walk(srcdir):
for file in filenames:
path = os.path.join(dirpath, file)
try:
vim = Vips.Image.new_from_file(path)
except Vips.Error, e:
print 'unable to open', path
print e
continue
try:
modality = get_field(vim, modality_name)
series = get_field(vim, series_name)
instance = get_field(vim, instance_name)
date = get_field(vim, date_name)
except Vips.Error, e:
print 'unable to get fields from header', path
print e
continue
match = re.match("(\d\d\d\d)(\d\d)(\d\d)", date)
date = match.group(1) + "." + match.group(2) + "." + match.group(3)
newname = "lan." + modality + "." + instance + "." + date + ".IMA"
shutil.copyfile(path, os.path.join(destdir, newname))
```

142
doc/How-it-opens-files.md Normal file
View File

@ -0,0 +1,142 @@
<refmeta>
<refentrytitle>Opening files</refentrytitle>
<manvolnum>3</manvolnum>
<refmiscinfo>libvips</refmiscinfo>
</refmeta>
<refnamediv>
<refname>Opening</refname>
<refpurpose>How libvips opens files</refpurpose>
</refnamediv>
libvips now has at least four different ways of opening image files, each
best for different file types, file sizes and image use cases. libvips tries
hard to pick the best strategy in each case and mostly you don't need to
know what it is doing behind the scenes, except unfortunately when you do.
This page tries to explain what the different strategies are and when each is
used. If you are running into unexpected memory, disc or CPU use, this might
be helpful. `vips_image_new_from_file()` has the official documentation.
# Direct access
This is the fastest and simplest one. The file is mapped directly into the
process's address space and can be read with ordinary pointer access. Small
files are completely mapped; large files are mapped in a series of small
windows that are shared and which scroll about as pixels are read. Files
which are accessed like this can be read by many threads at once, making
them especially quick. They also interact well with the computer's operating
system: your OS will use spare memory to cache recently used chunks of the
file.
For this to be possible, the file format needs to be a simple dump of a memory
array. libvips supports direct access for vips, 8-bit binary ppm/pbm/pnm,
analyse and raw.
libvips has a special direct write mode where pixels can be written directly
to the file image. This is used for the [draw operators](libvips-draw.html).
# Random access via load library
Some image file formats have libraries which allow true random access to
image pixels. For example, libtiff lets you read any tile out of a tiled
tiff image very quickly. Because the libraries allow true random access,
libvips can simply hook the image load library up to the input of the
operation pipeline.
These libraries are generally single-threaded, so only one thread may
read at once, making them slower than simple direct access.
Additionally, tiles are often compressed, meaning that each time a tile
is fetched it must be decompressed. libvips keeps a cache of
recently-decompressed tiles to try to avoid repeatedly decompressing the
same tile.
libvips can load tiled tiff, tiled OpenEXR, FITS and OpenSlide images in
this manner.
# Full decompression
Many image load libraries do not support random access. In order to use
images of this type as inputs to pipelines, libvips has to convert them
to a random access format first.
For small images (less than 100mb when decompressed), libvips allocates
a large area of memory and decompresses the entire image to that. It
then uses that memory buffer of decompressed pixels to feed the
pipeline. For large images, libvips decompresses to a temporary file on
disc, then loads that temporary file in direct access mode (see above).
Note that on open libvips just reads the image header and is quick: the
image decompress happens on the first pixel access.
You can control this process with environment variables, command-line
flags and API calls as you choose, see
`vips_image_new_from_file()`.
They let you set the threshold at which libvips switches between memory
and disc and where on disc the temporary files are held.
This is the slowest and most memory-hungry way to read files, but it's
unavoidable for many file formats. Unless you can use the next one!
# Sequential access
This a fairly recent addition to libvips and is a hybrid of the previous
two.
Imagine how this command might be executed:
```
$ vips flip fred.jpg jim.jpg vertical
```
meaning, read `fred.jpg`, flip it up-down, and write as `jim.jpg`.
In order to write `jim.jpg` top-to-bottom, it'll have to read `fred.jpg`
bottom-to-top. Unfortunately libjpeg only supports top-to-bottom reading
and writing, so libvips must convert `fred.jpg` to a random access format
before it can run the flip operation.
However many useful operations do not require true random access.  For
example:
```
$ vips shrink fred.png jim.png 10 10
```
meaning shrink `fred.png` by a factor of 10 in both axies and write as
`jim.png`.
You can imagine this operation running without needing `fred.png` to be
completely decompressed first. You just read 10 lines from `fred.png` for
every one line you write to `jim.png`.
To help in this case, libvips has a hint you can give to loaders to say
"I will only need pixels from this image in top-to-bottom order". With
this hint set, libvips will hook up the pipeline of operations directly
to the read-a-line interface provided by the image library, and add a
small cache of the most recent 100 or so lines.
There's an extra unbuffered sequential mode where vips does not keep a
cache of recent lines. This gives a useful memory saving for operations
like copy which do not need any non-local access. 
# Debugging
There are a few flags you can use to find out what libvips is doing.
`--vips-leak` This makes libvips test for leaks on program exit. It checks
for images which haven't been closed and also (usefully) shows the memory
high-water mark. It counts all memory allocated in libvips for pixel buffers.
`--vips-progress` This makes libvips show a crude progress bar for every major
image loop, with destination and elapsed time. You can see whether images
are going to disc or to memory and how long the decompression is taking.
`--vips-cache-trace This shows a line for every vips operation that executes,
with arguments. It's part of vips8, so it doesn't display vips7 operations,
sadly.
# Summary
libvips tries hard to do the quickest thing in every case, but will
sometimes fail. You can prod it in the right direction with a mixture of
hints and flags to the load system.

117
doc/How-it-opens-files.xml Normal file
View File

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<refentry id="How-it-opens-files.md">
<para>
<refmeta> <refentrytitle>Opening files</refentrytitle> <manvolnum>3</manvolnum> <refmiscinfo>libvips</refmiscinfo> </refmeta>
</para>
<para>
<refnamediv> <refname>Opening</refname> <refpurpose>How libvips opens files</refpurpose> </refnamediv>
</para>
<para>
libvips now has at least four different ways of opening image files, each best for different file types, file sizes and image use cases. libvips tries hard to pick the best strategy in each case and mostly you dont need to know what it is doing behind the scenes, except unfortunately when you do.
</para>
<para>
This page tries to explain what the different strategies are and when each is used. If you are running into unexpected memory, disc or CPU use, this might be helpful. <literal>vips_image_new_from_file()</literal> has the official documentation.
</para>
<refsect3 id="direct-access">
<title>Direct access</title>
<para>
This is the fastest and simplest one. The file is mapped directly into the processs address space and can be read with ordinary pointer access. Small files are completely mapped; large files are mapped in a series of small windows that are shared and which scroll about as pixels are read. Files which are accessed like this can be read by many threads at once, making them especially quick. They also interact well with the computers operating system: your OS will use spare memory to cache recently used chunks of the file.
</para>
<para>
For this to be possible, the file format needs to be a simple dump of a memory array. libvips supports direct access for vips, 8-bit binary ppm/pbm/pnm, analyse and raw.
</para>
<para>
libvips has a special direct write mode where pixels can be written directly to the file image. This is used for the <ulink url="libvips-draw.html">draw operators</ulink>.
</para>
</refsect3>
<refsect3 id="random-access-via-load-library">
<title>Random access via load library</title>
<para>
Some image file formats have libraries which allow true random access to image pixels. For example, libtiff lets you read any tile out of a tiled tiff image very quickly. Because the libraries allow true random access, libvips can simply hook the image load library up to the input of the operation pipeline.
</para>
<para>
These libraries are generally single-threaded, so only one thread may read at once, making them slower than simple direct access. Additionally, tiles are often compressed, meaning that each time a tile is fetched it must be decompressed. libvips keeps a cache of recently-decompressed tiles to try to avoid repeatedly decompressing the same tile.
</para>
<para>
libvips can load tiled tiff, tiled OpenEXR, FITS and OpenSlide images in this manner.
</para>
</refsect3>
<refsect3 id="full-decompression">
<title>Full decompression</title>
<para>
Many image load libraries do not support random access. In order to use images of this type as inputs to pipelines, libvips has to convert them to a random access format first.
</para>
<para>
For small images (less than 100mb when decompressed), libvips allocates a large area of memory and decompresses the entire image to that. It then uses that memory buffer of decompressed pixels to feed the pipeline. For large images, libvips decompresses to a temporary file on disc, then loads that temporary file in direct access mode (see above). Note that on open libvips just reads the image header and is quick: the image decompress happens on the first pixel access.
</para>
<para>
You can control this process with environment variables, command-line flags and API calls as you choose, see <literal>vips_image_new_from_file()</literal>. They let you set the threshold at which libvips switches between memory and disc and where on disc the temporary files are held.
</para>
<para>
This is the slowest and most memory-hungry way to read files, but its unavoidable for many file formats. Unless you can use the next one!
</para>
</refsect3>
<refsect3 id="sequential-access">
<title>Sequential access</title>
<para>
This a fairly recent addition to libvips and is a hybrid of the previous two.
</para>
<para>
Imagine how this command might be executed:
</para>
<programlisting>
$ vips flip fred.jpg jim.jpg vertical
</programlisting>
<para>
meaning, read <literal>fred.jpg</literal>, flip it up-down, and write as <literal>jim.jpg</literal>.
</para>
<para>
In order to write <literal>jim.jpg</literal> top-to-bottom, itll have to read <literal>fred.jpg</literal> bottom-to-top. Unfortunately libjpeg only supports top-to-bottom reading and writing, so libvips must convert <literal>fred.jpg</literal> to a random access format before it can run the flip operation.
</para>
<para>
However many useful operations do not require true random access.  For example:
</para>
<programlisting>
$ vips shrink fred.png jim.png 10 10
</programlisting>
<para>
meaning shrink <literal>fred.png</literal> by a factor of 10 in both axies and write as <literal>jim.png</literal>.
</para>
<para>
You can imagine this operation running without needing <literal>fred.png</literal> to be completely decompressed first. You just read 10 lines from <literal>fred.png</literal> for every one line you write to <literal>jim.png</literal>.
</para>
<para>
To help in this case, libvips has a hint you can give to loaders to say <quote>I will only need pixels from this image in top-to-bottom order</quote>. With this hint set, libvips will hook up the pipeline of operations directly to the read-a-line interface provided by the image library, and add a small cache of the most recent 100 or so lines.
</para>
<para>
Theres an extra unbuffered sequential mode where vips does not keep a cache of recent lines. This gives a useful memory saving for operations like copy which do not need any non-local access. 
</para>
</refsect3>
<refsect3 id="debugging">
<title>Debugging</title>
<para>
There are a few flags you can use to find out what libvips is doing.
</para>
<para>
<literal>--vips-leak</literal> This makes libvips test for leaks on program exit. It checks for images which havent been closed and also (usefully) shows the memory high-water mark. It counts all memory allocated in libvips for pixel buffers.
</para>
<para>
<literal>--vips-progress</literal> This makes libvips show a crude progress bar for every major image loop, with destination and elapsed time. You can see whether images are going to disc or to memory and how long the decompression is taking.
</para>
<para>
`vips-cache-trace This shows a line for every vips operation that executes, with arguments. Its part of vips8, so it doesnt display vips7 operations, sadly.
</para>
</refsect3>
<refsect3 id="summary">
<title>Summary</title>
<para>
libvips tries hard to do the quickest thing in every case, but will sometimes fail. You can prod it in the right direction with a mixture of hints and flags to the load system.
</para>
</refsect3>
</refentry>

327
doc/How-it-works.md Normal file
View File

@ -0,0 +1,327 @@
<refmeta>
<refentrytitle>How libvips works</refentrytitle>
<manvolnum>3</manvolnum>
<refmiscinfo>libvips</refmiscinfo>
</refmeta>
<refnamediv>
<refname>Internals</refname>
<refpurpose>A high-level technical overview of libvips's evaluation system</refpurpose>
</refnamediv>
Compared to most image processing libraries, VIPS needs little RAM and runs
quickly, especially on machines with more than one CPU. VIPS achieves this
improvement by only keeping the pixels currently being processed in RAM
and by having an efficient, threaded image IO system. This page explains
how these features are implemented.
# Images
VIPS images have three dimensions: width, height and bands. Bands usually
(though not always) represent colour. These three dimensions can be any
size up to 2 ** 31 elements. Every band element in an image has to have the
same format. A format is an 8-, 16- or 32-bit int, signed or unsigned, 32-
or 64-bit float, and 64- or 128-bit complex.
# Regions
An image can be very large, much larger than the available memory, so you
can't just access pixels with a pointer \*.
Instead, you read pixels from an image with a region. This is a rectangular
sub-area of an image. In C, the API looks like:
```c
VipsImage *image = vips_image_new_from_file( filename, NULL );
VipsRegion *region = vips_region_new( image );
// ask for a 100x100 pixel region at 0x0 (top left)
VipsRect r = { left: 0, top: 0, width: 100, height: 100 };
if( vips_region_prepare( region, &r ) )
vips_error( ... );
// get a pointer to the pixel at x, y, where x, y must
// be within the region
// as long as you stay within the valid area for the region,
// you can address pixels with regular pointer arithmetic
// compile with -DDEBUG and the macro will check bounds for you
// add VIPS_REGION_LSKIP() to move down a line
VipsPel *pixel = VIPS_REGION_ADDR( region, x, y );
// you can call vips_region_prepare() many times
// everything in libvips is a GObject ... when you're done,
// just free with
g_object_unref( region );
```
The action that `vips_region_prepare()` takes varies with the type of
image. If the image is a file on disc, for example, then VIPS will arrange
for a section of the file to be read in.
(\* there is an image access mode where you can just use a pointer, but
it's rarely used)
# Partial images
A partial image is one where, instead of storing a value for each pixel, VIPS
stores a function which can make any rectangular area of pixels on demand.
If you use `vips_region_prepare()` on a region created on a partial image,
VIPS will allocate enough memory to hold the pixels you asked for and use
the stored function to calculate values for just those pixels \*.
The stored function comes in three parts: a start function, a generate
function and a stop function. The start function creates a state, the
generate function uses the state plus a requested area to calculate pixel
values and the stop function frees the state again. Breaking the stored
function into three parts is good for SMP scaling: resource allocation and
synchronisation mostly happens in start functions, so generate functions
can run without having to talk to each other.
VIPS makes a set of guarantees about parallelism that make this simple to
program. Start and stop functions are mutually exclusive and a state is
never used by more than one generate. In other words, a start / generate /
generate / stop sequence works like a thread.
![](Sequence.png)
(\* in fact VIPS keeps a cache of calculated pixel buffers and will return
a pointer to a previously-calculated buffer if it can)
# Operations
VIPS operations read input images and write output images, performing some
transformation on the pixels. When an operation writes to an image the
action it takes depends upon the image type. For example, if the image is a
file on disc then VIPS will start a data sink to stream pixels to the file,
or if the image is a partial one then it will just attach start / generate /
stop functions.
Like most threaded image processing systems, all VIPS operations have to
be free of side-effects. In other words, operations cannot modify images,
they can only create new images. This could result in a lot of copying if
an operation is only making a small change to a large image so VIPS has a
set of mechanisms to copy image areas by just adjusting pointers. Most of
the time no actual copying is necessary and you can perform operations on
large images at low cost.
# Run-time code generation
VIPS uses [Orc](http://code.entropywave.com/orc/), a run-time compiler, to
generate code for some operations. For example, to compute a convolution
on an 8-bit image, VIPS will examine the convolution matrix and the source
image and generate a tiny program to calculate the convolution. This program
is then "compiled" to the vector instruction set for your CPU, for example
SSE3 on most x86 processors.
Run-time vector code generation typically speeds operations up by a factor
of three or four.
# Joining operations together
The region create / prepare / prepare / free calls you use to get pixels
from an image are an exact parallel to the start / generate / generate /
stop calls that images use to create pixels. In fact, they are the same:
a region on a partial image holds the state created by that image for the
generate function that will fill the region with pixels.
![](Combine.png)
VIPS joins image processing operations together by linking the output of one
operation (the start / generate / stop sequence) to the input of the next
(the region it uses to get pixels for processing). This link is a single
function call, and very fast. Additionally, because of the the split between
allocation and processing, once a pipeline of operations has been set up,
VIPS is able to run without allocating and freeing memory.
This graph (generated by `vipsprofile`, the vips profiler) shows memory use
over time for a vips pipeline running on a large image. The bottom trace
shows total memory, the upper traces show threads calculating useful results
(green), threads blocked on synchronisation (red) and memory allocations
(white ticks).
![](Memtrace.png)
Because the intermediate image is just a small region in memory, a pipeline
of operations running together needs very little RAM. In fact, intermediates
are small enough that they can fit in L2 cache on most machines, so an
entire pipeline can run without touching main memory. And finally, because
each thread runs a very cheap copy of just the writeable state of the
entire pipeline, threads can run with few locks. VIPS needs just four lock
operations per output tile, regardless of the pipeline length or complexity.
# Data sources
VIPS has data sources which can supply pixels for processing from a variety
of sources. VIPS can stream images from files in VIPS native format, from
tiled TIFF files, from binary PPM/PGM/PBM/PFM, from Radiance (HDR) files,
from FITS images and from tiled OpenEXR images. VIPS will automatically
unpack other formats to temporary disc files for you but this can
obviously generate a lot of disc traffic. It also has a special
sequential mode for streaming operations on non-random-access
formats. Another section in these docs explains [how libvips opens a
file](How-it-opens-files.html). One
of the sources uses the [ImageMagick](http://www.imagemagick.org) (or
optionally [GraphicsMagick](http://www.graphicsmagick.org)) library, so
VIPS can read any image format that these libraries can read.
VIPS images are held on disc as a 64-byte header containing basic image
information like width, height, bands and format, then the image data as
a single large block of pixels, left-to-right and top-to-bottom, then an
XML extension block holding all the image metadata, such as ICC profiles
and EXIF blocks.
When reading from a large VIPS image (or any other format with the same
structure on disc, such as binary PPM), VIPS keeps a set of small rolling
windows into the file, some small number of scanlines in size. As pixels
are demanded by different threads VIPS will move these windows up and down
the file. As a result, VIPS can process images much larger than RAM, even
on 32-bit machines.
# Data sinks
In a demand-driven system, something has to do the demanding. VIPS has a
variety of data sinks that you can use to pull image data though a pipeline
in various situations. There are sinks that will build a complete image
in memory, sinks to draw to a display, sinks to loop over an image (useful
for statistical operations, for example) and sinks to stream an image to disc.
The disc sink looks something like this:
![](Sink.png)
The sink keeps two buffers\*, each as wide as the image. It starts threads
as rapidly as it can up to the concurrency limit, filling each buffer with
tiles\*\* of calculated pixels, each thread calculating one tile at once. A
separate background thread watches each buffer and, as soon as the last tile
in a buffer finishes, writes that complete set of scanlines to disc using
whatever image write library is appropriate. VIPS can write with libjpeg,
libtiff, libpng and others. It then wipes the buffer and repositions it
further down the image, ready for the next set of tiles to stream in.
These features in combination mean that, once a pipeline of image processing
operations has been built, VIPS can run almost lock-free. This is very
important for SMP scaling: you don't want the synchronization overhead to
scale with either the number of threads or the complexity of the pipeline
of operations being performed. As a result, VIPS scales almost linearly
with increasing numbers of threads:
![](Vips-smp.png)
Number of CPUs is on the horizontal axis, speedup is on the vertical
axis. Taken from the [[Benchmarks]] page.
(\* there can actually be more than one, it allocate enough buffers to
ensure that there are at least two tiles for every thread)
(\*\* tiles can be any shape and size, VIPS has a tile hint system that
operations use to tell sinks what tile geometry they prefer)
# Operation cache
Because VIPS operations are free of side-effects\*, you can cache them. Every
time you call an operation, VIPS searches the cache for a previous call to
the same operation with the same arguments. If it finds a match, you get
the previous result again. This can give a huge speedup.
By default, VIPS caches the last 1,000 operation calls. You can also control
the cache size by memory use or by files opened.
(\* Some vips operations DO have side effects, for example,
`vips_draw_circle()` will draw a circle on an image. These operations emit an
"invalidate" signal on the image they are called on and this signal makes
all downstream operations and caches drop their contents.)
# Operation database and APIs
VIPS has around 300 image processing operations written in this style. Each
operation is a GObject class. You can use the standard GObject calls to walk
the class hierarchy and discover operations, and libvips adds a small amount
of extra introspection metadata to handle things like optional arguments.
The [C API](using-from-c.html) is a set of simple wrappers which create
class instances for you. The [C++ API](using-from-cpp.html) is a little
fancier and adds things like automatic object lifetime management. The
[command-line interface](using-cli.html) uses introspection to run any vips
operation in the class hierarchy.
The [Python API](using-from-python.html) is built on top of
gobject-introspection. It is written in Python, so as long as you can get
gobject-introspection working, you should be able to use vips. It supports
python2 and python3 and works on Linux, OS X and Windows.
# Snip
The VIPS GUI, nip2, has its own scripting language called Snip. Snip is a
lazy, higher-order, purely functional, object oriented language. Almost all
of nip2's menus are implemented in it, and nip2 workspaces are Snip programs.
VIPS operations listed in the operation database appear as Snip functions. For
example, `abs` can be used from Snip as:
```
// absolute value of image b
a = vips_call "abs" [b] [];
```
However, `abs` won't work on anything except the primitive vips image type. It
can't be used on any class, or list or number. Definitions in `_stdenv.dev`
wrap each VIPS operation as a higher level Snip operation. For example:
```
abs x
= oo_unary_function abs_op x, is_class x
= vips_call "abs" [x] [], is_image x
= abs_cmplx x, is_complex x
= abs_num x, is_real x
= abs_list x, is_real_list x
= abs_list (map abs_list x), is_matrix x
= error (_ "bad arguments to " ++ "abs")
{
abs_op = Operator "abs" abs Operator_type.COMPOUND false;
abs_list l = (sum (map square l)) ** 0.5;
abs_num n
= n, n >= 0
= -n;
abs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;
}
```
This defines the behaviour of `abs` for the base Snip types (number, list,
matrix, image and so on), then classes will use that to define operator
behaviour on higher-level objects.
Now you can use:
```
// absolute value of anything
a = abs b;
```
and you ought to get sane behaviour for any object, including things like
the `Matrix` class.
You can write Snip classes which present functions to the user as menu
items. For example, `Math.def` has this:
```
Math_arithmetic_item = class
Menupullright "_Arithmetic" "basic arithmetic for objects" {
Absolute_value_item = class
Menuaction "A_bsolute Value" "absolute value of x" {
action x = map_unary abs x;
}
}
```
Now the user can select an object and click `Math / Abs` to find the absolute
value of that object.

282
doc/How-it-works.xml Normal file
View File

@ -0,0 +1,282 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<refentry id="How-it-works.md">
<para>
<refmeta> <refentrytitle>How libvips works</refentrytitle> <manvolnum>3</manvolnum> <refmiscinfo>libvips</refmiscinfo> </refmeta>
</para>
<para>
<refnamediv> <refname>Internals</refname> <refpurpose>A high-level technical overview of libvipss evaluation system</refpurpose> </refnamediv>
</para>
<para>
Compared to most image processing libraries, VIPS needs little RAM and runs quickly, especially on machines with more than one CPU. VIPS achieves this improvement by only keeping the pixels currently being processed in RAM and by having an efficient, threaded image IO system. This page explains how these features are implemented.
</para>
<refsect3 id="images">
<title>Images</title>
<para>
VIPS images have three dimensions: width, height and bands. Bands usually (though not always) represent colour. These three dimensions can be any size up to 2 ** 31 elements. Every band element in an image has to have the same format. A format is an 8-, 16- or 32-bit int, signed or unsigned, 32- or 64-bit float, and 64- or 128-bit complex.
</para>
</refsect3>
<refsect3 id="regions">
<title>Regions</title>
<para>
An image can be very large, much larger than the available memory, so you cant just access pixels with a pointer *.
</para>
<para>
Instead, you read pixels from an image with a region. This is a rectangular sub-area of an image. In C, the API looks like:
</para>
<programlisting language="c">
VipsImage *image = vips_image_new_from_file( filename, NULL );
VipsRegion *region = vips_region_new( image );
// ask for a 100x100 pixel region at 0x0 (top left)
VipsRect r = { left: 0, top: 0, width: 100, height: 100 };
if( vips_region_prepare( region, &amp;r ) )
vips_error( ... );
// get a pointer to the pixel at x, y, where x, y must
// be within the region
// as long as you stay within the valid area for the region,
// you can address pixels with regular pointer arithmetic
// compile with -DDEBUG and the macro will check bounds for you
// add VIPS_REGION_LSKIP() to move down a line
VipsPel *pixel = VIPS_REGION_ADDR( region, x, y );
// you can call vips_region_prepare() many times
// everything in libvips is a GObject ... when you're done,
// just free with
g_object_unref( region );
</programlisting>
<para>
The action that <literal>vips_region_prepare()</literal> takes varies with the type of image. If the image is a file on disc, for example, then VIPS will arrange for a section of the file to be read in.
</para>
<para>
(* there is an image access mode where you can just use a pointer, but its rarely used)
</para>
</refsect3>
<refsect3 id="partial-images">
<title>Partial images</title>
<para>
A partial image is one where, instead of storing a value for each pixel, VIPS stores a function which can make any rectangular area of pixels on demand.
</para>
<para>
If you use <literal>vips_region_prepare()</literal> on a region created on a partial image, VIPS will allocate enough memory to hold the pixels you asked for and use the stored function to calculate values for just those pixels *.
</para>
<para>
The stored function comes in three parts: a start function, a generate function and a stop function. The start function creates a state, the generate function uses the state plus a requested area to calculate pixel values and the stop function frees the state again. Breaking the stored function into three parts is good for SMP scaling: resource allocation and synchronisation mostly happens in start functions, so generate functions can run without having to talk to each other.
</para>
<para>
VIPS makes a set of guarantees about parallelism that make this simple to program. Start and stop functions are mutually exclusive and a state is never used by more than one generate. In other words, a start / generate / generate / stop sequence works like a thread.
</para>
<figure>
<mediaobject>
<imageobject>
<imagedata fileref="Sequence.png" />
</imageobject>
<textobject><phrase></phrase></textobject>
</mediaobject>
</figure>
<para>
(* in fact VIPS keeps a cache of calculated pixel buffers and will return a pointer to a previously-calculated buffer if it can)
</para>
</refsect3>
<refsect3 id="operations">
<title>Operations</title>
<para>
VIPS operations read input images and write output images, performing some transformation on the pixels. When an operation writes to an image the action it takes depends upon the image type. For example, if the image is a file on disc then VIPS will start a data sink to stream pixels to the file, or if the image is a partial one then it will just attach start / generate / stop functions.
</para>
<para>
Like most threaded image processing systems, all VIPS operations have to be free of side-effects. In other words, operations cannot modify images, they can only create new images. This could result in a lot of copying if an operation is only making a small change to a large image so VIPS has a set of mechanisms to copy image areas by just adjusting pointers. Most of the time no actual copying is necessary and you can perform operations on large images at low cost.
</para>
</refsect3>
<refsect3 id="run-time-code-generation">
<title>Run-time code generation</title>
<para>
VIPS uses <ulink url="http://code.entropywave.com/orc/">Orc</ulink>, a run-time compiler, to generate code for some operations. For example, to compute a convolution on an 8-bit image, VIPS will examine the convolution matrix and the source image and generate a tiny program to calculate the convolution. This program is then <quote>compiled</quote> to the vector instruction set for your CPU, for example SSE3 on most x86 processors.
</para>
<para>
Run-time vector code generation typically speeds operations up by a factor of three or four.
</para>
</refsect3>
<refsect3 id="joining-operations-together">
<title>Joining operations together</title>
<para>
The region create / prepare / prepare / free calls you use to get pixels from an image are an exact parallel to the start / generate / generate / stop calls that images use to create pixels. In fact, they are the same: a region on a partial image holds the state created by that image for the generate function that will fill the region with pixels.
</para>
<figure>
<mediaobject>
<imageobject>
<imagedata fileref="Combine.png" />
</imageobject>
<textobject><phrase></phrase></textobject>
</mediaobject>
</figure>
<para>
VIPS joins image processing operations together by linking the output of one operation (the start / generate / stop sequence) to the input of the next (the region it uses to get pixels for processing). This link is a single function call, and very fast. Additionally, because of the the split between allocation and processing, once a pipeline of operations has been set up, VIPS is able to run without allocating and freeing memory.
</para>
<para>
This graph (generated by <literal>vipsprofile</literal>, the vips profiler) shows memory use over time for a vips pipeline running on a large image. The bottom trace shows total memory, the upper traces show threads calculating useful results (green), threads blocked on synchronisation (red) and memory allocations (white ticks).
</para>
<figure>
<mediaobject>
<imageobject>
<imagedata fileref="Memtrace.png" />
</imageobject>
<textobject><phrase></phrase></textobject>
</mediaobject>
</figure>
<para>
Because the intermediate image is just a small region in memory, a pipeline of operations running together needs very little RAM. In fact, intermediates are small enough that they can fit in L2 cache on most machines, so an entire pipeline can run without touching main memory. And finally, because each thread runs a very cheap copy of just the writeable state of the entire pipeline, threads can run with few locks. VIPS needs just four lock operations per output tile, regardless of the pipeline length or complexity.
</para>
</refsect3>
<refsect3 id="data-sources">
<title>Data sources</title>
<para>
VIPS has data sources which can supply pixels for processing from a variety of sources. VIPS can stream images from files in VIPS native format, from tiled TIFF files, from binary PPM/PGM/PBM/PFM, from Radiance (HDR) files, from FITS images and from tiled OpenEXR images. VIPS will automatically unpack other formats to temporary disc files for you but this can obviously generate a lot of disc traffic. It also has a special sequential mode for streaming operations on non-random-access formats. A post on the libvips blog <ulink url="http://libvips.blogspot.co.uk/2012/06/how-libvips-opens-file.html">explains how libvips opens a file</ulink>. One of the sources uses the <ulink url="http://www.imagemagick.org">ImageMagick</ulink> (or optionally <ulink url="http://www.graphicsmagick.org">GraphicsMagick</ulink>) library, so VIPS can read any image format that these libraries can read.
</para>
<para>
VIPS images are held on disc as a 64-byte header containing basic image information like width, height, bands and format, then the image data as a single large block of pixels, left-to-right and top-to-bottom, then an XML extension block holding all the image metadata, such as ICC profiles and EXIF blocks.
</para>
<para>
When reading from a large VIPS image (or any other format with the same structure on disc, such as binary PPM), VIPS keeps a set of small rolling windows into the file, some small number of scanlines in size. As pixels are demanded by different threads VIPS will move these windows up and down the file. As a result, VIPS can process images much larger than RAM, even on 32-bit machines.
</para>
</refsect3>
<refsect3 id="data-sinks">
<title>Data sinks</title>
<para>
In a demand-driven system, something has to do the demanding. VIPS has a variety of data sinks that you can use to pull image data though a pipeline in various situations. There are sinks that will build a complete image in memory, sinks to draw to a display, sinks to loop over an image (useful for statistical operations, for example) and sinks to stream an image to disc.
</para>
<para>
The disc sink looks something like this:
</para>
<figure>
<mediaobject>
<imageobject>
<imagedata fileref="Sink.png" />
</imageobject>
<textobject><phrase></phrase></textobject>
</mediaobject>
</figure>
<para>
The sink keeps two buffers*, each as wide as the image. It starts threads as rapidly as it can up to the concurrency limit, filling each buffer with tiles** of calculated pixels, each thread calculating one tile at once. A separate background thread watches each buffer and, as soon as the last tile in a buffer finishes, writes that complete set of scanlines to disc using whatever image write library is appropriate. VIPS can write with libjpeg, libtiff, libpng and others. It then wipes the buffer and repositions it further down the image, ready for the next set of tiles to stream in.
</para>
<para>
These features in combination mean that, once a pipeline of image processing operations has been built, VIPS can run almost lock-free. This is very important for SMP scaling: you dont want the synchronization overhead to scale with either the number of threads or the complexity of the pipeline of operations being performed. As a result, VIPS scales almost linearly with increasing numbers of threads:
</para>
<figure>
<mediaobject>
<imageobject>
<imagedata fileref="Vips-smp.png" />
</imageobject>
<textobject><phrase></phrase></textobject>
</mediaobject>
</figure>
<para>
Number of CPUs is on the horizontal axis, speedup is on the vertical axis. Taken from the [[Benchmarks]] page.
</para>
<para>
(* there can actually be more than one, it allocate enough buffers to ensure that there are at least two tiles for every thread)
</para>
<para>
(** tiles can be any shape and size, VIPS has a tile hint system that operations use to tell sinks what tile geometry they prefer)
</para>
</refsect3>
<refsect3 id="operation-cache">
<title>Operation cache</title>
<para>
Because VIPS operations are free of side-effects*, you can cache them. Every time you call an operation, VIPS searches the cache for a previous call to the same operation with the same arguments. If it finds a match, you get the previous result again. This can give a huge speedup.
</para>
<para>
By default, VIPS caches the last 1,000 operation calls. You can also control the cache size by memory use or by files opened.
</para>
<para>
(* Some vips operations DO have side effects, for example, <literal>vips_draw_circle()</literal> will draw a circle on an image. These operations emit an <quote>invalidate</quote> signal on the image they are called on and this signal makes all downstream operations and caches drop their contents.)
</para>
</refsect3>
<refsect3 id="operation-database-and-apis">
<title>Operation database and APIs</title>
<para>
VIPS has around 300 image processing operations written in this style. Each operation is a GObject class. You can use the standard GObject calls to walk the class hierarchy and discover operations, and libvips adds a small amount of extra introspection metadata to handle things like optional arguments.
</para>
<para>
The <ulink url="using-from-c.html">C API</ulink> is a set of simple wrappers which create class instances for you. The <ulink url="using-from-cpp.html">C++ API</ulink> is a little fancier and adds things like automatic object lifetime management. The <ulink url="using-cli.html">command-line interface</ulink> uses introspection to run any vips operation in the class hierarchy.
</para>
<para>
The <ulink url="using-from-python.html">Python API</ulink> is built on top of gobject-introspection. It is written in Python, so as long as you can get gobject-introspection working, you should be able to use vips. It supports python2 and python3 and works on Linux, OS X and Windows.
</para>
</refsect3>
<refsect3 id="snip">
<title>Snip</title>
<para>
The VIPS GUI, nip2, has its own scripting language called Snip. Snip is a lazy, higher-order, purely functional, object oriented language. Almost all of nip2s menus are implemented in it, and nip2 workspaces are Snip programs.
</para>
<para>
VIPS operations listed in the operation database appear as Snip functions. For example, <literal>abs</literal> can be used from Snip as:
</para>
<programlisting>
// absolute value of image b
a = vips_call &quot;abs&quot; [b] [];
</programlisting>
<para>
However, <literal>abs</literal> wont work on anything except the primitive vips image type. It cant be used on any class, or list or number. Definitions in <literal>_stdenv.dev</literal> wrap each VIPS operation as a higher level Snip operation. For example:
</para>
<programlisting>
abs x
= oo_unary_function abs_op x, is_class x
= vips_call &quot;abs&quot; [x] [], is_image x
= abs_cmplx x, is_complex x
= abs_num x, is_real x
= abs_list x, is_real_list x
= abs_list (map abs_list x), is_matrix x
= error (_ &quot;bad arguments to &quot; ++ &quot;abs&quot;)
{
abs_op = Operator &quot;abs&quot; abs Operator_type.COMPOUND false;
abs_list l = (sum (map square l)) ** 0.5;
abs_num n
= n, n &gt;= 0
= -n;
abs_cmplx c = ((re c)**2 + (im c)**2) ** 0.5;
}
</programlisting>
<para>
This defines the behaviour of <literal>abs</literal> for the base Snip types (number, list, matrix, image and so on), then classes will use that to define operator behaviour on higher-level objects.
</para>
<para>
Now you can use:
</para>
<programlisting>
// absolute value of anything
a = abs b;
</programlisting>
<para>
and you ought to get sane behaviour for any object, including things like the <literal>Matrix</literal> class.
</para>
<para>
You can write Snip classes which present functions to the user as menu items. For example, <literal>Math.def</literal> has this:
</para>
<programlisting>
Math_arithmetic_item = class
Menupullright &quot;_Arithmetic&quot; &quot;basic arithmetic for objects&quot; {
Absolute_value_item = class
Menuaction &quot;A_bsolute Value&quot; &quot;absolute value of x&quot; {
action x = map_unary abs x;
}
}
</programlisting>
<para>
Now the user can select an object and click <literal>Math / Abs</literal> to find the absolute value of that object.
</para>
</refsect3>
</refentry>

View File

@ -126,7 +126,31 @@ IGNORE_HFILES = $(IGNORE_VIPS_INCLUDE) $(IGNORE_VIPS_C)
# Images to copy into HTML directory.
# e.g. HTML_IMAGES=$(top_srcdir)/gtk/stock-icons/stock_about_24.png
HTML_IMAGES = \
$(top_srcdir)/doc/images/interconvert.png
$(top_srcdir)/doc/images/owl.jpg \
$(top_srcdir)/doc/images/tn_owl.jpg \
$(top_srcdir)/doc/images/interconvert.png \
$(top_srcdir)/doc/images/Combine.png \
$(top_srcdir)/doc/images/Memtrace.png \
$(top_srcdir)/doc/images/Sequence.png \
$(top_srcdir)/doc/images/Sink.png \
$(top_srcdir)/doc/images/Vips-smp.png
# we have some files in markdown ... convert to docbook for gtk-doc
# pandoc makes sect1 headers, we want refsect3 for gtk-doc
.md.xml:
pandoc -s -S --template="$(realpath pandoc-docbook-template.docbook)" --wrap=none -V title="$<" -f markdown -t docbook -o $@ $<
sed -e s/sect1/refsect3/g < $@ > x && mv x $@
# Our markdown source files
markdown_content_files = \
How-it-works.md \
Using-vipsthumbnail.md \
How-it-opens-files.md \
Examples.md \
Making-image-pyramids.md
# converted to xml in this dir by pandoc
markdown_content_files_docbook = $(markdown_content_files:.md=.xml)
# Extra SGML files that are included by $(DOC_MAIN_SGML_FILE).
# e.g. content_files=running.sgml building.sgml changes-2.0.sgml
@ -139,6 +163,7 @@ content_files = \
extending.xml \
function-list.xml \
file-format.xml \
${markdown_content_files_docbook} \
binding.xml
# SGML files where gtk-doc abbrevations (#GtkWidget) are expanded
@ -153,6 +178,7 @@ expand_content_files = \
extending.xml \
function-list.xml \
file-format.xml \
${markdown_content_files_docbook} \
binding.xml
# CFLAGS and LDFLAGS for compiling gtkdoc-scangobj with your library.
@ -169,13 +195,14 @@ include gtk-doc.make
# Other files to distribute
# e.g. EXTRA_DIST += version.xml.in
EXTRA_DIST += \
${markdown_content_files} \
images \
gen-function-list.py
# Files not to distribute
# for --rebuild-types in $(SCAN_OPTIONS), e.g. $(DOC_MODULE).types
# for --rebuild-sections in $(SCAN_OPTIONS) e.g. $(DOC_MODULE)-sections.txt
DISTCLEANFILES = libvips.types
DISTCLEANFILES = libvips.types
# Comment this out if you want 'make check' to test you doc status
# and run some sanity checks

View File

@ -0,0 +1,202 @@
<refmeta>
<refentrytitle>Image pyramids</refentrytitle>
<manvolnum>3</manvolnum>
<refmiscinfo>libvips</refmiscinfo>
</refmeta>
<refnamediv>
<refname>Pyramids</refname>
<refpurpose>How to use libvips to make image pyramids</refpurpose>
</refnamediv>
libvips includes `vips_dzsave()`, an operation that can build image pyramids
compatible with [DeepZoom](http://en.wikipedia.org/wiki/Deep_Zoom), Zoomify
and [Google Maps](https://developers.google.com/maps/) image viewers. It's
fast and can generate pyramids for large images using only a small amount
of memory.
The TIFF writer, `vips_tiffsave()` can also build tiled pyramidal TIFF images,
but that's very simple to use. This page concentrates on the DeepZoom builder.
Run dzsave with no arguments to see a summary:
```
$ vips dzsave
save image to deepzoom file
usage:
dzsave in filename
where:
in - Image to save, input VipsImage
filename - Filename to save to, input gchararray
optional arguments:
basename - Base name to save to, input gchararray
layout - Directory layout, input VipsForeignDzLayout
default: dz
allowed: dz, zoomify, google
suffix - Filename suffix for tiles, input gchararray
overlap - Tile overlap in pixels, input gint
default: 1
min: 0, max: 8192
tile-size - Tile size in pixels, input gint
default: 254
min: 1, max: 8192
centre - Center image in tile, input gboolean
default: false
depth - Pyramid depth, input VipsForeignDzDepth
default: onepixel
allowed: onepixel, onetile, one
angle - Rotate image during save, input VipsAngle
default: d0
allowed: d0, d90, d180, d270
container - Pyramid container type, input VipsForeignDzContainer
default: fs
allowed: fs, zip
properties - Write a properties file to the output directory, input
gboolean
default: false
compression - ZIP deflate compression level, input gint
default: 0
min: -1, max: 9
strip - Strip all metadata from image, input gboolean
default: false
background - Background value, input VipsArrayDouble
operation flags: sequential nocache
```
You can also call `vips_dzsave()` from any language with a libvips binding, or
by using `.dz` or `.szi` as an output file suffix.
# Writing [DeepZoom](http://en.wikipedia.org/wiki/Deep_Zoom) pyramids
The `--layout` option sets the basic mode of operation. With no
`--layout`, dzsave writes DeepZoom pyramids. For example:
```
$ vips dzsave huge.tif mydz
```
This will create a directory called `mydz_files` containing the image
tiles, and write a file called `mydz.dzi` containing the image
metadata. 
You can use the `--suffix` option to control how tiles are written. For
example:
```
$ vips dzsave huge.tif mydz --suffix .jpg[Q=90]
```
will write JPEG tiles with the quality factor set to 90. You can set any
format write options you like, see the API docs for `vips_jpegsave()`
for details.
# Writing Zoomify pyramids
Use `--layout zoomify` to put dzsave into zoomify mode. For example:
```
$ vips dzsave huge.tif myzoom --layout zoomify
```
This will create a directory called `myzoom` containing a file called
`ImageProperties.xml` with the image metadata in, and a series of
directories called `TileGroupn`, each containing 256 image tiles.
As with DeepZoom, you can use `--suffix` to set jpeg quality.
# Writing [Google Maps](https://developers.google.com/maps/) pyramids
Use `--layout google` to write Google maps-style pyramids. These are
compatible with the [NYU Pathology pyramid
builder](http://code.google.com/p/virtualmicroscope/wiki/SlideTiler).
For example:
```
$ vips dzsave wtc.tif gmapdir --layout google
```
Will create a directory called `gmapdir` containing `blank.png`, the
file to display for blank tiles, and a set of numbered directories, one
for each zoom level. The pyramid can be sparse (blank tiles are not
written).
As with DeepZoom, you can use `--suffix` to set jpeg quality.
Use `--background` to set the background colour. This is the colour
displayed for bits of the pyramid not in the image (image edges, for
example). By default, the image background is white.
Use `--centre` to add a border to the image large enough to centre the
image within the lowest resolution tile. By default, images are not
centred.
For example:
```
$ vips dzsave wtc.tif gmapdir --layout google --background 0 --centre
```
# Other options
You can use `--tile-size` and `--overlap` to control how large the tiles
are and how they overlap (obviously). They default to the correct values
for the selected layout.
You can use `--depth` to control how deep the pyramid should be. Possible
values are `onepixel`, `onetile` and `one`. `onepixel` means the image
is shrunk until it fits within a single pixel. `onetile` means shrink
until it fits with a tile. `one` means only write one pyramid layer (the
highest resolution one). It defaults to the correct value for the selected
layout. `--depth one` is handy for slicing up a large image into tiles
(rather than a pyramid).
You can use `--angle` to do a 90, 180 or 270 degree rotate of an image
during pyramid write.
You can use `--container` to set the container type. Normally dzsave will
write a tree of directories, but with `--container zip` you'll get a zip file
instead. Use .zip as the directory suffix to turn on zip format automatically:
```
$ vips dzsave wtc.tif mypyr.zip
```
to write a zipfile containing the tiles. You can use `.szi` as a suffix to
enable zip output as well.
Use `--properties` to output an XML file called `vips-properties.xml`. This
contains a dump of all the metadata vips has about the image as a set of
name-value pairs. It's handy with openslide image sources.
# Preprocessing images
You can use `.dz` as a filename suffix, meaning send the image to
`vips_dzsave()`. This means you can write the output of any vips operation to a
pyramid. For example:
```
$ vips extract_area huge.svs mypy.dz[layout=google] 100 100 10000 10000
```
The arguments to `extract_area` are image-in, image-out, left, top,
width, height. So this command will cut out a 10,000 by 10,000 pixel
area from near the top-left-hand corner of an Aperio slide image, then
build a pyramid in Google layout using just those pixels.
If you are working from OpenSlide images, you can use the shrink-on-load
feature of many of those formats. For example:
```
$ vips dzsave CMU-1.mrxs[level=1] x
```
Will pull out level 1 (the half-resolution level of an MRXS slide) and
make a pyramid from that.
# Troubleshooting
If you are building vips from source you do need to check the summary at
the end of configure carefully. You must have the `libgsf-1-dev` package
for `vips_dzsave()` to work.

View File

@ -0,0 +1,183 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<refentry id="Making-image-pyramids.md">
<para>
<refmeta> <refentrytitle>Image pyramids</refentrytitle> <manvolnum>3</manvolnum> <refmiscinfo>libvips</refmiscinfo> </refmeta>
</para>
<para>
<refnamediv> <refname>Pyramids</refname> <refpurpose>How to use libvips to make image pyramids</refpurpose> </refnamediv>
</para>
<para>
libvips includes <literal>vips_dzsave()</literal>, an operation that can build image pyramids compatible with <ulink url="http://en.wikipedia.org/wiki/Deep_Zoom">DeepZoom</ulink>, Zoomify and <ulink url="https://developers.google.com/maps/">Google Maps</ulink> image viewers. Its fast and can generate pyramids for large images using only a small amount of memory.
</para>
<para>
The TIFF writer, <literal>vips_tiffsave()</literal> can also build tiled pyramidal TIFF images, but thats very simple to use. This page concentrates on the DeepZoom builder.
</para>
<para>
Run dzsave with no arguments to see a summary:
</para>
<programlisting>
$ vips dzsave
save image to deepzoom file
usage:
dzsave in filename
where:
in - Image to save, input VipsImage
filename - Filename to save to, input gchararray
optional arguments:
basename - Base name to save to, input gchararray
layout - Directory layout, input VipsForeignDzLayout
default: dz
allowed: dz, zoomify, google
suffix - Filename suffix for tiles, input gchararray
overlap - Tile overlap in pixels, input gint
default: 1
min: 0, max: 8192
tile-size - Tile size in pixels, input gint
default: 254
min: 1, max: 8192
centre - Center image in tile, input gboolean
default: false
depth - Pyramid depth, input VipsForeignDzDepth
default: onepixel
allowed: onepixel, onetile, one
angle - Rotate image during save, input VipsAngle
default: d0
allowed: d0, d90, d180, d270
container - Pyramid container type, input VipsForeignDzContainer
default: fs
allowed: fs, zip
properties - Write a properties file to the output directory, input
gboolean
default: false
compression - ZIP deflate compression level, input gint
default: 0
min: -1, max: 9
strip - Strip all metadata from image, input gboolean
default: false
background - Background value, input VipsArrayDouble
operation flags: sequential nocache
</programlisting>
<para>
You can also call <literal>vips_dzsave()</literal> from any language with a libvips binding, or by using <literal>.dz</literal> or <literal>.szi</literal> as an output file suffix.
</para>
<refsect3 id="writing-deepzoom-pyramids">
<title>Writing <ulink url="http://en.wikipedia.org/wiki/Deep_Zoom">DeepZoom</ulink> pyramids</title>
<para>
The <literal>--layout</literal> option sets the basic mode of operation. With no <literal>--layout</literal>, dzsave writes DeepZoom pyramids. For example:
</para>
<programlisting>
$ vips dzsave huge.tif mydz
</programlisting>
<para>
This will create a directory called <literal>mydz_files</literal> containing the image tiles, and write a file called <literal>mydz.dzi</literal> containing the image metadata. 
</para>
<para>
You can use the <literal>--suffix</literal> option to control how tiles are written. For example:
</para>
<programlisting>
$ vips dzsave huge.tif mydz --suffix .jpg[Q=90]
</programlisting>
<para>
will write JPEG tiles with the quality factor set to 90. You can set any format write options you like, see the API docs for <literal>vips_jpegsave()</literal> for details.
</para>
</refsect3>
<refsect3 id="writing-zoomify-pyramids">
<title>Writing Zoomify pyramids</title>
<para>
Use <literal>--layout zoomify</literal> to put dzsave into zoomify mode. For example:
</para>
<programlisting>
$ vips dzsave huge.tif myzoom --layout zoomify
</programlisting>
<para>
This will create a directory called <literal>myzoom</literal> containing a file called <literal>ImageProperties.xml</literal> with the image metadata in, and a series of directories called <literal>TileGroupn</literal>, each containing 256 image tiles.
</para>
<para>
As with DeepZoom, you can use <literal>--suffix</literal> to set jpeg quality.
</para>
</refsect3>
<refsect3 id="writing-google-maps-pyramids">
<title>Writing <ulink url="https://developers.google.com/maps/">Google Maps</ulink> pyramids</title>
<para>
Use <literal>--layout google</literal> to write Google maps-style pyramids. These are compatible with the <ulink url="http://code.google.com/p/virtualmicroscope/wiki/SlideTiler">NYU Pathology pyramid builder</ulink>. For example:
</para>
<programlisting>
$ vips dzsave wtc.tif gmapdir --layout google
</programlisting>
<para>
Will create a directory called <literal>gmapdir</literal> containing <literal>blank.png</literal>, the file to display for blank tiles, and a set of numbered directories, one for each zoom level. The pyramid can be sparse (blank tiles are not written).
</para>
<para>
As with DeepZoom, you can use <literal>--suffix</literal> to set jpeg quality.
</para>
<para>
Use <literal>--background</literal> to set the background colour. This is the colour displayed for bits of the pyramid not in the image (image edges, for example). By default, the image background is white.
</para>
<para>
Use <literal>--centre</literal> to add a border to the image large enough to centre the image within the lowest resolution tile. By default, images are not centred.
</para>
<para>
For example:
</para>
<programlisting>
$ vips dzsave wtc.tif gmapdir --layout google --background 0 --centre
</programlisting>
</refsect3>
<refsect3 id="other-options">
<title>Other options</title>
<para>
You can use <literal>--tile-size</literal> and <literal>--overlap</literal> to control how large the tiles are and how they overlap (obviously). They default to the correct values for the selected layout.
</para>
<para>
You can use <literal>--depth</literal> to control how deep the pyramid should be. Possible values are <literal>onepixel</literal>, <literal>onetile</literal> and <literal>one</literal>. <literal>onepixel</literal> means the image is shrunk until it fits within a single pixel. <literal>onetile</literal> means shrink until it fits with a tile. <literal>one</literal> means only write one pyramid layer (the highest resolution one). It defaults to the correct value for the selected layout. <literal>--depth one</literal> is handy for slicing up a large image into tiles (rather than a pyramid).
</para>
<para>
You can use <literal>--angle</literal> to do a 90, 180 or 270 degree rotate of an image during pyramid write.
</para>
<para>
You can use <literal>--container</literal> to set the container type. Normally dzsave will write a tree of directories, but with <literal>--container zip</literal> youll get a zip file instead. Use .zip as the directory suffix to turn on zip format automatically:
</para>
<programlisting>
$ vips dzsave wtc.tif mypyr.zip
</programlisting>
<para>
to write a zipfile containing the tiles. You can use <literal>.szi</literal> as a suffix to enable zip output as well.
</para>
<para>
Use <literal>--properties</literal> to output an XML file called <literal>vips-properties.xml</literal>. This contains a dump of all the metadata vips has about the image as a set of name-value pairs. Its handy with openslide image sources.
</para>
</refsect3>
<refsect3 id="preprocessing-images">
<title>Preprocessing images</title>
<para>
You can use <literal>.dz</literal> as a filename suffix, meaning send the image to <literal>vips_dzsave()</literal>. This means you can write the output of any vips operation to a pyramid. For example:
</para>
<programlisting>
$ vips extract_area huge.svs mypy.dz[layout=google] 100 100 10000 10000
</programlisting>
<para>
The arguments to <literal>extract_area</literal> are image-in, image-out, left, top, width, height. So this command will cut out a 10,000 by 10,000 pixel area from near the top-left-hand corner of an Aperio slide image, then build a pyramid in Google layout using just those pixels.
</para>
<para>
If you are working from OpenSlide images, you can use the shrink-on-load feature of many of those formats. For example:
</para>
<programlisting>
$ vips dzsave CMU-1.mrxs[level=1] x
</programlisting>
<para>
Will pull out level 1 (the half-resolution level of an MRXS slide) and make a pyramid from that.
</para>
</refsect3>
<refsect3 id="troubleshooting">
<title>Troubleshooting</title>
<para>
If you are building vips from source you do need to check the summary at the end of configure carefully. You must have the <literal>libgsf-1-dev</literal> package for <literal>vips_dzsave()</literal> to work.
</para>
</refsect3>
</refentry>

299
doc/Using-vipsthumbnail.md Normal file
View File

@ -0,0 +1,299 @@
<refmeta>
<refentrytitle>Using `vipsthumbnail`</refentrytitle>
<manvolnum>3</manvolnum>
<refmiscinfo>libvips</refmiscinfo>
</refmeta>
<refnamediv>
<refname>`vipsthumbnail`</refname>
<refpurpose>Introduction to `vipsthumbnail`, with examples</refpurpose>
</refnamediv>
libvips ships with a handy command-line image thumbnailer, `vipsthumbnail`.
This page introduces it, with some examples.
The thumbnailing functionality is implemented by `vips_thumbnail()` and
`vips_thumbnail_buffer()` (which thumbnails an image held as a string),
see the docs for details. You can use these functions from any language
with a libvips binding. For example, from PHP you could write:
```php
$filename = ...;
$image = Vips\Image::thumbnail($filename, 200, ["height" => 200]);
$image.writeToFile("my-thumbnail.jpg");
```
# libvips options
`vipsthumbnail` supports the usual range of vips command-line options. A
few of them are useful:
`--vips-cache-trace` shows each operation as libvips starts it. It can be
handy to see exactly what operations `vipsthumbnail` is running for you.
`--vips-leak` turns on the libvips memory leak checker. As well as reporting
leaks (hopefully there are none) it also tracks and reports peak memory use.
`--vips-progress` runs a progress indicator during computation. It can be
useful to see where libvips is looping and how often.
`--vips-info` shows a higher level view of the operations that `vipsthumbnail`
is running. 
# Looping
`vipsthumbnail` can process many images in one command. For example:
```
$ vipsthumbnail *.jpg
```
will make a thumbnail for every jpeg in the current directory.  See the
[Output directory](#output-directory) section below to see how to change
where thumbnails are written.
`vipsthumbnail` will process images one after the other. You can get a good
speedup by running several `vipsthumbnail`s in parallel, depending on how
much load you want to put on your system. For example:
```
$ parallel vipsthumbnail ::: *.jpg
```
# Thumbnail size
You can set the bounding box of the generated thumbnail with the `--size`
option. For example:
```
$ vipsthumbnail shark.jpg --size 200x100
```
Use a single number to set a square bounding box. You can omit either number
but keep the x to mean resize just based on that axis, for example:
```
$ vipsthumbnail shark.jpg --size 200x
```
Will resize to 200 pixels across, no matter what the height of the input image
is.
You can append `<` or `>` to mean only resize if the image is smaller or larger
than the target.
# Cropping
`vipsthumbnail` normally shrinks images to fit within the box set by `--size`.
You can use the `--smartcrop` option to crop to fill the box instead. Excess
pixels are trimmed away using the strategy you set. For example:
```
$ vipsthumbnail owl.jpg --smartcrop attention -s 128
```
Where `owl.jpg` is an off-centre composition:
![](owl.jpg)
Gives this result:
![](tn_owl.jpg)
First it shrinks the image to get the vertical axis to 128 pixels, then crops
down to 128 pixels across using the `attention` strategy. This one searches
the image for features which might catch a human eye, see `vips_smartcrop()`
for details.
# Linear light
Shrinking images involves combining many pixels into one. Arithmetic
averaging really ought to be in terms of the number of photons, but (for
historical reasons) the values stored in image files are usually related
to the voltage that should be applied to the electron gun in a CRT display.
`vipsthumbnail` has an option to perform image shrinking in linear space, that
is, a colourspace where values are proportional to photon numbers. For example:
```
$ vipsthumbnail fred.jpg --linear
```
The downside is that in linear mode, none of the very fast shrink-on-load
tricks that `vipsthumbnail` normally uses are possible, since the shrinking is
done at encode time, not decode time, and is done in terms of CRT voltage, not
photons. This can make linear light thumbnailing of large images extremely slow.
For example, for a 10,000 x 10,000 pixel JPEG I see:
```
$ time vipsthumbnail wtc.jpg
real 0m0.317s
user 0m0.292s
sys 0m0.016s
$ time vipsthumbnail wtc.jpg --linear
real 0m4.660s
user 0m4.640s
sys 0m0.016s
```
# Output directory
You set the thumbnail write parameters with the `-o`
option. This is a pattern which the input filename is pasted into to
produce the output filename. For example:
```
$ vipsthumbnail fred.jpg jim.tif -o tn_%s.jpg
```
For each of the files to be thumbnailed, `vipsthumbnail` will drop the
extension (`.jpg` and `.tif` in this case) and then substitute the name into
the `-o` option, replacing the `%s` So this example will write thumbnails to
`tn_fred.jpg` and `tn_jim.jpg`.
If the pattern given to `-o` is an absolute path, any path components are
dropped from the input filenames. This lets you write all of your thumbnails
to a specific directory, if you want. For example:
```
$ vipsthumbnail fred.jpg ../jim.tif -o /mythumbs/tn_%s.jpg
```
Now both thumbnails will be written to `/mythumbs`, even though the source
images are in different directories.
Conversely, if `-o` is set to a relative path, any path component from the
input file is prepended. For example:
```
$ vipsthumbnail fred.jpg ../jim.tif -o mythumbs/tn_%s.jpg
```
Now both input files will have thumbnails written to a subdirectory of
their current directory.
# Output format and options
You can use `-o` to specify the thumbnail image format too. For example: 
```
$ vipsthumbnail fred.jpg ../jim.tif -o tn_%s.png
```
Will write thumbnails in PNG format.
You can give options to the image write operation as a list of comma-separated
arguments in square brackets. For example:
```
$ vipsthumbnail fred.jpg ../jim.tif -o > tn_%s.jpg[Q=90,optimize_coding]
```
will write jpeg images with quality 90, and will turn on the libjpeg coding
optimizer.
Check the image write operations to see all the possible options. For example:
```
$ vips jpegsave
save image to jpeg file
usage:
jpegsave in filename
where:
in - Image to save, input VipsImage
filename - Filename to save to, input gchararray
optional arguments:
Q - Q factor, input gint
default: 75
min: 1, max: 100
profile - ICC profile to embed, input gchararray
optimize-coding - Compute optimal Huffman coding tables, input gboolean
default: false
interlace - Generate an interlaced (progressive) jpeg, input gboolean
default: false
no-subsample - Disable chroma subsample, input gboolean
default: false
trellis-quant - Apply trellis quantisation to each 8x8 block, input gboolean
default: false
overshoot-deringing - Apply overshooting to samples with extreme values, input gboolean
default: false
optimize-scans - Split the spectrum of DCT coefficients into separate scans, input gboolean
default: false
quant-table - Use predefined quantization table with given index, input gint
default: 0
min: 0, max: 8
strip - Strip all metadata from image, input gboolean
default: false
background - Background value, input VipsArrayDouble
```
The `strip` option is especially useful. Many image have very large IPCT, ICC or
XMP metadata items embedded in them, and removing these can give a large
saving.
For example:
```
$ vipsthumbnail 42-32157534.jpg
$ ls -l tn_42-32157534.jpg
-rw-rr 1 john john 6682 Nov 12 21:27 tn_42-32157534.jpg
```
`strip` almost halves the size of the thumbnail:
```
$ vipsthumbnail 42-32157534.jpg -o x.jpg[optimize_coding,strip]
$ ls -l x.jpg
-rw-rr 1 john john 3600 Nov 12 21:27 x.jpg
```
# Colour management
`vipsthumbnail` will optionally put images through LittleCMS for you. You can
use this to move all thumbnails to the same colour space. All web browsers
assume that images without an ICC profile are in sRGB colourspace, so if
you move your thumbnails to sRGB, you can strip all the embedded profiles.
This can save several kb per thumbnail.
For example:
```
$ vipsthumbnail shark.jpg
$ ls -l tn_shark.jpg
-rw-rr 1 john john 7295 Nov  9 14:33 tn_shark.jpg
```
Now encode with sRGB and delete any embedded profile:
```
$ vipsthumbnail shark.jpg --eprofile /usr/share/color/icc/sRGB.icc --delete
$ ls -l tn_shark.jpg
-rw-rr 1 john john 4229 Nov  9 14:33 tn_shark.jpg
```
Itll look identical to a user, but be almost half the size.
You can also specify a fallback input profile to use if the image has no
embedded one, but this is less useful.
# Auto-rotate
Many JPEG files have a hint set in the header giving the image orientation. If
you strip out the metadata, this hint will be lost, and the image will appear
to be rotated.
If you use the `--rotate` option, `vipsthumbnail` examines the image header and
if there's an orientation tag, applies and removes it.
# Final suggestion
Putting all this together, I suggest this as a sensible set of options:
```
$ vipsthumbnail fred.jpg \
--size 128 \
-o tn_%s.jpg[optimize_coding,strip] \
--eprofile /usr/share/color/icc/sRGB.icc \
--rotate
```

300
doc/Using-vipsthumbnail.xml Normal file
View File

@ -0,0 +1,300 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<refentry id="Using-vipsthumbnail.md">
<para>
<refmeta> <refentrytitle>Using <literal>vipsthumbnail</literal></refentrytitle> <manvolnum>3</manvolnum> <refmiscinfo>libvips</refmiscinfo> </refmeta>
</para>
<para>
<refnamediv> <refname><literal>vipsthumbnail</literal></refname> <refpurpose>Introduction to <literal>vipsthumbnail</literal>, with examples</refpurpose> </refnamediv>
</para>
<para>
libvips ships with a handy command-line image thumbnailer, <literal>vipsthumbnail</literal>. This page introduces it, with some examples.
</para>
<para>
The thumbnailing functionality is implemented by <literal>vips_thumbnail()</literal> and <literal>vips_thumbnail_buffer()</literal> (which thumbnails an image held as a string), see the docs for details. You can use these functions from any language with a libvips binding. For example, from PHP you could write:
</para>
<programlisting language="php">
$filename = ...;
$image = Vips\Image::thumbnail($filename, 200, [&quot;height&quot; =&gt; 200]);
$image.writeToFile(&quot;my-thumbnail.jpg&quot;);
</programlisting>
<refsect3 id="libvips-options">
<title>libvips options</title>
<para>
<literal>vipsthumbnail</literal> supports the usual range of vips command-line options. A few of them are useful:
</para>
<para>
<literal>--vips-cache-trace</literal> shows each operation as libvips starts it. It can be handy to see exactly what operations <literal>vipsthumbnail</literal> is running for you.
</para>
<para>
<literal>--vips-leak</literal> turns on the libvips memory leak checker. As well as reporting leaks (hopefully there are none) it also tracks and reports peak memory use.
</para>
<para>
<literal>--vips-progress</literal> runs a progress indicator during computation. It can be useful to see where libvips is looping and how often.
</para>
<para>
<literal>--vips-info</literal> shows a higher level view of the operations that <literal>vipsthumbnail</literal> is running. 
</para>
</refsect3>
<refsect3 id="looping">
<title>Looping</title>
<para>
<literal>vipsthumbnail</literal> can process many images in one command. For example:
</para>
<programlisting>
$ vipsthumbnail *.jpg
</programlisting>
<para>
will make a thumbnail for every jpeg in the current directory.  See the <link linkend="output-directory">Output directory</link> section below to see how to change where thumbnails are written.
</para>
<para>
<literal>vipsthumbnail</literal> will process images one after the other. You can get a good speedup by running several <literal>vipsthumbnail</literal>s in parallel, depending on how much load you want to put on your system. For example:
</para>
<programlisting>
$ parallel vipsthumbnail ::: *.jpg
</programlisting>
</refsect3>
<refsect3 id="thumbnail-size">
<title>Thumbnail size</title>
<para>
You can set the bounding box of the generated thumbnail with the <literal>--size</literal> option. For example:
</para>
<programlisting>
$ vipsthumbnail shark.jpg --size 200x100
</programlisting>
<para>
Use a single number to set a square bounding box. You can omit either number but keep the x to mean resize just based on that axis, for example:
</para>
<programlisting>
$ vipsthumbnail shark.jpg --size 200x
</programlisting>
<para>
Will resize to 200 pixels across, no matter what the height of the input image is.
</para>
<para>
You can append <literal>&lt;</literal> or <literal>&gt;</literal> to mean only resize if the image is smaller or larger than the target.
</para>
</refsect3>
<refsect3 id="cropping">
<title>Cropping</title>
<para>
<literal>vipsthumbnail</literal> normally shrinks images to fit within the box set by <literal>--size</literal>. You can use the <literal>--smartcrop</literal> option to crop to fill the box instead. Excess pixels are trimmed away using the strategy you set. For example:
</para>
<programlisting>
$ vipsthumbnail owl.jpg --smartcrop attention -s 128
</programlisting>
<para>
Where <literal>owl.jpg</literal> is an off-centre composition:
</para>
<figure>
<mediaobject>
<imageobject>
<imagedata fileref="owl.jpg" />
</imageobject>
<textobject><phrase></phrase></textobject>
</mediaobject>
</figure>
<para>
Gives this result:
</para>
<figure>
<mediaobject>
<imageobject>
<imagedata fileref="tn_owl.jpg" />
</imageobject>
<textobject><phrase></phrase></textobject>
</mediaobject>
</figure>
<para>
First it shrinks the image to get the vertical axis to 128 pixels, then crops down to 128 pixels across using the <literal>attention</literal> strategy. This one searches the image for features which might catch a human eye, see <literal>vips_smartcrop()</literal> for details.
</para>
</refsect3>
<refsect3 id="linear-light">
<title>Linear light</title>
<para>
Shrinking images involves combining many pixels into one. Arithmetic averaging really ought to be in terms of the number of photons, but (for historical reasons) the values stored in image files are usually related to the voltage that should be applied to a CRT electron gun.
</para>
<para>
<literal>vipsthumbnail</literal> has an option to perform image shrinking in linear space, that is, a colourspace where values are proportional to photon numbers. For example:
</para>
<programlisting>
$ vipsthumbnail fred.jpg --linear
</programlisting>
<para>
The downside is that in linear mode, none of the very fast shrink-on-load tricks that <literal>vipsthumbnail</literal> normally uses are possible, since the shrinking is done at encode time, not decode time, and is done in terms of CRT voltage, not photons. This can make linear light thumbnailing of large images extremely slow.
</para>
<para>
For example, for a 10,000 x 10,000 pixel JPEG I see:
</para>
<programlisting>
$ time vipsthumbnail wtc.jpg
real 0m0.317s
user 0m0.292s
sys 0m0.016s
$ time vipsthumbnail wtc.jpg --linear
real 0m4.660s
user 0m4.640s
sys 0m0.016s
</programlisting>
</refsect3>
<refsect3 id="output-directory">
<title>Output directory</title>
<para>
You set the thumbnail write parameters with the <literal>-o</literal> option. This is a pattern which the input filename is pasted into to produce the output filename. For example:
</para>
<programlisting>
$ vipsthumbnail fred.jpg jim.tif -o tn_%s.jpg
</programlisting>
<para>
For each of the files to be thumbnailed, <literal>vipsthumbnail</literal> will drop the extension (<literal>.jpg</literal> and <literal>.tif</literal> in this case) and then substitute the name into the <literal>-o</literal> option, replacing the <literal>%s</literal> So this example will write thumbnails to <literal>tn_fred.jpg</literal> and <literal>tn_jim.jpg</literal>.
</para>
<para>
If the pattern given to <literal>-o</literal> is an absolute path, any path components are dropped from the input filenames. This lets you write all of your thumbnails to a specific directory, if you want. For example:
</para>
<programlisting>
$ vipsthumbnail fred.jpg ../jim.tif -o /mythumbs/tn_%s.jpg
</programlisting>
<para>
Now both thumbnails will be written to <literal>/mythumbs</literal>, even though the source images are in different directories.
</para>
<para>
Conversely, if <literal>-o</literal> is set to a relative path, any path component from the input file is prepended. For example:
</para>
<programlisting>
$ vipsthumbnail fred.jpg ../jim.tif -o mythumbs/tn_%s.jpg
</programlisting>
<para>
Now both input files will have thumbnails written to a subdirectory of their current directory.
</para>
</refsect3>
<refsect3 id="output-format-and-options">
<title>Output format and options</title>
<para>
You can use <literal>-o</literal> to specify the thumbnail image format too. For example: 
</para>
<programlisting>
$ vipsthumbnail fred.jpg ../jim.tif -o tn_%s.png
</programlisting>
<para>
Will write thumbnails in PNG format.
</para>
<para>
You can give options to the image write operation as a list of comma-separated arguments in square brackets. For example:
</para>
<programlisting>
$ vipsthumbnail fred.jpg ../jim.tif -o &gt; tn_%s.jpg[Q=90,optimize_coding]
</programlisting>
<para>
will write jpeg images with quality 90, and will turn on the libjpeg coding optimizer.
</para>
<para>
Check the image write operations to see all the possible options. For example:
</para>
<programlisting>
$ vips jpegsave
save image to jpeg file
usage:
jpegsave in filename
where:
in - Image to save, input VipsImage
filename - Filename to save to, input gchararray
optional arguments:
Q - Q factor, input gint
default: 75
min: 1, max: 100
profile - ICC profile to embed, input gchararray
optimize-coding - Compute optimal Huffman coding tables, input gboolean
default: false
interlace - Generate an interlaced (progressive) jpeg, input gboolean
default: false
no-subsample - Disable chroma subsample, input gboolean
default: false
trellis-quant - Apply trellis quantisation to each 8x8 block, input gboolean
default: false
overshoot-deringing - Apply overshooting to samples with extreme values, input gboolean
default: false
optimize-scans - Split the spectrum of DCT coefficients into separate scans, input gboolean
default: false
quant-table - Use predefined quantization table with given index, input gint
default: 0
min: 0, max: 8
strip - Strip all metadata from image, input gboolean
default: false
background - Background value, input VipsArrayDouble
</programlisting>
<para>
The <literal>strip</literal> option is especially useful. Many image have very large IPCT, ICC or XMP metadata items embedded in them, and removing these can give a large saving.
</para>
<para>
For example:
</para>
<programlisting>
$ vipsthumbnail 42-32157534.jpg
$ ls -l tn_42-32157534.jpg
-rw-rr 1 john john 6682 Nov 12 21:27 tn_42-32157534.jpg
</programlisting>
<para>
<literal>strip</literal> almost halves the size of the thumbnail:
</para>
<programlisting>
$ vipsthumbnail 42-32157534.jpg -o x.jpg[optimize_coding,strip]
$ ls -l x.jpg
-rw-rr 1 john john 3600 Nov 12 21:27 x.jpg
</programlisting>
</refsect3>
<refsect3 id="colour-management">
<title>Colour management</title>
<para>
<literal>vipsthumbnail</literal> will optionally put images through LittleCMS for you. You can use this to move all thumbnails to the same colour space. All web browsers assume that images without an ICC profile are in sRGB colourspace, so if you move your thumbnails to sRGB, you can strip all the embedded profiles. This can save several kb per thumbnail.
</para>
<para>
For example:
</para>
<programlisting>
$ vipsthumbnail shark.jpg
$ ls -l tn_shark.jpg
-rw-rr 1 john john 7295 Nov  9 14:33 tn_shark.jpg
</programlisting>
<para>
Now encode with sRGB and delete any embedded profile:
</para>
<programlisting>
$ vipsthumbnail shark.jpg --eprofile /usr/share/color/icc/sRGB.icc --delete
$ ls -l tn_shark.jpg
-rw-rr 1 john john 4229 Nov  9 14:33 tn_shark.jpg
</programlisting>
<para>
Itll look identical to a user, but be almost half the size.
</para>
<para>
You can also specify a fallback input profile to use if the image has no embedded one, but this is less useful.
</para>
</refsect3>
<refsect3 id="auto-rotate">
<title>Auto-rotate</title>
<para>
Many JPEG files have a hint set in the header giving the image orientation. If you strip out the metadata, this hint will be lost, and the image will appear to be rotated.
</para>
<para>
If you use the <literal>--rotate</literal> option, <literal>vipsthumbnail</literal> examines the image header and if theres an orientation tag, applies and removes it.
</para>
</refsect3>
<refsect3 id="final-suggestion">
<title>Final suggestion</title>
<para>
Putting all this together, I suggest this as a sensible set of options:
</para>
<programlisting>
$ vipsthumbnail fred.jpg \
--size 128 \
-o tn_%s.jpg[optimize_coding,strip] \
--eprofile /usr/share/color/icc/sRGB.icc \
--rotate
</programlisting>
</refsect3>
</refentry>

View File

@ -92,21 +92,21 @@ $ vips gamma t.v output.tif
<row>
<entry>4 -- 7</entry>
<entry>%gint</entry>
<entry>int32</entry>
<entry><code>width</code></entry>
<entry>Width of image, in pixels</entry>
</row>
<row>
<entry>8 -- 11</entry>
<entry>%gint</entry>
<entry>int32</entry>
<entry><code>height</code></entry>
<entry>Height of image, in pixels</entry>
</row>
<row>
<entry>12 -- 15</entry>
<entry>%gint</entry>
<entry>int32</entry>
<entry><code>bands</code></entry>
<entry>Number of image bands</entry>
</row>
@ -141,14 +141,14 @@ $ vips gamma t.v output.tif
<row>
<entry>32 -- 35</entry>
<entry>%gfloat</entry>
<entry>float32</entry>
<entry><code>xres</code></entry>
<entry>Horizontal resolution, in pixels per millimetre</entry>
</row>
<row>
<entry>36 -- 39</entry>
<entry>%gfloat</entry>
<entry>float32</entry>
<entry><code>yres</code></entry>
<entry>Vertical resolution, in pixels per millimetre</entry>
</row>
@ -162,14 +162,14 @@ $ vips gamma t.v output.tif
<row>
<entry>48 -- 51</entry>
<entry>%gint</entry>
<entry>int32</entry>
<entry><code>xoffset</code></entry>
<entry>Horizontal offset of origin, in pixels</entry>
</row>
<row>
<entry>52 -- 55</entry>
<entry>%gint</entry>
<entry>int32</entry>
<entry><code>yoffset</code></entry>
<entry>Vertical offset of origin, in pixels</entry>
</row>

BIN
doc/images/Combine.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
doc/images/Memtrace.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
doc/images/Sequence.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
doc/images/Sink.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

BIN
doc/images/Vips-smp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
doc/images/owl.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
doc/images/tn_owl.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

BIN
doc/images/x.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

View File

@ -39,6 +39,11 @@
<xi:include href="xml/function-list.xml"/>
<xi:include href="xml/file-format.xml"/>
<xi:include href="xml/using-threads.xml"/>
<xi:include href="xml/How-it-works.xml"/>
<xi:include href="xml/How-it-opens-files.xml"/>
<xi:include href="xml/Making-image-pyramids.xml"/>
<xi:include href="xml/Using-vipsthumbnail.xml"/>
<xi:include href="xml/Examples.xml"/>
</chapter>
<chapter>

View File

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8" ?>
$if(mathml)$
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook EBNF Module V1.1CR1//EN"
"http://www.oasis-open.org/docbook/xml/mathml/1.1CR1/dbmathml.dtd">
$else$
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
$endif$
<refentry id="$title$">
$for(include-before)$
$include-before$
$endfor$
$body$
$for(include-after)$
$include-after$
$endfor$
</refentry>

View File

@ -178,10 +178,14 @@ void vips__demand_hint_array( struct _VipsImage *image,
int vips__image_copy_fields_array( struct _VipsImage *out,
struct _VipsImage *in[] );
void vips__region_count_pixels( struct _VipsRegion *region, const char *nickname );
void vips_region_dump_all( void );
/* Deprecated.
*/
int vips__init( const char *argv0 );
size_t vips__get_sizeof_vipsobject( void );
int vips_region_prepare_many( struct _VipsRegion **reg, VipsRect *r );
#ifdef __cplusplus
}

View File

@ -121,16 +121,9 @@ int vips_region_shrink( VipsRegion *from, VipsRegion *to, VipsRect *target );
int vips_region_prepare( VipsRegion *reg, VipsRect *r );
int vips_region_prepare_to( VipsRegion *reg,
VipsRegion *dest, VipsRect *r, int x, int y );
int vips_region_prepare_many( VipsRegion **reg, VipsRect *r );
void vips_region_invalidate( VipsRegion *reg );
void vips_region_dump_all( void );
#ifdef DEBUG_LEAK
void vips__region_count_pixels( VipsRegion *region, const char *nickname );
#endif /*DEBUG_LEAK*/
/* Use this to count pixels passing through key points. Handy for spotting bad
* overcomputation.
*/

View File

@ -105,7 +105,7 @@
* <link linkend="libvips-generate">generate</link>
* @include: vips/vips.h
*
* A #VipsRegion is a small part of an image and some pixels. You use regions to
* A #VipsRegion is a small part of an image. You use regions to
* read pixels out of images without having to have the whole image in memory
* at once.
*
@ -558,7 +558,7 @@ vips_region_new( VipsImage *image )
* @r: #VipsRect of pixels you need to be able to address
*
* The region is transformed so that at least @r pixels are available as a
* memory buffer.
* memory buffer that can be written to.
*
* Returns: 0 on success, or -1 for error.
*/
@ -626,8 +626,8 @@ vips_region_buffer( VipsRegion *reg, VipsRect *r )
* @reg: region to operate upon
* @r: #VipsRect of pixels you need to be able to address
*
* The region is transformed so that at least @r pixels are available directly
* from the image. The image needs to be a memory buffer or represent a file
* The region is transformed so that at least @r pixels are available to be read from
* image. The image needs to be a memory buffer or represent a file
* on disc that has been mapped or can be mapped.
*
* Returns: 0 on success, or -1 for error.
@ -725,7 +725,7 @@ vips_region_image( VipsRegion *reg, VipsRect *r )
* Performs all clipping necessary to ensure that @reg->valid is indeed
* valid.
*
* If the region we attach to is modified, we can be left with dangling
* If the region we attach to is moved or destroyed, we can be left with dangling
* pointers! If the region we attach to is on another image, the two images
* must have
* the same sizeof( pel ).
@ -933,7 +933,11 @@ vips_region_fill( VipsRegion *reg, VipsRect *r, VipsRegionFillFn fn, void *a )
* @r: area to paint
* @value: value to paint
*
* Paints @value into @reg covering rectangle @r. For int images, @value is
* Paints @value into @reg covering rectangle @r.
* @r is clipped against
* @reg->valid.
*
* For int images, @value is
* passed to memset(), so it usually needs to be 0 or 255. For float images,
* value is cast to a float and copied in to each band element.
*
@ -955,7 +959,6 @@ vips_region_paint( VipsRegion *reg, VipsRect *r, int value )
int y;
if( vips_band_format_isint( reg->im->BandFmt ) ) {
for( y = 0; y < clipped.height; y++ ) {
memset( (char *) q, value, wd );
q += ls;
@ -1519,19 +1522,17 @@ vips_region_prepare_to_generate( VipsRegion *reg,
* @x: postion of @r in @dest
* @y: postion of @r in @dest
*
* Like vips_region_prepare(): fill @reg with data, ready to be read from by
* our caller. Unlike vips_region_prepare(), rather than allocating memory
* local to @reg for the result, we guarantee that we will fill the pixels
* in @dest at offset @x, @y. In other words, we generate an extra copy
* operation if necessary.
* Like vips_region_prepare(): fill @reg with the pixels in area @r.
* Unlike vips_region_prepare(), rather than writing the result to @reg, the pixels are
* written into @dest
* at offset @x, @y.
*
* Also unlike vips_region_prepare(), @dest is not set up for writing for
* you with
* vips_region_buffer(). You can
* point @dest at anything, and pixels really will be written there.
* This makes vips_region_prepare_to() useful for making the ends of
* pipelines, since
* it (effectively) makes a break in the pipe.
* pipelines.
*
* See also: vips_region_prepare(), vips_sink_disc().
*
@ -1671,6 +1672,8 @@ vips_region_prepare_to( VipsRegion *reg,
return( 0 );
}
/* Don't use this, use vips_reorder_prepare_many() instead.
*/
int
vips_region_prepare_many( VipsRegion **reg, VipsRect *r )
{

View File

@ -156,9 +156,10 @@ static GOptionEntry options[] = {
{ "linear", 'a', 0,
G_OPTION_ARG_NONE, &linear_processing,
N_( "process in linear space" ), NULL },
{ "smartcrop", 'c', 0,
{ "smartcrop", 'm', 0,
G_OPTION_ARG_STRING, &smartcrop_image,
N_( "crop exactly to SIZE" ), NULL },
N_( "shrink and crop to fill SIZE using STRATEGY" ),
N_( "STRATEGY" ) },
{ "rotate", 't', 0,
G_OPTION_ARG_NONE, &rotate_image,
N_( "auto-rotate" ), NULL },