libvips/doc/src/wio.tex
2007-08-29 16:23:50 +00:00

364 lines
9.6 KiB
TeX

\section{Programming WIO operations}
WIO is the style for you if you want ease of programming, or if your
algorithm must have the whole of the input image available at the same
time. For example, a Fourier transform operation is unable to produce any
output until it has seen the whole of the input image.
\subsection{Input from an image}
In WIO input, the whole of the image data is made available to the program
via the \verb+data+ field of the descriptor. To make an image ready for reading
in this style, programs should call \verb+im_incheck()+:
\begin{verbatim}
int im_incheck( IMAGE *im )
\end{verbatim}
\noindent
If it succeeds, it returns 0, if it fails, it returns non-zero and
sets \verb+im_error()+. On success, VIPS guarantees that all of the
user-accessible fields in the descriptor contain valid data, and that all
of the image data may be read by simply reading from the \verb+data+ field
(see below for an example). This will only work for images less than about
2GB in size.
VIPS has some simple macros to help address calculations on images:
\begin{verbatim}
int IM_IMAGE_SIZEOF_ELEMENT( IMAGE * )
int IM_IMAGE_SIZEOF_PEL( IMAGE * )
int IM_IMAGE_SIZEOF_LINE( IMAGE * )
int IM_IMAGE_N_ELEMENTS( IMAGE * )
char *IM_IMAGE_ADDR( IMAGE *,
int x, int y )
\end{verbatim}
\noindent
These macros calculate \verb+sizeof()+ a band element, a pel and a horizontal
line of pels. \verb+IM_IMAGE_N_ELEMENTS+ returns the number of band elements
across an image. \verb+IM_IMAGE_ADDR+ calculates the address of a pixel in an
image. If \verb+DEBUG+ is defined, it does bounds checking too.
\begin{fig2}
\begin{verbatim}
#include <stdio.h>
#include <stdlib.h>
#include <vips/vips.h>
int
average( IMAGE *im, double *out )
{
int x, y;
long total;
/* Prepare for reading.
*/
if( im_incheck( im ) )
return( -1 );
/* Check that this is the kind of image we can process.
*/
if( im->BandFmt != IM_BANDFMT_UCHAR ||
im->Coding != IM_CODING_NONE ) {
im_error( "average", "uncoded uchar images only" );
return( -1 );
}
/* Loop over the image, summing pixels.
*/
total = 0;
for( y = 0; y < im->Ysize; y++ ) {
unsigned char *p = (unsigned char *) IM_IMAGE_ADDR( im, 0, y );
for( x = 0; x < IM_IMAGE_N_ELEMENTS( im ); x++ )
total += p[x];
}
/* Calculate average.
*/
*out = (double) total /
(IM_IMAGE_N_ELEMENTS( im ) * im->Ysize));
/* Success!
*/
return( 0 );
}
\end{verbatim}
\caption{Find average of image}
\label{fg:average}
\end{fig2}
\fref{fg:average} is a simple WIO operation which calculates the
average of an unsigned char image. It will work for any size image, with any
number of bands. See~\pref{sec:poly} for techniques for making operations
which will work for any image type. This operation might be called from an
application with:
\begin{verbatim}
#include <stdio.h>
#include <stdlib.h>
#include <vips/vips.h>
void
find_average( char *name )
{
IMAGE *im;
double avg;
if( !(im = im_open( name, "r" )) ||
average( im, &avg ) ||
im_close( im ) )
error_exit( "failure!" );
printf( "Average of \"%s\" is %G\n",
name, avg );
}
\end{verbatim}
\noindent
When you write an image processing operation, you can test it by writing
a VIPS function descriptor and calling it from the \vips{} universal
main program, or from the \nip{} interface. See \pref{sec:appl}.
\subsection{Output to an image}
Before attempting WIO output, programs should call \verb+im_outcheck()+. It
has type:
\begin{verbatim}
int im_outcheck( IMAGE *im )
\end{verbatim}
\noindent
If \verb+im_outcheck()+ succeeds, VIPS guarantees that WIO output is sensible.
Programs should then set fields in the output descriptor to describe
the sort of image they wish to write (size, type, and so on) and call
\verb+im_setupout()+. It has type:
\begin{verbatim}
int im_setupout( IMAGE *im )
\end{verbatim}
\noindent
\verb+im_setupout()+ creates the output file or memory buffer, using the
size and type fields that were filled in by the program between the calls to
\verb+im_outcheck()+ and \verb+im_setupout()+, and gets it ready for writing.
Pels are written with \verb+im_writeline()+. This takes a y position (pel
(0,0) is in the top-left-hand corner of the image), a descriptor and a
pointer to a line of pels. It has type:
\begin{verbatim}
int im_writeline( int y,
IMAGE *im, unsigned char *pels )
\end{verbatim}
Two convenience functions are available to make this process slightly
easier. \verb+im_iocheck()+ is useful for programs which take one input
image and produce one image output. It simply calls \verb+im_incheck()+
and \verb+im_outcheck()+. It has type:
\begin{verbatim}
int im_iocheck( IMAGE *in, IMAGE *out )
\end{verbatim}
The second convenience function copies the fields describing size, type,
metadata and history from one image descriptor to another. It is useful when
the output
image will be similar in size and type to the input image. It has type:
\begin{verbatim}
int im_cp_desc( IMAGE *out, IMAGE *in )
\end{verbatim}
\noindent
There's also \verb+im_cp_descv()+, see the man page.
\begin{fig2}
\begin{verbatim}
#include <stdio.h>
#include <stdlib.h>
#include <vips/vips.h>
#include <vips/util.h>
int
invert( IMAGE *in, IMAGE *out )
{
int x, y;
unsigned char *buffer;
/* Check images.
*/
if( im_iocheck( in, out ) )
return( -1 );
if( in->BandFmt != IM_BANDFMT_UCHAR || in->Coding != IM_CODING_NONE ) {
im_error( "invert", "uncoded uchar images only" );
return( -1 );
}
/* Make output image.
*/
if( im_cp_desc( out, in ) )
return( -1 );
if( im_setupout( out ) )
return( -1 );
/* Allocate a line buffer and make sure it will be freed correctly.
*/
if( !(buffer = IM_ARRAY( out,
IM_IMAGE_SIZEOF_LINE( in ), unsigned char )) )
return( -1 );
/* Loop over the image!
*/
for( y = 0; y < in->Ysize; y++ ) {
unsigned char *p = (unsigned char *) IM_IMAGE_ADDR( in, 0, y );
for( x = 0; x < IM_IMAGE_N_ELEMENTS( in ); x++ )
buffer[x] = 255 - p[x];
if( im_writeline( y, out, buffer ) )
return( -1 );
}
return( 0 );
}
\end{verbatim}
\caption{Invert an image}
\label{fg:invert}
\end{fig2}
\fref{fg:invert} is a WIO VIPS operation which finds the photographic
negative of an unsigned char image. See \pref{sec:malloc} for an explanation
of \verb+IM_ARRAY+. This operation might be called from an
application with:
\begin{verbatim}
#include <stdio.h>
#include <stdlib.h>
#include <vips/vips.h>
void
find_negative( char *inn, char *outn )
{
IMAGE *in, *out;
if( !(in = im_open( inn, "r" )) ||
!(out = im_open( outn, "w" )) ||
invert( in, out ) ||
im_updatehist( out, "invert" ) ||
im_close( in ) ||
im_close( out ) )
error_exit( "failure!" );
}
\end{verbatim}
See \pref{sec:history} for an explanation of the call to \verb+im_updatehist()+.
\subsection{Polymorphism}
\label{sec:poly}
Most image processing operations in the VIPS library can operate on
images of any type (\verb+IM_BANDFMT_UCHAR+, as in our examples above,
also \verb+IM_BANDFMT_UINT+ etc.). This is usually implemented with code
replication: the operation contains loops for processing every kind of image,
and when called, invokes the appropriate loop for the image it is given.
As an example, figure~\ref{fg:exp} calculates \verb+exp()+ for every pel
in an image. If the input image is \verb+double+, we write \verb+double+
output. If it is any other non-complex type, we write \verb+float+. If it
is complex, we flag an error (\verb+exp()+ of a complex number is fiddly).
The example uses an image type predicate, \verb+im_iscomplex()+. There are
a number of these predicate functions, see the manual page.
\begin{fig2}
\begin{verbatim}
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <vips/vips.h>
#include <vips/util.h>
/* Exponential transform.
*/
int
exptra( IMAGE *in, IMAGE *out )
{
int x, y;
unsigned char *buffer;
/* Check descriptors.
*/
if( im_iocheck( in, out ) )
return( -1 );
if( in->Coding != IM_CODING_NONE || im_iscomplex( in ) ) {
im_error( "exptra", "uncoded non-complex only" );
return( -1 );
}
/* Make output image.
*/
if( im_cp_desc( out, in ) )
return( -1 );
if( in->BandFmt != IM_BANDFMT_DOUBLE )
out->BandFmt = IM_BANDFMT_FLOAT;
if( im_setupout( out ) )
return( -1 );
\end{verbatim}
\caption{Calculate \texttt{exp()} for an image}
\label{fg:exp}
\end{fig2}
\begin{fig2}
\begin{verbatim}
/* Allocate a line buffer.
*/
if( !(buffer = IM_ARRAY( out, IM_IMAGE_SIZEOF_LINE( in ), unsigned char )) )
return( -1 );
/* Our inner loop, parameterised for both the input and output
* types. Note the use of `\', since macros have to be all on
* one line.
*/
#define loop(IN, OUT) { \
for( y = 0; y < in->Ysize; y++ ) { \
IN *p = (IN *) IM_IMAGE_ADDR( in, 0, y ); \
OUT *q = (OUT *) buffer; \
\
for( x = 0; x < IM_IMAGE_N_ELEMENTS( in ); x++ ) \
q[x] = exp( p[x] ); \
if( im_writeline( y, out, buffer ) ) \
return( -1 ); \
} \
}
/* Switch for all the types we can handle.
*/
switch( in->BandFmt ) {
case IM_BANDFMT_UCHAR: loop( unsigned char, float ); break;
case IM_BANDFMT_CHAR: loop( char, float ); break;
case IM_BANDFMT_USHORT:loop( unsigned short, float ); break;
case IM_BANDFMT_SHORT: loop( short, float ); break;
case IM_BANDFMT_UINT: loop( unsigned int, float ); break;
case IM_BANDFMT_INT: loop( int, float ); break;
case IM_BANDFMT_FLOAT: loop( float, float ); break;
case IM_BANDFMT_DOUBLE:loop( double, double ); break;
default:
im_error( "exptra", "internal error" );
return( -1 );
}
/* Success.
*/
return( 0 );
}
\end{verbatim}
\caption{Calculate \texttt{exp()} for an image (cont)}
\end{fig2}