blob: 20e3195ade7bf9fff5b0a290dfc826348dc3eabe [file] [log] [blame]
\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.