| \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} |