diff --git a/ChangeLog b/ChangeLog index 1ee76505..8137cf60 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,12 @@ 15/4/17 started 8.6.0 - supports fits images with leading non-image HDUs, thanks benepo +23/4/17 started 8.5.5 +- doc polishing + +23/4/17 started 8.5.4 +- don't depend on image width when setting n_lines, thanks kleisauke + 7/4/17 started 8.5.3 - more link fixing in docs - revise cache sizing again to help out of order errors under heavy load, thanks @@ -131,7 +137,6 @@ 18/5/16 started 8.3.2 - more robust vips image reading - more robust tiff read [Matt Richards] ->>>>>>> master 15/4/16 started 8.3.1 - rename vips wrapper script, it was still vips-8.2, thanks Benjamin diff --git a/configure.ac b/configure.ac index 15d088c5..f5c2755c 100644 --- a/configure.ac +++ b/configure.ac @@ -38,7 +38,7 @@ VIPS_VERSION_STRING=$VIPS_VERSION-`date` # binary interface changes not backwards compatible?: reset age to 0 LIBRARY_CURRENT=49 -LIBRARY_REVISION=4 +LIBRARY_REVISION=5 LIBRARY_AGE=7 # patched into include/vips/version.h diff --git a/doc/Cite.xml b/doc/Cite.xml new file mode 100644 index 00000000..94588c68 --- /dev/null +++ b/doc/Cite.xml @@ -0,0 +1,21 @@ + + + + + + + Cite 3 libvips + + + Cite References to cite for libvips + + + Martinez, K. and Cupitt, J. (2005) VIPS – a highly tuned image processing software architecture. In Proceedings of IEEE International Conference on Image Processing 2, pp. 574-577, Genova. + + + Cupitt, J. and Martinez, K. (1996) VIPS: An image processing system for large images, Proc. SPIE, vol. 2663, pp. 19–28. + + + + diff --git a/doc/Using-vipsthumbnail.md b/doc/Using-vipsthumbnail.md index 09428ea6..1ba6e9b3 100644 --- a/doc/Using-vipsthumbnail.md +++ b/doc/Using-vipsthumbnail.md @@ -17,10 +17,10 @@ The thumbnailing functionality is implemented by `vips_thumbnail()` and see the docs for details. You can use these functions from any language with a libvips binding. For example, from PHP you could write: -```php -$filename = ...; +```php?start_inline=1 +$filename = "image.jpg"; $image = Vips\Image::thumbnail($filename, 200, ["height" => 200]); -$image.writeToFile("my-thumbnail.jpg"); +$image->writeToFile("my-thumbnail.jpg"); ``` # libvips options diff --git a/doc/Using-vipsthumbnail.xml b/doc/Using-vipsthumbnail.xml index 71d62f62..4d51cf56 100644 --- a/doc/Using-vipsthumbnail.xml +++ b/doc/Using-vipsthumbnail.xml @@ -16,10 +16,10 @@ The thumbnailing functionality is implemented by vips_thumbnail() and vips_thumbnail_buffer() (which thumbnails an image held as a string), see the docs for details. You can use these functions from any language with a libvips binding. For example, from PHP you could write: - -$filename = ...; + +$filename = "image.jpg"; $image = Vips\Image::thumbnail($filename, 200, ["height" => 200]); -$image.writeToFile("my-thumbnail.jpg"); +$image->writeToFile("my-thumbnail.jpg"); libvips options @@ -115,7 +115,7 @@ $ vipsthumbnail owl.jpg --smartcrop attention -s 128 Linear light - Shrinking images involves combining many pixels into one. Arithmetic averaging really ought to be in terms of the number of photons, but (for historical reasons) the values stored in image files are usually related to the voltage that should be applied to a CRT electron gun. + Shrinking images involves combining many pixels into one. Arithmetic averaging really ought to be in terms of the number of photons, but (for historical reasons) the values stored in image files are usually related to the voltage that should be applied to the electron gun in a CRT display. vipsthumbnail has an option to perform image shrinking in linear space, that is, a colourspace where values are proportional to photon numbers. For example: diff --git a/doc/function-list.xml b/doc/function-list.xml index 8a1d1864..70557baa 100644 --- a/doc/function-list.xml +++ b/doc/function-list.xml @@ -328,6 +328,11 @@ extract an area from an image vips_extract_area(), vips_crop() + + smartcrop + extract an area from an image + vips_smartcrop() + extract_band extract band from an image @@ -591,6 +596,16 @@ make a fractal surface vips_fractsurf() + + worley + make a worley noise image + vips_worley() + + + perlin + make a perlin noise image + vips_perlin() + radload load a Radiance image from a file @@ -761,6 +776,11 @@ save image to deep zoom format vips_dzsave() + + dzsave_buffer + save image to dz buffer + vips_dzsave_buffer() + pngsave save image to png file @@ -801,6 +821,11 @@ save image to tiff file vips_tiffsave() + + tiffsave_buffer + save image to tiff buffer + vips_tiffsave_buffer() + fitssave save image to fits file @@ -836,6 +861,16 @@ reduce an image vips_reduce() + + thumbnail + generate thumbnail from file + vips_thumbnail() + + + thumbnail_buffer + generate thumbnail from buffer + vips_thumbnail_buffer() + mapim resample an image with an arbitrary warp @@ -971,6 +1006,11 @@ convert an sRGB image to scRGB vips_sRGB2scRGB() + + scRGB2BW + convert scRGB to BW + vips_scRGB2BW() + scRGB2sRGB convert an scRGB image to sRGB @@ -1066,6 +1106,21 @@ convolution operation vips_conv() + + conva + approximate integer convolution + vips_conva() + + + convf + float convolution operation + vips_convf() + + + convi + int convolution operation + vips_convi() + compass convolve with rotating mask @@ -1076,6 +1131,11 @@ seperable convolution operation vips_convsep() + + convasep + approximate separable integer convolution + vips_convasep() + fastcor fast correlation diff --git a/doc/gen-function-list.py b/doc/gen-function-list.py index 3573b62a..5856bd3e 100755 --- a/doc/gen-function-list.py +++ b/doc/gen-function-list.py @@ -11,6 +11,8 @@ # vips_gamma() # +import gi +gi.require_version('Vips', '8.0') from gi.repository import Vips, GObject vips_type_operation = GObject.GType.from_name("VipsOperation") diff --git a/doc/using-C.xml b/doc/using-C.xml index b9315bd1..e6c3e4c4 100644 --- a/doc/using-C.xml +++ b/doc/using-C.xml @@ -155,6 +155,12 @@ operation flags: sequential-unbuffered See #VipsOperation for more information on running operations on images. + + The API docs have a handy table of all vips + operations, if you want to find out how to do something, try + searching that. + + When you are done, you can write the final image to a disc file, to a formatted memory buffer, or to diff --git a/doc/using-command-line.xml b/doc/using-command-line.xml index 828fc256..73c42504 100644 --- a/doc/using-command-line.xml +++ b/doc/using-command-line.xml @@ -71,6 +71,12 @@ VipsOperation (operation), operations VipsForeign will show some of the extra flags supported by the file load/save operations. + + + The API docs have a handy table of all vips + operations, if you want to find out how to do something, try + searching that. + diff --git a/doc/using-cpp.xml b/doc/using-cpp.xml index 9cbe9e15..e739e176 100644 --- a/doc/using-cpp.xml +++ b/doc/using-cpp.xml @@ -219,6 +219,12 @@ VImage VImage::add( VImage right, VOption *options = 0 ); you can write to a memory array, to a formatted image in memory, or to another image. + + + The API docs have a handy table of all vips + operations, if you want to find out how to do something, try + searching that. + diff --git a/libvips/conversion/sequential.c b/libvips/conversion/sequential.c index 69f2b048..508269c5 100644 --- a/libvips/conversion/sequential.c +++ b/libvips/conversion/sequential.c @@ -117,8 +117,10 @@ vips_sequential_generate( VipsRegion *or, VipsRect *r = &or->valid; VipsRegion *ir = (VipsRegion *) seq; - VIPS_DEBUG_MSG_GREEN( "thread %p request for line %d, height %d\n", - g_thread_self(), r->top, r->height ); + if( sequential->trace ) + printf( "vips_sequential_generate %p: " + "request for line %d, height %d\n", + sequential, r->top, r->height ); VIPS_GATE_START( "vips_sequential_generate: wait" ); @@ -141,9 +143,10 @@ vips_sequential_generate( VipsRegion *or, */ VipsRect area; - VIPS_DEBUG_MSG_GREEN( "thread %p skipping to line %d ...\n", - g_thread_self(), - r->top ); + if( sequential->trace ) + printf( "vips_sequential_generate %p: " + "skipping to line %d ...\n", + sequential, r->top ); area.left = 0; area.top = sequential->y_pos; @@ -236,7 +239,6 @@ vips_sequential_class_init( VipsSequentialClass *class ) G_STRUCT_OFFSET( VipsSequential, tile_height ), 1, 1000000, 1 ); - VIPS_ARG_ENUM( class, "access", 6, _( "Strategy" ), _( "Expected access pattern" ), @@ -259,6 +261,7 @@ vips_sequential_init( VipsSequential *sequential ) sequential->lock = vips_g_mutex_new(); sequential->tile_height = 1; sequential->error = 0; + sequential->trace = FALSE; } /** diff --git a/libvips/include/vips/threadpool.h b/libvips/include/vips/threadpool.h index add66565..8adb97b2 100644 --- a/libvips/include/vips/threadpool.h +++ b/libvips/include/vips/threadpool.h @@ -88,6 +88,11 @@ typedef struct _VipsThreadState { */ void *a; + /* Set in allocate to stall this thread for a moment. Handy for + * debugging race conditions. + */ + gboolean stall; + } VipsThreadState; typedef struct _VipsThreadStateClass { diff --git a/libvips/iofuncs/sinkdisc.c b/libvips/iofuncs/sinkdisc.c index 30f2134b..b0ac977e 100644 --- a/libvips/iofuncs/sinkdisc.c +++ b/libvips/iofuncs/sinkdisc.c @@ -331,6 +331,10 @@ wbuffer_allocate_fn( VipsThreadState *state, void *a, gboolean *stop ) sink_base->y += sink_base->tile_height; if( sink_base->y >= VIPS_RECT_BOTTOM( &write->buf->area ) ) { + VIPS_DEBUG_MSG( "wbuffer_allocate_fn: " + "finished top = %d, height = %d\n", + write->buf->area.top, write->buf->area.height ); + /* Block until the write of the previous buffer * is done, then set write of this buffer going. */ @@ -346,10 +350,6 @@ wbuffer_allocate_fn( VipsThreadState *state, void *a, gboolean *stop ) return( 0 ); } - VIPS_DEBUG_MSG( "wbuffer_allocate_fn: " - "finished top = %d, height = %d\n", - write->buf->area.top, write->buf->area.height ); - VIPS_DEBUG_MSG( "wbuffer_allocate_fn: " "starting top = %d, height = %d\n", sink_base->y, sink_base->nlines ); @@ -365,6 +365,11 @@ wbuffer_allocate_fn( VipsThreadState *state, void *a, gboolean *stop ) *stop = TRUE; return( -1 ); } + + /* This will be the first tile of a new buffer ... + * stall for a moment to stress the caching system. + */ + state->stall = TRUE; } } diff --git a/libvips/iofuncs/threadpool.c b/libvips/iofuncs/threadpool.c index ef74a7fa..149c0de3 100644 --- a/libvips/iofuncs/threadpool.c +++ b/libvips/iofuncs/threadpool.c @@ -18,6 +18,9 @@ * 6/3/17 * - remove single-thread-first-request thing, new seq system makes it * unnecessary + * 23/4/17 + * - add ->stall + * - don't depend on image width when setting n_lines */ /* @@ -111,6 +114,10 @@ int vips__n_active_threads = 0; */ static GPrivate *is_worker_key = NULL; +/* Set to stall threads for debugging. + */ +static gboolean vips__stall = FALSE; + /* Glib 2.32 revised the thread API. We need some compat functions. */ @@ -466,6 +473,7 @@ vips_thread_state_init( VipsThreadState *state ) state->reg = NULL; state->stop = FALSE; + state->stall = FALSE; } void * @@ -634,6 +642,17 @@ vips_thread_work_unit( VipsThread *thr ) g_mutex_unlock( pool->allocate_lock ); + if( thr->state->stall && + vips__stall ) { + /* Sleep for 0.5s. Handy for stressing the seq system. Stall + * is set by allocate funcs in various places. + */ + g_usleep( 500000 ); + thr->state->stall = FALSE; + printf( "vips_thread_work_unit: " + "stall done, releasing y = %d ...\n", thr->state->y ); + } + /* Process a work unit. */ if( pool->work( thr->state, pool->a ) ) { @@ -999,6 +1018,9 @@ vips__threadpool_init( void ) if( !is_worker_key ) is_worker_key = g_private_new( NULL ); #endif + + if( g_getenv( "VIPS_STALL" ) ) + vips__stall = TRUE; } /** @@ -1021,6 +1043,7 @@ vips_get_tile_size( VipsImage *im, int *tile_width, int *tile_height, int *n_lines ) { const int nthr = vips_concurrency_get(); + const int typical_image_width = 1000; /* Compiler warnings. */ @@ -1054,11 +1077,15 @@ vips_get_tile_size( VipsImage *im, * the pipeline might see a different hint and we need to synchronise * buffer sizes everywhere. * + * We also can't depend on the current image size, since that might + * change down the pipeline too. Pick a typical image width. + * * Pick the maximum buffer size we might possibly need, then round up * to a multiple of tileheight. */ *n_lines = vips__tile_height * - VIPS_ROUND_UP( vips__tile_width * nthr, im->Xsize ) / im->Xsize; + VIPS_ROUND_UP( vips__tile_width * nthr, typical_image_width ) / + typical_image_width; *n_lines = VIPS_MAX( *n_lines, vips__fatstrip_height * nthr ); *n_lines = VIPS_MAX( *n_lines, vips__thinstrip_height * nthr ); *n_lines = VIPS_ROUND_UP( *n_lines, *tile_height ); diff --git a/libvips/resample/reducev.cpp b/libvips/resample/reducev.cpp index fae1ca40..42b31533 100644 --- a/libvips/resample/reducev.cpp +++ b/libvips/resample/reducev.cpp @@ -835,8 +835,6 @@ vips_reducev_build( VipsObject *object ) if( VIPS_OBJECT_CLASS( vips_reducev_parent_class )->build( object ) ) return( -1 ); - g_info( "reducev by factor %g", reducev->vshrink ); - in = resample->in; if( reducev->vshrink < 1 ) { @@ -895,6 +893,7 @@ vips_reducev_build( VipsObject *object ) if( vips_sequential( in, &t[3], "tile_height", 10, + // "trace", TRUE, NULL ) ) return( -1 ); in = t[3]; diff --git a/test/test_python.sh b/test/test_python.sh index e361d4f2..8d996d59 100755 --- a/test/test_python.sh +++ b/test/test_python.sh @@ -25,3 +25,7 @@ Darwin) esac $PYTHON -m unittest -v test_all + +echo rerunning with VIPS_STALL enabled ... +export VIPS_STALL=1 +$PYTHON -m unittest -v test_all diff --git a/test/test_thumbnail.sh b/test/test_thumbnail.sh index 73912e8c..28927677 100755 --- a/test/test_thumbnail.sh +++ b/test/test_thumbnail.sh @@ -24,6 +24,9 @@ break_threshold() { return $(echo "$diff > $threshold" | bc -l) } +# run the test with VIPS_STALL enabled to stress the seq system +export VIPS_STALL=1 + size=1000 while [ $size -gt 99 ]; do printf "testing size to $size ... "