diff --git a/TODO b/TODO index 76c61348..8bf4f929 100644 --- a/TODO +++ b/TODO @@ -1,32 +1,5 @@ - add MATLAB write -- sink.c, sinkdisc.c, sinkmemory.c all define this function: - - static int - sink_progress( void *a ) - { - Sink *sink = (Sink *) a; - - VIPS_DEBUG_MSG( "sink_progress: %d x %d\n", - sink->tile_width, sink->tile_height ); - - /* Trigger any eval callbacks on our source image and - * check for errors. - */ - vips_image_eval( sink->im, - sink->tile_width, sink->tile_height ); - if( vips_image_get_kill( im ) ) - return( -1 ); - - return( 0 ); - } - - how dumb, common this up somehow - - sink.c is the replacement for im_iterate() - - - - need a way to make the vips.1 etc. man pages gtk has things like docs/reference/gtk/gtk-update-icon-cache.xml and man diff --git a/libvips/iofuncs/Makefile.am b/libvips/iofuncs/Makefile.am index bec8e5d1..5946d6c6 100644 --- a/libvips/iofuncs/Makefile.am +++ b/libvips/iofuncs/Makefile.am @@ -11,10 +11,11 @@ libiofuncs_la_SOURCES = \ vips.c \ generate.c \ mapfile.c \ - sinkmemory.c \ - sinkscreen.c \ - sinkdisc.c \ + sink.h \ sink.c \ + sinkmemory.c \ + sinkdisc.c \ + sinkscreen.c \ memory.c \ package.c \ header.c \ diff --git a/libvips/iofuncs/sink.c b/libvips/iofuncs/sink.c index ec30862f..b7aa4e4b 100644 --- a/libvips/iofuncs/sink.c +++ b/libvips/iofuncs/sink.c @@ -47,6 +47,8 @@ #include #include +#include "sink.h" + #ifdef WITH_DMALLOC #include #endif /*WITH_DMALLOC*/ @@ -54,24 +56,13 @@ /* Per-call state. */ typedef struct _Sink { - VipsImage *im; + SinkBase sink_base; /* We need a temp "p" image between the source image and us to * make sure we can't damage the original. */ VipsImage *t; - /* The position we're at in the image. - */ - int x; - int y; - - /* The tilesize we've picked. - */ - int tile_width; - int tile_height; - int nlines; - /* Call params. */ VipsStartFn start; @@ -112,9 +103,11 @@ sink_call_stop( Sink *sink, SinkThreadState *state ) VIPS_DEBUG_MSG( "sink_call_stop: state = %p\n", state ); if( sink->stop( state->seq, sink->a, sink->b ) ) { + SinkBase *sink_base = (SinkBase *) sink; + vips_error( "vips_sink", _( "stop function failed for image \"%s\"" ), - sink->im->filename ); + sink_base->im->filename ); return( -1 ); } @@ -147,9 +140,11 @@ sink_call_start( Sink *sink, SinkThreadState *state ) state->seq = sink->start( sink->t, sink->a, sink->b ); if( !state->seq ) { + SinkBase *sink_base = (SinkBase *) sink; + vips_error( "vips_sink", _( "start function failed for image \"%s\"" ), - sink->im->filename ); + sink_base->im->filename ); return( -1 ); } } @@ -205,16 +200,27 @@ sink_free( Sink *sink ) VIPS_FREEF( g_object_unref, sink->t ); } +void +vips_sink_base_init( SinkBase *sink_base, VipsImage *image ) +{ + sink_base->im = image; + sink_base->x = 0; + sink_base->y = 0; + + vips_get_tile_size( image, + &sink_base->tile_width, &sink_base->tile_height, + &sink_base->nlines ); +} + static int sink_init( Sink *sink, - VipsImage *im, + VipsImage *image, VipsStartFn start, VipsGenerateFn generate, VipsStopFn stop, void *a, void *b ) { - sink->im = im; + vips_sink_base_init( &sink->sink_base, image ); + sink->t = NULL; - sink->x = 0; - sink->y = 0; sink->start = start; sink->generate = generate; sink->stop = stop; @@ -222,31 +228,28 @@ sink_init( Sink *sink, sink->b = b; if( !(sink->t = vips_image_new( "p" )) || - im_copy( sink->im, sink->t ) ) { + im_copy( sink->sink_base.im, sink->t ) ) { sink_free( sink ); return( -1 ); } - vips_get_tile_size( im, - &sink->tile_width, &sink->tile_height, &sink->nlines ); - return( 0 ); } -static int -sink_allocate( VipsThreadState *state, void *a, gboolean *stop ) +int +vips_sink_base_allocate( VipsThreadState *state, void *a, gboolean *stop ) { - Sink *sink = (Sink *) a; + SinkBase *sink_base = (SinkBase *) a; VipsRect image, tile; /* Is the state x/y OK? New line or maybe all done. */ - if( sink->x >= sink->im->Xsize ) { - sink->x = 0; - sink->y += sink->tile_height; + if( sink_base->x >= sink_base->im->Xsize ) { + sink_base->x = 0; + sink_base->y += sink_base->tile_height; - if( sink->y >= sink->im->Ysize ) { + if( sink_base->y >= sink_base->im->Ysize ) { *stop = TRUE; return( 0 ); @@ -257,17 +260,17 @@ sink_allocate( VipsThreadState *state, void *a, gboolean *stop ) */ image.left = 0; image.top = 0; - image.width = sink->im->Xsize; - image.height = sink->im->Ysize; - tile.left = sink->x; - tile.top = sink->y; - tile.width = sink->tile_width; - tile.height = sink->tile_height; + image.width = sink_base->im->Xsize; + image.height = sink_base->im->Ysize; + tile.left = sink_base->x; + tile.top = sink_base->y; + tile.width = sink_base->tile_width; + tile.height = sink_base->tile_height; vips_rect_intersectrect( &image, &tile, &state->pos ); /* Move state on. */ - sink->x += sink->tile_width; + sink_base->x += sink_base->tile_width; return( 0 ); } @@ -285,19 +288,20 @@ sink_work( VipsThreadState *state, void *a ) return( 0 ); } -static int -sink_progress( void *a ) +int +vips_sink_base_progress( void *a ) { - Sink *sink = (Sink *) a; + SinkBase *sink_base = (SinkBase *) a; - VIPS_DEBUG_MSG( "sink_progress: %d x %d\n", - sink->tile_width, sink->tile_height ); + VIPS_DEBUG_MSG( "vips_sink_base_progress: %d x %d\n", + sink_base->tile_width, sink_base->tile_height ); /* Trigger any eval callbacks on our source image and * check for errors. */ - vips_image_eval( sink->im, sink->tile_width, sink->tile_height ); - if( vips_image_get_kill( sink->im ) ) + vips_image_eval( sink_base->im, + sink_base->tile_width, sink_base->tile_height ); + if( vips_image_get_kill( sink_base->im ) ) return( -1 ); return( 0 ); @@ -349,17 +353,17 @@ vips_sink_tile( VipsImage *im, return( -1 ); if( tile_width > 0 ) { - sink.tile_width = tile_width; - sink.tile_height = tile_height; + sink.sink_base.tile_width = tile_width; + sink.sink_base.tile_height = tile_height; } vips_image_preeval( sink.t ); result = vips_threadpool_run( im, sink_thread_state_new, - sink_allocate, + vips_sink_base_allocate, sink_work, - sink_progress, + vips_sink_base_progress, &sink ); vips_image_posteval( sink.t ); diff --git a/libvips/iofuncs/sink.h b/libvips/iofuncs/sink.h new file mode 100644 index 00000000..5eb9339e --- /dev/null +++ b/libvips/iofuncs/sink.h @@ -0,0 +1,68 @@ +/* A sink that's not attached to anything, eg. find image average, + * + * 28/3/10 + * - from im_iterate(), reworked for threadpool + */ + +/* + + This file is part of VIPS. + + VIPS is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + */ + +/* + + These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk + + */ + +#ifndef VIPS_SINK_H +#define VIPS_SINK_H + +#ifdef __cplusplus +extern "C" { +#endif /*__cplusplus*/ + +/* Base for sink.c / sinkdisc.c / sinkmemory.c + */ +typedef struct _SinkBase { + VipsImage *im; + + /* The position we're at in buf. + */ + int x; + int y; + + /* The tilesize we've picked. + */ + int tile_width; + int tile_height; + int nlines; + +} SinkBase; + +/* Some function we can share. + */ +void vips_sink_base_init( SinkBase *sink_base, VipsImage *image ); +int vips_sink_base_allocate( VipsThreadState *state, void *a, gboolean *stop ); +int vips_sink_base_progress( void *a ); + +#ifdef __cplusplus +} +#endif /*__cplusplus*/ + +#endif /*VIPS_SINK_H*/ diff --git a/libvips/iofuncs/sinkdisc.c b/libvips/iofuncs/sinkdisc.c index d6fe3c98..37219e3d 100644 --- a/libvips/iofuncs/sinkdisc.c +++ b/libvips/iofuncs/sinkdisc.c @@ -61,6 +61,8 @@ #include #include +#include "sink.h" + #ifdef WITH_DMALLOC #include #endif /*WITH_DMALLOC*/ @@ -83,7 +85,7 @@ typedef struct _WriteBuffer { /* Per-call state. */ typedef struct _Write { - VipsImage *im; + SinkBase sink_base; /* We are current writing tiles to buf, buf_back is in the hands of * the bg write thread. @@ -91,17 +93,6 @@ typedef struct _Write { WriteBuffer *buf; WriteBuffer *buf_back; - /* The position we're at in buf. - */ - int x; - int y; - - /* The tilesize we've picked. - */ - int tile_width; - int tile_height; - int nlines; - /* The file format write operation. */ VipsRegionWrite write_fn; @@ -234,7 +225,7 @@ wbuffer_new( Write *write ) wbuffer->thread = NULL; wbuffer->kill = FALSE; - if( !(wbuffer->region = vips_region_new( write->im )) ) { + if( !(wbuffer->region = vips_region_new( write->sink_base.im )) ) { wbuffer_free( wbuffer ); return( NULL ); } @@ -303,12 +294,12 @@ wbuffer_position( WriteBuffer *wbuffer, int top, int height ) image.left = 0; image.top = 0; - image.width = wbuffer->write->im->Xsize; - image.height = wbuffer->write->im->Ysize; + image.width = wbuffer->write->sink_base.im->Xsize; + image.height = wbuffer->write->sink_base.im->Ysize; area.left = 0; area.top = top; - area.width = wbuffer->write->im->Xsize; + area.width = wbuffer->write->sink_base.im->Xsize; area.height = height; vips_rect_intersectrect( &area, &image, &wbuffer->area ); @@ -338,6 +329,7 @@ wbuffer_allocate_fn( VipsThreadState *state, void *a, gboolean *stop ) { WriteThreadState *wstate = (WriteThreadState *) state; Write *write = (Write *) a; + SinkBase *sink_base = (SinkBase *) write; VipsRect image; VipsRect tile; @@ -347,11 +339,11 @@ wbuffer_allocate_fn( VipsThreadState *state, void *a, gboolean *stop ) /* Is the state x/y OK? New line or maybe new buffer or maybe even * all done. */ - if( write->x >= write->buf->area.width ) { - write->x = 0; - write->y += write->tile_height; + if( sink_base->x >= write->buf->area.width ) { + sink_base->x = 0; + sink_base->y += sink_base->tile_height; - if( write->y >= VIPS_RECT_BOTTOM( &write->buf->area ) ) { + if( sink_base->y >= VIPS_RECT_BOTTOM( &write->buf->area ) ) { /* Block until the last write is done, then set write * of the front buffer going. */ @@ -360,7 +352,7 @@ wbuffer_allocate_fn( VipsThreadState *state, void *a, gboolean *stop ) /* End of image? */ - if( write->y >= write->im->Ysize ) { + if( sink_base->y >= sink_base->im->Ysize ) { *stop = TRUE; return( 0 ); } @@ -378,7 +370,7 @@ wbuffer_allocate_fn( VipsThreadState *state, void *a, gboolean *stop ) /* Position buf at the new y. */ if( wbuffer_position( write->buf, - write->y, write->nlines ) ) + sink_base->y, sink_base->nlines ) ) return( -1 ); } } @@ -387,12 +379,12 @@ wbuffer_allocate_fn( VipsThreadState *state, void *a, gboolean *stop ) */ image.left = 0; image.top = 0; - image.width = write->im->Xsize; - image.height = write->im->Ysize; - tile.left = write->x; - tile.top = write->y; - tile.width = write->tile_width; - tile.height = write->tile_height; + image.width = sink_base->im->Xsize; + image.height = sink_base->im->Ysize; + tile.left = sink_base->x; + tile.top = sink_base->y; + tile.width = sink_base->tile_width; + tile.height = sink_base->tile_height; vips_rect_intersectrect( &image, &tile, &state->pos ); wstate->buf = write->buf; @@ -402,7 +394,7 @@ wbuffer_allocate_fn( VipsThreadState *state, void *a, gboolean *stop ) /* Move state on. */ - write->x += write->tile_width; + sink_base->x += sink_base->tile_width; return( 0 ); } @@ -427,40 +419,16 @@ wbuffer_work_fn( VipsThreadState *state, void *a ) return( 0 ); } -/* Our VipsThreadpoolProgress function ... send some eval progress feedback. - */ -static int -wbuffer_progress_fn( void *a ) -{ - Write *write = (Write *) a; - - VIPS_DEBUG_MSG( "wbuffer_progress_fn: %d x %d\n", - write->tile_width, write->tile_height ); - - /* Trigger any eval callbacks on our source image and - * check for errors. - */ - vips_image_eval( write->im, write->tile_width, write->tile_height ); - if( vips_image_get_kill( write->im ) ) - return( -1 ); - - return( 0 ); -} - static void write_init( Write *write, - VipsImage *im, VipsRegionWrite write_fn, void *a ) + VipsImage *image, VipsRegionWrite write_fn, void *a ) { - write->im = im; + vips_sink_base_init( &write->sink_base, image ); + write->buf = wbuffer_new( write ); write->buf_back = wbuffer_new( write ); - write->x = 0; - write->y = 0; write->write_fn = write_fn; write->a = a; - - vips_get_tile_size( im, - &write->tile_width, &write->tile_height, &write->nlines ); } static void @@ -479,7 +447,7 @@ write_free( Write *write ) * The function should write the pixels in @area from @region. @a is the * value passed into vips_discsink(). * - * See also: vips_discsink(). + * See also: vips_sink_disc(). * * Returns: 0 on success, -1 on error. */ @@ -517,12 +485,12 @@ vips_sink_disc( VipsImage *im, VipsRegionWrite write_fn, void *a ) result = 0; if( !write.buf || !write.buf_back || - wbuffer_position( write.buf, 0, write.nlines ) || + wbuffer_position( write.buf, 0, write.sink_base.nlines ) || vips_threadpool_run( im, write_thread_state_new, wbuffer_allocate_fn, wbuffer_work_fn, - wbuffer_progress_fn, + vips_sink_base_progress, &write ) ) result = -1; diff --git a/libvips/iofuncs/sinkmemory.c b/libvips/iofuncs/sinkmemory.c index a277fb4f..025c3b21 100644 --- a/libvips/iofuncs/sinkmemory.c +++ b/libvips/iofuncs/sinkmemory.c @@ -47,6 +47,8 @@ #include #include +#include "sink.h" + #ifdef WITH_DMALLOC #include #endif /*WITH_DMALLOC*/ @@ -54,22 +56,11 @@ /* Per-call state. */ typedef struct _Sink { - VipsImage *im; + SinkBase sink_base; /* A big region for the image memory. All the threads write to this. */ VipsRegion *all; - - /* The position we're at in the image. - */ - int x; - int y; - - /* The tilesize we've picked. - */ - int tile_width; - int tile_height; - int nlines; } Sink; static void @@ -83,9 +74,7 @@ sink_init( Sink *sink, VipsImage *im ) { VipsRect all; - sink->im = im; - sink->x = 0; - sink->y = 0; + vips_sink_base_init( &sink->sink_base, im ); all.left = 0; all.top = 0; @@ -98,48 +87,6 @@ sink_init( Sink *sink, VipsImage *im ) return( -1 ); } - vips_get_tile_size( im, - &sink->tile_width, &sink->tile_height, &sink->nlines ); - - return( 0 ); -} - -static int -sink_allocate( VipsThreadState *state, void *a, gboolean *stop ) -{ - Sink *sink = (Sink *) a; - - VipsRect image, tile; - - /* Is the state x/y OK? New line or maybe all done. - */ - if( sink->x >= sink->im->Xsize ) { - sink->x = 0; - sink->y += sink->tile_height; - - if( sink->y >= sink->im->Ysize ) { - *stop = TRUE; - - return( 0 ); - } - } - - /* x, y and buf are good: save params for thread. - */ - image.left = 0; - image.top = 0; - image.width = sink->im->Xsize; - image.height = sink->im->Ysize; - tile.left = sink->x; - tile.top = sink->y; - tile.width = sink->tile_width; - tile.height = sink->tile_height; - vips_rect_intersectrect( &image, &tile, &state->pos ); - - /* Move state on. - */ - sink->x += sink->tile_width; - return( 0 ); } @@ -155,24 +102,6 @@ sink_work( VipsThreadState *state, void *a ) return( 0 ); } -static int -sink_progress( void *a ) -{ - Sink *sink = (Sink *) a; - - VIPS_DEBUG_MSG( "sink_progress: %d x %d\n", - sink->tile_width, sink->tile_height ); - - /* Trigger any eval callbacks on our source image and - * check for errors. - */ - vips_image_eval( sink->im, sink->tile_width, sink->tile_height ); - if( vips_image_get_kill( sink->im ) ) - return( -1 ); - - return( 0 ); -} - /** * vips_sink_memory: * @im: generate this image to memory @@ -204,9 +133,9 @@ vips_sink_memory( VipsImage *im ) result = vips_threadpool_run( im, vips_thread_state_new, - sink_allocate, + vips_sink_base_allocate, sink_work, - sink_progress, + vips_sink_base_progress, &sink ); vips_image_posteval( im );