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 @@
+
+
+
+
+
+
+ Cite3libvips
+
+
+ CiteReferences 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 imagevips_extract_area(), vips_crop()
+
+ smartcrop
+ extract an area from an image
+ vips_smartcrop()
+extract_bandextract band from an image
@@ -591,6 +596,16 @@
make a fractal surfacevips_fractsurf()
+
+ worley
+ make a worley noise image
+ vips_worley()
+
+
+ perlin
+ make a perlin noise image
+ vips_perlin()
+radloadload a Radiance image from a file
@@ -761,6 +776,11 @@
save image to deep zoom formatvips_dzsave()
+
+ dzsave_buffer
+ save image to dz buffer
+ vips_dzsave_buffer()
+pngsavesave image to png file
@@ -801,6 +821,11 @@
save image to tiff filevips_tiffsave()
+
+ tiffsave_buffer
+ save image to tiff buffer
+ vips_tiffsave_buffer()
+fitssavesave image to fits file
@@ -836,6 +861,16 @@
reduce an imagevips_reduce()
+
+ thumbnail
+ generate thumbnail from file
+ vips_thumbnail()
+
+
+ thumbnail_buffer
+ generate thumbnail from buffer
+ vips_thumbnail_buffer()
+mapimresample an image with an arbitrary warp
@@ -971,6 +1006,11 @@
convert an sRGB image to scRGBvips_sRGB2scRGB()
+
+ scRGB2BW
+ convert scRGB to BW
+ vips_scRGB2BW()
+scRGB2sRGBconvert an scRGB image to sRGB
@@ -1066,6 +1106,21 @@
convolution operationvips_conv()
+
+ conva
+ approximate integer convolution
+ vips_conva()
+
+
+ convf
+ float convolution operation
+ vips_convf()
+
+
+ convi
+ int convolution operation
+ vips_convi()
+compassconvolve with rotating mask
@@ -1076,6 +1131,11 @@
seperable convolution operationvips_convsep()
+
+ convasep
+ approximate separable integer convolution
+ vips_convasep()
+fastcorfast 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 ... "