837 lines
28 KiB
TeX
837 lines
28 KiB
TeX
\section{Core C API}
|
|
|
|
VIPS is built on top of several other libraries, two of which, glib and
|
|
gobject, are exposed at various points in the C API.
|
|
|
|
You can read up on glib at the GTK+ website:
|
|
|
|
\begin{verbatim}
|
|
http://www.gtk.org
|
|
\end{verbatim}
|
|
|
|
There's also an excellent book by Matthias Warkus, \emph{The Official
|
|
GNOME 2 Developer's Guide}, which covers the same material in a tutorial
|
|
manner.
|
|
|
|
\subsection{Startup}
|
|
|
|
Before calling any VIPS function, you need to start VIPS up:
|
|
|
|
\begin{verbatim}
|
|
int im_init_world( const char *argv0 );
|
|
\end{verbatim}
|
|
|
|
The \verb+argv0+ argument is the value of \verb+argv[0]+ your
|
|
program was passed by the host operating system. VIPS uses this with
|
|
\verb+im_guess_prefix()+ and \verb+im_guess_libdir()+ to try to find various
|
|
VIPS data files.
|
|
|
|
If you don't call this function, VIPS will call it for you the first time you
|
|
use a VIPS function. But it won't be able to get the \verb+argv0+ value for
|
|
you, so it may not be able to find it's data files.
|
|
|
|
VIPS also offers the optional:
|
|
|
|
\begin{verbatim}
|
|
GOptionGroup *im_get_option_group( void );
|
|
\end{verbatim}
|
|
|
|
You can use this with GOption to parse your program's command-line arguments.
|
|
It adds several useful VIPS flags, including \verb+--vips-concurrency+.
|
|
|
|
\fref{fg:hello} shows both these functions in use. Again, the GOption stuff is
|
|
optional and just lets VIPS add some flags to your program. You do need the
|
|
\verb+im_init_world()+ though.
|
|
|
|
\begin{fig2}
|
|
\begin{verbatim}
|
|
#include <stdio.h>
|
|
#include <vips/vips.h>
|
|
|
|
static gboolean print_stuff;
|
|
|
|
static GOptionEntry options[] = {
|
|
{ "print", 'p', 0, G_OPTION_ARG_NONE, &print_stuff,
|
|
"print \"hello world!\"", NULL },
|
|
{ NULL }
|
|
};
|
|
|
|
int
|
|
main( int argc, char **argv )
|
|
{
|
|
GOptionContext *context;
|
|
GError *error = NULL;
|
|
|
|
if( im_init_world( argv[0] ) )
|
|
error_exit( "unable to start VIPS" );
|
|
|
|
context = g_option_context_new( "- my program" );
|
|
g_option_context_add_main_entries( context,
|
|
options, "main" );
|
|
g_option_context_add_group( context, im_get_option_group() );
|
|
if( !g_option_context_parse( context, &argc, &argv, &error ) ) {
|
|
if( error ) {
|
|
fprintf( stderr, "%s\n", error->message );
|
|
g_error_free( error );
|
|
}
|
|
error_exit( "try \"%s --help\"", g_get_prgname() );
|
|
}
|
|
g_option_context_free( context );
|
|
|
|
if( print_stuff )
|
|
printf( "hello, world!\n" );
|
|
|
|
return( 0 );
|
|
}
|
|
\end{verbatim}
|
|
\caption{Hello World for VIPS}
|
|
\label{fg:hello}
|
|
\end{fig2}
|
|
|
|
\subsection{Image descriptors}
|
|
|
|
The base level of the VIPS I/O system provides \verb+IMAGE+ descriptors.
|
|
An image represented by a descriptor may be an image file on disc, an area
|
|
of memory that has been allocated for the image, an output file, a delayed
|
|
computation, and so on. Programs need (usually) only know that they have
|
|
a descriptor, they do not see many of the details. \fref{fg:image}
|
|
shows the definition of the \verb+IMAGE+ descriptor.
|
|
|
|
\begin{fig2}
|
|
\begin{verbatim}
|
|
typedef struct {
|
|
/* Fields from image header.
|
|
*/
|
|
int Xsize; /* Pels per line */
|
|
int Ysize; /* Lines */
|
|
int Bands; /* Number of bands */
|
|
int Bbits; /* Bits per band */
|
|
int BandFmt; /* Band format */
|
|
int Coding; /* Coding type */
|
|
int Type; /* Type of file */
|
|
float XRes; /* Horizontal res in pels/mm */
|
|
float YRes; /* Vertical res in pels/mm */
|
|
int Length; /* Obsolete (unused) */
|
|
short Compression; /* Obsolete (unused) */
|
|
short Level; /* Obsolete (unused) */
|
|
int Xoffset; /* Position of origin */
|
|
int Yoffset;
|
|
|
|
/* Derived fields that may be read by the user.
|
|
*/
|
|
char *filename; /* File name */
|
|
im_time_t *time; /* Timing for eval callback */
|
|
int kill; /* Set to non-zero to block eval */
|
|
|
|
... and lots of other private fields used by VIPS for
|
|
... housekeeping.
|
|
} IMAGE;
|
|
\end{verbatim}
|
|
\caption{The \texttt{IMAGE} descriptor}
|
|
\label{fg:image}
|
|
\end{fig2}
|
|
|
|
The first set of fields simply come from the image file header:
|
|
see \pref{sec:header} for a full description of all the fields. The next
|
|
set are maintained for you by the VIPS I/O system. \verb+filename+ is the
|
|
name of the file that this image came from. If you have attached an eval
|
|
callback to this image, \verb+time+ points to a set of timing statistics
|
|
which can be used by user-interfaces built on VIPS to provide feedback
|
|
about the progress of evaluation --- see \pref{sec:eval}. Finally, if you
|
|
set \verb+kill+ to non-zero, VIPS will block any pipelines which use this
|
|
descriptor as an intermediate. See \pref{sec:block}.
|
|
|
|
The remaining fields are private and are used by VIPS for housekeeping.
|
|
|
|
\subsection{Header fields}
|
|
\label{sec:fields}
|
|
|
|
You can access header fields either directly (as \verb+im->Xsize+, for
|
|
example) or programmatically with \verb+im_header_int()+ and friends. For
|
|
example:
|
|
|
|
\begin{verbatim}
|
|
int i;
|
|
|
|
im_header_int( im, "Xsize", &i );
|
|
\end{verbatim}
|
|
|
|
There's also \verb+im_header_map()+ to loop over header fields, and
|
|
\verb+im_header_get_type+ to test the type of fields. These functions work for
|
|
image meta fields as well, see \pref{sec:meta}.
|
|
|
|
\subsection{Opening and closing}
|
|
\label{sec:open}
|
|
|
|
Descriptors are created with \verb+im_open()+. You can also read images with
|
|
the format system: see \pref{sec:format}. The two APIs are complimentary,
|
|
though \verb+im_open()+ is more useful.
|
|
|
|
At the command-line, try:
|
|
|
|
\begin{verbatim}
|
|
$ vips --list classes
|
|
\end{verbatim}
|
|
|
|
/noindent
|
|
to see a list of all the supported file formats.
|
|
|
|
\verb+im_open()+ takes a file name and a string representing the mode with
|
|
which the descriptor is to be opened:
|
|
|
|
\begin{verbatim}
|
|
IMAGE *im_open( const char *filename,
|
|
const char *mode )
|
|
\end{verbatim}
|
|
|
|
The possible values for mode are:
|
|
|
|
\begin{description}
|
|
|
|
\item[\texttt{"r"}]
|
|
The file is opened read-only.
|
|
If you open a non-VIPS image, or a VIPS image written on a machine with a
|
|
different byte ordering, \verb+im_open()+ will automatically convert it to
|
|
native VIPS format. If the underlying file does not support random access
|
|
(JPEG, for example), the entire file will be converted in memory.
|
|
|
|
VIPS can read images in many file formats. You can control the details of
|
|
the conversion with extra characters embedded in the filename. For example:
|
|
|
|
\begin{verbatim}
|
|
fred = im_open( "fred.tif:2",
|
|
"r" );
|
|
\end{verbatim}
|
|
|
|
\noindent
|
|
will read page 2 of a multi-page TIFF. See the man pages for details.
|
|
|
|
\item[\texttt{"w"}]
|
|
An \verb+IMAGE+ descriptor is created which, when written to, will write
|
|
pixels to disc in the specified file. Any existing file of that name is
|
|
deleted.
|
|
|
|
VIPS looks at the filename suffix to determine the save format. If there
|
|
is no suffix, or the filename ends in \verb+".v"+, the image is written
|
|
in VIPS native format.
|
|
|
|
If you want to control the details of the conversion to the disc format (such
|
|
as setting the Q factor for a JPEG, for example), you embed extra control
|
|
characters in the filename. For example:
|
|
|
|
\begin{verbatim}
|
|
fred = im_open( "fred.jpg:95",
|
|
"w" );
|
|
\end{verbatim}
|
|
|
|
\noindent
|
|
writes to \verb+fred+ will write a JPEG with Q 95. Again, see the man pages
|
|
for the conversion functions for details.
|
|
|
|
\item[\texttt{"t"}]
|
|
As the \verb+"w"+ mode, but pels written to the descriptor will be saved
|
|
in a temporary memory buffer.
|
|
|
|
\item[\texttt{"p"}]
|
|
This creates a special partial image. Partial images are used to join VIPS
|
|
operations together, see \pref{sec:joinup}.
|
|
|
|
\item[\texttt{"rw"}]
|
|
As the \verb+"r"+ mode, but the image is mapped into the caller's address
|
|
space read-write. This mode is only provided for the use of paintbox-style
|
|
applications which need to directly modify an image. Most programs should
|
|
use the \verb+"w"+ mode for image output.
|
|
|
|
\end{description}
|
|
|
|
If an error occurs opening the image, \verb+im_open()+ calls
|
|
\verb+im_error()+ with a string describing the cause of the error and
|
|
returns \verb+NULL+. \verb+im_error()+ has type
|
|
|
|
\begin{verbatim}
|
|
void im_error( const char *domain,
|
|
const char *format, ... )
|
|
\end{verbatim}
|
|
|
|
\noindent
|
|
The first argument is a string giving the name of the thing that raised
|
|
the error (just \verb+"im_open"+, for example). The format and subsequent
|
|
arguments work exactly as \verb+printf()+. It formats the message and
|
|
appends the string formed to the error log. You can get a pointer to the
|
|
error text with \verb+im_error_buffer()+.
|
|
|
|
\begin{verbatim}
|
|
const char *im_error_buffer()
|
|
\end{verbatim}
|
|
|
|
\noindent
|
|
Applications may display this string to give users feedback about the
|
|
cause of the error. The VIPS exit function, \verb+error_exit()+, prints
|
|
\verb+im_error_buffer()+ to \verb+stderr+ and terminates the program with an
|
|
error code of 1.
|
|
|
|
\begin{verbatim}
|
|
void error_exit( const char *format,
|
|
... )
|
|
\end{verbatim}
|
|
|
|
\noindent
|
|
There are other functions for handling errors: see the man page for
|
|
\verb+im_error()+.
|
|
|
|
Descriptors are closed with \verb+im_close()+. It has type:
|
|
|
|
\begin{verbatim}
|
|
int im_close( IMAGE *im )
|
|
\end{verbatim}
|
|
|
|
\verb+im_close()+ returns 0 on success and non-zero on error.
|
|
|
|
\subsection{Examples}
|
|
\label{sec:examples}
|
|
|
|
As an example, \fref{fg:widthheight} will print the width and height
|
|
of an image stored on disc.
|
|
|
|
\begin{fig2}
|
|
\begin{verbatim}
|
|
#include <stdio.h>
|
|
#include <vips/vips.h>
|
|
|
|
int
|
|
main( int argc, char **argv )
|
|
{
|
|
IMAGE *im;
|
|
|
|
/* Check arguments.
|
|
*/
|
|
if( im_init_world( argv[0] ) )
|
|
error_exit( "unable to start VIPS" );
|
|
if( argc != 2 )
|
|
error_exit( "usage: %s filename", argv[0] );
|
|
|
|
/* Open file.
|
|
*/
|
|
if( !(im = im_open( argv[1], "r" )) )
|
|
error_exit( "unable to open %s for input", argv[1] );
|
|
|
|
/* Process.
|
|
*/
|
|
printf( "width = %d, height = %d\n", im->Xsize, im->Ysize );
|
|
|
|
/* Close.
|
|
*/
|
|
if( im_close( im ) )
|
|
error_exit( "unable to close %s", argv[1] );
|
|
|
|
return( 0 );
|
|
}
|
|
\end{verbatim}
|
|
\label{fg:widthheight}
|
|
\caption{Print width and height of an image}
|
|
\end{fig2}
|
|
|
|
To compile this example, use:
|
|
|
|
\begin{verbatim}
|
|
cc `pkg-config vips-7.14 \
|
|
--cflags --libs` myfunc.c
|
|
\end{verbatim}
|
|
|
|
As a slightly more complicated example, \fref{fg:negative}
|
|
will calculate the photographic negative of an image.
|
|
|
|
\begin{fig2}
|
|
\begin{verbatim}
|
|
#include <stdio.h>
|
|
#include <vips/vips.h>
|
|
|
|
int
|
|
main( int argc, char **argv )
|
|
{
|
|
IMAGE *in, *out;
|
|
|
|
/* Check arguments.
|
|
*/
|
|
if( im_init_world( argv[0] ) )
|
|
error_exit( "unable to start VIPS" );
|
|
if( argc != 3 )
|
|
error_exit( "usage: %s infile outfile", argv[0] );
|
|
|
|
/* Open images for read and write, invert, update the history with our
|
|
* args, and close.
|
|
*/
|
|
if( !(in = im_open( argv[1], "r" )) ||
|
|
!(out = im_open( argv[2], "w" )) ||
|
|
im_invert( in, out ) ||
|
|
im_updatehist( out, argc, argv ) ||
|
|
im_close( in ) ||
|
|
im_close( out ) )
|
|
error_exit( argv[0] );
|
|
|
|
return( 0 );
|
|
}
|
|
\end{verbatim}
|
|
\label{fg:negative}
|
|
\caption{Find photographic negative}
|
|
\end{fig2}
|
|
|
|
\subsection{Metadata}
|
|
\label{sec:meta}
|
|
|
|
VIPS lets you attach arbitrary metadata to an IMAGE. For example, ICC
|
|
profiles, EXIF tags, image history, whatever you like. VIPS will efficiently
|
|
propagate metadata as images are processed (usually just by copying
|
|
pointers) and will automatically save and load metadata from VIPS files
|
|
(see \pref{sec:header}).
|
|
|
|
A piece of metadata is a value and an identifying name. A set of
|
|
convenience functions let you set and get int, double, string and blob. For
|
|
example:
|
|
|
|
\begin{verbatim}
|
|
int im_meta_set_int( IMAGE *,
|
|
const char *field, int );
|
|
int im_meta_get_int( IMAGE *,
|
|
const char *field, int * );
|
|
\end{verbatim}
|
|
|
|
So you can do:
|
|
|
|
\begin{verbatim}
|
|
if( im_meta_set_int( im, "poop", 42 ) )
|
|
return( -1 );
|
|
\end{verbatim}
|
|
|
|
\noindent
|
|
to create an int called \verb+"poop"+, then at some later point (possibly much,
|
|
much later), in an image distantly derived from \verb+im+, you can use:
|
|
|
|
\begin{verbatim}
|
|
int i;
|
|
|
|
if( im_meta_get_int( im, "poop", &i ) )
|
|
return( -1 );
|
|
\end{verbatim}
|
|
|
|
\noindent
|
|
And get the value 42 back.
|
|
|
|
You can use \verb+im_meta_set()+ and \verb+im_meta_get()+ to attach arbitrary
|
|
\verb+GValue+ to images. See the man page for \verb+im_meta_set()+ for
|
|
full details.
|
|
|
|
You can test for a field being present with \verb+im_meta_get_type()+ (you'll
|
|
get \verb+G_TYPE_INT+ back for \verb+"poop"+, for example, or 0 if it is not
|
|
defined for this image).
|
|
|
|
\subsection{History}
|
|
\label{sec:history}
|
|
|
|
VIPS tracks the history of an image, that is, the sequence of operations which
|
|
have led to the creation of an image. You can view a VIPS image's history with
|
|
the \verb+header+ command, or with \nip{}'s \ct{View Header} menu. Whenever an
|
|
application performs an action, it should append a line of shell script to the
|
|
history which would perform the same action.
|
|
|
|
The call to \verb+im_updatehist()+ in \fref{fg:negative} adds a line to the
|
|
image history noting the invocation of this program, its arguments, and the
|
|
time and date at which it was run. You may also find \verb+im_histlin()+
|
|
helpful. It has type:
|
|
|
|
\begin{verbatim}
|
|
void im_histlin( IMAGE *im,
|
|
const char *fmt, ... )
|
|
\end{verbatim}
|
|
|
|
\noindent
|
|
It formats its arguments as \verb+printf()+ and appends the string formed
|
|
to the image history.
|
|
|
|
You read an image's history with \verb+im_history_get()+. It returns the
|
|
entire history of an image, one action per line. No need to free the result.
|
|
|
|
\begin{verbatim}
|
|
const char *
|
|
im_history_get( IMAGE *im );
|
|
\end{verbatim}
|
|
|
|
\subsection{Eval callbacks}
|
|
\label{sec:eval}
|
|
|
|
VIPS lets you attach callbacks to image descriptors. These are functions
|
|
you provide which VIPS will call when certain events occur. See
|
|
\pref{sec:callback} for more detail.
|
|
|
|
Eval callbacks are called repeatedly during evaluation and can be used by
|
|
user-interface programs to give feedback about the progress of evaluation.
|
|
|
|
\subsection{Detailed rules for descriptors}
|
|
|
|
These rules are intended to answer awkward questions.
|
|
|
|
\begin{enumerate}
|
|
|
|
\item
|
|
You can output to a descriptor only once.
|
|
|
|
\item
|
|
You can use a descriptor as an input many times.
|
|
|
|
\item
|
|
You can only output to a descriptor that was opened with modes \verb+"w"+,
|
|
\verb+"t"+ and \verb+"p"+.
|
|
|
|
\item
|
|
You can only use a descriptor as input if it was opened with modes \verb+"r"+
|
|
or \verb+"rw"+.
|
|
|
|
\item
|
|
If you have output to a descriptor, you may subsequently use it as an
|
|
input. \verb+"w"+ descriptors are automatically changed to \verb+"r"+
|
|
descriptors.
|
|
|
|
If the function you are passing the descriptor to uses WIO (see
|
|
\pref{sec:limit}), then \verb+"p"+ descriptors become \verb+"t"+.
|
|
If the function you are passing the descriptor to uses PIO, then \verb+"p"+
|
|
descriptors are unchanged.
|
|
|
|
\end{enumerate}
|
|
|
|
\subsection{Automatic resource deallocation}
|
|
|
|
VIPS lets you allocate resources local to an image descriptor, that is,
|
|
when the descriptor is closed, all resources which were allocated local to
|
|
that descriptor are automatically released for you.
|
|
|
|
\subsubsection{Local image descriptors}
|
|
|
|
VIPS provides a function which will open a new image local to
|
|
an existing image. \verb+im_open_local()+ has type:
|
|
|
|
\begin{verbatim}
|
|
IMAGE *im_open_local( IMAGE *im,
|
|
const char *filename,
|
|
const char *mode )
|
|
\end{verbatim}
|
|
|
|
It behaves exactly as \verb+im_open()+, except that you do not need to close
|
|
the descriptor it returns. It will be closed automatically when its parent
|
|
descriptor \verb+im+ is closed.
|
|
|
|
\begin{fig2}
|
|
\begin{verbatim}
|
|
/* Add another image to the accumulated total.
|
|
*/
|
|
static int
|
|
sum1( IMAGE *acc, IMAGE **in, int nin, IMAGE *out )
|
|
{
|
|
IMAGE *t;
|
|
|
|
if( nin == 0 )
|
|
/* All done ... copy to out.
|
|
*/
|
|
return( im_copy( acc, out ) );
|
|
|
|
/* Make a new intermediate, and add to it..
|
|
*/
|
|
return( !(t = im_open_local( out, "sum1:1", "p" )) ||
|
|
im_add( acc, in[0], t ) ||
|
|
sum1( t, in + 1, nin - 1, out ) );
|
|
}
|
|
|
|
/* Sum the array of images in[]. nin is the number of images in
|
|
* in[], out is the descriptor we write the final image to.
|
|
*/
|
|
int
|
|
total( IMAGE **in, int nin, IMAGE *out )
|
|
{
|
|
/* Check that we have at least one image.
|
|
*/
|
|
if( nin <= 0 ) {
|
|
im_error( "total", "nin should be > 0" );
|
|
return( -1 );
|
|
}
|
|
|
|
/* More than 1, sum recursively.
|
|
*/
|
|
return( sum1( in[0], in + 1, nin - 1, out ) );
|
|
}
|
|
\end{verbatim}
|
|
\caption{Sum an array of images}
|
|
\label{fg:addemup}
|
|
\end{fig2}
|
|
|
|
\fref{fg:addemup} is a function which will sum an array of images.
|
|
We need never close any of the (unknown) number of intermediate images which
|
|
we open. They will all be closed for us by our caller, when our caller
|
|
finally closes \verb+out+. VIPS lets local images themselves have local
|
|
images and automatically makes sure that all are closed in the correct order.
|
|
|
|
It is very important that these intermediate images are made local to
|
|
\verb+out+ rather than \verb+in+, for reasons which should become apparent
|
|
in the section on combining operations below.
|
|
|
|
There's also \verb+im_open_local_array()+ for when you need a lot of local
|
|
descriptors, see the man page.
|
|
|
|
\subsubsection{Local memory allocation}
|
|
\label{sec:malloc}
|
|
|
|
VIPS includes a set of functions for memory allocation local to an image
|
|
descriptor. The base memory allocation function is \verb+im_malloc()+. It
|
|
has type:
|
|
|
|
\begin{verbatim}
|
|
void *im_malloc( IMAGE *, size_t )
|
|
\end{verbatim}
|
|
|
|
It operates exactly as the standard \verb+malloc()+ C library function,
|
|
except that the area of memory it allocates is local to an image.
|
|
If \verb+im_malloc()+ is unable to allocate memory, it returns
|
|
\verb+NULL+. If you pass \verb+NULL+ instead of a valid image descriptor,
|
|
then \verb+im_malloc()+ allocates memory globally and you must free it
|
|
yourself at some stage.
|
|
|
|
To free memory explicitly, use \verb+im_free()+:
|
|
|
|
\begin{verbatim}
|
|
int im_free( void * )
|
|
\end{verbatim}
|
|
|
|
\noindent
|
|
\verb+im_free()+ always returns 0, so you can use it as an argument to a
|
|
callback.
|
|
|
|
Three macros make memory allocation even easier. \verb+IM_NEW()+ allocates
|
|
a new object. You give it a descriptor and a type, and it returns a pointer
|
|
to enough space to hold an object of that type. It has type:
|
|
|
|
\begin{verbatim}
|
|
type-name *IM_NEW( IMAGE *, type-name )
|
|
\end{verbatim}
|
|
|
|
The second macro, \verb+IM_ARRAY()+, is very similar, but allocates
|
|
space for an array of objects. Note that, unlike the usual \verb+calloc()+
|
|
C library function, it does not initialise the array to zero. It has type:
|
|
|
|
\begin{verbatim}
|
|
type-name *IM_ARRAY( IMAGE *, int, type-name )
|
|
\end{verbatim}
|
|
|
|
Finally, \verb+IM_NUMBER()+ returns the number of elements in an array of
|
|
defined size. See the man pages for a series of examples, or
|
|
see \pref{sec:number}.
|
|
|
|
\subsubsection{Other local operations}
|
|
|
|
The above facilities are implemented with the VIPS core function
|
|
\verb+im_add_close_callback()+. You can use this facility to make your own
|
|
local resource allocators for other types of object --- see the manual page
|
|
for more help.
|
|
|
|
\subsection{Error handling}
|
|
|
|
All VIPS operations return 0 on success and non-zero on error, setting
|
|
\verb+im_error()+. As a consequence, when a VIPS function fails, you do not
|
|
need to generate an error message --- you can simply propagate the error back
|
|
up to your caller. If however you detect some error yourself (for example,
|
|
the bad parameter in the example above), you must call \verb+im_error()+
|
|
to let your caller know what the problem was.
|
|
|
|
VIPS provides two more functions for error message handling: \verb+im_warn()+
|
|
and \verb+im_diag()+. These are intended to be used for less serious
|
|
messages, as their names suggest. Currently, they simply format and print
|
|
their arguments to \verb+stderr+, optionally suppressed by the setting of an
|
|
environment variable. Future releases of VIPS may allow more sophisticated
|
|
trapping of these functions to allow their text to be easily presented to
|
|
the user by VIPS applications. See the manual pages.
|
|
|
|
\subsection{Joining operations together}
|
|
\label{sec:joinup}
|
|
|
|
VIPS lets you join image processing operations together so that they
|
|
behave as a single unit. \fref{fg:join} shows the definition of the
|
|
function \verb+im_Lab2disp()+ from the VIPS library. This function converts
|
|
an image in \cielab{} colour space to an RGB image for a monitor. The
|
|
monitor characteristics (gamma, phosphor type, etc.) are described by the
|
|
\verb+im_col_display+ structure, see the man page for \verb+im_col_XYZ2rgb()+.
|
|
|
|
\begin{fig2}
|
|
\begin{verbatim}
|
|
int
|
|
im_Lab2disp( IMAGE *in, IMAGE *out, struct im_col_display *disp )
|
|
{
|
|
IMAGE *t1;
|
|
|
|
if( !(t1 = im_open_local( out, "im_Lab2disp:1", "p" )) ||
|
|
im_Lab2XYZ( in, t1 ) ||
|
|
im_XYZ2disp( t1, out, disp ) )
|
|
return( -1 );
|
|
|
|
return( 0 );
|
|
}
|
|
\end{verbatim}
|
|
\caption{Two image-processing operations joined together}
|
|
\label{fg:join}
|
|
\end{fig2}
|
|
|
|
The special \verb+"p"+ mode (for partial) used to open the image descriptor
|
|
used as the intermediate image in this function `glues' the two operations
|
|
together. When you use \verb+im_Lab2disp()+, the two operations inside it
|
|
will execute together and no extra storage is necessary for the intermediate
|
|
image (\verb+t1+ in this example). This is important if you want to process
|
|
images larger than the amount of RAM you have on your machine.
|
|
|
|
As an added bonus, if you have more than one CPU in your computer, the work
|
|
will be automatically spread across the processors for you. You can control
|
|
this parallelization with the \verb+IM_CONCURRENCY+ environment variable,
|
|
\verb+im_concurrency_set()+, and with the \verb+--vips-concurrency+
|
|
command-line switch. See the man page for \verb+im_generate()+.
|
|
|
|
\subsubsection{How it works}
|
|
|
|
When a VIPS function is asked to output to a \verb+"p"+ image descriptor,
|
|
all the fields in the descriptor are set (the output image size and type
|
|
are set, for example), but no image data is actually generated. Instead,
|
|
the function attaches callbacks to the image descriptor which VIPS can use
|
|
later to generate any piece of the output image that might be needed.
|
|
|
|
When a VIPS function is asked to output to a \verb+"w"+ or a \verb+"t"+
|
|
descriptor (a real disc file or a real memory buffer), it evaluates
|
|
immediately and its evaluation in turn forces the evaluation of any earlier
|
|
\verb+"p"+ images.
|
|
|
|
In the example in \fref{fg:join}, whether or not any pixels are really
|
|
processed when \verb+im_Lab2disp()+ is called depends upon the mode in
|
|
which \verb+out+ was opened. If \verb+out+ is also a partial image, then
|
|
no pixels will be calculated --- instead, a pipeline of VIPS operations
|
|
will be constructed behind the scenes and attached to \verb+out+.
|
|
|
|
Conversely, if \verb+out+ is a real image (that is, either \verb+"w"+
|
|
or \verb+"t"+), then the final VIPS operation in the function
|
|
(\verb+im_XYZ2disp()+) will output the entire image to \verb+out+, causing
|
|
the earlier parts of \verb+im_Lab2disp()+ (and indeed possibly some earlier
|
|
pieces of program, if \verb+in+ was also a \verb+"p"+ image) to run.
|
|
|
|
When a VIPS pipeline does finally evaluate, all of the functions in the
|
|
pipeline execute together, sucking image data through the system in small
|
|
pieces. As a consequence, no intermediate images are generated, large
|
|
amounts of RAM are not needed, and no slow disc I/O needs to be performed.
|
|
|
|
Since VIPS partial I/O is demand-driven rather than data-driven this works
|
|
even if some of the operations perform coordinate transformations. We could,
|
|
for example, include a call to \verb+im_affine()+, which performs
|
|
arbitrary rotation and scaling, and everything would still work correctly.
|
|
|
|
\subsubsection{Pitfalls with partials}
|
|
|
|
To go with all of the benefits that partial image I/O brings, there are
|
|
also some problems. The most serious is that you are often not quite certain
|
|
when computation will happen. This can cause problems if you close an input
|
|
file, thinking that it is finished with, when in fact that file has not
|
|
been processed yet. Doing this results in dangling pointers and an almost
|
|
certain core-dump.
|
|
|
|
You can prevent this from happening with careful use of
|
|
\verb+im_open_local()+. If you always open local to your output image,
|
|
you can be sure that the input will not be closed before the output has been
|
|
generated to a file or memory buffer. You do not need to be so careful with
|
|
non-image arguments. VIPS functions which take extra non-image arguments
|
|
(a matrix, perhaps) are careful to make their own copy of the object before
|
|
returning.
|
|
|
|
\subsubsection{Non-image output}
|
|
|
|
Some VIPS functions consume images, but make no image
|
|
output. \verb+im_stats()+ for example, scans an image calculating various
|
|
statistical values. When you use \verb+im_stats()+, it behaves as a data
|
|
sink, sucking image data through any earlier pipeline stages.
|
|
|
|
\subsubsection{Calculating twice}
|
|
|
|
In some circumstances, the same image data can be generated twice.
|
|
\fref{fg:thrmean} is a function which finds the mean value of an
|
|
image, and writes a new image in which pixels less than the mean are set to
|
|
0 and images greater than the mean are set to 255.
|
|
|
|
\begin{fig2}
|
|
\begin{verbatim}
|
|
int
|
|
threshold_at_mean( IMAGE *in, IMAGE *out )
|
|
{
|
|
double mean;
|
|
|
|
if( im_avg( in, &mean ) ||
|
|
im_moreconst( in, out, mean ) )
|
|
return( -1 );
|
|
|
|
return( 0 );
|
|
}
|
|
\end{verbatim}
|
|
\caption{Threshold an image at the mean value}
|
|
\label{fg:thrmean}
|
|
\end{fig2}
|
|
|
|
This seems straightforward --- but consider if image \verb+in+ were a
|
|
\verb+"p"+, and represented the output of a large pipeline of operations. The
|
|
call to \verb+im_avg()+ would force the evaluation of the entire pipeline,
|
|
and throw it all away, keeping only the average value. The subsequent call to
|
|
\verb+im_moreconst()+ will cause the pipeline to be evaluated a second time.
|
|
|
|
When designing a program, it is sensible to pay attention to these
|
|
issues. It might be faster, in some cases, to output to a file before
|
|
calling \verb+im_avg()+, find the average of the disc file, and then run
|
|
\verb+im_moreconst()+ from that. There's also \verb+im_cache()+ which can keep
|
|
recent parts of a very large image.
|
|
|
|
\subsubsection{Blocking computation}
|
|
\label{sec:block}
|
|
|
|
\verb+IMAGE+ descriptors have a flag called \verb+kill+ which can be used
|
|
to block computation. If \verb+im->kill+ is set to a non-zero value,
|
|
then any VIPS pipelines which use \verb+im+ as an intermediate will fail
|
|
with an error message. This is useful for user-interface writers ---
|
|
suppose your interface is forced to close an image which many other images
|
|
are using as a source of data. You can just set the \verb+kill+ flag in all
|
|
of the deleted image's immediate children and prevent any dangling pointers
|
|
from being followed.
|
|
|
|
\subsubsection{Limitations}
|
|
\label{sec:limit}
|
|
|
|
Not all VIPS operations are partial-aware. These non-partial operations
|
|
use a pre-VIPS 7.0 I/O scheme in which the whole of the input image has to
|
|
be present at the same time. In some cases, this is because partial I/O
|
|
simply makes no sense --- for example, a Fourier Transform can produce no
|
|
output until it has seen all of the input. \verb+im_fwfft()+ is therefore
|
|
not a partial operation. In other cases, we have simply not got around to
|
|
rewriting the old non-partial operation in the newer partial style.
|
|
|
|
You can mix partial and non-partial VIPS operations freely, without worrying
|
|
about which type they are. The only effect will be on the time your pipeline
|
|
takes to execute, and the memory requirements of the intermediate images. VIPS
|
|
uses the following rules when you mix the two styles of operation:
|
|
|
|
\begin{enumerate}
|
|
|
|
\item
|
|
When a non-partial operation is asked to output to a partial image descriptor,
|
|
the \verb+"p"+ descriptor is magically transformed into a \verb+"t"+
|
|
descriptor.
|
|
|
|
\item
|
|
When a non-partial operation is asked to read from a \verb+"p"+ descriptor,
|
|
the \verb+"p"+ descriptor is turned into a \verb+"t"+ type, and any earlier
|
|
stages in the pipeline forced to evaluate into that memory buffer.
|
|
|
|
The non-partial operation then processes from the memory buffer.
|
|
|
|
\end{enumerate}
|
|
|
|
These rules have the consequence that you may only process very large images
|
|
if you only use partial operations. If you use any non-partial operations,
|
|
then parts of your pipelines will fall back to old whole-image I/O and you
|
|
will need to think carefully about where your intermediates should be stored.
|
|
|