im_vips2tiff() uses vips_sink() instead of threadgroup

This commit is contained in:
John Cupitt 2010-04-16 15:48:30 +00:00
parent 31b06dbc5a
commit 54730feadc
6 changed files with 108 additions and 102 deletions

View File

@ -12,6 +12,7 @@
- set G_LOG_DOMAIN to VIPS so we can use g_warning etc.
- added VIPS_DEBUG_MSG() macro
- --vips-wbuffer2 turns on threadpool for im_iterate as well
- im_vips2tiff() uses vips_sink() instead of threadgroup
16/1/10 started 7.21.2
- "invalidate" is careful to keep images alive, so invalidate callbacks can do

2
TODO
View File

@ -3,8 +3,6 @@
- im_prepare_thread() can go? I think it was only used by im_render()
wtf, im_vips2tiff.c seems to be using it, what's wrong with im_wbuffer()?
- get rid of threadgroup too (deprecate?)

View File

@ -110,6 +110,8 @@
* - gtkdoc
* 26/2/10
* - option to turn on bigtiff output
* 16/4/10
* - use vips_sink_*() instead of threadgroup and friends
*/
/*
@ -230,7 +232,6 @@ typedef struct tiff_write {
/* Read from im with these.
*/
REGION *reg;
im_threadgroup_t *tg;
char *bname; /* Name for base layer */
TIFF *tif; /* Image we write to */
@ -252,6 +253,8 @@ typedef struct tiff_write {
int embed; /* Embed ICC profile */
char *icc_profile; /* Profile to embed */
int bigtiff; /* True for bigtiff write */
GMutex *write_lock; /* Lock TIFF*() calls with this */
} TiffWrite;
/* Use these from im_tiff2vips().
@ -570,14 +573,8 @@ free_layer( PyramidLayer *layer )
/* And close the TIFF file we are writing to.
*/
if( layer->tbuf ) {
im_free( layer->tbuf );
layer->tbuf = NULL;
}
if( layer->tif ) {
TIFFClose( layer->tif );
layer->tif = NULL;
}
IM_FREEF( im_free, layer->tbuf );
IM_FREEF( TIFFClose, layer->tif );
}
/* Free an entire pyramid.
@ -1032,18 +1029,50 @@ new_tile( PyramidLayer *layer, REGION *tile, Rect *area )
return( 0 );
}
/* Write as tiles. This is called by vips_sink_tile() for every tile
* generated.
*/
static int
write_tif_tile( REGION *out, void *seq, void *a, void *b )
{
TiffWrite *tw = (TiffWrite *) a;
g_mutex_lock( tw->write_lock );
/* Write to TIFF.
*/
if( save_tile( tw, tw->tif, tw->tbuf, out, &out->valid ) ) {
g_mutex_unlock( tw->write_lock );
return( -1 );
}
/* Is there a pyramid? Write to that too.
*/
if( tw->layer &&
new_tile( tw->layer, out, &out->valid ) ) {
g_mutex_unlock( tw->write_lock );
return( -1 );
}
g_mutex_unlock( tw->write_lock );
return( 0 );
}
/* Write as tiles.
*/
static int
write_tif_tile( TiffWrite *tw )
write_tif_tilewise( TiffWrite *tw )
{
IMAGE *im = tw->im;
Rect area;
int x, y;
g_assert( !tw->tbuf );
if( !(tw->tbuf = im_malloc( NULL, TIFFTileSize( tw->tif ) )) )
return( -1 );
g_assert( !tw->write_lock );
tw->write_lock = g_mutex_new();
/* Write pyramid too? Only bother if bigger than tile size.
*/
if( tw->pyramid &&
@ -1051,41 +1080,15 @@ write_tif_tile( TiffWrite *tw )
build_pyramid( tw, NULL, &tw->layer, im->Xsize, im->Ysize ) )
return( -1 );
for( y = 0; y < im->Ysize; y += tw->tileh )
for( x = 0; x < im->Xsize; x += tw->tilew ) {
/* Set up rect we write.
*/
area.left = x;
area.top = y;
area.width = IM_MIN( tw->tilew, im->Xsize - x );
area.height = IM_MIN( tw->tileh, im->Ysize - y );
if( im_prepare_thread( tw->tg, tw->reg, &area ) )
return( -1 );
/* Write to TIFF.
*/
if( save_tile( tw, tw->tif, tw->tbuf, tw->reg, &area ) )
return( -1 );
/* Is there a pyramid? Write to that too.
*/
if( tw->layer && new_tile( tw->layer, tw->reg, &area ) )
return( -1 );
/* Trigger any eval callbacks on our source image and
* check for errors.
*/
if( im__handle_eval( im, area.width, area.height ) ||
im_threadgroup_iserror( tw->tg ) )
return( -1 );
}
if( vips_sink_tile( im, tw->tilew, tw->tileh,
NULL, write_tif_tile, NULL, tw, NULL ) )
return( -1 );
return( 0 );
}
static int
write_tif_block( REGION *region, Rect *area, void *a, void *b )
write_tif_block( REGION *region, Rect *area, void *a )
{
TiffWrite *tw = (TiffWrite *) a;
IMAGE *im = tw->im;
@ -1121,14 +1124,14 @@ write_tif_block( REGION *region, Rect *area, void *a, void *b )
/* Write as scan-lines.
*/
static int
write_tif_strip( TiffWrite *tw )
write_tif_stripwise( TiffWrite *tw )
{
g_assert( !tw->tbuf );
if( !(tw->tbuf = im_malloc( NULL, TIFFScanlineSize( tw->tif ) )) )
return( -1 );
if( im_wbuffer( tw->tg, write_tif_block, tw, NULL ) )
if( vips_sink_disc( tw->im, write_tif_block, tw ) )
return( -1 );
return( 0 );
@ -1162,28 +1165,11 @@ free_tiff_write( TiffWrite *tw )
delete_files( tw );
#endif /*DEBUG*/
if( tw->tg ) {
im_threadgroup_free( tw->tg );
tw->tg = NULL;
}
if( tw->reg ) {
im_region_free( tw->reg );
tw->reg = NULL;
}
if( tw->tif ) {
TIFFClose( tw->tif );
tw->tif = NULL;
}
if( tw->tbuf ) {
im_free( tw->tbuf );
tw->tbuf = NULL;
}
if( tw->layer )
free_pyramid( tw->layer );
if( tw->icc_profile ) {
im_free( tw->icc_profile );
tw->icc_profile = NULL;
}
IM_FREEF( TIFFClose, tw->tif );
IM_FREEF( im_free, tw->tbuf );
IM_FREEF( g_mutex_free, tw->write_lock );
IM_FREEF( free_pyramid, tw->layer );
IM_FREEF( im_free, tw->icc_profile );
}
/* Round N down to P boundary.
@ -1211,8 +1197,6 @@ make_tiff_write( IMAGE *im, const char *filename )
im_filename_split( filename, name, mode );
tw->name = im_strdup( im, name );
tw->mode = im_strdup( im, mode );
tw->tg = NULL;
tw->reg = NULL;
tw->bname = NULL;
tw->tif = NULL;
tw->layer = NULL;
@ -1228,6 +1212,7 @@ make_tiff_write( IMAGE *im, const char *filename )
tw->embed = 0;
tw->icc_profile = NULL;
tw->bigtiff = 0;
tw->write_lock = NULL;
/* Output resolution settings ... default to VIPS-alike.
*/
@ -1434,14 +1419,6 @@ make_tiff_write( IMAGE *im, const char *filename )
tw->compression = COMPRESSION_NONE;
}
/* Make region and threadgroup.
*/
if( !(tw->reg = im_region_create( tw->im )) ||
!(tw->tg = im_threadgroup_create( tw->im )) ) {
free_tiff_write( tw );
return( NULL );
}
/* Sizeof a line of bytes in the TIFF tile.
*/
if( im->Coding == IM_CODING_LABQ )
@ -1766,20 +1743,10 @@ im_vips2tiff( IMAGE *in, const char *filename )
}
if( tw->tile ) {
/* The strip writer uses wbuffer and does start/end for us, we
* have our own loop for tile writing and so we need to call
* ourselves.
*/
if( im__start_eval( in ) ) {
free_tiff_write( tw );
return( -1 );
}
res = write_tif_tile( tw );
im__end_eval( in );
}
if( tw->tile )
res = write_tif_tilewise( tw );
else
res = write_tif_strip( tw );
res = write_tif_stripwise( tw );
if( res ) {
free_tiff_write( tw );
return( -1 );

View File

@ -133,6 +133,10 @@ typedef int (*VipsStop)( void *seq, void *a, void *b );
int vips_sink( VipsImage *im,
VipsStart start, VipsGenerate generate, VipsStop stop,
void *a, void *b );
int vips_sink_tile( VipsImage *im,
int tile_width, int tile_height,
VipsStart start, VipsGenerate generate, VipsStop stop,
void *a, void *b );
typedef void (*VipsSinkNotify)( VipsImage *im, Rect *rect, void *a );
int vips_sink_screen( VipsImage *in, VipsImage *out, VipsImage *mask,

View File

@ -301,8 +301,10 @@ sink_progress( void *a )
}
/**
* vips_sink:
* vips_sink_tile:
* @im: scan over this image
* @tile_width: tile width
* @tile_height: tile height
* @start: start sequences with this function
* @generate: generate pixels with this function
* @stop: stop sequences with this function
@ -310,15 +312,23 @@ sink_progress( void *a )
* @b: user data
*
* Loops over an image. @generate is called for every pixel in the image, with
* the @reg argument being a region of pixels for processing. vips_sink() is
* the @reg argument being a region of pixels for processing.
* vips_sink_tile() is
* used to implement operations like im_avg() which have no image output.
*
* See also: im_generate(), im_open().
* Each set of
* pixels is @tile_width by @tile_height pixels (less at the image edges).
* This is handy for things like
* writing a tiled TIFF image, where tiles have to be generated with a certain
* size.
*
* See also: vips_sink(), vips_get_tile_size().
*
* Returns: 0 on success, or -1 on error.
*/
int
vips_sink( VipsImage *im,
vips_sink_tile( VipsImage *im,
int tile_width, int tile_height,
VipsStart start, VipsGenerate generate, VipsStop stop,
void *a, void *b )
{
@ -335,6 +345,11 @@ vips_sink( VipsImage *im,
if( sink_init( &sink, im, start, generate, stop, a, b ) )
return( -1 );
if( tile_width > 0 ) {
sink.tile_width = tile_width;
sink.tile_height = tile_height;
}
if( im__start_eval( sink.t ) ) {
sink_free( &sink );
return( -1 );
@ -353,3 +368,31 @@ vips_sink( VipsImage *im,
return( result );
}
/**
* vips_sink:
* @im: scan over this image
* @start: start sequences with this function
* @generate: generate pixels with this function
* @stop: stop sequences with this function
* @a: user data
* @b: user data
*
* Loops over an image. @generate is called for every pixel in the image, with
* the @reg argument being a region of pixels for processing. vips_sink() is
* used to implement operations like im_avg() which have no image output.
*
* Each set of pixels is sized according to the requirements of the image
* pipeline that generated @im.
*
* See also: im_generate(), im_open().
*
* Returns: 0 on success, or -1 on error.
*/
int
vips_sink( VipsImage *im,
VipsStart start, VipsGenerate generate, VipsStop stop,
void *a, void *b )
{
return( vips_sink_tile( im, -1, -1, start, generate, stop, a, b ) );
}

View File

@ -516,14 +516,7 @@ vips_sink_disc( VipsImage *im, VipsRegionWrite write_fn, void *a )
write_init( &write, im, write_fn, a );
printf( "initing thread state\n" );
vips_thread_state_get_type();
printf( "made thread state\n" );
result = 0;
if( !write.buf ||
!write.buf_back ||
wbuffer_position( write.buf, 0, write.nlines ) ||