| <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" |
| "http://www.w3.org/TR/html4/loose.dtd"> |
| <html > |
| <head><title>Programming PIO functions</title> |
| <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> |
| <meta name="generator" content="TeX4ht (http://www.cse.ohio-state.edu/~gurari/TeX4ht/)"> |
| <meta name="originator" content="TeX4ht (http://www.cse.ohio-state.edu/~gurari/TeX4ht/)"> |
| <!-- 3,html --> |
| <meta name="src" content="vipsmanual.tex"> |
| <meta name="date" content="2010-06-09 21:39:00"> |
| <link rel="stylesheet" type="text/css" href="vipsmanual.css"> |
| </head><body |
| > |
| <!--l. 1--><div class="crosslinks"><p class="noindent">[<a |
| href="vipsmanualse16.html" >next</a>] [<a |
| href="vipsmanualse14.html" >prev</a>] [<a |
| href="vipsmanualse14.html#tailvipsmanualse14.html" >prev-tail</a>] [<a |
| href="#tailvipsmanualse15.html">tail</a>] [<a |
| href="vipsmanualch3.html#vipsmanualse15.html" >up</a>] </p></div> |
| <h3 class="sectionHead"><span class="titlemark">3.3 </span> <a |
| id="x22-920003.3"></a>Programming PIO functions</h3> |
| <!--l. 4--><p class="noindent" >The VIPS PIO system has a number of advantages over |
| WIO, as summarised in the introduction. On the other hand, |
| they are a bit more complicated. |
| <!--l. 7--><p class="noindent" > |
| <h4 class="subsectionHead"><span class="titlemark">3.3.1 </span> <a |
| id="x22-930003.3.1"></a>Easy PIO with <span |
| class="pcrr7t-">im</span><span |
| class="pcrr7t-">_wrapone() </span>and |
| <span |
| class="pcrr7t-">im</span><span |
| class="pcrr7t-">_wrapmany()</span></h4> |
| <!--l. 10--><p class="noindent" >PIO is a very general image IO system, and because of this |
| flexibility, can be complicated to program. As a convenience, |
| VIPS offers an easy-to-use layer over PIO with the funtions |
| <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_wrapone()</span></span></span> and <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_wrapmany()</span></span></span>. |
| <!--l. 14--><p class="indent" > If your image processing function is uninterested in |
| coordinates, that is, if your input and output images are the |
| same size, and each output pixel depends only upon the |
| value of the corresponding pixel in the input image or |
| images, then these functions are for you. |
| <!--l. 19--><p class="indent" > Consider the <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">invert()</span></span></span> function of figure <a |
| href="vipsmanualse14.html#x21-900012">3.2<!--tex4ht:ref: fg:invert --></a>. First, we |
| have to write the core of this as a buffer-processing |
| function: |
| <div class="verbatim" id="verbatim-140"> |
| #include <stdio.h> |
|  <br />#include <stdlib.h> |
|  <br /> |
|  <br />#include <vips/vips.h> |
|  <br /> |
|  <br />/⋆ p points to a buffer of pixels which |
|  <br /> ⋆ need inverting, q points to the buffer |
|  <br /> ⋆ we should write the result to, and n |
|  <br /> ⋆ is the number of pels present. |
|  <br /> ⋆/ |
|  <br />static void |
|  <br />invert_buffer( unsigned char ⋆p, |
|  <br />   unsigned char ⋆q, int n ) |
|  <br />{ |
|  <br />   int i; |
|  <br /> |
|  <br />   for( i = 0; i < n; i++ ) |
|  <br />      q[i] = 255 - p[i]; |
|  <br />} |
| </div> |
| <!--l. 42--><p class="nopar" > |
| <!--l. 44--><p class="indent" > Now we have to wrap up this very primitive expression |
| of the invert operation as a PIO function. We use |
| <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_wrapone()</span></span></span> to do this. It has type: |
| |
| |
| |
| <div class="verbatim" id="verbatim-141"> |
| int |
|  <br />im_wrapone( IMAGE ⋆in, IMAGE ⋆out, |
|  <br />   im_wrapone_fn fn, void ⋆a, void ⋆b ) |
| </div> |
| <!--l. 51--><p class="nopar" > |
| <!--l. 53--><p class="noindent" >where: |
| <div class="verbatim" id="verbatim-142"> |
| void |
|  <br />(⋆im_wrapone_fn)(void ⋆in, void ⋆out, |
|  <br />   int n, void ⋆a, void ⋆b ) |
| </div> |
| <!--l. 60--><p class="nopar" > |
| <!--l. 62--><p class="noindent" >almost the same type as our buffer-processing function |
| above. The values <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">a</span></span></span> and <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">b</span></span></span> are carried around by VIPS for |
| whatever use you fancy. <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">invert()</span></span></span> can now be written |
| as: |
| |
| |
| |
| <div class="verbatim" id="verbatim-143"> |
| int |
|  <br />invert( IMAGE ⋆in, IMAGE ⋆out ) |
|  <br />{ |
|  <br />   /⋆ Check parameters. |
|  <br />    ⋆/ |
|  <br />   if( in->BandFmt != IM_BANDFMT_UCHAR || |
|  <br />      in->Bands != 1 || |
|  <br />      in->Coding != IM_CODING_NONE ) { |
|  <br />      im_error( "invert", "bad image" ); |
|  <br />      return( -1 ); |
|  <br />   } |
|  <br /> |
|  <br />   /⋆ Set fields in output image. |
|  <br />    ⋆/ |
|  <br />   if( im_cp_desc( out, in ) ) |
|  <br />      return( -1 ); |
|  <br /> |
|  <br />   /⋆ Process! We don't use either of the |
|  <br />    ⋆ user parameters in this function, |
|  <br />    ⋆ so leave them as NULL. |
|  <br />    ⋆/ |
|  <br />   if( im_wrapone( in, out, |
|  <br />      (im_wrapone_fn) invert_buffer, |
|  <br />      NULL, NULL ) ) |
|  <br />      return( -1 ); |
|  <br /> |
|  <br />   return( 0 ); |
|  <br />} |
| </div> |
| <!--l. 96--><p class="nopar" > |
| <!--l. 98--><p class="indent" > And that’s all there is to it. This function will have all of |
| the desirable properties of PIO functions, while being as |
| easy to program as the WIO <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">invert()</span></span></span> earlier in this |
| chapter. |
| <!--l. 102--><p class="indent" > This version of <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">invert()</span></span></span> is not very general: it will |
| only accept one-band unsigned char images. It is easy to |
| modify for n-band images: |
| <div class="verbatim" id="verbatim-144"> |
| /⋆ As before, but use one of the user |
|  <br /> ⋆ parameters to pass in the number of |
|  <br /> ⋆ bands in the image. |
|  <br /> ⋆/ |
|  <br />static void |
|  <br />invert_buffer( unsigned char ⋆p, |
|  <br />   unsigned char ⋆q, int n, |
|  <br />   IMAGE ⋆in ) |
|  <br />{ |
|  <br />   int i; |
|  <br />   int sz = n ⋆ in->Bands; |
|  <br /> |
|  <br />   for( i = 0; i < sz; i++ ) |
|  <br />      q[i] = 255 - p[i]; |
|  <br />} |
| </div> |
| <!--l. 121--><p class="nopar" > |
| <!--l. 123--><p class="indent" > We must also modify <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">invert()</span></span></span>: |
| |
| |
| |
| <div class="verbatim" id="verbatim-145"> |
| int |
|  <br />invert( IMAGE ⋆in, IMAGE ⋆out ) |
|  <br />{ |
|  <br />   /⋆ Check parameters. |
|  <br />    ⋆/ |
|  <br />   if( in->BandFmt != IM_BANDFMT_UCHAR || |
|  <br />      in->Coding != IM_CODING_NONE ) { |
|  <br />      im_error( "invert", "bad image" ); |
|  <br />      return( -1 ); |
|  <br />   } |
|  <br /> |
|  <br />   /⋆ Set fields in output image. |
|  <br />    ⋆/ |
|  <br />   if( im_cp_desc( out, in ) ) |
|  <br />      return( -1 ); |
|  <br /> |
|  <br />   /⋆ Process! The first user-parameter |
|  <br />    ⋆ is the number of bands involved. |
|  <br />    ⋆/ |
|  <br />   if( im_wrapone( in, out, |
|  <br />      (im_wrapone_fn)invert_buffer, |
|  <br />      in, NULL ) ) |
|  <br />      return( -1 ); |
|  <br /> |
|  <br />   return( 0 ); |
|  <br />} |
| </div> |
| <!--l. 152--><p class="nopar" > |
| <!--l. 154--><p class="indent" > There are two significant hidden traps here. First, |
| inside the buffer processing functions, you may only |
| read the contents of the user parameters <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">a</span></span></span> and <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">b</span></span></span>, you |
| may not write to them. This is because on a multi-CPU |
| machine, several copies of your buffer-processing functions |
| will be run in parallel — if they all write to the same |
| place, there will be complete confusion. If you need |
| writeable parameters (for example, to count and report |
| overflows), you can’t use <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_wrapone()</span></span></span>, you’ll |
| have to use the PIO system in all its gory detail, see |
| below. |
| <!--l. 163--><p class="indent" > Secondly, your buffer processing function may not be |
| called immediately. VIPS may decide to delay evaluation of |
| your operation until long after the call to <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">invert()</span></span></span> has |
| returned. As a result, care is needed to ensure that you never |
| read anything in your buffer-processing function that may |
| have been freed. The best way to ensure this is to use the |
| local resource allocators, such as <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_open_local()</span></span></span> and<span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_malloc()</span></span></span>. This issue is discussed at length in the |
| sections below, and in <span |
| class="cmsy-10">§</span><a |
| href="vipsmanualse7.html#x13-360002.1">2.1<!--tex4ht:ref: sec:appl --></a>. |
| <!--l. 171--><p class="indent" > <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_wrapone()</span></span></span> is for operations which take exactly |
| one input image. VIPS provides a second function, |
| <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_wrapmany()</span></span></span>, which works for any number of input |
| images. The type of <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_wrapmany()</span></span></span> is slightly |
| different: |
| |
| |
| |
| <div class="verbatim" id="verbatim-146"> |
| int |
|  <br />im_wrapmany( IMAGE ⋆⋆in, IMAGE ⋆out, |
|  <br />   im_wrapmany_fn fn, void ⋆a, void ⋆b ) |
| </div> |
| <!--l. 179--><p class="nopar" > |
| <!--l. 181--><p class="noindent" > |
| <div class="verbatim" id="verbatim-147"> |
| void |
|  <br />(⋆im_wrapmany_fn)( void ⋆⋆in, void ⋆out, |
|  <br />   int n, void ⋆a, void ⋆b ) |
| </div> |
| <!--l. 187--><p class="nopar" > |
| <!--l. 189--><p class="noindent" ><span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_wrapmany()</span></span></span> takes a <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">NULL</span></span></span>-terminated array of |
| input images, and creates a <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">NULL</span></span></span>-terminated array of |
| buffers for the use of your buffer processing function. A |
| function to add two <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">IM_BANDFMT_UCHAR</span></span></span> images to |
| make a <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">IM_BANDFMT_UCHAR</span></span></span> image might be written |
| as: |
| |
| |
| |
| <div class="verbatim" id="verbatim-148"> |
| static void |
|  <br />add_buffer( unsigned char ⋆⋆in, |
|  <br />   unsigned short ⋆out, int n, |
|  <br />   IMAGE ⋆in ) |
|  <br />{ |
|  <br />   int i; |
|  <br />   int sz = n ⋆ in->Bands; |
|  <br />   unsigned char ⋆p1 = in[0]; |
|  <br />   unsigned char ⋆p2 = in[1]; |
|  <br /> |
|  <br />   for( i = 0; i < sz; i++ ) |
|  <br />      out[i] = p1[i] + p2[i]; |
|  <br />} |
| </div> |
| <!--l. 209--><p class="nopar" > |
| <!--l. 211--><p class="indent" > This can be made into a PIO function with: |
| <div class="verbatim" id="verbatim-149"> |
| int |
|  <br />add_uchar( IMAGE ⋆i1, IMAGE ⋆i2, |
|  <br />   IMAGE ⋆out ) |
|  <br />{ |
|  <br />   IMAGE ⋆invec[3]; |
|  <br /> |
|  <br />   /⋆ Check parameters. We don't need to |
|  <br />    ⋆ check that i1 and i2 are the same |
|  <br />    ⋆ size, im_wrapmany() does that for |
|  <br />    ⋆ us. |
|  <br />    ⋆/ |
|  <br />   if( i1->BandFmt != IM_BANDFMT_UCHAR || |
|  <br />      i1->Coding != IM_CODING_NONE || |
|  <br />      i2->BandFmt != IM_BANDFMT_UCHAR || |
|  <br />      i2->Coding != IM_CODING_NONE || |
|  <br />      i1->Bands != i2->Bands ) { |
|  <br />      im_error( "add_uchar", "bad in" ); |
|  <br />      return( -1 ); |
|  <br />   } |
|  <br /> |
|  <br />   /⋆ Set fields in output image. As |
|  <br />    ⋆ input image, but we want a USHORT. |
|  <br />    ⋆/ |
|  <br />   if( im_cp_desc( out, i1 ) ) |
|  <br />      return( -1 ); |
|  <br />   out->BandFmt = IM_BANDFMT_USHORT; |
|  <br />   out->Bbits = IM_BBITS_SHORT; |
|  <br /> |
|  <br />   /⋆ Process! The first user-parameter |
|  <br />    ⋆ is the number of bands involved. |
|  <br />    ⋆ invec is a NULL-terminated array of |
|  <br />    ⋆ input images. |
|  <br />    ⋆/ |
|  <br />   invec[0] = i1; invec[1] = i2; |
|  <br />   invec[2] = NULL; |
|  <br />   if( im_wrapmany( invec, out, |
|  <br />      (im_wrapone_fn)add_buffer, |
|  <br />      i1, NULL ) ) |
|  <br />      return( -1 ); |
|  <br /> |
|  <br />   return( 0 ); |
|  <br />} |
| </div> |
| <!--l. 256--><p class="nopar" > |
| |
| |
| |
| <!--l. 258--><p class="noindent" > |
| <h4 class="subsectionHead"><span class="titlemark">3.3.2 </span> <a |
| id="x22-940003.3.2"></a>Region descriptors</h4> |
| <!--l. 260--><p class="noindent" >Regions are the next layer of abstraction above image |
| descriptors. A region is a small part of an image, held |
| in memory ready for processing. A region is defined |
| as: |
| <div class="verbatim" id="verbatim-150"> |
| typedef struct { |
|  <br />   Rect valid; |
|  <br />   IMAGE ⋆im; |
|  <br /> |
|  <br />   ... and some other private fields, |
|  <br />   ... used by VIPS for housekeeping |
|  <br />} REGION; |
| </div> |
| <!--l. 272--><p class="nopar" > |
| <!--l. 274--><p class="noindent" >where <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">valid</span></span></span> holds the sub-area of image <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im</span></span></span> that this |
| region represents, and <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">Rect</span></span></span> is defined as: |
| |
| |
| |
| <div class="verbatim" id="verbatim-151"> |
| typedef struct { |
|  <br />   int left, top; |
|  <br />   int width, height; |
|  <br />} Rect; |
| </div> |
| <!--l. 283--><p class="nopar" > |
| <!--l. 285--><p class="noindent" >two macros are available for <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">Rect</span></span></span> calculations: |
| <div class="verbatim" id="verbatim-152"> |
| int IM_RECT_RIGHT( Rect ⋆r ) |
|  <br />int IM_RECT_BOTTOM( Rect ⋆r ) |
| </div> |
| <!--l. 291--><p class="nopar" > |
| <!--l. 293--><p class="noindent" >where <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">IM_RECT_RIGHT()</span></span></span> returns <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">left</span></span></span> + <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">width</span></span></span>, and |
| <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">IM_RECT_BOTTOM()</span></span></span> returns <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">top</span></span></span> + <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">height</span></span></span>. A small |
| library of C functions are also available for <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">Rect</span></span></span> algebra, see |
| the manual pages for <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_rect_intersectrect()</span></span></span>. |
| <!--l. 299--><p class="indent" > Regions are created with <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_region_create()</span></span></span>. |
| This has type: |
| |
| |
| |
| <div class="verbatim" id="verbatim-153"> |
| REGION ⋆im_region_create( IMAGE ⋆im ) |
| </div> |
| <!--l. 303--><p class="nopar" > |
| <!--l. 305--><p class="noindent" ><span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_region_create()</span></span></span> returns a pointer to a new |
| region structure, or <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">NULL</span></span></span> on error. Regions returned by |
| <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_region_create()</span></span></span> are blank — they contain no |
| image data and cannot be read from or written to. See the |
| next couple of sections for calls to fill regions with |
| data. |
| <!--l. 311--><p class="indent" > Regions are destroyed with <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_region_free()</span></span></span>. It |
| has type: |
| <div class="verbatim" id="verbatim-154"> |
| int im_region_free( REGION ⋆reg ) |
| </div> |
| <!--l. 315--><p class="nopar" > |
| <!--l. 317--><p class="noindent" >And, as usual, returns 0 on success and non-zero on |
| error, setting <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_error()</span></span></span>. You must free all regions |
| you create. If you close an image without freeing all |
| the regions defined on that image, the image is just |
| marked for future closure — it is not actually closed |
| until the final region is freed. This behaviour helps |
| to prevent dangling pointers, and it is not difficult to |
| make sure you free all regions — see the examples |
| below. |
| <!--l. 325--><p class="noindent" > |
| <h4 class="subsectionHead"><span class="titlemark">3.3.3 </span> <a |
| id="x22-950003.3.3"></a>Image input with regions</h4> |
| <!--l. 327--><p class="noindent" >Before you can read from a region, you need to call |
| <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_prepare()</span></span></span> to fill the region with image data. It has |
| type: |
| |
| |
| |
| <div class="verbatim" id="verbatim-155"> |
| int im_prepare( REGION ⋆reg, Rect ⋆r ) |
| </div> |
| <!--l. 332--><p class="nopar" > |
| <!--l. 334--><p class="indent" > Area <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">r</span></span></span> of the image on which <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">reg</span></span></span> has been created is |
| prepared and attached to the region. |
| <!--l. 337--><p class="indent" > Exactly what this preparation involves depends upon |
| the image — it can vary from simply adjusting some |
| pointers, to triggering the evaluation of a series of other |
| functions. If it returns successfully, <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_prepare()</span></span></span> |
| guarantees that all pixels within <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">reg->valid</span></span></span> may be |
| accessed. Note that this may be smaller or larger than <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">r</span></span></span>, |
| since <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_prepare()</span></span></span> clips <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">r</span></span></span> against the size of the |
| image. |
| <!--l. 344--><p class="indent" > Programs can access image data in the region by calling |
| the macro <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">IM_REGION_ADDR()</span></span></span>. It has type |
| <div class="verbatim" id="verbatim-156"> |
| char ⋆IM_REGION_ADDR( REGION ⋆reg, |
|  <br />  int x, int y ) |
| </div> |
| <!--l. 350--><p class="nopar" > |
| <!--l. 352--><p class="indent" > Provided that point (x,y) lies inside <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">reg->valid</span></span></span>, |
| <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">IM_REGION_ADDR()</span></span></span> returns a pointer to pel <span |
| class="cmr-10">(</span><span |
| class="cmmi-10">x,y</span><span |
| class="cmr-10">)</span>. |
| Adding to the result of <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">IM_REGION_ADDR()</span></span></span> moves to |
| the right along the line of pels, provided you stay strictly |
| within <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">reg->valid</span></span></span>. Add <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">IM_REGION_LSKIP()</span></span></span> to |
| move down a line, see below. <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">IM_REGION_ADDR()</span></span></span> has |
| some other useful features — see the manual page. |
| <!--l. 359--><p class="indent" > Other macros are available to ease address calculation: |
| |
| |
| |
| <div class="verbatim" id="verbatim-157"> |
| int IM_REGION_LSKIP( REGION ⋆reg ) |
|  <br />int IM_REGION_N_ELEMENTS( REGION ⋆reg ) |
|  <br />int IM_REGION_SIZEOF_LINE( REGION ⋆reg ) |
| </div> |
| <!--l. 365--><p class="nopar" > |
| <!--l. 367--><p class="noindent" >These find the number of bytes to add to the result of |
| <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">IM_REGION_ADDR()</span></span></span> to move down a line, the number of |
| band elements across the region and the number of bytes |
| across the region. |
| <!--l. 372--><p class="indent" > Figure <a |
| href="#x22-950015">3.5<!--tex4ht:ref: fg:paverage --></a> is a version of <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">average()</span></span></span> which uses |
| regions rather than WIO input. Two things: first, we |
| should really be using <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">vips_sink()</span></span></span>, see <span |
| class="cmsy-10">§</span><a |
| href="#x22-960003.3.4">3.3.4<!--tex4ht:ref: sec:sequence --></a>, to do |
| the rectangle algebra for us. Secondly, note that we |
| call <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_pincheck()</span></span></span> rather than <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_incheck()</span></span></span>. |
| <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_pincheck()</span></span></span> signals to the IO system that you are a |
| PIO-aware function, giving <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_prepare()</span></span></span> much more |
| flexibility in the sorts of preparation it can do. Also |
| see the manual pages for <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_poutcheck()</span></span></span> and |
| <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_piocheck()</span></span></span>. |
| |
| |
| |
| |
| <!--l. 382--><p class="indent" > <a |
| id="x22-950015"></a><hr class="float"><div class="float" |
| > |
| |
| |
| |
| |
| <div class="verbatim" id="verbatim-158"> |
| #include <stdio.h> |
|  <br />#include <stdlib.h> |
|  <br />#include <vips/vips.h> |
|  <br />#include <vips/region.h> |
|  <br /> |
|  <br />int |
|  <br />average( IMAGE ⋆im, double ⋆out ) |
|  <br />{ |
|  <br />   int total, i, y; |
|  <br />   REGION ⋆reg; |
|  <br />   Rect area, ⋆r; |
|  <br /> |
|  <br />   /⋆ Check im. |
|  <br />    ⋆/ |
|  <br />   if( im_pincheck( im ) ) |
|  <br />      return( -1 ); |
|  <br />   if( im->BandFmt != IM_BANDFMT_UCHAR || im->Coding != IM_CODING_NONE ) { |
|  <br />      im_error( "average", "uncoded uchar images only" ); |
|  <br />      return( -1 ); |
|  <br />   } |
|  <br /> |
|  <br />   /⋆ Make a region on im which we can use for reading. |
|  <br />    ⋆/ |
|  <br />   if( !(reg = im_region_create( im )) ) |
|  <br />      return( -1 ); |
| </div> |
| <!--l. 408--><p class="nopar" > |
| <br /><div class="caption" |
| ><span class="id">Figure 3.5: </span><span |
| class="content">First PIO average of image</span></div><!--tex4ht:label?: x22-950015 --> |
| |
| |
| |
| |
| </div><hr class="endfloat" /> |
| |
| |
| |
| |
| <!--l. 414--><p class="indent" > <a |
| id="x22-950026"></a><hr class="float"><div class="float" |
| > |
| |
| |
| |
| |
| <div class="verbatim" id="verbatim-159"> |
|    /⋆ Move area over the image in 100x100 pel chunks. |
|  <br />    ⋆ im_prepare() will clip against the edges of the image |
|  <br />    ⋆ for us. |
|  <br />    ⋆/ |
|  <br />   total = 0; |
|  <br />   r = &reg->valid; |
|  <br />   area.width = 100; area.height = 100; |
|  <br />   for( area.top = 0; area.top < im->Ysize; area.top += 100 ) |
|  <br />      for( area.left = 0; area.left < im->Xsize; |
|  <br />          area.left += 100 ) { |
|  <br />          /⋆ Fill reg with pels. |
|  <br />           ⋆/ |
|  <br />          if( im_prepare( reg, &area ) ) { |
|  <br />             /⋆ We must free the region! |
|  <br />              ⋆/ |
|  <br />             im_region_free( reg ); |
|  <br />             return( -1 ); |
|  <br />          } |
|  <br /> |
|  <br />          /⋆ Loop over reg, adding to our total. |
|  <br />           ⋆/ |
|  <br />          for( y = r->top; y < IM_RECT_BOTTOM( r ); y++ ) { |
|  <br />             unsigned char ⋆p = IM_REGION_ADDR( reg, r->left, y ); |
|  <br /> |
|  <br />             for( i = 0; i < IM_REGION_N_ELEMENTS( reg ); i++ ) |
|  <br />                 total += p[i]; |
|  <br />          } |
|  <br />      } |
|  <br /> |
|  <br />   /⋆ Make sure we free the region. |
|  <br />    ⋆/ |
|  <br />   im_region_free( reg ); |
|  <br /> |
|  <br />   /⋆ Find average. |
|  <br />    ⋆/ |
|  <br />   ⋆out = (double) total / (IM_IMAGE_N_ELEMENTS( im ) ⋆ im->Ysize); |
|  <br /> |
|  <br />   return( 0 ); |
|  <br />} |
| </div> |
| <!--l. 454--><p class="nopar" > |
| <br /><div class="caption" |
| ><span class="id">Figure 3.6: </span><span |
| class="content">First PIO average of image (cont.)</span></div><!--tex4ht:label?: x22-950026 --> |
| |
| |
| |
| |
| </div><hr class="endfloat" /> |
| <!--l. 458--><p class="indent" > This version of <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">average()</span></span></span> can be called in exactly the |
| same way as the previous one, but this version has the great |
| advantage of not needing to have the whole of the input |
| image available at once. |
| <!--l. 462--><p class="indent" > We can do one better than this — if the image is being |
| split into small pieces, we can assign each piece to a |
| separate thread of execution and get parallelism. To |
| support this splitting of tasks, VIPS has the notion of a |
| sequence. |
| <h4 class="subsectionHead"><span class="titlemark">3.3.4 </span> <a |
| id="x22-960003.3.4"></a>Splitting into sequences</h4> |
| <!--l. 470--><p class="noindent" >A sequence comes in three parts: a start function, a |
| processing function, and a stop function. When VIPS |
| starts up a new sequence, it runs the start function. |
| Start functions return sequence values: a void pointer |
| representing data local to this sequence. VIPS then |
| repeatedly calls the processing function, passing in |
| the sequence value and a new piece of image data for |
| processing. Finally, when processing is complete, VIPS |
| cleans up by calling the stop function, passing in the |
| sequence value as an argument. The types look like |
| this: |
| <div class="verbatim" id="verbatim-160"> |
| void ⋆ |
|  <br />(⋆start_fn)( IMAGE ⋆out, |
|  <br />   void ⋆a, void ⋆b ) |
|  <br />int |
|  <br />(⋆process_fn)( REGION ⋆reg, |
|  <br />   void ⋆seq, void ⋆a, void ⋆b ) |
|  <br />int |
|  <br />(⋆stop_fn)( void ⋆seq, void ⋆a, void ⋆b ) |
| </div> |
| <!--l. 488--><p class="nopar" > |
| <!--l. 490--><p class="noindent" >The values <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">a</span></span></span> and <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">b</span></span></span> are carried around by VIPS for your |
| use. |
| <!--l. 493--><p class="indent" > For functions like <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">average()</span></span></span> which consume |
| images but produce no image output, VIPS provides |
| <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">vips_sink()</span></span></span>. This has type: |
| |
| |
| |
| <div class="verbatim" id="verbatim-161"> |
| int vips_sink( VipsImage ⋆in, |
|  <br />   VipsStart start, |
|  <br />   VipsGenerate generate, |
|  <br />   VipsStop stop, |
|  <br />   void ⋆a, void ⋆b ) |
| </div> |
| <!--l. 502--><p class="nopar" > |
| <!--l. 504--><p class="indent" > VIPS starts one or more sequences, runs one or more |
| processing functions over image <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">in</span></span></span> until all of <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">in</span></span></span> has |
| been consumed, and then closes all of the sequences |
| down and returns. VIPS guarantees that the regions the |
| <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">process_fn()</span></span></span> is given will be complete and disjoint, |
| that is, every pixel in the image will be passed through |
| exactly one sequence. To make it possible for the sequences |
| to each contribute to the result of the function in an orderly |
| manner, VIPS also guarantees that all start and stop |
| functions are mutually exclusive. |
| <!--l. 513--><p class="indent" > An example should make this clearer. This version of |
| <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">average()</span></span></span> is very similar to the average function in the |
| VIPS library — it is only missing polymorphism. |
| |
| |
| |
| |
| <!--l. 518--><p class="indent" > <a |
| id="x22-960017"></a><hr class="float"><div class="float" |
| > |
| |
| |
| |
| |
| <div class="verbatim" id="verbatim-162"> |
| #include <stdio.h> |
|  <br />#include <stdlib.h> |
|  <br />#include <vips/vips.h> |
|  <br />#include <vips/region.h> |
|  <br /> |
|  <br />/⋆ Start function for average(). We allocate a small piece of |
|  <br /> ⋆ storage which this sequence will accumulate its total in. Our |
|  <br /> ⋆ sequence value is just a pointer to this storage area. |
|  <br /> ⋆ |
|  <br /> ⋆ The first of the two pointers VIPS carries around for us is a |
|  <br /> ⋆ pointer to the space where we store the grand total. |
|  <br /> ⋆/ |
|  <br />static int ⋆ |
|  <br />average_start( IMAGE ⋆out ) |
|  <br />{ |
|  <br />   int ⋆seq = IM_NEW( out, int ); |
|  <br /> |
|  <br />   if( !seq ) |
|  <br />      return( NULL ); |
|  <br />   ⋆seq = 0; |
|  <br /> |
|  <br />   return( seq ); |
|  <br />} |
|  <br /> |
|  <br />/⋆ Stop function for average(). Add the total which has |
|  <br /> ⋆ accumulated in our sequence value to the grand total for |
|  <br /> ⋆ the program. |
|  <br /> ⋆/ |
|  <br />static int |
|  <br />average_stop( int ⋆seq, int ⋆gtotal ) |
|  <br />{ |
|  <br />   /⋆ Stop functions are mutually exclusive, so we can write |
|  <br />    ⋆ to gtotal without clashing with any other stop functions. |
|  <br />    ⋆/ |
|  <br />   ⋆gtotal += ⋆seq; |
|  <br /> |
|  <br />   return( 0 ); |
|  <br />} |
| </div> |
| <!--l. 557--><p class="nopar" > |
| <br /><div class="caption" |
| ><span class="id">Figure 3.7: </span><span |
| class="content">Final PIO average of image</span></div><!--tex4ht:label?: x22-960017 --> |
| |
| |
| |
| |
| </div><hr class="endfloat" /> |
| |
| |
| |
| |
| <!--l. 563--><p class="indent" > <a |
| id="x22-960028"></a><hr class="float"><div class="float" |
| > |
| |
| |
| |
| |
| <div class="verbatim" id="verbatim-163"> |
| /⋆ Process function for average(). Total this region, and |
|  <br /> ⋆ add that total to the sequence value. |
|  <br /> ⋆/ |
|  <br />static int |
|  <br />average_process( REGION ⋆reg, int ⋆seq ) |
|  <br />{ |
|  <br />   int total, i, y; |
|  <br />   Rect ⋆r = &reg->valid; |
|  <br /> |
|  <br />   /⋆ Get the appropriate part of the input image ready. |
|  <br />    ⋆/ |
|  <br />   if( im_prepare( reg, r ) ) |
|  <br />      return( -1 ); |
|  <br /> |
|  <br />   /⋆ Loop over the region. |
|  <br />    ⋆/ |
|  <br />   total = 0; |
|  <br />   for( y = r->top; y < IM_RECT_BOTTOM( r ); y++ ) { |
|  <br />      unsigned char ⋆p = IM_REGION_ADDR( reg, r->left, y ); |
|  <br /> |
|  <br />      for( i = 0; i < IM_REGION_N_ELEMENTS( reg ); i++ ) |
|  <br />          total += p[i]; |
|  <br />   } |
|  <br /> |
|  <br />   /⋆ Add to the total for this sequence. |
|  <br />    ⋆/ |
|  <br />   ⋆seq += total; |
|  <br /> |
|  <br />   return( 0 ); |
|  <br />} |
| </div> |
| <!--l. 594--><p class="nopar" > |
| <br /><div class="caption" |
| ><span class="id">Figure 3.8: </span><span |
| class="content">Final PIO average of image (cont.)</span></div><!--tex4ht:label?: x22-960028 --> |
| |
| |
| |
| |
| </div><hr class="endfloat" /> |
| |
| |
| |
| |
| <!--l. 599--><p class="indent" > <a |
| id="x22-960039"></a><hr class="float"><div class="float" |
| > |
| |
| |
| |
| |
| <div class="verbatim" id="verbatim-164"> |
| /⋆ Find average of image. |
|  <br /> ⋆/ |
|  <br />int |
|  <br />average( IMAGE ⋆im, double ⋆out ) |
|  <br />{ |
|  <br />   /⋆ Accumulate grand total here. |
|  <br />    ⋆/ |
|  <br />   int gtotal = 0; |
|  <br /> |
|  <br />   /⋆ Prepare im for PIO reading. |
|  <br />    ⋆/ |
|  <br />   if( im_pincheck( im ) ) |
|  <br />      return( -1 ); |
|  <br /> |
|  <br />   /⋆ Check it is the sort of thing we can process. |
|  <br />    ⋆/ |
|  <br />   if( im->BandFmt != IM_BANDFMT_UCHAR || |
|  <br />      im->Coding != IM_CODING_NONE ) { |
|  <br />      im_error( "average", "uncoded uchar images only" ); |
|  <br />      return( -1 ); |
|  <br />   } |
|  <br /> |
|  <br />   /⋆ Loop over the image in pieces, and possibly in parallel. |
|  <br />    ⋆/ |
|  <br />   if( vips_sink( im, |
|  <br />      average_start, average_process, average_stop, |
|  <br />      &gtotal, NULL ) ) |
|  <br />      return( -1 ); |
|  <br /> |
|  <br />   /⋆ Calculate average. |
|  <br />    ⋆/ |
|  <br />   ⋆out = (double) gtotal / (IM_IMAGE_N_ELEMENTS( im ) ⋆ im->Ysize); |
|  <br /> |
|  <br />   return( 0 ); |
|  <br />} |
| </div> |
| <!--l. 635--><p class="nopar" > |
| <br /><div class="caption" |
| ><span class="id">Figure 3.9: </span><span |
| class="content">Final PIO average of image (cont.)</span></div><!--tex4ht:label?: x22-960039 --> |
| |
| |
| |
| |
| </div><hr class="endfloat" /> |
| <!--l. 639--><p class="indent" > There are a couple of variations on <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_prepare()</span></span></span>: |
| you can use <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_prepare_to()</span></span></span> to force writing to a |
| particular place, and <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_prepare_thread()</span></span></span> to use |
| threaded evaluation. See the man pages. |
| <h4 class="subsectionHead"><span class="titlemark">3.3.5 </span> <a |
| id="x22-970003.3.5"></a>Output to regions</h4> |
| <!--l. 646--><p class="noindent" >Regions are written to in just the same way they are |
| read from — by writing to a pointer found with the |
| <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">IM_REGION_ADDR()</span></span></span> macro. |
| <!--l. 649--><p class="indent" > <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">vips_sink()</span></span></span> does input — <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_generate()</span></span></span> does |
| output. It has the same type as <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">vips_sink()</span></span></span>: |
| <div class="verbatim" id="verbatim-165"> |
| int |
|  <br />im_generate( IMAGE ⋆out, |
|  <br />   void ⋆(⋆start_fn)(), |
|  <br />   int (⋆process_fn)(), |
|  <br />   int (⋆stop_fn)(), |
|  <br />   void ⋆a, void ⋆b ) |
| </div> |
| <!--l. 659--><p class="nopar" > |
| <!--l. 661--><p class="indent" > The region given to the process function is ready for |
| output. Each time the process function is called, it should |
| fill in the pels in the region it was given. Note that, unlike |
| <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">vips_sink()</span></span></span>, the areas the process function is asked to |
| produce are not guaranteed to be either disjoint or complete. |
| Again, VIPS may start up many process functions if it sees |
| fit. |
| <!--l. 667--><p class="indent" > Here is <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">invert()</span></span></span>, rewritten to use PIO. This piece of |
| code makes use of a pair of standard start and stop functions |
| provided by the VIPS library: <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_start_one()</span></span></span> and |
| <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_stop_one()</span></span></span>. They assume that the first of the two |
| user arguments to <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_generate()</span></span></span> is the input image. |
| They are defined as: |
| |
| |
| |
| <div class="verbatim" id="verbatim-166"> |
| REGION ⋆ |
|  <br />im_start_one( IMAGE ⋆out, IMAGE ⋆in ) |
|  <br />{ |
|  <br />   return( im_region_create( in ) ); |
|  <br />} |
| </div> |
| <!--l. 679--><p class="nopar" > |
| <!--l. 681--><p class="noindent" >and: |
| <div class="verbatim" id="verbatim-167"> |
| int |
|  <br />im_stop_one( REGION ⋆seq ) |
|  <br />{ |
|  <br />   return( im_region_free( seq ) ); |
|  <br />} |
| </div> |
| <!--l. 690--><p class="nopar" > |
| <!--l. 692--><p class="indent" > They are useful for simple functions which expect only one |
| input image. See the manual page for <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_start_many()</span></span></span> |
| for many-input functions. |
| |
| |
| |
| <!--l. 697--><p class="indent" > <a |
| id="x22-9700110"></a><hr class="float"><div class="float" |
| > |
| |
| |
| |
| |
| <div class="verbatim" id="verbatim-168"> |
| #include <stdio.h> |
|  <br />#include <stdlib.h> |
|  <br />#include <vips/vips.h> |
|  <br />#include <vips/region.h> |
|  <br /> |
|  <br />/⋆ Process function for invert(). Build the pixels in or |
|  <br /> ⋆ from the appropriate pixels in ir. |
|  <br /> ⋆/ |
|  <br />static int |
|  <br />invert_process( REGION ⋆or, REGION ⋆ir ) |
|  <br />{ |
|  <br />   Rect ⋆r = &or->valid; |
|  <br />   int i, y; |
|  <br /> |
|  <br />   /⋆ Ask for the part of ir we need to make or. In this |
|  <br />    ⋆ case, the two areas will be the same. |
|  <br />    ⋆/ |
|  <br />   if( im_prepare( ir, r ) ) |
|  <br />      return( -1 ); |
|  <br /> |
|  <br />   /⋆ Loop over or writing pels calculated from ir. |
|  <br />    ⋆/ |
|  <br />   for( y = r->top; y < IM_RECT_BOTTOM( r ); y++ ) { |
|  <br />      unsigned char ⋆p = IM_REGION_ADDR( ir, r->left, y ); |
|  <br />      unsigned char ⋆q = IM_REGION_ADDR( or, r->left, y ); |
|  <br /> |
|  <br />      for( i = 0; i < IM_REGION_N_ELEMENTS( or ); i++ ) |
|  <br />          q[i] = 255 - p[i]; |
|  <br />   } |
|  <br /> |
|  <br />   /⋆ Success! |
|  <br />    ⋆/ |
|  <br />   return( 0 ); |
|  <br />} |
| </div> |
| <!--l. 732--><p class="nopar" > |
| <br /><div class="caption" |
| ><span class="id">Figure 3.10: </span><span |
| class="content">PIO invert</span></div><!--tex4ht:label?: x22-9700110 --> |
| |
| |
| |
| |
| </div><hr class="endfloat" /> |
| |
| |
| |
| |
| <!--l. 738--><p class="indent" > <a |
| id="x22-9700211"></a><hr class="float"><div class="float" |
| > |
| |
| |
| |
| |
| <div class="verbatim" id="verbatim-169"> |
| /⋆ Invert an image. |
|  <br /> ⋆/ |
|  <br />int |
|  <br />invert( IMAGE ⋆in, IMAGE ⋆out ) |
|  <br />{ |
|  <br />   /⋆ Check descriptors for PIO compatibility. |
|  <br />    ⋆/ |
|  <br />   if( im_piocheck( in, out ) ) |
|  <br />      return( -1 ); |
|  <br /> |
|  <br />   /⋆ Check input image for compatibility with us. |
|  <br />    ⋆/ |
|  <br />   if( in->BandFmt != IM_BANDFMT_UCHAR || in->Coding != IM_CODING_NONE ) { |
|  <br />      im_error( "invert", "uncoded uchar images only" ); |
|  <br />      return( -1 ); |
|  <br />   } |
|  <br /> |
|  <br />   /⋆ out inherits from in, as before. |
|  <br />    ⋆/ |
|  <br />   if( im_cp_desc( out, in ) ) |
|  <br />      return( -1 ); |
|  <br /> |
|  <br />   /⋆ Set demand hints for out. |
|  <br />    ⋆/ |
|  <br />   if( im_demand_hint( out, IM_THINSTRIP, in, NULL ) ) |
|  <br />      return( -1 ); |
|  <br /> |
|  <br />   /⋆ Build out in pieces, and possibly in parallel! |
|  <br />    ⋆/ |
|  <br />   if( im_generate( out, |
|  <br />      im_start_one, invert_process, im_stop_one, |
|  <br />      in, NULL ) ) |
|  <br />      return( -1 ); |
|  <br /> |
|  <br />   return( 0 ); |
|  <br />} |
| </div> |
| <!--l. 775--><p class="nopar" > |
| <br /><div class="caption" |
| ><span class="id">Figure 3.11: </span><span |
| class="content">PIO invert (cont.)</span></div><!--tex4ht:label?: x22-9700211 --> |
| |
| |
| |
| |
| </div><hr class="endfloat" /> |
| <!--l. 779--><p class="indent" > Functions have some choice about the way they write |
| their output. Usually, they should just write to the region |
| they were given by <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_generate()</span></span></span>. They can, if they |
| wish, set up the region for output to some other place. See |
| the manual page for <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_region_region()</span></span></span>. See also |
| the source for <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_copy()</span></span></span> and <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_extract()</span></span></span> for |
| examples of these tricks. |
| <!--l. 785--><p class="indent" > Note also the call to <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_demand_hint()</span></span></span>. This |
| function hints to the IO system, suggesting the sorts of |
| shapes of region this function is happiest with. VIPS |
| supports four basic shapes — choosing the correct shape |
| can have a dramatic effect on the speed of your function. |
| See the man page for full details. |
| <h4 class="subsectionHead"><span class="titlemark">3.3.6 </span> <a |
| id="x22-980003.3.6"></a>Callbacks</h4> |
| <!--l. 794--><p class="noindent" >VIPS lets you attach callbacks to image descriptors. These |
| are functions you provide that VIPS will call when certain |
| events occur. There are more callbacks than are listed here: |
| see the man page for full details. |
| <!--l. 798--><p class="noindent" > |
| <h5 class="subsubsectionHead"><a |
| id="x22-990003.3.6"></a>Close callbacks</h5> |
| <!--l. 800--><p class="noindent" >These callbacks are invoked just before an image is |
| closed. They are useful for freeing objects which are |
| associated with the image. All callbacks are triggered |
| in the reverse order to the order in which they were |
| attached. This is sometimes important when freeing objects |
| which contain pointers to other objects. Close callbacks |
| are guaranteed to be called, and to be called exactly |
| once. |
| <!--l. 807--><p class="indent" > Use <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_add_close_callback()</span></span></span> to add a close |
| callback: |
| <div class="verbatim" id="verbatim-170"> |
| typedef int (⋆im_callback)( void ⋆, void ⋆ ) |
|  <br />int im_add_close_callback( IMAGE ⋆, |
|  <br />   im_callback_fn, |
|  <br />   void ⋆, void ⋆ ) |
| </div> |
| <!--l. 814--><p class="nopar" > |
| <!--l. 816--><p class="indent" > As with <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_generate()</span></span></span>, the two <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">void</span><span |
| class="pcrr7t-"> ⋆</span></span></span> pointers |
| are carried around for you by VIPS and may be used as your |
| function sees fit. |
| <!--l. 820--><p class="noindent" > |
| <h5 class="subsubsectionHead"><a |
| id="x22-1000003.3.6"></a>Preclose callbacks</h5> |
| <!--l. 822--><p class="noindent" >Preclose callbacks are called before any shutdown has |
| occured. Everything is still alive and your callback can do |
| anything to the image. Preclose callbacks are guaranteed to |
| be called, and to be called exactly once. See the manual |
| page for <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_add_preclose_callback()</span></span></span> for full |
| details. |
| <!--l. 827--><p class="noindent" > |
| <h5 class="subsubsectionHead"><a |
| id="x22-1010003.3.6"></a>Eval callbacks</h5> |
| <!--l. 829--><p class="noindent" >These are callbacks which are invoked periodically by VIPS |
| during evaluation. The callback has access to a struct |
| containing information about the progress of evaluation, |
| useful for user-interfaces built on top of VIPS. See the |
| manual page for <span class="obeylines-h"><span class="verb"><span |
| class="pcrr7t-">im_add_eval_callback()</span></span></span> for full |
| details. |
| <!--l. 834--><p class="noindent" > |
| <h4 class="subsectionHead"><span class="titlemark">3.3.7 </span> <a |
| id="x22-1020003.3.7"></a>Memory allocation revisited</h4> |
| <!--l. 836--><p class="noindent" >When you are using PIO, memory allocation becomes |
| rather more complicated than it was before. There are |
| essentially two types of memory which your function might |
| want to use for working space: memory which is associated |
| with each instance of your function (remember that two |
| copies of you function may be joined together in a |
| pipeline and be running at the same time — you can’t just |
| use global variables), and memory which is local to |
| each sequence which VIPS starts on your argument |
| image. |
| <!--l. 844--><p class="indent" > The first type, memory local to this function instance, |
| typically holds copies of any parameters passed to your |
| |
| |
| |
| image processing function, and links to any read-only tables |
| used by sequences which you run over the image. This |
| should be allocated in your main function. |
| <!--l. 849--><p class="indent" > The second type of memory, memory local to a sequence, |
| should be allocated in a start function. Because this space is |
| private to a sequence, it may be written to. Start and |
| stop functions are guaranteed to be single-threaded, so |
| you may write to the function-local memory within |
| them. |
| |
| |
| |
| |
| <!--l. 1--><div class="crosslinks"><p class="noindent">[<a |
| href="vipsmanualse16.html" >next</a>] [<a |
| href="vipsmanualse14.html" >prev</a>] [<a |
| href="vipsmanualse14.html#tailvipsmanualse14.html" >prev-tail</a>] [<a |
| href="vipsmanualse15.html" >front</a>] [<a |
| href="vipsmanualch3.html#vipsmanualse15.html" >up</a>] </p></div> |
| <!--l. 1--><p class="indent" > <a |
| id="tailvipsmanualse15.html"></a> |
| </body></html> |