From bf9fc7f855d6a49829aa34ab01dfb5399f9e21d2 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Wed, 22 Jan 2014 10:02:38 +0000 Subject: [PATCH 01/29] auto-unpack RAD in affine --- ChangeLog | 3 +++ configure.ac | 6 +++--- libvips/resample/affine.c | 15 +++++++++++---- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index 344903d4..d3177013 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,6 @@ +22/1/14 started 7.38.2 +- auto RAD decode for affine + 19/1/14 started 7.38.1 - bump soname, thanks benjamin - better conversion to and from scrgb/xyz for rad (hdr) diff --git a/configure.ac b/configure.ac index e314ed56..0850b6bc 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ # also update the version number in the m4 macros below -AC_INIT([vips], [7.38.1], [vipsip@jiscmail.ac.uk]) +AC_INIT([vips], [7.38.2], [vipsip@jiscmail.ac.uk]) # required for gobject-introspection AC_PREREQ(2.62) @@ -17,7 +17,7 @@ AC_CONFIG_MACRO_DIR([m4]) # user-visible library versioning m4_define([vips_major_version], [7]) m4_define([vips_minor_version], [38]) -m4_define([vips_micro_version], [1]) +m4_define([vips_micro_version], [2]) m4_define([vips_version], [vips_major_version.vips_minor_version.vips_micro_version]) @@ -37,7 +37,7 @@ VIPS_VERSION_STRING=$VIPS_VERSION-`date` # binary interface changes not backwards compatible?: reset age to 0 LIBRARY_CURRENT=37 -LIBRARY_REVISION=0 +LIBRARY_REVISION=1 LIBRARY_AGE=0 # patched into include/vips/version.h diff --git a/libvips/resample/affine.c b/libvips/resample/affine.c index a8988f3e..44d15b60 100644 --- a/libvips/resample/affine.c +++ b/libvips/resample/affine.c @@ -79,6 +79,8 @@ * 14/12/12 * - redone as a class * - added input space translation + * 22/1/14 + * - auto RAD decode */ /* @@ -392,7 +394,7 @@ vips_affine_build( VipsObject *object ) if( VIPS_OBJECT_CLASS( vips_affine_parent_class )->build( object ) ) return( -1 ); - if( vips_check_coding_noneorlabq( class->nickname, resample->in ) ) + if( vips_check_coding_known( class->nickname, resample->in ) ) return( -1 ); if( vips_check_vector_length( class->nickname, affine->matrix->n, 4 ) ) @@ -463,23 +465,28 @@ vips_affine_build( VipsObject *object ) return( -1 ); } - /* Unpack labq for processing. + /* Unpack for processing. */ if( in->Coding == VIPS_CODING_LABQ ) { if( vips_LabQ2LabS( in, &t[0], NULL ) ) return( -1 ); in = t[0]; + } + else if( in->Coding == VIPS_CODING_RAD ) { + if( vips_rad2float( in, &t[1], NULL ) ) + return( -1 ); + in = t[1]; } /* Add new pixels around the input so we can interpolate at the edges. */ - if( vips_embed( in, &t[1], + if( vips_embed( in, &t[2], window_offset, window_offset, in->Xsize + window_size, in->Ysize + window_size, "extend", VIPS_EXTEND_COPY, NULL ) ) return( -1 ); - in = t[1]; + in = t[2]; /* Normally SMALLTILE ... except if this is a size up/down affine. */ From 2f9cc275e6e8e740c01b8a4a62ef54a9d68439cf Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Wed, 22 Jan 2014 10:03:55 +0000 Subject: [PATCH 02/29] TODO notes --- TODO | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/TODO b/TODO index 701fda57..47904de6 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,21 @@ +- shrink does not auto unpack labq or rad, should it? + +- others .. differences in: + +grep -l CODING_LABQ */*.c +conversion/join.c +conversion/msb.c +inplace/im_draw_mask.c +resample/shrink.c + +grep -l CODING_RAD */*.c +conversion/embed.c +inplace/flood.c +inplace/im_draw_image.c + + + + - need to do mosaicing and inplace, plus im_label_regions in morph From 4ac08bc2d684137c94d92e85a5cc36703ddee6c7 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Wed, 22 Jan 2014 13:26:59 +0000 Subject: [PATCH 03/29] add some auto unpack stuff so RAD etc get unpacked automatically --- TODO | 21 +++++++++++++++++++++ libvips/convolution/conv.c | 17 ++++++++++++++--- libvips/include/vips/internal.h | 2 ++ libvips/resample/affine.c | 30 ++++++++++++++++++++++++------ libvips/resample/shrink.c | 26 +++++++++++++++++++------- 5 files changed, 80 insertions(+), 16 deletions(-) diff --git a/TODO b/TODO index 701fda57..32b3a8bf 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,24 @@ +- shrink does not auto unpack labq or rad, should it? + +- others .. differences in: + +grep -l CODING_LABQ */*.c +conversion/join.c +conversion/msb.c +inplace/im_draw_mask.c +resample/shrink.c + +grep -l CODING_RAD */*.c +conversion/embed.c +inplace/flood.c +inplace/im_draw_image.c + +- add unpack everywhere, eg. arithmetic + + + + +- move vips__image_decode() into the public API - need to do mosaicing and inplace, plus im_label_regions in morph diff --git a/libvips/convolution/conv.c b/libvips/convolution/conv.c index 441cb550..3608b031 100644 --- a/libvips/convolution/conv.c +++ b/libvips/convolution/conv.c @@ -65,7 +65,10 @@ vips_conv_build( VipsObject *object ) VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); VipsConvolution *convolution = (VipsConvolution *) object; VipsConv *conv = (VipsConv *) object; + VipsImage **t = (VipsImage **) + vips_object_local_array( object, 4 ); + VipsImage *in; INTMASK *imsk; DOUBLEMASK *dmsk; @@ -74,6 +77,8 @@ vips_conv_build( VipsObject *object ) if( VIPS_OBJECT_CLASS( vips_conv_parent_class )->build( object ) ) return( -1 ); + in = convolution->in; + /* printf( "vips_conv_build: convolving with:\n" ); vips_matrixprint( convolution->M, NULL ); @@ -86,19 +91,25 @@ vips_conv_build( VipsObject *object ) !im_local_dmask( convolution->out, dmsk ) ) return( -1 ); + /* Unpack for processing. + */ + if( vips__image_decode( in, &t[0] ) ) + return( -1 ); + in = t[0]; + switch( conv->precision ) { case VIPS_PRECISION_INTEGER: - if( im_conv( convolution->in, convolution->out, imsk ) ) + if( im_conv( in, convolution->out, imsk ) ) return( -1 ); break; case VIPS_PRECISION_FLOAT: - if( im_conv_f( convolution->in, convolution->out, dmsk ) ) + if( im_conv_f( in, convolution->out, dmsk ) ) return( -1 ); break; case VIPS_PRECISION_APPROXIMATE: - if( im_aconv( convolution->in, convolution->out, dmsk, + if( im_aconv( in, convolution->out, dmsk, conv->layers, conv->cluster ) ) return( -1 ); break; diff --git a/libvips/include/vips/internal.h b/libvips/include/vips/internal.h index 39c233b6..e29d64df 100644 --- a/libvips/include/vips/internal.h +++ b/libvips/include/vips/internal.h @@ -297,6 +297,8 @@ IMAGE *vips__deprecated_open_write( const char *filename ); int vips__input_interpolate_init( im_object *obj, char *str ); +int vips__image_decode( VipsImage *in, VipsImage **out ); + #ifdef __cplusplus } #endif /*__cplusplus*/ diff --git a/libvips/resample/affine.c b/libvips/resample/affine.c index a8988f3e..c8e325f1 100644 --- a/libvips/resample/affine.c +++ b/libvips/resample/affine.c @@ -373,13 +373,33 @@ vips_affine_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop ) return( 0 ); } +/* Unpack to a format that we can compute with. + */ +int +vips__image_decode( VipsImage *in, VipsImage **out ) +{ + if( in->Coding == VIPS_CODING_LABQ ) { + if( vips_LabQ2LabS( in, out, NULL ) ) + return( -1 ); + } + else if( in->Coding == VIPS_CODING_RAD ) { + if( vips_rad2float( in, out, NULL ) ) + return( -1 ); + } + else { + if( vips_copy( in, out, NULL ) ) + return( -1 ); + } + + return( 0 ); +} + static int vips_affine_build( VipsObject *object ) { VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); VipsResample *resample = VIPS_RESAMPLE( object ); VipsAffine *affine = (VipsAffine *) object; - VipsImage **t = (VipsImage **) vips_object_local_array( object, 4 ); @@ -465,11 +485,9 @@ vips_affine_build( VipsObject *object ) /* Unpack labq for processing. */ - if( in->Coding == VIPS_CODING_LABQ ) { - if( vips_LabQ2LabS( in, &t[0], NULL ) ) - return( -1 ); - in = t[0]; - } + if( vips__image_decode( in, &t[0] ) ) + return( -1 ); + in = t[0]; /* Add new pixels around the input so we can interpolate at the edges. */ diff --git a/libvips/resample/shrink.c b/libvips/resample/shrink.c index d15731e7..f70b4ded 100644 --- a/libvips/resample/shrink.c +++ b/libvips/resample/shrink.c @@ -310,6 +310,10 @@ vips_shrink_build( VipsObject *object ) VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); VipsResample *resample = VIPS_RESAMPLE( object ); VipsShrink *shrink = (VipsShrink *) object; + VipsImage **t = (VipsImage **) + vips_object_local_array( object, 1 ); + + VipsImage *in; if( VIPS_OBJECT_CLASS( vips_shrink_parent_class )->build( object ) ) return( -1 ); @@ -318,7 +322,9 @@ vips_shrink_build( VipsObject *object ) shrink->mh = ceil( shrink->yshrink ); shrink->np = shrink->mw * shrink->mh; - if( vips_check_noncomplex( class->nickname, resample->in ) ) + in = resample->in; + + if( vips_check_noncomplex( class->nickname, in ) ) return( -1 ); if( shrink->xshrink < 1.0 || @@ -336,14 +342,20 @@ vips_shrink_build( VipsObject *object ) if( shrink->xshrink == 1.0 && shrink->yshrink == 1.0 ) - return( vips_image_write( resample->in, resample->out ) ); + return( vips_image_write( in, resample->out ) ); + + /* Unpack for processing. + */ + if( vips__image_decode( in, &t[0] ) ) + return( -1 ); + in = t[0]; /* THINSTRIP will work, anything else will break seq mode. If you * combine shrink with conv you'll need to use a line cache to maintain * sequentiality. */ if( vips_image_pipelinev( resample->out, - VIPS_DEMAND_STYLE_THINSTRIP, resample->in, NULL ) ) + VIPS_DEMAND_STYLE_THINSTRIP, in, NULL ) ) return( -1 ); /* Size output. Note: we round the output width down! @@ -352,8 +364,8 @@ vips_shrink_build( VipsObject *object ) * example, vipsthumbnail knows the true shrink factor (including the * fractional part), we just see the integer part here. */ - resample->out->Xsize = resample->in->Xsize / shrink->xshrink; - resample->out->Ysize = resample->in->Ysize / shrink->yshrink; + resample->out->Xsize = in->Xsize / shrink->xshrink; + resample->out->Ysize = in->Ysize / shrink->yshrink; if( resample->out->Xsize <= 0 || resample->out->Ysize <= 0 ) { vips_error( class->nickname, @@ -363,7 +375,7 @@ vips_shrink_build( VipsObject *object ) #ifdef DEBUG printf( "vips_shrink_build: shrinking %d x %d image to %d x %d\n", - resample->in->Xsize, resample->in->Ysize, + in->Xsize, in->Ysize, resample->out->Xsize, resample->out->Ysize ); printf( "vips_shrink_build: %d x %d block average\n", shrink->mw, shrink->mh ); @@ -371,7 +383,7 @@ vips_shrink_build( VipsObject *object ) if( vips_image_generate( resample->out, vips_shrink_start, vips_shrink_gen, vips_shrink_stop, - resample->in, shrink ) ) + in, shrink ) ) return( -1 ); return( 0 ); From d0594318672f3acb6b4a61fa0a6fe12928a9a58a Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Wed, 22 Jan 2014 14:53:48 +0000 Subject: [PATCH 04/29] more auto-decode stuff more to do though --- TODO | 5 +++++ libvips/arithmetic/arithmetic.c | 17 +++++++++++------ libvips/arithmetic/linear.c | 16 +++++++++++++++- libvips/convolution/conv.c | 1 + libvips/morphology/morph.c | 16 ++++++++++++---- libvips/morphology/rank.c | 12 ++++++++---- libvips/resample/shrink.c | 1 + 7 files changed, 53 insertions(+), 15 deletions(-) diff --git a/TODO b/TODO index 32b3a8bf..c1c3f7ae 100644 --- a/TODO +++ b/TODO @@ -15,6 +15,11 @@ inplace/im_draw_image.c - add unpack everywhere, eg. arithmetic + look for + + vips_check_uncoded + + certainly can use it there diff --git a/libvips/arithmetic/arithmetic.c b/libvips/arithmetic/arithmetic.c index bf631dea..a8aea1de 100644 --- a/libvips/arithmetic/arithmetic.c +++ b/libvips/arithmetic/arithmetic.c @@ -51,6 +51,7 @@ #include #include +#include #include "parithmetic.h" @@ -500,6 +501,7 @@ vips_arithmetic_build( VipsObject *object ) VipsArithmetic *arithmetic = VIPS_ARITHMETIC( object ); VipsArithmeticClass *aclass = VIPS_ARITHMETIC_GET_CLASS( arithmetic ); + VipsImage **decode; VipsImage **format; VipsImage **band; VipsImage **size; @@ -524,12 +526,9 @@ vips_arithmetic_build( VipsObject *object ) "%s", _( "too many input images" ) ); return( -1 ); } - for( i = 0; i < arithmetic->n; i++ ) - if( vips_image_pio_input( arithmetic->in[i] ) || - vips_check_uncoded( class->nickname, - arithmetic->in[i] ) ) - return( -1 ); + decode = (VipsImage **) + vips_object_local_array( object, arithmetic->n ); format = (VipsImage **) vips_object_local_array( object, arithmetic->n ); band = (VipsImage **) @@ -537,9 +536,15 @@ vips_arithmetic_build( VipsObject *object ) size = (VipsImage **) vips_object_local_array( object, arithmetic->n ); + /* Decode RAD/LABQ etc. + */ + for( i = 0; i < arithmetic->n; i++ ) + if( vips__image_decode( arithmetic->in[i], &decode[i] ) ) + return( -1 ); + /* Cast our input images up to a common format, bands and size. */ - if( vips__formatalike_vec( arithmetic->in, format, arithmetic->n ) || + if( vips__formatalike_vec( decode, format, arithmetic->n ) || vips__bandalike_vec( class->nickname, format, band, arithmetic->n, arithmetic->base_bands ) || vips__sizealike_vec( band, size, arithmetic->n ) ) diff --git a/libvips/arithmetic/linear.c b/libvips/arithmetic/linear.c index 26ee9d48..a44b296b 100644 --- a/libvips/arithmetic/linear.c +++ b/libvips/arithmetic/linear.c @@ -122,8 +122,22 @@ vips_linear_build( VipsObject *object ) VipsUnary *unary = (VipsUnary *) object; VipsLinear *linear = (VipsLinear *) object; + int bands; int i; + /* How many bands will our input image have after decoding? + */ + switch( unary->in->Coding ) { + case VIPS_CODING_RAD: + case VIPS_CODING_LABQ: + bands = 3; + break; + + default: + bands = unary->in->Bands; + break; + } + /* If we have a three-element vector we need to bandup the image to * match. */ @@ -133,7 +147,7 @@ vips_linear_build( VipsObject *object ) if( linear->b ) linear->n = VIPS_MAX( linear->n, linear->b->n ); if( unary->in ) - linear->n = VIPS_MAX( linear->n, unary->in->Bands ); + linear->n = VIPS_MAX( linear->n, bands ); arithmetic->base_bands = linear->n; if( unary->in && linear->a && linear->b ) { diff --git a/libvips/convolution/conv.c b/libvips/convolution/conv.c index 3608b031..151a23bb 100644 --- a/libvips/convolution/conv.c +++ b/libvips/convolution/conv.c @@ -44,6 +44,7 @@ #include #include +#include #include "pconvolution.h" diff --git a/libvips/morphology/morph.c b/libvips/morphology/morph.c index 5270a581..8ce26671 100644 --- a/libvips/morphology/morph.c +++ b/libvips/morphology/morph.c @@ -44,6 +44,7 @@ #include #include +#include #include "pmorphology.h" @@ -83,15 +84,22 @@ vips_morph_build( VipsObject *object ) VipsImage **t = (VipsImage **) vips_object_local_array( object, 2 ); INTMASK *imsk; + VipsImage *in; g_object_set( morph, "out", vips_image_new(), NULL ); if( VIPS_OBJECT_CLASS( vips_morph_parent_class )->build( object ) ) return( -1 ); - if( vips_check_matrix( class->nickname, morph->mask, &t[0] ) ) + in = morphology->in; + + if( vips__image_decode( in, &t[0] ) ) + return( -1 ); + in = t[0]; + + if( vips_check_matrix( class->nickname, morph->mask, &t[1] ) ) return( -1 ); - morph->M = t[0]; + morph->M = t[1]; if( !(imsk = im_vips2imask( morph->M, class->nickname )) || !im_local_imask( morph->out, imsk ) ) @@ -99,12 +107,12 @@ vips_morph_build( VipsObject *object ) switch( morph->morph ) { case VIPS_OPERATION_MORPHOLOGY_DILATE: - if( im_dilate( morphology->in, morph->out, imsk ) ) + if( im_dilate( in, morph->out, imsk ) ) return( -1 ); break; case VIPS_OPERATION_MORPHOLOGY_ERODE: - if( im_erode( morphology->in, morph->out, imsk ) ) + if( im_erode( in, morph->out, imsk ) ) return( -1 ); break; diff --git a/libvips/morphology/rank.c b/libvips/morphology/rank.c index fdc47695..b88154a5 100644 --- a/libvips/morphology/rank.c +++ b/libvips/morphology/rank.c @@ -64,6 +64,7 @@ #include #include +#include #include "pmorphology.h" @@ -340,8 +341,11 @@ vips_rank_build( VipsObject *object ) in = morphology->in; - if( vips_check_uncoded( class->nickname, in ) || - vips_check_noncomplex( class->nickname, in ) ) + if( vips__image_decode( in, &t[0] ) ) + return( -1 ); + in = t[0]; + + if( vips_check_noncomplex( class->nickname, in ) ) return( -1 ); if( rank->width > in->Xsize || rank->height > in->Ysize ) { @@ -356,13 +360,13 @@ vips_rank_build( VipsObject *object ) /* Expand the input. */ - if( vips_embed( in, &t[0], + if( vips_embed( in, &t[1], rank->width / 2, rank->height / 2, in->Xsize + rank->width - 1, in->Ysize + rank->height - 1, "extend", VIPS_EXTEND_COPY, NULL ) ) return( -1 ); - in = t[0]; + in = t[1]; g_object_set( object, "out", vips_image_new(), NULL ); diff --git a/libvips/resample/shrink.c b/libvips/resample/shrink.c index f70b4ded..f27e4bf9 100644 --- a/libvips/resample/shrink.c +++ b/libvips/resample/shrink.c @@ -85,6 +85,7 @@ #include #include +#include #include "presample.h" From affb274d858e47dd94e821465cad3b1a8c2c42e4 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Thu, 23 Jan 2014 13:19:37 +0000 Subject: [PATCH 05/29] more auto unpack hacking --- TODO | 52 ++++++++++++++++++++++++++ libvips/arithmetic/hist_find_indexed.c | 2 +- libvips/arithmetic/statistic.c | 21 +++++------ libvips/colour/colour.c | 22 +++-------- libvips/conversion/bandary.c | 12 +++--- libvips/conversion/cast.c | 23 +++++++----- libvips/conversion/falsecolour.c | 10 ++--- 7 files changed, 93 insertions(+), 49 deletions(-) diff --git a/TODO b/TODO index d2bf16ed..733fbad8 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,55 @@ +- try: + + $ vips falsecolour k2.jpg x.jpg + vips warning: VipsJpeg: read gave 896 warnings + vips warning: VipsJpeg: Application transferred too many scanlines + + seems to read twice? + + problem in 7.38 too + +- check_uncoded() left to do: + + conversion/falsecolour.c + conversion/flatten.c + conversion/recomb.c + convolution/sharpen.c + deprecated/im_gradcor.c + deprecated/im_lab_morph.c + deprecated/im_maxpos_avg.c + deprecated/im_measure.c + deprecated/im_vips2mask.c + deprecated/im_zerox.c + deprecated/rename.c + deprecated/tone.c + deprecated/vips7compat.c + foreign/csv.c + foreign/ppm.c + freqfilt/fwfft.c + freqfilt/invfft.c + histogram/hist_local.c + histogram/histogram.c + histogram/hist_plot.c + histogram/maplut.c + histogram/stdif.c + inplace/flood.c + inplace/im_draw_mask.c + inplace/inplace_dispatch.c + iofuncs/error.c + morphology/hitmiss.c + resample/quadratic.c + +- we vips_image_write() a lot, could we do this by + + int + vips_image_write( in, out ) + { + g_object_ref( in) + vips_object_local( out,in ) + } + + i.e. do everything at pipe build time + - inplace can we set a region for the pixels we will modify? diff --git a/libvips/arithmetic/hist_find_indexed.c b/libvips/arithmetic/hist_find_indexed.c index e2632a42..17612e83 100644 --- a/libvips/arithmetic/hist_find_indexed.c +++ b/libvips/arithmetic/hist_find_indexed.c @@ -130,7 +130,7 @@ vips_hist_find_indexed_build( VipsObject *object ) VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); VipsStatistic *statistic = VIPS_STATISTIC( object ); VipsHistFindIndexed *indexed = (VipsHistFindIndexed *) object; - VipsImage **t = (VipsImage **) vips_object_local_array( object, 1 ); + VipsImage **t = (VipsImage **) vips_object_local_array( object, 2 ); g_object_set( object, "out", vips_image_new(), diff --git a/libvips/arithmetic/statistic.c b/libvips/arithmetic/statistic.c index fc340984..1ab1cc2f 100644 --- a/libvips/arithmetic/statistic.c +++ b/libvips/arithmetic/statistic.c @@ -50,6 +50,7 @@ #include #include +#include #include "statistic.h" @@ -109,9 +110,7 @@ vips_statistic_build( VipsObject *object ) { VipsStatistic *statistic = VIPS_STATISTIC( object ); VipsStatisticClass *sclass = VIPS_STATISTIC_GET_CLASS( statistic ); - VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); - const char *domain = class->nickname; - VipsImage **t = (VipsImage **) vips_object_local_array( object, 1 ); + VipsImage **t = (VipsImage **) vips_object_local_array( object, 2 ); #ifdef DEBUG printf( "vips_statistic_build: " ); @@ -122,20 +121,20 @@ vips_statistic_build( VipsObject *object ) if( VIPS_OBJECT_CLASS( vips_statistic_parent_class )->build( object ) ) return( -1 ); + statistic->ready = statistic->in; + + if( vips__image_decode( statistic->ready, &t[0] ) ) + return( -1 ); + statistic->ready = t[0]; + /* If there's a format table, cast the input. */ if( sclass->format_table ) { - if( vips_cast( statistic->in, &t[0], + if( vips_cast( statistic->ready, &t[1], sclass->format_table[statistic->in->BandFmt], NULL ) ) return( -1 ); - statistic->ready = t[0]; + statistic->ready = t[1]; } - else - statistic->ready = statistic->in; - - if( vips_image_pio_input( statistic->ready ) || - vips_check_uncoded( domain, statistic->ready ) ) - return( -1 ); if( vips_sink( statistic->ready, vips_statistic_scan_start, diff --git a/libvips/colour/colour.c b/libvips/colour/colour.c index f313851d..3645dc88 100644 --- a/libvips/colour/colour.c +++ b/libvips/colour/colour.c @@ -627,30 +627,18 @@ vips_colour_difference_build( VipsObject *object ) right = difference->right; extra = NULL; - /* Unpack LABQ images, - */ - if( left && - left->Coding == VIPS_CODING_LABQ ) { - if( vips_LabQ2Lab( left, &t[0], NULL ) ) + if( left ) { + if( vips__image_decode( left, &t[0] ) ) return( -1 ); left = t[0]; } - if( right && - right->Coding == VIPS_CODING_LABQ ) { - if( vips_LabQ2Lab( right, &t[1], NULL ) ) + + if( right ) { + if( vips__image_decode( right, &t[1] ) ) return( -1 ); right = t[1]; } - if( left && - vips_check_uncoded( VIPS_OBJECT_CLASS( class )->nickname, - left ) ) - return( -1 ); - if( right && - vips_check_uncoded( VIPS_OBJECT_CLASS( class )->nickname, - right ) ) - return( -1 ); - /* Detach and reattach extra bands, if any. If both left and right * have extra bands, give up. */ diff --git a/libvips/conversion/bandary.c b/libvips/conversion/bandary.c index 194878c4..06ede11a 100644 --- a/libvips/conversion/bandary.c +++ b/libvips/conversion/bandary.c @@ -123,6 +123,7 @@ vips_bandary_build( VipsObject *object ) VipsBandary *bandary = (VipsBandary *) object; int i; + VipsImage **decode; VipsImage **format; VipsImage **size; @@ -139,14 +140,15 @@ vips_bandary_build( VipsObject *object ) "%s", _( "too many input images" ) ); return( -1 ); } - for( i = 0; i < bandary->n; i++ ) - if( vips_image_pio_input( bandary->in[i] ) || - vips_check_uncoded( class->nickname, bandary->in[i] ) ) - return( -1 ); + decode = (VipsImage **) vips_object_local_array( object, bandary->n ); format = (VipsImage **) vips_object_local_array( object, bandary->n ); size = (VipsImage **) vips_object_local_array( object, bandary->n ); - if( vips__formatalike_vec( bandary->in, format, bandary->n ) || + + for( i = 0; i < bandary->n; i++ ) + if( vips__image_decode( bandary->in[i], &decode[i] ) ) + return( -1 ); + if( vips__formatalike_vec( decode, format, bandary->n ) || vips__sizealike_vec( format, size, bandary->n ) ) return( -1 ); bandary->ready = size; diff --git a/libvips/conversion/cast.c b/libvips/conversion/cast.c index 17384521..9a080fdb 100644 --- a/libvips/conversion/cast.c +++ b/libvips/conversion/cast.c @@ -429,36 +429,41 @@ vips_cast_gen( VipsRegion *or, void *vseq, void *a, void *b, static int vips_cast_build( VipsObject *object ) { - VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); VipsConversion *conversion = VIPS_CONVERSION( object ); VipsCast *cast = (VipsCast *) object; + VipsImage **t = (VipsImage **) + vips_object_local_array( object, 2 ); + + VipsImage *in; if( VIPS_OBJECT_CLASS( vips_cast_parent_class )->build( object ) ) return( -1 ); + in = cast->in; + /* Trivial case: fall back to copy(). */ - if( cast->in->BandFmt == cast->format ) - return( vips_image_write( cast->in, conversion->out ) ); + if( in->BandFmt == cast->format ) + return( vips_image_write( in, conversion->out ) ); - if( vips_check_uncoded( class->nickname, cast->in ) || - vips_image_pio_input( cast->in ) ) + if( vips__image_decode( in, &t[0] ) ) return( -1 ); + in = t[0]; if( vips_image_pipelinev( conversion->out, - VIPS_DEMAND_STYLE_THINSTRIP, cast->in, NULL ) ) + VIPS_DEMAND_STYLE_THINSTRIP, in, NULL ) ) return( -1 ); conversion->out->BandFmt = cast->format; - g_signal_connect( cast->in, "preeval", + g_signal_connect( in, "preeval", G_CALLBACK( vips_cast_preeval ), cast ); - g_signal_connect( cast->in, "posteval", + g_signal_connect( in, "posteval", G_CALLBACK( vips_cast_posteval ), cast ); if( vips_image_generate( conversion->out, vips_cast_start, vips_cast_gen, vips_cast_stop, - cast->in, cast ) ) + in, cast ) ) return( -1 ); return( 0 ); diff --git a/libvips/conversion/falsecolour.c b/libvips/conversion/falsecolour.c index 697c7125..ff03ae39 100644 --- a/libvips/conversion/falsecolour.c +++ b/libvips/conversion/falsecolour.c @@ -329,10 +329,9 @@ static unsigned char vips_falsecolour_pet[][3] = { static int vips_falsecolour_build( VipsObject *object ) { - VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); VipsConversion *conversion = VIPS_CONVERSION( object ); VipsFalsecolour *falsecolour = (VipsFalsecolour *) object; - VipsImage **t = (VipsImage **) vips_object_local_array( object, 4 ); + VipsImage **t = (VipsImage **) vips_object_local_array( object, 5 ); if( VIPS_OBJECT_CLASS( vips_falsecolour_parent_class )-> build( object ) ) @@ -345,10 +344,9 @@ vips_falsecolour_build( VipsObject *object ) /* Force to mono 8-bit. */ - if( vips_check_uncoded( class->nickname, falsecolour->in ) || - vips_extract_band( falsecolour->in, &t[1], 0, NULL ) || - vips_cast( t[1], &t[2], VIPS_FORMAT_UCHAR, NULL ) || - vips_maplut( falsecolour->in, &t[3], t[0], NULL ) || + if( vips_colourspace( falsecolour->in, &t[1], + VIPS_INTERPRETATION_B_W, NULL ) || + vips_maplut( t[1], &t[3], t[0], NULL ) || vips_image_write( t[3], conversion->out ) ) return( -1 ); From 12454d3225d9a6ec07c5167032b8e1e43e31d546 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Thu, 23 Jan 2014 14:19:55 +0000 Subject: [PATCH 06/29] more jpeg read sanity checking --- libvips/foreign/jpeg2vips.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/libvips/foreign/jpeg2vips.c b/libvips/foreign/jpeg2vips.c index 6adc2555..abae4195 100644 --- a/libvips/foreign/jpeg2vips.c +++ b/libvips/foreign/jpeg2vips.c @@ -150,6 +150,10 @@ typedef struct _ReadJpeg { /* Set if we need to finish the decompress. */ gboolean decompressing; + + /* Track the y pos during a read with this. + */ + int y_pos; } ReadJpeg; static int @@ -222,6 +226,8 @@ readjpeg_new( VipsImage *out, int shrink, gboolean fail, gboolean readbehind ) jpeg->eman.pub.output_message = vips__new_output_message; jpeg->eman.fp = NULL; + jpeg->y_pos = 0; + /* jpeg_create_decompress() can fail on some sanity checks. Don't * readjpeg_free() since we don't want to jpeg_destroy_decompress(). */ @@ -907,6 +913,11 @@ read_jpeg_generate( VipsRegion *or, */ g_assert( r->height == VIPS_MIN( 8, or->im->Ysize - r->top ) ); + /* And check that y_pos is correct. It should be, since we are inside + * a vips_sequential(). + */ + g_assert( r->top == jpeg->y_pos ); + /* Here for longjmp() from vips__new_error_exit(). */ if( setjmp( jpeg->eman.jmp ) ) @@ -926,6 +937,8 @@ read_jpeg_generate( VipsRegion *or, for( x = 0; x < sz; x++ ) row_pointer[0][x] = 255 - row_pointer[0][x]; } + + jpeg->y_pos += 1; } VIPS_GATE_STOP( "read_jpeg_generate: work" ); From b875221005d1c571239c4c4ab41eeb455bc21eea Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Thu, 23 Jan 2014 14:22:41 +0000 Subject: [PATCH 07/29] foreign memory images tagges as ANY we weren't tagging foreign memory buffers as supporting ANY demand style, so they were falling back to SMALLTILE this broke any operation using SEQUENTIAL_UNBUFFERED plus foreign buffers, eg. falsecolour, since UNBUF needs very strict seq access --- libvips/iofuncs/image.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libvips/iofuncs/image.c b/libvips/iofuncs/image.c index 499f6f45..5f765904 100644 --- a/libvips/iofuncs/image.c +++ b/libvips/iofuncs/image.c @@ -937,6 +937,7 @@ vips_image_build( VipsObject *object ) image->Type = VIPS_INTERPRETATION_MULTIBAND; image->dtype = VIPS_IMAGE_SETBUF_FOREIGN; + image->dhint = VIPS_DEMAND_STYLE_ANY; break; From f5799c46081d9f14b4b6e0f8631c87fdc4672159 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Thu, 23 Jan 2014 14:27:45 +0000 Subject: [PATCH 08/29] falsecolour failed for some image types type prevented the auto-cast-first-band thing working --- ChangeLog | 3 +++ libvips/conversion/falsecolour.c | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index d3177013..11a39e66 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,8 @@ 22/1/14 started 7.38.2 - auto RAD decode for affine +- falsecolour was not working for some image types +- foreign memory buffer images did not have the right dhint, broke + command-line falsecolour on sequential images 19/1/14 started 7.38.1 - bump soname, thanks benjamin diff --git a/libvips/conversion/falsecolour.c b/libvips/conversion/falsecolour.c index 697c7125..ab77c0ec 100644 --- a/libvips/conversion/falsecolour.c +++ b/libvips/conversion/falsecolour.c @@ -14,6 +14,8 @@ * - force input to mono 8-bit for the user * 1/8/13 * - redone as a class + * 23/1/14 + * - oops, was not auto-getting and casting the first band */ /* @@ -348,7 +350,7 @@ vips_falsecolour_build( VipsObject *object ) if( vips_check_uncoded( class->nickname, falsecolour->in ) || vips_extract_band( falsecolour->in, &t[1], 0, NULL ) || vips_cast( t[1], &t[2], VIPS_FORMAT_UCHAR, NULL ) || - vips_maplut( falsecolour->in, &t[3], t[0], NULL ) || + vips_maplut( t[2], &t[3], t[0], NULL ) || vips_image_write( t[3], conversion->out ) ) return( -1 ); From ae6ea3ba873b044360cce42ee73e219fd8585aab Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Thu, 23 Jan 2014 15:06:37 +0000 Subject: [PATCH 09/29] support many Radiance readers active at once we had some globals for the Rad reader state, whcih was fine with the old reader, but with the new sequential one you can have several active at once --- ChangeLog | 1 + TODO | 18 ------ libvips/foreign/jpeg2vips.c | 2 +- libvips/foreign/radiance.c | 122 ++++++++++++++++++++++-------------- 4 files changed, 78 insertions(+), 65 deletions(-) diff --git a/ChangeLog b/ChangeLog index 11a39e66..1cc4d0ab 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,7 @@ - falsecolour was not working for some image types - foreign memory buffer images did not have the right dhint, broke command-line falsecolour on sequential images +- support many Radiance readers active at once 19/1/14 started 7.38.1 - bump soname, thanks benjamin diff --git a/TODO b/TODO index 47904de6..701fda57 100644 --- a/TODO +++ b/TODO @@ -1,21 +1,3 @@ -- shrink does not auto unpack labq or rad, should it? - -- others .. differences in: - -grep -l CODING_LABQ */*.c -conversion/join.c -conversion/msb.c -inplace/im_draw_mask.c -resample/shrink.c - -grep -l CODING_RAD */*.c -conversion/embed.c -inplace/flood.c -inplace/im_draw_image.c - - - - - need to do mosaicing and inplace, plus im_label_regions in morph diff --git a/libvips/foreign/jpeg2vips.c b/libvips/foreign/jpeg2vips.c index abae4195..f103b912 100644 --- a/libvips/foreign/jpeg2vips.c +++ b/libvips/foreign/jpeg2vips.c @@ -894,7 +894,7 @@ read_jpeg_generate( VipsRegion *or, printf( "read_jpeg_generate: line %d, %d rows\n", r->top, r->height ); #endif /*DEBUG*/ - + VIPS_GATE_START( "read_jpeg_generate: work" ); /* We're inside a tilecache where tiles are the full image width, so diff --git a/libvips/foreign/radiance.c b/libvips/foreign/radiance.c index e45a944f..d52e0ab8 100644 --- a/libvips/foreign/radiance.c +++ b/libvips/foreign/radiance.c @@ -12,6 +12,9 @@ * - support sequential read * 5/11/13 * - rewritten scanline encode and decode, now much faster + * 23/1/14 + * - put the reader globals into a struct so we can have many active + * readers */ /* @@ -617,38 +620,57 @@ register RESOLU *rp; #define BUFFER_SIZE (4096) #define BUFFER_MARGIN (256) -static unsigned char buffer[BUFFER_SIZE + BUFFER_MARGIN]; -static int buffer_length = 0; -static int buffer_position = 0; -static FILE *buffer_fp = NULL; +/* Read from a FILE with a rolling memory buffer ... this lets us reduce the + * number of fgetc() and gives us some very quick readahead. + */ -static void -buffer_init( FILE *fp ) +typedef struct _Buffer { + unsigned char text[BUFFER_SIZE + BUFFER_MARGIN]; + int length; + int position; + FILE *fp; +} Buffer; + +static Buffer * +buffer_new( FILE *fp ) { - buffer_length = 0; - buffer_position = 0; - buffer_fp = fp; + Buffer *buffer = g_new0( Buffer, 1 ); + + buffer->length = 0; + buffer->position = 0; + buffer->fp = fp; + + return( buffer ); } +static void +buffer_free( Buffer *buffer ) +{ + g_free( buffer ); +} + +/* Make sure there are at least @require bytes of readahead available. + */ static int -buffer_need( int require ) +buffer_need( Buffer *buffer, int require ) { int remaining; g_assert( require < BUFFER_MARGIN ); - remaining = buffer_length - buffer_position; + remaining = buffer->length - buffer->position; if( remaining < require ) { size_t len; - memcpy( buffer, buffer + buffer_position, remaining ); - buffer_position = 0; - buffer_length = remaining; + memcpy( buffer->text, + buffer->text + buffer->position, remaining ); + buffer->position = 0; + buffer->length = remaining; - len = fread( buffer + buffer_length, 1, BUFFER_SIZE, - buffer_fp ); - buffer_length += len; - remaining = buffer_length - buffer_position; + len = fread( buffer->text + buffer->length, + 1, BUFFER_SIZE, buffer->fp ); + buffer->length += len; + remaining = buffer->length - buffer->position; if( remaining < require ) { vips_error( "rad2vips", "%s", _( "end of file" ) ); @@ -659,26 +681,26 @@ buffer_need( int require ) return( 0 ); } -#define BUFFER_FETCH (buffer[buffer_position++]) -#define BUFFER_PEEK (buffer[buffer_position]) +#define BUFFER_FETCH(B) ((B)->text[(B)->position++]) +#define BUFFER_PEEK(B) ((B)->text[(B)->position]) /* Read a single scanlne, encoded in the old style. */ static int -scanline_read_old( COLR *scanline, int width ) +scanline_read_old( Buffer *buffer, COLR *scanline, int width ) { int rshift; rshift = 0; while( width > 0 ) { - if( buffer_need( 4 ) ) + if( buffer_need( buffer, 4 ) ) return( -1 ); - scanline[0][RED] = BUFFER_FETCH; - scanline[0][GRN] = BUFFER_FETCH; - scanline[0][BLU] = BUFFER_FETCH; - scanline[0][EXP] = BUFFER_FETCH; + scanline[0][RED] = BUFFER_FETCH( buffer ); + scanline[0][GRN] = BUFFER_FETCH( buffer ); + scanline[0][BLU] = BUFFER_FETCH( buffer ); + scanline[0][EXP] = BUFFER_FETCH( buffer ); if( scanline[0][RED] == 1 && scanline[0][GRN] == 1 && @@ -706,7 +728,7 @@ scanline_read_old( COLR *scanline, int width ) /* Read a single encoded scanline. */ static int -scanline_read( COLR *scanline, int width ) +scanline_read( Buffer *buffer, COLR *scanline, int width ) { int i, j; @@ -714,21 +736,21 @@ scanline_read( COLR *scanline, int width ) */ if( width < MINELEN || width > MAXELEN ) - return( scanline_read_old( scanline, width ) ); + return( scanline_read_old( buffer, scanline, width ) ); - if( buffer_need( 4 ) ) + if( buffer_need( buffer, 4 ) ) return( -1 ); - if( BUFFER_PEEK != 2 ) - return( scanline_read_old( scanline, width ) ); + if( BUFFER_PEEK( buffer ) != 2 ) + return( scanline_read_old( buffer, scanline, width ) ); - scanline[0][RED] = BUFFER_FETCH; - scanline[0][GRN] = BUFFER_FETCH; - scanline[0][BLU] = BUFFER_FETCH; - scanline[0][EXP] = BUFFER_FETCH; + scanline[0][RED] = BUFFER_FETCH( buffer ); + scanline[0][GRN] = BUFFER_FETCH( buffer ); + scanline[0][BLU] = BUFFER_FETCH( buffer ); + scanline[0][EXP] = BUFFER_FETCH( buffer ); if( scanline[0][GRN] != 2 || scanline[0][BLU] & 128 ) - return( scanline_read_old( scanline + 1, width - 1 ) ); + return( scanline_read_old( buffer, scanline + 1, width - 1 ) ); if( ((scanline[0][BLU] << 8) | scanline[0][EXP]) != width ) { vips_error( "rad2vips", "%s", _( "scanline length mismatch" ) ); @@ -740,10 +762,10 @@ scanline_read( COLR *scanline, int width ) int code, len; gboolean run; - if( buffer_need( 2 ) ) + if( buffer_need( buffer, 2 ) ) return( -1 ); - code = BUFFER_FETCH; + code = BUFFER_FETCH( buffer ); run = code > 128; len = run ? code & 127 : code; @@ -755,15 +777,16 @@ scanline_read( COLR *scanline, int width ) if( run ) { int val; - val = BUFFER_FETCH; + val = BUFFER_FETCH( buffer ); while( len-- ) scanline[j++][i] = val; } else { - if( buffer_need( len ) ) + if( buffer_need( buffer, len ) ) return( -1 ); while( len-- ) - scanline[j++][i] = BUFFER_FETCH; + scanline[j++][i] = + BUFFER_FETCH( buffer ); } } @@ -861,6 +884,7 @@ typedef struct { double aspect; RGBPRIMS prims; RESOLU rs; + Buffer *buffer; } Read; int @@ -888,7 +912,7 @@ read_destroy( VipsObject *object, Read *read ) { VIPS_FREE( read->filename ); VIPS_FREEF( fclose, read->fin ); - buffer_init( NULL ); + VIPS_FREEF( buffer_free, read->buffer ); } static Read * @@ -920,9 +944,9 @@ read_new( const char *filename, VipsImage *out ) g_signal_connect( out, "close", G_CALLBACK( read_destroy ), read ); - if( !(read->fin = vips__file_open_read( filename, NULL, FALSE )) ) + if( !(read->fin = vips__file_open_read( filename, NULL, FALSE )) || + !(read->buffer = buffer_new( read->fin )) ) return( NULL ); - buffer_init( read->fin ); return( read ); } @@ -1037,24 +1061,30 @@ rad2vips_generate( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop ) { VipsRect *r = &or->valid; + Read *read = (Read *) a; int y; #ifdef DEBUG - printf( "rad2vips_get_data\n" ); + printf( "rad2vips_generate: line %d, %d rows\n", + r->top, r->height ); #endif /*DEBUG*/ + VIPS_GATE_START( "rad2vips_generate: work" ); + for( y = 0; y < r->height; y++ ) { COLR *buf = (COLR *) VIPS_REGION_ADDR( or, 0, r->top + y ); - if( scanline_read( buf, or->im->Xsize ) ) { + if( scanline_read( read->buffer, buf, or->im->Xsize ) ) { vips_error( "rad2vips", _( "read error line %d" ), r->top + y ); return( -1 ); } } + VIPS_GATE_STOP( "rad2vips_generate: work" ); + return( 0 ); } From 4dae352d28009c4d4e78f790d625b82f6d23efd1 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Thu, 23 Jan 2014 15:36:34 +0000 Subject: [PATCH 10/29] better autounpack for falsecolour --- libvips/conversion/falsecolour.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/libvips/conversion/falsecolour.c b/libvips/conversion/falsecolour.c index 8049e04c..867e6fe2 100644 --- a/libvips/conversion/falsecolour.c +++ b/libvips/conversion/falsecolour.c @@ -54,6 +54,7 @@ #include #include +#include #include "pconversion.h" @@ -348,11 +349,11 @@ vips_falsecolour_build( VipsObject *object ) * want to work for images which aren't in a recognised space, like * MULTIBAND. */ - if( vips_check_uncoded( class->nickname, falsecolour->in ) || - vips_extract_band( falsecolour->in, &t[1], 0, NULL ) || - vips_cast( t[1], &t[2], VIPS_FORMAT_UCHAR, NULL ) || - vips_maplut( t[2], &t[3], t[0], NULL ) || - vips_image_write( t[3], conversion->out ) ) + if( vips__image_decode( falsecolour->in, &t[1] ) || + vips_extract_band( t[1], &t[2], 0, NULL ) || + vips_cast( t[2], &t[3], VIPS_FORMAT_UCHAR, NULL ) || + vips_maplut( t[3], &t[4], t[0], NULL ) || + vips_image_write( t[4], conversion->out ) ) return( -1 ); return( 0 ); From e7efa8e6f2dd967b294776926322f648430dd6b7 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Thu, 23 Jan 2014 16:51:32 +0000 Subject: [PATCH 11/29] more auto-decode --- ChangeLog | 2 +- TODO | 29 ++--------------------------- libvips/conversion/flatten.c | 21 ++++++++++++++------- libvips/conversion/recomb.c | 21 ++++++++++++++------- libvips/freqfilt/fwfft.c | 17 +++++++++++++---- libvips/freqfilt/invfft.c | 15 ++++++++++++--- libvips/histogram/hist_local.c | 12 ++++++++---- libvips/histogram/histogram.c | 11 ++++++----- libvips/histogram/stdif.c | 12 ++++++++---- 9 files changed, 78 insertions(+), 62 deletions(-) diff --git a/ChangeLog b/ChangeLog index 16cbc04d..069a8d63 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,5 @@ 21/1/14 started 7.39.0 -- fancy auto-decode for all operations +- auto-decode for (almost) all operations 22/1/14 started 7.38.2 - auto RAD decode for affine diff --git a/TODO b/TODO index 733fbad8..b0d478f2 100644 --- a/TODO +++ b/TODO @@ -8,35 +8,10 @@ problem in 7.38 too +- vips_colourspace() needs an option from_space param,? + - check_uncoded() left to do: - conversion/falsecolour.c - conversion/flatten.c - conversion/recomb.c - convolution/sharpen.c - deprecated/im_gradcor.c - deprecated/im_lab_morph.c - deprecated/im_maxpos_avg.c - deprecated/im_measure.c - deprecated/im_vips2mask.c - deprecated/im_zerox.c - deprecated/rename.c - deprecated/tone.c - deprecated/vips7compat.c - foreign/csv.c - foreign/ppm.c - freqfilt/fwfft.c - freqfilt/invfft.c - histogram/hist_local.c - histogram/histogram.c - histogram/hist_plot.c - histogram/maplut.c - histogram/stdif.c - inplace/flood.c - inplace/im_draw_mask.c - inplace/inplace_dispatch.c - iofuncs/error.c - morphology/hitmiss.c resample/quadratic.c - we vips_image_write() a lot, could we do this by diff --git a/libvips/conversion/flatten.c b/libvips/conversion/flatten.c index 889844a9..1bf4626e 100644 --- a/libvips/conversion/flatten.c +++ b/libvips/conversion/flatten.c @@ -300,24 +300,31 @@ vips_flatten_build( VipsObject *object ) VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); VipsConversion *conversion = VIPS_CONVERSION( object ); VipsFlatten *flatten = (VipsFlatten *) object; + VipsImage **t = (VipsImage **) vips_object_local_array( object, 1 ); + + VipsImage *in; int i; gboolean black; if( VIPS_OBJECT_CLASS( vips_flatten_parent_class )->build( object ) ) return( -1 ); + in = flatten->in; + + if( vips__image_decode( in, &t[0] ) ) + return( -1 ); + in = t[0]; + /* Trivial case: fall back to copy(). */ if( flatten->in->Bands == 1 ) - return( vips_image_write( flatten->in, conversion->out ) ); + return( vips_image_write( in, conversion->out ) ); - if( vips_check_uncoded( class->nickname, flatten->in ) || - vips_check_noncomplex( class->nickname, flatten->in ) || - vips_image_pio_input( flatten->in ) ) + if( vips_check_noncomplex( class->nickname, in ) ) return( -1 ); if( vips_image_pipelinev( conversion->out, - VIPS_DEMAND_STYLE_THINSTRIP, flatten->in, NULL ) ) + VIPS_DEMAND_STYLE_THINSTRIP, in, NULL ) ) return( -1 ); conversion->out->Bands -= 1; @@ -334,7 +341,7 @@ vips_flatten_build( VipsObject *object ) if( black ) { if( vips_image_generate( conversion->out, vips_start_one, vips_flatten_black_gen, vips_stop_one, - flatten->in, flatten ) ) + in, flatten ) ) return( -1 ); } else { @@ -347,7 +354,7 @@ vips_flatten_build( VipsObject *object ) if( vips_image_generate( conversion->out, vips_start_one, vips_flatten_gen, vips_stop_one, - flatten->in, flatten ) ) + in, flatten ) ) return( -1 ); } diff --git a/libvips/conversion/recomb.c b/libvips/conversion/recomb.c index 9158af0a..0e39beb9 100644 --- a/libvips/conversion/recomb.c +++ b/libvips/conversion/recomb.c @@ -50,6 +50,7 @@ #include #include +#include #include "pconversion.h" @@ -142,19 +143,25 @@ vips_recomb_build( VipsObject *object ) VipsRecomb *recomb = (VipsRecomb *) object; VipsImage **t = (VipsImage **) vips_object_local_array( object, 2 ); + VipsImage *in; + if( VIPS_OBJECT_CLASS( vips_recomb_parent_class )->build( object ) ) return( -1 ); - if( vips_image_pio_input( recomb->in ) || - vips_check_uncoded( class->nickname, recomb->in ) || - vips_check_noncomplex( class->nickname, recomb->in ) ) + in = recomb->in; + + if( vips__image_decode( in, &t[0] ) ) + return( -1 ); + in = t[0]; + + if( vips_check_noncomplex( class->nickname, in ) ) return( -1 ); if( vips_image_pio_input( recomb->m ) || vips_check_uncoded( class->nickname, recomb->m ) || vips_check_noncomplex( class->nickname, recomb->m ) || vips_check_mono( class->nickname, recomb->m ) ) return( -1 ); - if( recomb->in->Bands != recomb->m->Xsize ) { + if( in->Bands != recomb->m->Xsize ) { vips_error( class->nickname, "%s", _( "bands in must equal matrix width" ) ); return( -1 ); @@ -165,16 +172,16 @@ vips_recomb_build( VipsObject *object ) recomb->coeff = t[0]; if( vips_image_pipelinev( conversion->out, - VIPS_DEMAND_STYLE_THINSTRIP, recomb->in, NULL ) ) + VIPS_DEMAND_STYLE_THINSTRIP, in, NULL ) ) return( -1 ); conversion->out->Bands = recomb->m->Ysize; - if( vips_bandfmt_isint( recomb->in->BandFmt ) ) + if( vips_bandfmt_isint( in->BandFmt ) ) conversion->out->BandFmt = VIPS_FORMAT_FLOAT; if( vips_image_generate( conversion->out, vips_start_one, vips_recomb_gen, vips_stop_one, - recomb->in, recomb ) ) + in, recomb ) ) return( -1 ); return( 0 ); diff --git a/libvips/freqfilt/fwfft.c b/libvips/freqfilt/fwfft.c index 3c9fd8b2..813a5cc1 100644 --- a/libvips/freqfilt/fwfft.c +++ b/libvips/freqfilt/fwfft.c @@ -75,6 +75,7 @@ #include #include +#include #include "pfreqfilt.h" #ifdef HAVE_FFTW @@ -294,22 +295,30 @@ vips_fwfft_build( VipsObject *object ) VipsFwfft *fwfft = (VipsFwfft *) object; VipsImage **t = (VipsImage **) vips_object_local_array( object, 4 ); + VipsImage *in; + if( VIPS_OBJECT_CLASS( vips_fwfft_parent_class )-> build( object ) ) return( -1 ); - if( vips_bandfmt_iscomplex( freqfilt->in->BandFmt ) ) { - if( vips__fftproc( VIPS_OBJECT( fwfft ), freqfilt->in, &t[0], + in = freqfilt->in; + + if( vips__image_decode( in, &t[0] ) ) + return( -1 ); + in = t[0]; + + if( vips_bandfmt_iscomplex( in->BandFmt ) ) { + if( vips__fftproc( VIPS_OBJECT( fwfft ), in, &t[1], cfwfft1 ) ) return( -1 ); } else { - if( vips__fftproc( VIPS_OBJECT( fwfft ), freqfilt->in, &t[0], + if( vips__fftproc( VIPS_OBJECT( fwfft ), in, &t[1], rfwfft1 ) ) return( -1 ); } - if( vips_image_write( t[0], freqfilt->out ) ) + if( vips_image_write( t[1], freqfilt->out ) ) return( -1 ); return( 0 ); diff --git a/libvips/freqfilt/invfft.c b/libvips/freqfilt/invfft.c index 30ea23a9..8b8611ee 100644 --- a/libvips/freqfilt/invfft.c +++ b/libvips/freqfilt/invfft.c @@ -64,6 +64,7 @@ #include #include +#include #include "pfreqfilt.h" #ifdef HAVE_FFTW @@ -207,22 +208,30 @@ vips_invfft_build( VipsObject *object ) VipsInvfft *invfft = (VipsInvfft *) object; VipsImage **t = (VipsImage **) vips_object_local_array( object, 4 ); + VipsImage *in; + if( VIPS_OBJECT_CLASS( vips_invfft_parent_class )-> build( object ) ) return( -1 ); + in = freqfilt->in; + + if( vips__image_decode( in, &t[0] ) ) + return( -1 ); + in = t[0]; + if( invfft->real ) { if( vips__fftproc( VIPS_OBJECT( invfft ), - freqfilt->in, &t[0], rinvfft1 ) ) + in, &t[1], rinvfft1 ) ) return( -1 ); } else { if( vips__fftproc( VIPS_OBJECT( invfft ), - freqfilt->in, &t[0], cinvfft1 ) ) + in, &t[1], cinvfft1 ) ) return( -1 ); } - if( vips_image_write( t[0], freqfilt->out ) ) + if( vips_image_write( t[1], freqfilt->out ) ) return( -1 ); return( 0 ); diff --git a/libvips/histogram/hist_local.c b/libvips/histogram/hist_local.c index c9ee1b06..9243ec05 100644 --- a/libvips/histogram/hist_local.c +++ b/libvips/histogram/hist_local.c @@ -60,6 +60,7 @@ #include #include +#include typedef struct _VipsHistLocal { VipsOperation parent_instance; @@ -235,8 +236,11 @@ vips_hist_local_build( VipsObject *object ) in = local->in; - if( vips_check_uncoded( class->nickname, in ) || - vips_check_format( class->nickname, in, VIPS_FORMAT_UCHAR ) ) + if( vips__image_decode( in, &t[0] ) ) + return( -1 ); + in = t[0]; + + if( vips_check_format( class->nickname, in, VIPS_FORMAT_UCHAR ) ) return( -1 ); if( local->width > in->Xsize || @@ -247,13 +251,13 @@ vips_hist_local_build( VipsObject *object ) /* Expand the input. */ - if( vips_embed( in, &t[0], + if( vips_embed( in, &t[1], local->width / 2, local->height / 2, in->Xsize + local->width - 1, in->Ysize + local->height - 1, "extend", VIPS_EXTEND_COPY, NULL ) ) return( -1 ); - in = t[0]; + in = t[1]; g_object_set( object, "out", vips_image_new(), NULL ); diff --git a/libvips/histogram/histogram.c b/libvips/histogram/histogram.c index e57fe2e5..8064dfa7 100644 --- a/libvips/histogram/histogram.c +++ b/libvips/histogram/histogram.c @@ -111,6 +111,7 @@ vips_histogram_build( VipsObject *object ) VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object ); VipsHistogramClass *hclass = VIPS_HISTOGRAM_GET_CLASS( histogram ); + VipsImage **decode; VipsImage **format; VipsImage **band; VipsImage **size; @@ -134,6 +135,7 @@ vips_histogram_build( VipsObject *object ) */ g_assert( !histogram->in[histogram->n] ); + decode = (VipsImage **) vips_object_local_array( object, histogram->n ); format = (VipsImage **) vips_object_local_array( object, histogram->n ); band = (VipsImage **) vips_object_local_array( object, histogram->n ); size = (VipsImage **) vips_object_local_array( object, histogram->n ); @@ -141,8 +143,8 @@ vips_histogram_build( VipsObject *object ) g_object_set( histogram, "out", vips_image_new(), NULL ); for( i = 0; i < histogram->n; i++ ) - if( vips_check_uncoded( class->nickname, histogram->in[i] ) || - vips_check_hist( class->nickname, histogram->in[i] ) ) + if( vips__image_decode( histogram->in[i], &decode[i] ) || + vips_check_hist( class->nickname, decode[i] ) ) return( -1 ); /* Cast our input images up to a common format, bands and size. If @@ -150,13 +152,12 @@ vips_histogram_build( VipsObject *object ) */ if( hclass->input_format != VIPS_FORMAT_NOTSET ) { for( i = 0; i < histogram->n; i++ ) - if( vips_cast( histogram->in[i], &format[i], + if( vips_cast( decode[i], &format[i], hclass->input_format, NULL ) ) return( -1 ); } else { - if( vips__formatalike_vec( histogram->in, - format, histogram->n ) ) + if( vips__formatalike_vec( decode, format, histogram->n ) ) return( -1 ); } diff --git a/libvips/histogram/stdif.c b/libvips/histogram/stdif.c index 59e0fe95..0406bbd2 100644 --- a/libvips/histogram/stdif.c +++ b/libvips/histogram/stdif.c @@ -64,6 +64,7 @@ #include #include +#include typedef struct _VipsStdif { VipsOperation parent_instance; @@ -223,8 +224,11 @@ vips_stdif_build( VipsObject *object ) in = stdif->in; - if( vips_check_uncoded( class->nickname, in ) || - vips_check_format( class->nickname, in, VIPS_FORMAT_UCHAR ) ) + if( vips__image_decode( in, &t[0] ) ) + return( -1 ); + in = t[0]; + + if( vips_check_format( class->nickname, in, VIPS_FORMAT_UCHAR ) ) return( -1 ); if( stdif->width > in->Xsize || @@ -239,13 +243,13 @@ vips_stdif_build( VipsObject *object ) /* Expand the input. */ - if( vips_embed( in, &t[0], + if( vips_embed( in, &t[1], stdif->width / 2, stdif->height / 2, in->Xsize + stdif->width - 1, in->Ysize + stdif->height - 1, "extend", VIPS_EXTEND_COPY, NULL ) ) return( -1 ); - in = t[0]; + in = t[1]; g_object_set( object, "out", vips_image_new(), NULL ); From 805d0cceee6a67cd90c946016ec26144fa151f93 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Thu, 23 Jan 2014 17:25:19 +0000 Subject: [PATCH 12/29] better fits docs --- libvips/foreign/foreign.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/libvips/foreign/foreign.c b/libvips/foreign/foreign.c index 51f1167f..09e262d9 100644 --- a/libvips/foreign/foreign.c +++ b/libvips/foreign/foreign.c @@ -2405,6 +2405,14 @@ vips_openslideload( const char *filename, VipsImage **out, ... ) * * Read a FITS image file into a VIPS image. * + * This operation can read images with up to three dimensions. Any higher + * dimensions must be empty. + * + * It can read 8, 16 and 32-bit integer images, signed and unsigned, float and + * double. + * + * FITS metadata is attached with the "fits-" prefix. + * * See also: vips_image_new_from_file(). * * Returns: 0 on success, -1 on error. @@ -2428,7 +2436,7 @@ vips_fitsload( const char *filename, VipsImage **out, ... ) * @filename: file to write to * @...: %NULL-terminated list of optional named arguments * - * Write a VIPS image to a file as FITS. + * Write a VIPS image to a file in FITS format. * * See also: vips_image_write_file(). * From c2ff2c6e5d4bc6de16916c042cce91faa05277a0 Mon Sep 17 00:00:00 2001 From: Benjamin Gilbert Date: Sun, 27 Oct 2013 22:01:47 -0400 Subject: [PATCH 13/29] fix stray uses of "layer" in openslideload documentation --- libvips/foreign/foreign.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libvips/foreign/foreign.c b/libvips/foreign/foreign.c index 09e262d9..0f6cc8e0 100644 --- a/libvips/foreign/foreign.c +++ b/libvips/foreign/foreign.c @@ -2357,7 +2357,7 @@ vips_openexrload( const char *filename, VipsImage **out, ... ) * * Optional arguments: * - * @layer: load this layer + * @level: load this level * @associated: load this associated image * * Read a virtual slide supported by the OpenSlide library into a VIPS image. @@ -2366,9 +2366,8 @@ vips_openexrload( const char *filename, VipsImage **out, ... ) * * To facilitate zooming, virtual slide formats include multiple scaled-down * versions of the high-resolution image. These are typically called - * "levels", though OpenSlide and im_openslide2vips() call them "layers". - * By default, vips_openslideload() reads the highest-resolution layer - * (layer 0). Set @layer to the layer number you want. + * "levels". By default, vips_openslideload() reads the highest-resolution + * level (level 0). Set @level to the level number you want. * * In addition to the slide image itself, virtual slide formats sometimes * include additional images, such as a scan of the slide's barcode. From 524f37c1b989374f953f159074afa955d7ebe799 Mon Sep 17 00:00:00 2001 From: Benjamin Gilbert Date: Sun, 27 Oct 2013 22:16:35 -0400 Subject: [PATCH 14/29] drop error freeze/thaw around openslide_open() openslide_open() hasn't been able to cause a call to vips_error() since c98d6543. --- libvips/foreign/openslide2vips.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/libvips/foreign/openslide2vips.c b/libvips/foreign/openslide2vips.c index 59ccd931..2102f234 100644 --- a/libvips/foreign/openslide2vips.c +++ b/libvips/foreign/openslide2vips.c @@ -109,9 +109,7 @@ vips__openslide_isslide( const char *filename ) int ok; ok = 0; - vips_error_freeze(); osr = openslide_open( filename ); - vips_error_thaw(); if( osr ) { const char *vendor; From 2e8d01481198ac9edf70de89a5af3d219bb8e323 Mon Sep 17 00:00:00 2001 From: Benjamin Gilbert Date: Sat, 25 Jan 2014 02:31:20 -0500 Subject: [PATCH 15/29] update for new format support in OpenSlide 3.4.0 --- README.md | 2 +- libvips/deprecated/im_openslide2vips.c | 2 ++ libvips/foreign/foreign.c | 4 ++-- libvips/foreign/openslideload.c | 2 ++ 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 979fb164..820f139e 100644 --- a/README.md +++ b/README.md @@ -189,7 +189,7 @@ OpenEXR images. ## OpenSlide If available, libvips can load OpenSlide-supported virtual slide -files: Aperio, Hamamatsu VMS and VMU, Leica, MIRAX, and Trestle. +files: Aperio, Hamamatsu, Leica, MIRAX, Sakura, Trestle, and Ventana. ## swig, python, python-dev diff --git a/libvips/deprecated/im_openslide2vips.c b/libvips/deprecated/im_openslide2vips.c index a1c27d58..105ea762 100644 --- a/libvips/deprecated/im_openslide2vips.c +++ b/libvips/deprecated/im_openslide2vips.c @@ -98,7 +98,9 @@ static const char *openslide_suffs[] = { ".vms", ".vmu", ".ndpi", /* Hamamatsu */ ".scn", /* Leica */ ".mrxs", /* MIRAX */ + ".svslide", /* Sakura */ ".tif", /* Trestle */ + ".bif", /* Ventana */ NULL }; diff --git a/libvips/foreign/foreign.c b/libvips/foreign/foreign.c index 0f6cc8e0..eb91a9b8 100644 --- a/libvips/foreign/foreign.c +++ b/libvips/foreign/foreign.c @@ -2361,8 +2361,8 @@ vips_openexrload( const char *filename, VipsImage **out, ... ) * @associated: load this associated image * * Read a virtual slide supported by the OpenSlide library into a VIPS image. - * OpenSlide supports images in Aperio, Hamamatsu VMS, Hamamatsu VMU, MIRAX, - * and Trestle formats. + * OpenSlide supports images in Aperio, Hamamatsu, MIRAX, Sakura, Trestle, + * and Ventana formats. * * To facilitate zooming, virtual slide formats include multiple scaled-down * versions of the high-resolution image. These are typically called diff --git a/libvips/foreign/openslideload.c b/libvips/foreign/openslideload.c index 4d52301b..dc44d037 100644 --- a/libvips/foreign/openslideload.c +++ b/libvips/foreign/openslideload.c @@ -140,7 +140,9 @@ static const char *vips_foreign_openslide_suffs[] = { ".vms", ".vmu", ".ndpi", /* Hamamatsu */ ".scn", /* Leica */ ".mrxs", /* MIRAX */ + ".svslide", /* Sakura */ ".tif", /* Trestle */ + ".bif", /* Ventana */ NULL }; From ebf4fb807bf6ba92ffe2e89a52a161fed862c329 Mon Sep 17 00:00:00 2001 From: Benjamin Gilbert Date: Sat, 25 Jan 2014 02:56:27 -0500 Subject: [PATCH 16/29] use openslide_detect_vendor() on OpenSlide 3.4.0 It is much more efficient than openslide_open(). It also fixes a bug: If openslide_open() failed, we had no way of knowing whether it was an interesting failure (for relevant slide formats) or an uninteresting one (for a generic TIFF). So, the is_a method would always return false in this case. This could cause unexpected results; for example, on MIRAX slides, VIPS would open the .mrxs file itself (a JPEG thumbnail) and the user would be left wondering where all their pixels went. Now, if there is an interesting failure, is_a will succeed but header/load will fail. --- configure.ac | 15 +++++++++++---- libvips/foreign/openslide2vips.c | 22 +++++++++++++++++++++- 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 3a079bd9..183fac93 100644 --- a/configure.ac +++ b/configure.ac @@ -497,12 +497,19 @@ AC_ARG_WITH([openslide], AS_HELP_STRING([--without-openslide], [build without OpenSlide (default: test)])) if test x"$with_openslide" != x"no"; then - PKG_CHECK_MODULES(OPENSLIDE, openslide >= 3.3.0, - [AC_DEFINE(HAVE_OPENSLIDE,1,[define if you have OpenSlide >= 3.3.0 installed.]) + PKG_CHECK_MODULES(OPENSLIDE, [openslide >= 3.4.0], + [AC_DEFINE(HAVE_OPENSLIDE_3_4,1,[define if you have OpenSlide >= 3.4.0 installed.]) + AC_DEFINE(HAVE_OPENSLIDE,1,[define if you have OpenSlide >= 3.3.0 installed.]) with_openslide=yes PACKAGES_USED="$PACKAGES_USED openslide"], - [AC_MSG_WARN([OpenSlide >= 3.3.0 not found; disabling virtual slide support]) - with_openslide=no + [AC_MSG_NOTICE([OpenSlide >= 3.4.0 not found; checking for >= 3.3.0]) + PKG_CHECK_MODULES(OPENSLIDE, [openslide >= 3.3.0], + [AC_DEFINE(HAVE_OPENSLIDE,1,[define if you have OpenSlide >= 3.3.0 installed.]) + with_openslide=yes + PACKAGES_USED="$PACKAGES_USED openslide"], + [AC_MSG_WARN([OpenSlide >= 3.3.0 not found; disabling virtual slide support]) + with_openslide=no + ]) ]) fi diff --git a/libvips/foreign/openslide2vips.c b/libvips/foreign/openslide2vips.c index 2102f234..e68c6da8 100644 --- a/libvips/foreign/openslide2vips.c +++ b/libvips/foreign/openslide2vips.c @@ -2,7 +2,7 @@ * * Benjamin Gilbert * - * Copyright (c) 2011-2012 Carnegie Mellon University + * Copyright (c) 2011-2014 Carnegie Mellon University * * 26/11/11 * - initial version @@ -39,6 +39,8 @@ * - use threaded tile cache * 6/8/13 * - always output solid (not transparent) pixels + * 25/1/14 + * - use openslide_detect_vendor() on >= 3.4.0 */ /* @@ -105,6 +107,23 @@ typedef struct { int vips__openslide_isslide( const char *filename ) { +#ifdef HAVE_OPENSLIDE_3_4 + const char *vendor; + int ok; + + vendor = openslide_detect_vendor( filename ); + + /* Generic tiled tiff images can be opened by openslide as well. + * Only offer to load this file if it's not a generic tiff since + * we want vips_tiffload() to handle these. + */ + ok = ( vendor && + strcmp( vendor, "generic-tiff" ) != 0 ); + + VIPS_DEBUG_MSG( "vips__openslide_isslide: %s - %d\n", filename, ok ); + + return( ok ); +#else openslide_t *osr; int ok; @@ -133,6 +152,7 @@ vips__openslide_isslide( const char *filename ) VIPS_DEBUG_MSG( "vips__openslide_isslide: %s - %d\n", filename, ok ); return( ok ); +#endif } static void From acbb77ac40d0889f4115fd4c66d0dfc967200580 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Sun, 26 Jan 2014 10:43:32 +0000 Subject: [PATCH 17/29] add "rgbjpeg" flag to tiffsave add a secret "rgbjpeg" flag to tiffsave to help IIPImage server iipimage server 0.9.9 and earlier don't handle YCbCr-coded JPEG tiffs correctly ... setting --rgbjpeg makes vips output RGB coded JPEG tiff which iipsrv can handle. Using this flag makes files 2x to 3x larger with no quality improvement, so it is tagged as deprecated to keep it hidden. --- ChangeLog | 1 + libvips/foreign/tiff.h | 3 ++- libvips/foreign/tiffsave.c | 13 ++++++++++++- libvips/foreign/vips2tiff.c | 15 +++++++++++---- 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1cc4d0ab..a9386b99 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,7 @@ - foreign memory buffer images did not have the right dhint, broke command-line falsecolour on sequential images - support many Radiance readers active at once +- add secret "rgbjpeg" flag to vips_tiffsave() to help IIP 19/1/14 started 7.38.1 - bump soname, thanks benjamin diff --git a/libvips/foreign/tiff.h b/libvips/foreign/tiff.h index af8a308f..5090df53 100644 --- a/libvips/foreign/tiff.h +++ b/libvips/foreign/tiff.h @@ -47,7 +47,8 @@ int vips__tiff_write( VipsImage *in, const char *filename, gboolean pyramid, gboolean squash, VipsForeignTiffResunit resunit, double xres, double yres, - gboolean bigtiff ); + gboolean bigtiff, + gboolean rgbjpeg ); int vips__tiff_read( const char *filename, VipsImage *out, int page, gboolean readbehind ); diff --git a/libvips/foreign/tiffsave.c b/libvips/foreign/tiffsave.c index aa20c34a..14f71a92 100644 --- a/libvips/foreign/tiffsave.c +++ b/libvips/foreign/tiffsave.c @@ -4,6 +4,8 @@ * - wrap a class around the tiff writer * 17/3/12 * - argh xres/yres macro was wrong + * 26/1/14 + * - add rgbjpeg flag */ /* @@ -75,6 +77,7 @@ typedef struct _VipsForeignSaveTiff { double xres; double yres; gboolean bigtiff; + gboolean rgbjpeg; } VipsForeignSaveTiff; typedef VipsForeignSaveClass VipsForeignSaveTiffClass; @@ -123,7 +126,8 @@ vips_foreign_save_tiff_build( VipsObject *object ) tiff->pyramid, tiff->squash, tiff->resunit, tiff->xres, tiff->yres, - tiff->bigtiff ) ) + tiff->bigtiff, + tiff->rgbjpeg ) ) return( -1 ); return( 0 ); @@ -249,6 +253,13 @@ vips_foreign_save_tiff_class_init( VipsForeignSaveTiffClass *class ) VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET( VipsForeignSaveTiff, bigtiff ), FALSE ); + + VIPS_ARG_BOOL( class, "rgbjpeg", 20, + _( "RGB JPEG" ), + _( "Output RGB JPEG rather than YCbCr" ), + VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED, + G_STRUCT_OFFSET( VipsForeignSaveTiff, rgbjpeg ), + FALSE ); } static void diff --git a/libvips/foreign/vips2tiff.c b/libvips/foreign/vips2tiff.c index 73081cda..0294f9ba 100644 --- a/libvips/foreign/vips2tiff.c +++ b/libvips/foreign/vips2tiff.c @@ -136,6 +136,8 @@ * 24/9/13 * - support many more vips formats, eg. complex, 32-bit int, any number * of bands, etc., see the tiff loader + * 26/1/14 + * - add RGB as well as YCbCr write */ /* @@ -261,6 +263,7 @@ typedef struct tiff_write { float yres; /* Resolution in Y */ char *icc_profile; /* Profile to embed */ int bigtiff; /* True for bigtiff write */ + int rgbjpeg; /* True for RGB not YCbCr */ GMutex *write_lock; /* Lock TIFF*() calls with this */ } TiffWrite; @@ -529,7 +532,8 @@ write_tiff_header( TiffWrite *tw, TIFF *tif, int width, int height ) } else if( tw->compression == COMPRESSION_JPEG && tw->im->Bands == 3 && - tw->im->BandFmt == VIPS_FORMAT_UCHAR ) { + tw->im->BandFmt == VIPS_FORMAT_UCHAR && + !tw->rgbjpeg ) { /* This signals to libjpeg that it can do * YCbCr chrominance subsampling from RGB, not * that we will supply the image as YCbCr. @@ -1291,7 +1295,8 @@ make_tiff_write( VipsImage *im, const char *filename, gboolean pyramid, gboolean squash, VipsForeignTiffResunit resunit, double xres, double yres, - gboolean bigtiff ) + gboolean bigtiff, + gboolean rgbjpeg ) { TiffWrite *tw; @@ -1313,6 +1318,7 @@ make_tiff_write( VipsImage *im, const char *filename, tw->onebit = squash; tw->icc_profile = profile; tw->bigtiff = bigtiff; + tw->rgbjpeg = rgbjpeg; tw->write_lock = NULL; tw->resunit = get_resunit( resunit ); @@ -1531,7 +1537,8 @@ vips__tiff_write( VipsImage *in, const char *filename, gboolean pyramid, gboolean squash, VipsForeignTiffResunit resunit, double xres, double yres, - gboolean bigtiff ) + gboolean bigtiff, + gboolean rgbjpeg ) { TiffWrite *tw; int res; @@ -1553,7 +1560,7 @@ vips__tiff_write( VipsImage *in, const char *filename, if( !(tw = make_tiff_write( in, filename, compression, Q, predictor, profile, tile, tile_width, tile_height, pyramid, squash, - resunit, xres, yres, bigtiff )) ) + resunit, xres, yres, bigtiff, rgbjpeg )) ) return( -1 ); if( tw->pyramid ) { if( !(tw->bname = vips__temp_name( "%s.tif" )) || From 33b95631700ef08ba9160c0967b6bb264348d2db Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Sun, 26 Jan 2014 10:54:31 +0000 Subject: [PATCH 18/29] fix a warning --- libvips/iofuncs/buffer.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libvips/iofuncs/buffer.c b/libvips/iofuncs/buffer.c index 52602061..62299a3f 100644 --- a/libvips/iofuncs/buffer.c +++ b/libvips/iofuncs/buffer.c @@ -276,7 +276,6 @@ vips_buffer_undone( VipsBuffer *buffer ) { if( buffer->done ) { VipsBufferCache *cache = buffer->cache; - VipsBufferThread *buffer_thread = cache->buffer_thread; #ifdef DEBUG_VERBOSE printf( "vips_buffer_undone: thread %p removing " @@ -285,9 +284,9 @@ vips_buffer_undone( VipsBuffer *buffer ) #endif /*DEBUG_VERBOSE*/ g_assert( cache->thread == g_thread_self() ); - g_assert( buffer_thread->thread == cache->thread ); + g_assert( cache->buffer_thread->thread == cache->thread ); g_assert( g_slist_find( cache->buffers, buffer ) ); - g_assert( buffer_thread == buffer_thread_get() ); + g_assert( cache->buffer_thread == buffer_thread_get() ); cache->buffers = g_slist_remove( cache->buffers, buffer ); From c80e7292be8a0598d77e476c32ad2364b801fc41 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Mon, 27 Jan 2014 15:03:08 +0000 Subject: [PATCH 19/29] formatting --- libvips/iofuncs/sinkscreen.c | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/libvips/iofuncs/sinkscreen.c b/libvips/iofuncs/sinkscreen.c index 358fbadd..ca9523c6 100644 --- a/libvips/iofuncs/sinkscreen.c +++ b/libvips/iofuncs/sinkscreen.c @@ -896,14 +896,17 @@ static int image_fill( VipsRegion *out, void *seq, void *a, void *b, gboolean *stop ) { Render *render = (Render *) a; + int tile_width = render->tile_width; + int tile_height = render->tile_height; VipsRegion *reg = (VipsRegion *) seq; VipsRect *r = &out->valid; + int x, y; /* Find top left of tiles we need. */ - int xs = (r->left / render->tile_width) * render->tile_width; - int ys = (r->top / render->tile_height) * render->tile_height; + int xs = (r->left / tile_width) * tile_width; + int ys = (r->top / tile_height) * tile_height; VIPS_DEBUG_MSG( "image_fill: left = %d, top = %d, " "width = %d, height = %d\n", @@ -918,15 +921,15 @@ image_fill( VipsRegion *out, void *seq, void *a, void *b, gboolean *stop ) */ - for( y = ys; y < VIPS_RECT_BOTTOM( r ); y += render->tile_height ) - for( x = xs; x < VIPS_RECT_RIGHT( r ); x += render->tile_width ) { + for( y = ys; y < VIPS_RECT_BOTTOM( r ); y += tile_height ) + for( x = xs; x < VIPS_RECT_RIGHT( r ); x += tile_width ) { VipsRect area; Tile *tile; area.left = x; area.top = y; - area.width = render->tile_width; - area.height = render->tile_height; + area.width = tile_width; + area.height = tile_height; tile = render_tile_request( render, reg, &area ); if( tile ) @@ -956,13 +959,16 @@ static int mask_fill( VipsRegion *out, void *seq, void *a, void *b, gboolean *stop ) { Render *render = (Render *) a; + int tile_width = render->tile_width; + int tile_height = render->tile_height; VipsRect *r = &out->valid; + int x, y; /* Find top left of tiles we need. */ - int xs = (r->left / render->tile_width) * render->tile_width; - int ys = (r->top / render->tile_height) * render->tile_height; + int xs = (r->left / tile_width) * tile_width; + int ys = (r->top / tile_height) * tile_height; VIPS_DEBUG_MSG( "mask_fill: left = %d, top = %d, " "width = %d, height = %d\n", @@ -970,16 +976,16 @@ mask_fill( VipsRegion *out, void *seq, void *a, void *b, gboolean *stop ) g_mutex_lock( render->lock ); - for( y = ys; y < VIPS_RECT_BOTTOM( r ); y += render->tile_height ) - for( x = xs; x < VIPS_RECT_RIGHT( r ); x += render->tile_width ) { + for( y = ys; y < VIPS_RECT_BOTTOM( r ); y += tile_height ) + for( x = xs; x < VIPS_RECT_RIGHT( r ); x += tile_width ) { VipsRect area; Tile *tile; int value; area.left = x; area.top = y; - area.width = render->tile_width; - area.height = render->tile_height; + area.width = tile_width; + area.height = tile_height; tile = render_tile_lookup( render, &area ); value = (tile && From 16830d69375f41b14b7b2eb790ac4f025d9ad318 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Tue, 28 Jan 2014 13:08:02 +0000 Subject: [PATCH 20/29] vips_sink_screen() now invalidates for you clients no longer need to call vips_image_invalidate_all() --- TODO | 10 ---------- libvips/include/vips/region.h | 2 ++ libvips/iofuncs/image.c | 8 +++++--- libvips/iofuncs/region.c | 19 +++++++++++++++++++ libvips/iofuncs/sinkscreen.c | 5 +++++ 5 files changed, 31 insertions(+), 13 deletions(-) diff --git a/TODO b/TODO index b0d478f2..2b7fb047 100644 --- a/TODO +++ b/TODO @@ -1,13 +1,3 @@ -- try: - - $ vips falsecolour k2.jpg x.jpg - vips warning: VipsJpeg: read gave 896 warnings - vips warning: VipsJpeg: Application transferred too many scanlines - - seems to read twice? - - problem in 7.38 too - - vips_colourspace() needs an option from_space param,? - check_uncoded() left to do: diff --git a/libvips/include/vips/region.h b/libvips/include/vips/region.h index a38bda33..ecc127d5 100644 --- a/libvips/include/vips/region.h +++ b/libvips/include/vips/region.h @@ -120,6 +120,8 @@ int vips_region_prepare_to( VipsRegion *reg, VipsRegion *dest, VipsRect *r, int x, int y ); int vips_region_prepare_many( VipsRegion **reg, VipsRect *r ); +void vips_region_invalidate( VipsRegion *reg ); + void vips_region_dump_all( void ); /* Macros on VipsRegion. diff --git a/libvips/iofuncs/image.c b/libvips/iofuncs/image.c index 5f765904..e97bcdef 100644 --- a/libvips/iofuncs/image.c +++ b/libvips/iofuncs/image.c @@ -953,9 +953,9 @@ vips_image_build( VipsObject *object ) } static void * -vips_region_invalidate( VipsRegion *reg ) +vips_image_real_invalidate_cb( VipsRegion *reg ) { - reg->invalid = TRUE; + vips_region_invalidate( reg ); return( NULL ); } @@ -972,7 +972,7 @@ vips_image_real_invalidate( VipsImage *image ) VIPS_GATE_STOP( "vips_image_real_invalidate: wait" ); (void) vips_slist_map2( image->regions, - (VipsSListMap2Fn) vips_region_invalidate, NULL, NULL ); + (VipsSListMap2Fn) vips_image_real_invalidate_cb, NULL, NULL ); g_mutex_unlock( image->sslock ); } @@ -1274,6 +1274,8 @@ vips_image_invalidate_all_cb( VipsImage *image ) * is, images which depend on this image. * * The "invalidate" callback is triggered for all invalidated images. + * + * See also: vips_region_invalidate(). */ void vips_image_invalidate_all( VipsImage *image ) diff --git a/libvips/iofuncs/region.c b/libvips/iofuncs/region.c index 1cf20a24..42152971 100644 --- a/libvips/iofuncs/region.c +++ b/libvips/iofuncs/region.c @@ -1375,6 +1375,25 @@ vips_region_prepare_many( VipsRegion **reg, VipsRect *r ) return( 0 ); } +/** + * vips_region_invalidate: + * @reg: region to invalidate + * + * Mark a region as containing invalid pixels. Calling this function means + * that the next time vips_region_prepare() is called, the region will be + * recalculated. + * + * This is faster than calling vips_image_invalidate_all(), but obviously only + * affects a single region. + * + * See also: vips_image_invalidate_all(), vips_region_prepare(). + */ +void +vips_region_invalidate( VipsRegion *reg ) +{ + reg->invalid = TRUE; +} + #ifdef VIPS_DEBUG static void * vips_region_dump_all_cb( VipsRegion *region, size_t *alive ) diff --git a/libvips/iofuncs/sinkscreen.c b/libvips/iofuncs/sinkscreen.c index ca9523c6..7ecbdc65 100644 --- a/libvips/iofuncs/sinkscreen.c +++ b/libvips/iofuncs/sinkscreen.c @@ -424,6 +424,11 @@ render_work( VipsThreadState *state, void *a ) } tile->painted = TRUE; + /* All downstream images must drop caches, since we've (effectively) + * modified render->out. + */ + vips_image_invalidate_all( render->out ); + /* Now clients can update. */ if( render->notify ) From 54f19a00e5121521086858d0da8c2b9e0b49fc21 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Tue, 28 Jan 2014 14:51:30 +0000 Subject: [PATCH 21/29] update valgrind supp --- TODO | 37 ++++++++++++++++++++++++ libvips.supp | 80 +++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 113 insertions(+), 4 deletions(-) diff --git a/TODO b/TODO index 2b7fb047..f4411419 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,40 @@ +- leak ... nip2 ~/pics/babe.jpg, ^Q + +==4389== 784 bytes in 1 blocks are possibly lost in loss record 14,881 of +15,393 +==4389== at 0x4C2A2DB: malloc (in +/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) +==4389== by 0x6749221: vips_tracked_malloc (memory.c:289) +==4389== by 0x67587E9: buffer_move (buffer.c:368) +==4389== by 0x675898B: vips_buffer_new (buffer.c:412) +==4389== by 0x6758C11: vips_buffer_unref_ref (buffer.c:519) +==4389== by 0x674F5FB: vips_region_buffer (region.c:602) +==4389== by 0x674FF73: vips_region_fill (region.c:887) +==4389== by 0x67505AD: vips_region_prepare (region.c:1139) +==4389== by 0x67400FB: vips_image_write_gen (image.c:1930) +==4389== by 0x67504CF: vips_region_generate (region.c:1074) +==4389== by 0x6750718: vips_region_prepare_to_generate (region.c:1196) +==4389== by 0x6750A55: vips_region_prepare_to (region.c:1315) + +==4389== 784 bytes in 1 blocks are possibly lost in loss record 14,882 of +15,393 +==4389== at 0x4C2A2DB: malloc (in +/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) +==4389== by 0x6749221: vips_tracked_malloc (memory.c:289) +==4389== by 0x67587E9: buffer_move (buffer.c:368) +==4389== by 0x6758BC6: vips_buffer_unref_ref (buffer.c:508) +==4389== by 0x674F5FB: vips_region_buffer (region.c:602) +==4389== by 0x674FF73: vips_region_fill (region.c:887) +==4389== by 0x67505AD: vips_region_prepare (region.c:1139) +==4389== by 0x67400FB: vips_image_write_gen (image.c:1930) +==4389== by 0x67504CF: vips_region_generate (region.c:1074) +==4389== by 0x6750718: vips_region_prepare_to_generate (region.c:1196) +==4389== by 0x6750A55: vips_region_prepare_to (region.c:1315) +==4389== by 0x6747EC1: render_work (sinkscreen.c:418) + + + + - vips_colourspace() needs an option from_space param,? - check_uncoded() left to do: diff --git a/libvips.supp b/libvips.supp index ef277189..c3b3e74c 100644 --- a/libvips.supp +++ b/libvips.supp @@ -45,7 +45,7 @@ init7 Memcheck:Leak ... - fun:g_malloc0 + fun:*alloc* ... fun:_dl_init } @@ -85,13 +85,29 @@ fun:XInitExtension } +{ + gio + Memcheck:Leak + fun:malloc + ... + fun:g_simple_async_result_complete +} + +{ + pthread + Memcheck:Leak + fun:calloc + fun:_dl_allocate_tls + fun:pthread_create@@GLIBC_* +} + # hide all dbus reports, not the app's problem { dbus Memcheck:Leak fun:*alloc ... - obj:/lib/libdbus-1.so.* + obj:*/libdbus-1.so.* } # hide all orbit leaks, not our problem @@ -112,6 +128,31 @@ fun:FcConfigParseAndLoad } +{ + fontconfig2 + Memcheck:Leak + fun:malloc + fun:strdup + fun:FcValueSave + obj:*/libfontconfig.so.* +} + +{ + fontconfig3 + Memcheck:Leak + fun:realloc + ... + fun:FcFontMatch +} + +{ + fontconfig4 + Memcheck:Leak + fun:realloc + ... + fun:FcPatternAddInteger +} + { freetype_init Memcheck:Leak @@ -120,6 +161,14 @@ fun:FT_Open_Face } +{ + harfbuzz + Memcheck:Leak + fun:calloc + ... + fun:hb_shape_plan_execute +} + { goffice_init Memcheck:Leak @@ -257,8 +306,6 @@ fun:write_vips } -# ubuntu 13.04 suppressions - { pixman1 Memcheck:Cond @@ -272,6 +319,30 @@ fun:rsvg_cairo_surface_to_pixbuf } +{ + rsvg + Memcheck:Cond + obj:*/librsvg-2.so.* +} + +{ + murrine + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:raico_blur_create +} + +{ + signal_connect + Memcheck:Leak + fun:calloc + fun:g_malloc0 + fun:g_closure_new_simple + fun:g_cclosure_new + fun:g_signal_connect_data +} + # ruby has some annoying ones too { @@ -304,3 +375,4 @@ + From 9cb152596c3cc5b83abcf5f07dd2ef41509ff381 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Wed, 29 Jan 2014 09:07:58 +0000 Subject: [PATCH 22/29] bg render thread quits on shutdown fixes a small memleak --- ChangeLog | 1 + TODO | 36 -------------- libvips/include/vips/private.h | 6 ++- libvips/iofuncs/buffer.c | 89 +++++++++++++++++++++++++--------- libvips/iofuncs/init.c | 6 +++ libvips/iofuncs/sinkscreen.c | 80 +++++++++++++++++++----------- 6 files changed, 129 insertions(+), 89 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9fe97e87..ec45da72 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,6 @@ 21/1/14 started 7.39.0 - auto-decode for (almost) all operations +- background render thread cleans up and quits neatly 22/1/14 started 7.38.2 - auto RAD decode for affine diff --git a/TODO b/TODO index f4411419..469c8703 100644 --- a/TODO +++ b/TODO @@ -1,39 +1,3 @@ -- leak ... nip2 ~/pics/babe.jpg, ^Q - -==4389== 784 bytes in 1 blocks are possibly lost in loss record 14,881 of -15,393 -==4389== at 0x4C2A2DB: malloc (in -/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) -==4389== by 0x6749221: vips_tracked_malloc (memory.c:289) -==4389== by 0x67587E9: buffer_move (buffer.c:368) -==4389== by 0x675898B: vips_buffer_new (buffer.c:412) -==4389== by 0x6758C11: vips_buffer_unref_ref (buffer.c:519) -==4389== by 0x674F5FB: vips_region_buffer (region.c:602) -==4389== by 0x674FF73: vips_region_fill (region.c:887) -==4389== by 0x67505AD: vips_region_prepare (region.c:1139) -==4389== by 0x67400FB: vips_image_write_gen (image.c:1930) -==4389== by 0x67504CF: vips_region_generate (region.c:1074) -==4389== by 0x6750718: vips_region_prepare_to_generate (region.c:1196) -==4389== by 0x6750A55: vips_region_prepare_to (region.c:1315) - -==4389== 784 bytes in 1 blocks are possibly lost in loss record 14,882 of -15,393 -==4389== at 0x4C2A2DB: malloc (in -/usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so) -==4389== by 0x6749221: vips_tracked_malloc (memory.c:289) -==4389== by 0x67587E9: buffer_move (buffer.c:368) -==4389== by 0x6758BC6: vips_buffer_unref_ref (buffer.c:508) -==4389== by 0x674F5FB: vips_region_buffer (region.c:602) -==4389== by 0x674FF73: vips_region_fill (region.c:887) -==4389== by 0x67505AD: vips_region_prepare (region.c:1139) -==4389== by 0x67400FB: vips_image_write_gen (image.c:1930) -==4389== by 0x67504CF: vips_region_generate (region.c:1074) -==4389== by 0x6750718: vips_region_prepare_to_generate (region.c:1196) -==4389== by 0x6750A55: vips_region_prepare_to (region.c:1315) -==4389== by 0x6747EC1: render_work (sinkscreen.c:418) - - - - vips_colourspace() needs an option from_space param,? diff --git a/libvips/include/vips/private.h b/libvips/include/vips/private.h index 6d3a1f89..a1ee8ebc 100644 --- a/libvips/include/vips/private.h +++ b/libvips/include/vips/private.h @@ -89,8 +89,8 @@ typedef struct { GThread *thread; /* Just for sanity checking */ } VipsBufferThread; -/* Per-image buffer cache. Hash to this from VipsBufferCache. - * We can't store the GSList directly in the hash table, as GHashTable lacks an +/* Per-image buffer cache. Hash to this from VipsBufferThread::hash. + * We can't store the GSList directly in the hash table as GHashTable lacks an * update operation and we'd need to _remove() and _insert() on every list * operation. */ @@ -127,6 +127,8 @@ VipsBuffer *vips_buffer_unref_ref( VipsBuffer *buffer, struct _VipsImage *im, VipsRect *area ); void vips_buffer_print( VipsBuffer *buffer ); +void vips__render_shutdown( void ); + /* Sections of region.h that are private to VIPS. */ diff --git a/libvips/iofuncs/buffer.c b/libvips/iofuncs/buffer.c index 62299a3f..950a16ef 100644 --- a/libvips/iofuncs/buffer.c +++ b/libvips/iofuncs/buffer.c @@ -50,10 +50,10 @@ */ /* -#define DEBUG_CREATE #define DEBUG_VERBOSE -#define DEBUG +#define DEBUG_CREATE */ +#define DEBUG #ifdef HAVE_CONFIG_H #include @@ -70,11 +70,11 @@ #ifdef DEBUG /* Track all regions here for debugging. */ -static GSList *vips__buffers_all = NULL; +static GSList *vips__buffer_all = NULL; #endif /*DEBUG*/ #ifdef DEBUG_CREATE -static int buffer_cache_n = 0; +static GSList *vips__buffer_cache_all = NULL; #endif /*DEBUG_CREATE*/ /* The maximum numbers of buffers we hold in reserve per image. @@ -87,13 +87,19 @@ static GPrivate *buffer_thread_key = NULL; static void * vips_buffer_dump( VipsBuffer *buffer, size_t *reserve, size_t *alive ) { + vips_buffer_print( buffer ); + if( buffer->im && - buffer->buf ) { - printf( "buffer %p, %gMB\n", + buffer->buf && + buffer->cache ) { + printf( "buffer %p, %.3g MB\n", buffer, buffer->bsize / (1024 * 1024.0) ); *alive += buffer->bsize; } - else if( !buffer->im ) + else + if( buffer->im && + buffer->buf && + !buffer->cache ) *reserve += buffer->bsize; else printf( "buffer craziness!\n" ); @@ -101,18 +107,47 @@ vips_buffer_dump( VipsBuffer *buffer, size_t *reserve, size_t *alive ) return( NULL ); } +#ifdef DEBUG_CREATE +static void * +vips_buffer_cache_dump( VipsBufferCache *cache ) +{ + printf( "VipsBufferCache: %p\n", cache ); + printf( "\t%d buffers\n", g_slist_length( cache->buffers ) ); + printf( "\tthread %p\n", cache->thread ); + printf( "\timage %p\n", cache->im ); + printf( "\tbuffer_thread %p\n", cache->buffer_thread ); + printf( "\t%d in reserve\n", g_slist_length( cache->reserve ) ); + + return( NULL ); +} +#endif /*DEBUG_CREATE*/ + void vips_buffer_dump_all( void ) { - size_t reserve; - size_t alive; + if( vips__buffer_all ) { + size_t reserve; + size_t alive; - reserve = 0; - alive = 0; - vips_slist_map2( vips__buffers_all, - (VipsSListMap2Fn) vips_buffer_dump, &reserve, &alive ); - printf( "%gMB alive\n", alive / (1024 * 1024.0) ); - printf( "%gMB in reserve\n", reserve / (1024 * 1024.0) ); + printf( "buffers:\n" ); + + reserve = 0; + alive = 0; + vips_slist_map2( vips__buffer_all, + (VipsSListMap2Fn) vips_buffer_dump, &reserve, &alive ); + printf( "%.3g MB alive\n", alive / (1024 * 1024.0) ); + printf( "%.3g MB in reserve\n", reserve / (1024 * 1024.0) ); + } + +#ifdef DEBUG_CREATE + if( vips__buffer_cache_all ) { + printf( "buffers: %d buffer cache still alive\n", + g_slist_length( vips__buffer_cache_all ) ); + vips_slist_map2( vips__buffer_cache_all, + (VipsSListMap2Fn) vips_buffer_cache_dump, NULL, NULL ); + printf( "g_thread_self() == %p\n", g_thread_self() ); + } +#endif /*DEBUG_CREATE*/ } #endif /*DEBUG*/ @@ -126,8 +161,8 @@ vips_buffer_free( VipsBuffer *buffer ) #ifdef DEBUG g_mutex_lock( vips__global_lock ); - g_assert( g_slist_find( vips__buffers_all, buffer ) ); - vips__buffers_all = g_slist_remove( vips__buffers_all, buffer ); + g_assert( g_slist_find( vips__buffer_all, buffer ) ); + vips__buffer_all = g_slist_remove( vips__buffer_all, buffer ); g_mutex_unlock( vips__global_lock ); #endif /*DEBUG*/ @@ -146,11 +181,15 @@ buffer_cache_free( VipsBufferCache *cache ) GSList *p; #ifdef DEBUG_CREATE - buffer_cache_n -= 1; + g_mutex_lock( vips__global_lock ); + vips__buffer_cache_all = + g_slist_remove( vips__buffer_cache_all, cache ); + g_mutex_unlock( vips__global_lock ); printf( "buffer_cache_free: freeing cache %p on thread %p\n", cache, g_thread_self() ); - printf( "\t(%d caches left)\n", buffer_cache_n ); + printf( "\t(%d caches left)\n", + g_slist_length( vips__buffer_cache_all ) ); #endif /*DEBUG_CREATE*/ /* Need to mark undone so we don't try and take them off this hash on @@ -187,11 +226,15 @@ buffer_cache_new( VipsBufferThread *buffer_thread, VipsImage *im ) cache->n_reserve = 0; #ifdef DEBUG_CREATE - buffer_cache_n += 1; + g_mutex_lock( vips__global_lock ); + vips__buffer_cache_all = + g_slist_prepend( vips__buffer_cache_all, cache ); + g_mutex_unlock( vips__global_lock ); printf( "buffer_cache_new: new cache %p for thread %p\n", cache, g_thread_self() ); - printf( "\t(%d caches now)\n", buffer_cache_n ); + printf( "\t(%d caches now)\n", + g_slist_length( vips__buffer_cache_all ) ); #endif /*DEBUG_CREATE*/ return( cache ); @@ -403,8 +446,8 @@ vips_buffer_new( VipsImage *im, VipsRect *area ) #ifdef DEBUG g_mutex_lock( vips__global_lock ); - vips__buffers_all = - g_slist_prepend( vips__buffers_all, buffer ); + vips__buffer_all = + g_slist_prepend( vips__buffer_all, buffer ); g_mutex_unlock( vips__global_lock ); #endif /*DEBUG*/ } diff --git a/libvips/iofuncs/init.c b/libvips/iofuncs/init.c index 7ab48b77..cda33dbb 100644 --- a/libvips/iofuncs/init.c +++ b/libvips/iofuncs/init.c @@ -368,6 +368,10 @@ vips_leak( void ) fprintf( stderr, "%s", vips_buf_all( &buf ) ); vips__type_leak(); + +#ifdef DEBUG +#endif /*DEBUG*/ + vips_buffer_dump_all(); } /** @@ -418,6 +422,8 @@ vips_shutdown( void ) vips__thread_gate_stop( "init: main" ); } + vips__render_shutdown(); + vips_thread_shutdown(); vips__thread_profile_stop(); diff --git a/libvips/iofuncs/sinkscreen.c b/libvips/iofuncs/sinkscreen.c index 7ecbdc65..71747254 100644 --- a/libvips/iofuncs/sinkscreen.c +++ b/libvips/iofuncs/sinkscreen.c @@ -5,6 +5,8 @@ * 25/11/10 * - in synchronous mode, use a single region for input and save huge * mem use + * 20/1/14 + * - bg render thread quits on shutdown */ /* @@ -160,6 +162,10 @@ static GThread *render_thread = NULL; */ static VipsSemaphore render_dirty_sem; +/* Set this to ask the render thread to quit. + */ +static gboolean render_kill = FALSE; + /* All the renders with dirty tiles. */ static GMutex *render_dirty_lock = NULL; @@ -476,44 +482,62 @@ render_dirty_put( Render *render ) static void * render_thread_main( void *client ) { - for(;;) { - Render *render; + Render *render; - if( (render = render_dirty_get()) ) { - /* Ignore errors, I'm not sure what we'd do with them - * anyway. - */ - VIPS_DEBUG_MSG_GREEN( "render_thread_main: " - "threadpool start\n" ); + while( (render = render_dirty_get()) && + !render_kill ) { + VIPS_DEBUG_MSG_GREEN( "render_thread_main: " + "threadpool start\n" ); - render_reschedule = FALSE; - if( vips_threadpool_run( render->in, - render_thread_state_new, - render_allocate, - render_work, - NULL, - render ) ) - VIPS_DEBUG_MSG_RED( "render_thread_main: " - "threadpool_run failed\n" ); + render_reschedule = FALSE; + if( vips_threadpool_run( render->in, + render_thread_state_new, + render_allocate, + render_work, + NULL, + render ) ) + VIPS_DEBUG_MSG_RED( "render_thread_main: " + "threadpool_run failed\n" ); - VIPS_DEBUG_MSG_GREEN( "render_thread_main: " - "threadpool return\n" ); + VIPS_DEBUG_MSG_GREEN( "render_thread_main: " + "threadpool return\n" ); - /* Add back to the jobs list, if we need to. - */ - render_dirty_put( render ); + /* Add back to the jobs list, if we need to. + */ + render_dirty_put( render ); - /* _get() does a ref to make sure we keep the render - * alive during processing ... unref before we loop. - * This can kill off the render. - */ - render_unref( render ); - } + /* _get() does a ref to make sure we keep the render + * alive during processing ... unref before we loop. + * This can kill off the render. + */ + render_unref( render ); } return( NULL ); } +void +vips__render_shutdown( void ) +{ + g_mutex_lock( render_dirty_lock ); + + if( render_thread ) { + GThread *thread; + + thread = render_thread; + render_thread = NULL; + + g_mutex_unlock( render_dirty_lock ); + + render_reschedule = TRUE; + render_kill = TRUE; + vips_semaphore_up( &render_dirty_sem ); + (void) g_thread_join( thread ); + } + else + g_mutex_unlock( render_dirty_lock ); +} + /* Create our set of RenderThread. Assume we're single-threaded here. */ static int From 1564213b6786fac5322ce9faa2f24b15f7e15717 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Wed, 29 Jan 2014 12:21:47 +0000 Subject: [PATCH 23/29] oop, invalidate mask as well --- libvips/iofuncs/sinkscreen.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libvips/iofuncs/sinkscreen.c b/libvips/iofuncs/sinkscreen.c index 71747254..54a377b2 100644 --- a/libvips/iofuncs/sinkscreen.c +++ b/libvips/iofuncs/sinkscreen.c @@ -434,6 +434,7 @@ render_work( VipsThreadState *state, void *a ) * modified render->out. */ vips_image_invalidate_all( render->out ); + vips_image_invalidate_all( render->mask ); /* Now clients can update. */ From 2cbaacbb0b2780c35fdf5e245ab1024d526c3c5a Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Wed, 29 Jan 2014 14:26:09 +0000 Subject: [PATCH 24/29] oops! --- libvips/iofuncs/sinkscreen.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libvips/iofuncs/sinkscreen.c b/libvips/iofuncs/sinkscreen.c index 54a377b2..59d6c664 100644 --- a/libvips/iofuncs/sinkscreen.c +++ b/libvips/iofuncs/sinkscreen.c @@ -434,7 +434,8 @@ render_work( VipsThreadState *state, void *a ) * modified render->out. */ vips_image_invalidate_all( render->out ); - vips_image_invalidate_all( render->mask ); + if( render->mask ) + vips_image_invalidate_all( render->mask ); /* Now clients can update. */ From f582c1bd4effc23bfe4273e4a8a5c3aa850a891c Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Fri, 31 Jan 2014 14:48:15 +0000 Subject: [PATCH 25/29] check for init before render shutdown we could shut down render without having inited it, check thanks andrea --- libvips/iofuncs/sinkscreen.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libvips/iofuncs/sinkscreen.c b/libvips/iofuncs/sinkscreen.c index 59d6c664..1c49efd9 100644 --- a/libvips/iofuncs/sinkscreen.c +++ b/libvips/iofuncs/sinkscreen.c @@ -521,6 +521,11 @@ render_thread_main( void *client ) void vips__render_shutdown( void ) { + /* We may come here without having inited. + */ + if( !render_dirty_lock ) + return; + g_mutex_lock( render_dirty_lock ); if( render_thread ) { From 4167bdf0e685146caa2200c34e2639e2d42f4ca3 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Mon, 3 Feb 2014 09:25:09 +0000 Subject: [PATCH 26/29] small operation description fixes more consistency, fix a couple of missing ones --- libvips/arithmetic/complex.c | 2 +- libvips/arithmetic/deviate.c | 2 +- libvips/arithmetic/hist_find_ndim.c | 2 +- libvips/arithmetic/math.c | 2 +- libvips/arithmetic/relational.c | 3 +-- libvips/convolution/compass.c | 2 +- libvips/convolution/convsep.c | 2 +- libvips/convolution/gaussblur.c | 2 +- libvips/convolution/sharpen.c | 2 +- libvips/resample/bicubic.cpp | 2 +- libvips/resample/interpolate.c | 4 ++-- libvips/resample/lbb.cpp | 2 +- libvips/resample/nohalo.cpp | 2 +- 13 files changed, 14 insertions(+), 15 deletions(-) diff --git a/libvips/arithmetic/complex.c b/libvips/arithmetic/complex.c index b6b0d01d..14b54d38 100644 --- a/libvips/arithmetic/complex.c +++ b/libvips/arithmetic/complex.c @@ -492,7 +492,7 @@ vips_complex2_class_init( VipsComplex2Class *class ) object_class->nickname = "complex2"; object_class->description = - _( "perform a binary complex operation on two images" ); + _( "complex binary operations on two images" ); aclass->process_line = vips_complex2_buffer; diff --git a/libvips/arithmetic/deviate.c b/libvips/arithmetic/deviate.c index 86fc4b4e..2446eb39 100644 --- a/libvips/arithmetic/deviate.c +++ b/libvips/arithmetic/deviate.c @@ -210,7 +210,7 @@ vips_deviate_class_init( VipsDeviateClass *class ) gobject_class->get_property = vips_object_get_property; object_class->nickname = "deviate"; - object_class->description = _( "find image average" ); + object_class->description = _( "find image standard deviation" ); object_class->build = vips_deviate_build; sclass->start = vips_deviate_start; diff --git a/libvips/arithmetic/hist_find_ndim.c b/libvips/arithmetic/hist_find_ndim.c index 85db4a98..c18a0b54 100644 --- a/libvips/arithmetic/hist_find_ndim.c +++ b/libvips/arithmetic/hist_find_ndim.c @@ -286,7 +286,7 @@ vips_hist_find_ndim_class_init( VipsHistFindNDimClass *class ) gobject_class->get_property = vips_object_get_property; object_class->nickname = "hist_find_ndim"; - object_class->description = _( "find image histogram" ); + object_class->description = _( "find n-dimensional image histogram" ); object_class->build = vips_hist_find_ndim_build; sclass->start = vips_hist_find_ndim_start; diff --git a/libvips/arithmetic/math.c b/libvips/arithmetic/math.c index df9fe75e..aad84c96 100644 --- a/libvips/arithmetic/math.c +++ b/libvips/arithmetic/math.c @@ -196,7 +196,7 @@ vips_math_class_init( VipsMathClass *class ) gobject_class->get_property = vips_object_get_property; object_class->nickname = "math"; - object_class->description = _( "perform a math function on an image" ); + object_class->description = _( "apply a math operation to an image" ); object_class->build = vips_math_build; aclass->process_line = vips_math_buffer; diff --git a/libvips/arithmetic/relational.c b/libvips/arithmetic/relational.c index e40f36fa..c12672d7 100644 --- a/libvips/arithmetic/relational.c +++ b/libvips/arithmetic/relational.c @@ -216,8 +216,7 @@ vips_relational_class_init( VipsRelationalClass *class ) gobject_class->get_property = vips_object_get_property; object_class->nickname = "relational"; - object_class->description = - _( "a relational operation on a pair of images" ); + object_class->description = _( "relational operation on two images" ); object_class->build = vips_relational_build; aclass->process_line = vips_relational_buffer; diff --git a/libvips/convolution/compass.c b/libvips/convolution/compass.c index 5ff9c522..9a173834 100644 --- a/libvips/convolution/compass.c +++ b/libvips/convolution/compass.c @@ -142,7 +142,7 @@ vips_compass_class_init( VipsCompassClass *class ) gobject_class->get_property = vips_object_get_property; object_class->nickname = "compass"; - object_class->description = _( "convolution operation" ); + object_class->description = _( "convolve with rotaing mask" ); object_class->build = vips_compass_build; VIPS_ARG_INT( class, "times", 101, diff --git a/libvips/convolution/convsep.c b/libvips/convolution/convsep.c index b942f67b..196ec28a 100644 --- a/libvips/convolution/convsep.c +++ b/libvips/convolution/convsep.c @@ -100,7 +100,7 @@ vips_convsep_class_init( VipsConvsepClass *class ) gobject_class->get_property = vips_object_get_property; object_class->nickname = "convsep"; - object_class->description = _( "convolution operation" ); + object_class->description = _( "seperable convolution operation" ); object_class->build = vips_convsep_build; VIPS_ARG_ENUM( class, "precision", 203, diff --git a/libvips/convolution/gaussblur.c b/libvips/convolution/gaussblur.c index b3290a56..8b1c253c 100644 --- a/libvips/convolution/gaussblur.c +++ b/libvips/convolution/gaussblur.c @@ -108,7 +108,7 @@ vips_gaussblur_class_init( VipsGaussblurClass *class ) gobject_class->get_property = vips_object_get_property; object_class->nickname = "gaussblur"; - object_class->description = _( "Unsharp masking for print" ); + object_class->description = _( "gaussian blur" ); object_class->build = vips_gaussblur_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; diff --git a/libvips/convolution/sharpen.c b/libvips/convolution/sharpen.c index 37eaaa60..5860b230 100644 --- a/libvips/convolution/sharpen.c +++ b/libvips/convolution/sharpen.c @@ -309,7 +309,7 @@ vips_sharpen_class_init( VipsSharpenClass *class ) gobject_class->get_property = vips_object_get_property; object_class->nickname = "sharpen"; - object_class->description = _( "Unsharp masking for print" ); + object_class->description = _( "unsharp masking for print" ); object_class->build = vips_sharpen_build; operation_class->flags = VIPS_OPERATION_SEQUENTIAL; diff --git a/libvips/resample/bicubic.cpp b/libvips/resample/bicubic.cpp index c59e23b8..1488f8c9 100644 --- a/libvips/resample/bicubic.cpp +++ b/libvips/resample/bicubic.cpp @@ -428,7 +428,7 @@ vips_interpolate_bicubic_class_init( VipsInterpolateBicubicClass *iclass ) VIPS_INTERPOLATE_CLASS( iclass ); object_class->nickname = "bicubic"; - object_class->description = _( "Bicubic interpolation (Catmull-Rom)" ); + object_class->description = _( "bicubic interpolation (Catmull-Rom)" ); interpolate_class->interpolate = vips_interpolate_bicubic_interpolate; interpolate_class->window_size = 4; diff --git a/libvips/resample/interpolate.c b/libvips/resample/interpolate.c index 42b83309..a58ffb25 100644 --- a/libvips/resample/interpolate.c +++ b/libvips/resample/interpolate.c @@ -354,7 +354,7 @@ vips_interpolate_nearest_class_init( VipsInterpolateNearestClass *class ) VIPS_INTERPOLATE_CLASS( class ); object_class->nickname = "nearest"; - object_class->description = _( "Nearest-neighbour interpolation" ); + object_class->description = _( "nearest-neighbour interpolation" ); interpolate_class->interpolate = vips_interpolate_nearest_interpolate; interpolate_class->window_size = 1; @@ -525,7 +525,7 @@ vips_interpolate_bilinear_class_init( VipsInterpolateBilinearClass *class ) (VipsInterpolateClass *) class; object_class->nickname = "bilinear"; - object_class->description = _( "Bilinear interpolation" ); + object_class->description = _( "bilinear interpolation" ); interpolate_class->interpolate = vips_interpolate_bilinear_interpolate; interpolate_class->window_size = 2; diff --git a/libvips/resample/lbb.cpp b/libvips/resample/lbb.cpp index b47aa6c5..c664460a 100644 --- a/libvips/resample/lbb.cpp +++ b/libvips/resample/lbb.cpp @@ -856,7 +856,7 @@ vips_interpolate_lbb_class_init( VipsInterpolateLbbClass *klass ) VIPS_INTERPOLATE_CLASS( klass ); object_class->nickname = "lbb"; - object_class->description = _( "Reduced halo bicubic" ); + object_class->description = _( "reduced halo bicubic" ); interpolate_class->interpolate = vips_interpolate_lbb_interpolate; interpolate_class->window_size = 4; diff --git a/libvips/resample/nohalo.cpp b/libvips/resample/nohalo.cpp index 6b730814..374ab2bd 100644 --- a/libvips/resample/nohalo.cpp +++ b/libvips/resample/nohalo.cpp @@ -1577,7 +1577,7 @@ vips_interpolate_nohalo_class_init( VipsInterpolateNohaloClass *klass ) object_class->nickname = "nohalo"; object_class->description = - _( "Edge sharpening resampler with halo reduction" ); + _( "edge sharpening resampler with halo reduction" ); interpolate_class->interpolate = vips_interpolate_nohalo_interpolate; interpolate_class->window_size = 5; From 874511470f6f1c56b22749c4fe3b2c3c87a84f29 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Mon, 3 Feb 2014 09:33:15 +0000 Subject: [PATCH 27/29] add source_space to vips_colourspace() you can now specify the source colourspace, if you want --- ChangeLog | 1 + TODO | 3 +-- libvips/colour/colourspace.c | 25 ++++++++++++++++++++++--- 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/ChangeLog b/ChangeLog index ec45da72..ebac3ca5 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ 21/1/14 started 7.39.0 - auto-decode for (almost) all operations - background render thread cleans up and quits neatly +- colourspace has a source_space option 22/1/14 started 7.38.2 - auto RAD decode for affine diff --git a/TODO b/TODO index 469c8703..a2ecc5ca 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,4 @@ - -- vips_colourspace() needs an option from_space param,? +- can we deprecate classes? eg. VipsFormat and VipsWrap7 should be hidden - check_uncoded() left to do: diff --git a/libvips/colour/colourspace.c b/libvips/colour/colourspace.c index 111438ed..fbbba5a8 100644 --- a/libvips/colour/colourspace.c +++ b/libvips/colour/colourspace.c @@ -8,6 +8,8 @@ * - add RGB16 as a source * 19/1/14 * - auto-decode RAD images + * 3/2/14 + * - add "source_space", overrides source space guess */ /* @@ -388,6 +390,7 @@ typedef struct _VipsColourspace { VipsImage *in; VipsImage *out; VipsInterpretation space; + VipsInterpretation source_space; } VipsColourspace; typedef VipsOperationClass VipsColourspaceClass; @@ -408,7 +411,6 @@ vips_colourspace_build( VipsObject *object ) VipsInterpretation interpretation; - /* Verify that all input args have been set. */ if( VIPS_OBJECT_CLASS( vips_colourspace_parent_class )-> @@ -426,7 +428,10 @@ vips_colourspace_build( VipsObject *object ) x = t[0]; } - interpretation = vips_image_guess_interpretation( x ); + if( vips_object_argument_isset( object, "source_space" ) ) + interpretation = colourspace->source_space; + else + interpretation = vips_image_guess_interpretation( x ); /* Treat RGB and RGB16 as sRGB. If you want some other treatment, * you'll need to use the icc funcs. @@ -506,11 +511,20 @@ vips_colourspace_class_init( VipsColourspaceClass *class ) VIPS_ARGUMENT_REQUIRED_INPUT, G_STRUCT_OFFSET( VipsColourspace, space ), VIPS_TYPE_INTERPRETATION, VIPS_INTERPRETATION_sRGB ); + + VIPS_ARG_ENUM( class, "source-space", 6, + _( "Source space" ), + _( "Source colour space" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsColourspace, source_space ), + VIPS_TYPE_INTERPRETATION, VIPS_INTERPRETATION_sRGB ); + } static void vips_colourspace_init( VipsColourspace *colourspace ) { + colourspace->source_space = VIPS_INTERPRETATION_sRGB; } /** @@ -519,7 +533,12 @@ vips_colourspace_init( VipsColourspace *colourspace ) * @out: output image * @space: convert to this colour space * - * This operation looks at the interpretation field of @in and runs + * Optional arguments: + * + * @source_space: input colour space + * + * This operation looks at the interpretation field of @in (or uses + * @source_space, if set) and runs * a set of colourspace conversion functions to move it to @space. * * For example, given an image tagged as #VIPS_INTERPRETATION_YXY, running From 9f2169748b1de5143a8ddc1301ac2974349df890 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Mon, 3 Feb 2014 11:26:15 +0000 Subject: [PATCH 28/29] sync --- TODO | 45 ++++++++++++++-------------------------- libvips/iofuncs/object.c | 9 ++++++-- 2 files changed, 23 insertions(+), 31 deletions(-) diff --git a/TODO b/TODO index a2ecc5ca..6e7db58e 100644 --- a/TODO +++ b/TODO @@ -1,9 +1,24 @@ - can we deprecate classes? eg. VipsFormat and VipsWrap7 should be hidden + we have + + gboolean output_needs_arg; + + in vipsobjectclass at the moment, but that's the only flag-like thing + + add a get_flags() member whose values include needs_arg and deprecated? + + add a couple of void * blank pointers to object and objectclass for future + expansion .. a couple of ints as well? + +- introspection example in gist should not list abstract classes? + - check_uncoded() left to do: resample/quadratic.c +- move vips__image_decode() into the public API + - we vips_image_write() a lot, could we do this by int @@ -22,33 +37,6 @@ is there any point doing this? only useful on 32-bit machines, which don't really exist any more -- shrink does not auto unpack labq or rad, should it? - -- others .. differences in: - -grep -l CODING_LABQ */*.c -conversion/join.c -conversion/msb.c -inplace/im_draw_mask.c -resample/shrink.c - -grep -l CODING_RAD */*.c -conversion/embed.c -inplace/flood.c -inplace/im_draw_image.c - -- add unpack everywhere, eg. arithmetic - - look for - - vips_check_uncoded - - certainly can use it there - - - -- move vips__image_decode() into the public API - - need to do mosaicing and inplace, plus im_label_regions in morph - now vips_linear() has uchar output, can we do something with orc? @@ -65,8 +53,7 @@ inplace/im_draw_image.c interpolator would need to be built for the bands / stride / type of the image - need new API For this, since interpolators currently work for any image - + need new API For this since interpolators currently work for any image - vips_gaussblur() should switch to float prec if given a float image? diff --git a/libvips/iofuncs/object.c b/libvips/iofuncs/object.c index bb93e76f..605a9c4a 100644 --- a/libvips/iofuncs/object.c +++ b/libvips/iofuncs/object.c @@ -1708,9 +1708,9 @@ gboolean vips_object_argument_needsstring( VipsObject *object, const char *name ) { GParamSpec *pspec; - GType otype; VipsArgumentClass *argument_class; VipsArgumentInstance *argument_instance; + GType otype; VipsObjectClass *oclass; #ifdef DEBUG @@ -1725,10 +1725,15 @@ vips_object_argument_needsstring( VipsObject *object, const char *name ) /* Bools, input or output, don't need args. */ return( FALSE ); - else if( argument_class->flags & VIPS_ARGUMENT_INPUT ) + + if( argument_class->flags & VIPS_ARGUMENT_INPUT ) /* All other inputs need something. */ return( TRUE ); + + /* Just output objects. + */ + if( (otype = G_PARAM_SPEC_VALUE_TYPE( pspec )) && g_type_is_a( otype, VIPS_TYPE_OBJECT ) && (oclass = g_type_class_ref( otype )) ) From b72818a2b85c0076993a9702f35380b1e35c266f Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Mon, 3 Feb 2014 13:23:58 +0000 Subject: [PATCH 29/29] add VIPS_OPERATION_DEPRECATED and fix a tiny problem in vipswrap7 --- ChangeLog | 1 + TODO | 14 ------------- libvips/deprecated/wrapvips7.c | 20 +++++++++++++----- libvips/include/vips/object.h | 36 +++++++------------------------- libvips/include/vips/operation.h | 3 ++- libvips/iofuncs/enumtypes.c | 1 + libvips/iofuncs/object.c | 29 +++++++++++++++++++++++++ libvips/iofuncs/operation.c | 4 ++++ 8 files changed, 60 insertions(+), 48 deletions(-) diff --git a/ChangeLog b/ChangeLog index ebac3ca5..a97c1924 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,7 @@ - auto-decode for (almost) all operations - background render thread cleans up and quits neatly - colourspace has a source_space option +- operations can be tagged as "deprecated" 22/1/14 started 7.38.2 - auto RAD decode for affine diff --git a/TODO b/TODO index 6e7db58e..3831bfd4 100644 --- a/TODO +++ b/TODO @@ -1,17 +1,3 @@ -- can we deprecate classes? eg. VipsFormat and VipsWrap7 should be hidden - - we have - - gboolean output_needs_arg; - - in vipsobjectclass at the moment, but that's the only flag-like thing - - add a get_flags() member whose values include needs_arg and deprecated? - - add a couple of void * blank pointers to object and objectclass for future - expansion .. a couple of ints as well? - -- introspection example in gist should not list abstract classes? - check_uncoded() left to do: diff --git a/libvips/deprecated/wrapvips7.c b/libvips/deprecated/wrapvips7.c index 4b0165f6..bcb15c91 100644 --- a/libvips/deprecated/wrapvips7.c +++ b/libvips/deprecated/wrapvips7.c @@ -183,8 +183,7 @@ vips_wrap7_vargv_dispose( im_function *fn, im_object *vargv ) case VIPS_WRAP7_INTERPOLATE: case VIPS_WRAP7_IMAGE: - if( vargv[i] ) - VIPS_UNREF( vargv[i] ); + VIPS_UNREF( vargv[i] ); break; case VIPS_WRAP7_IMAGEVEC: @@ -193,13 +192,21 @@ vips_wrap7_vargv_dispose( im_function *fn, im_object *vargv ) int j; for( j = 0; j < iv->n; j++ ) - if( iv->vec[j] ) - VIPS_UNREF( iv->vec[j] ); + VIPS_UNREF( iv->vec[j] ); } break; case VIPS_WRAP7_GVALUE: - g_value_unset( vargv[i] ); + if( vargv[i] ) { + GValue *value = (GValue *) vargv[i]; + + if( G_VALUE_TYPE( value ) ) + g_value_unset( value ); + } + break; + + case VIPS_WRAP7_STRING: + VIPS_FREE( vargv[i] ); break; default: @@ -686,6 +693,7 @@ vips_wrap7_class_init( VipsWrap7Class *class ) { GObjectClass *gobject_class = (GObjectClass *) class; VipsObjectClass *vobject_class = (VipsObjectClass *) class; + VipsOperationClass *operation_class = (VipsOperationClass *) class; gobject_class->dispose = vips_wrap7_dispose; gobject_class->finalize = vips_wrap7_finalize; @@ -695,6 +703,8 @@ vips_wrap7_class_init( VipsWrap7Class *class ) vobject_class->build = vips_wrap7_build; vobject_class->summary_class = vips_wrap7_summary_class; vobject_class->dump = vips_wrap7_dump; + + operation_class->flags = VIPS_OPERATION_DEPRECATED; } static void diff --git a/libvips/include/vips/object.h b/libvips/include/vips/object.h index 5d27210a..2184491a 100644 --- a/libvips/include/vips/object.h +++ b/libvips/include/vips/object.h @@ -55,34 +55,6 @@ typedef struct _VipsObjectClass VipsObjectClass; /* Track extra stuff for arguments to objects */ -/** - * VipsArgumentFlags: - * @VIPS_ARGUMENT_NONE: no flags - * @VIPS_ARGUMENT_REQUIRED: must be set in the constructor - * @VIPS_ARGUMENT_CONSTRUCT: can only be set in the constructor - * @VIPS_ARGUMENT_SET_ONCE: can only be set once - * @VIPS_ARGUMENT_SET_ALWAYS: don't do use-before-set checks - * @VIPS_ARGUMENT_INPUT: is an input argument (one we depend on) - * @VIPS_ARGUMENT_OUTPUT: is an output argument (depends on us) - * @VIPS_ARGUMENT_DEPRECATED: just there for back-compat, hide - * - * Flags we associate with each object argument. - * - * Have separate input & output flags. Both set is an error; neither set is OK. - * - * Input gobjects are automatically reffed, output gobjects automatically ref - * us. We also automatically watch for "destroy" and unlink. - * - * @VIPS_ARGUMENT_SET_ALWAYS is handy for arguments which are set from C. For - * example, VipsImage::width is a property that gives access to the Xsize - * member of struct _VipsImage. We default its 'assigned' to TRUE - * since the field is always set directly by C. - * - * @VIPS_ARGUMENT_DEPRECATED arguments are not shown in help text, are not - * looked for if required, are not checked for "have-been-set". You can - * deprecate a required argument, but you must obviously add a new required - * argument if you do. - */ typedef enum /*< flags >*/ { VIPS_ARGUMENT_NONE = 0, VIPS_ARGUMENT_REQUIRED = 1, @@ -461,6 +433,7 @@ struct _VipsObject { * profiling. */ size_t local_memory; + }; struct _VipsObjectClass { @@ -561,6 +534,13 @@ struct _VipsObjectClass { */ GSList *argument_table_traverse; GType argument_table_traverse_gtype; + + /* Reserved for future expansion. + */ + void (*_vips_reserved1)( void ); + void (*_vips_reserved2)( void ); + void (*_vips_reserved3)( void ); + void (*_vips_reserved4)( void ); }; gboolean vips_value_is_null( GParamSpec *psoec, const GValue *value ); diff --git a/libvips/include/vips/operation.h b/libvips/include/vips/operation.h index 18270e13..e9697e61 100644 --- a/libvips/include/vips/operation.h +++ b/libvips/include/vips/operation.h @@ -41,7 +41,8 @@ typedef enum /*< flags >*/ { VIPS_OPERATION_NONE = 0, VIPS_OPERATION_SEQUENTIAL = 1, VIPS_OPERATION_SEQUENTIAL_UNBUFFERED = 2, - VIPS_OPERATION_NOCACHE = 4 + VIPS_OPERATION_NOCACHE = 4, + VIPS_OPERATION_DEPRECATED = 8 } VipsOperationFlags; #define VIPS_TYPE_OPERATION (vips_operation_get_type()) diff --git a/libvips/iofuncs/enumtypes.c b/libvips/iofuncs/enumtypes.c index 7ab61739..fec6fe77 100644 --- a/libvips/iofuncs/enumtypes.c +++ b/libvips/iofuncs/enumtypes.c @@ -624,6 +624,7 @@ vips_operation_flags_get_type( void ) {VIPS_OPERATION_SEQUENTIAL, "VIPS_OPERATION_SEQUENTIAL", "sequential"}, {VIPS_OPERATION_SEQUENTIAL_UNBUFFERED, "VIPS_OPERATION_SEQUENTIAL_UNBUFFERED", "sequential-unbuffered"}, {VIPS_OPERATION_NOCACHE, "VIPS_OPERATION_NOCACHE", "nocache"}, + {VIPS_OPERATION_DEPRECATED, "VIPS_OPERATION_DEPRECATED", "deprecated"}, {0, NULL, NULL} }; diff --git a/libvips/iofuncs/object.c b/libvips/iofuncs/object.c index 605a9c4a..37948b4f 100644 --- a/libvips/iofuncs/object.c +++ b/libvips/iofuncs/object.c @@ -79,6 +79,35 @@ * */ +/** + * VipsArgumentFlags: + * @VIPS_ARGUMENT_NONE: no flags + * @VIPS_ARGUMENT_REQUIRED: must be set in the constructor + * @VIPS_ARGUMENT_CONSTRUCT: can only be set in the constructor + * @VIPS_ARGUMENT_SET_ONCE: can only be set once + * @VIPS_ARGUMENT_SET_ALWAYS: don't do use-before-set checks + * @VIPS_ARGUMENT_INPUT: is an input argument (one we depend on) + * @VIPS_ARGUMENT_OUTPUT: is an output argument (depends on us) + * @VIPS_ARGUMENT_DEPRECATED: just there for back-compat, hide + * + * Flags we associate with each object argument. + * + * Have separate input & output flags. Both set is an error; neither set is OK. + * + * Input gobjects are automatically reffed, output gobjects automatically ref + * us. We also automatically watch for "destroy" and unlink. + * + * @VIPS_ARGUMENT_SET_ALWAYS is handy for arguments which are set from C. For + * example, VipsImage::width is a property that gives access to the Xsize + * member of struct _VipsImage. We default its 'assigned' to TRUE + * since the field is always set directly by C. + * + * @VIPS_ARGUMENT_DEPRECATED arguments are not shown in help text, are not + * looked for if required, are not checked for "have-been-set". You can + * deprecate a required argument, but you must obviously add a new required + * argument if you do. + */ + /* Our signals. */ enum { diff --git a/libvips/iofuncs/operation.c b/libvips/iofuncs/operation.c index 94a3592d..cd2e17e2 100644 --- a/libvips/iofuncs/operation.c +++ b/libvips/iofuncs/operation.c @@ -70,6 +70,7 @@ * @VIPS_OPERATION_NONE: no flags * @VIPS_OPERATION_SEQUENTIAL: can work sequentially * @VIPS_OPERATION_NOCACHE: must not be cached + * @VIPS_OPERATION_DEPRECATED: a compatibility thing * * Flags we associate with an operation. * @@ -83,6 +84,9 @@ * * @VIPS_OPERATION_NOCACHE means that the operation must not be cached by * vips. + * + * @VIPS_OPERATION_DEPRECATED means this is an old operation kept in vips for + * compatibility only and should be hidden from users. */ /* Abstract base class for operations.