\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 #include #include 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 #include #include 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 #include #include #include 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 #include #include 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 #include #include #include #include /* 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}