From 85615a7fbd8a6571eb0e1c8f18b4dd6f36da3474 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Thu, 29 Mar 2018 09:18:36 +0100 Subject: [PATCH 1/6] gtk-doc annotation update --- libvips/conversion/bandjoin.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libvips/conversion/bandjoin.c b/libvips/conversion/bandjoin.c index f5327a48..7f284907 100644 --- a/libvips/conversion/bandjoin.c +++ b/libvips/conversion/bandjoin.c @@ -499,7 +499,7 @@ vips_bandjoin_const1( VipsImage *in, VipsImage **out, double c, ... ) return( result ); } -/* vips_addalpha: +/* vips_addalpha: (method) * @in: input image * @out: (out): output image * @...: %NULL-terminated list of optional named arguments From e686614f2ce4a130ecb8f264d100410ac55a7507 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Sun, 1 Apr 2018 10:32:48 +0100 Subject: [PATCH 2/6] drop incompatible profiles from save libpng has started throwing hard errors if the profile does not match the image -- this can happen all the time with perofiles inherited from images that have been processed. Test profiles before save and drop them (with a warning) if they are incompatible with the image. --- ChangeLog | 1 + libvips/colour/icc_transform.c | 37 ++++++++++++++++++++++++++++++++++ libvips/foreign/foreign.c | 17 ++++++++++++++++ libvips/foreign/vipspng.c | 3 ++- libvips/include/vips/colour.h | 2 ++ 5 files changed, 59 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 2f015aed..ff184274 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,7 @@ - add vips_rotate() ... a convenience method for vips_similarity() - svgload was missing is_a [lovell] - better header sniffing for small files +- drop incompatible ICC profiles before save 12/3/18 started 8.6.4 - better fitting of fonts with overhanging edges, thanks Adrià diff --git a/libvips/colour/icc_transform.c b/libvips/colour/icc_transform.c index 7b9d0d53..67053214 100644 --- a/libvips/colour/icc_transform.c +++ b/libvips/colour/icc_transform.c @@ -1226,6 +1226,36 @@ vips_icc_ac2rc( VipsImage *in, VipsImage **out, const char *profile_filename ) return( 0 ); } +/* TRUE if a profile is compatible with an image. + */ +gboolean +vips_icc_is_compatible_profile( VipsImage *image, + void *data, size_t data_length ) +{ + cmsHPROFILE profile; + + if( !(profile = cmsOpenProfileFromMem( data, data_length )) ) { + g_warning( "%s", _( "corrupt profile" ) ); + return( FALSE ); + } + + if( vips_image_expected_bands( image ) != + vips_icc_profile_needs_bands( profile ) ) { + VIPS_FREEF( cmsCloseProfile, profile ); + g_warning( "%s", + _( "profile incompatible with image" ) ); + return( FALSE ); + } + if( vips_image_expected_sig( image ) != cmsGetColorSpace( profile ) ) { + VIPS_FREEF( cmsCloseProfile, profile ); + g_warning( "%s", + _( "profile colourspace differs from image" ) ); + return( FALSE ); + } + + return( TRUE ); +} + #else /*!HAVE_LCMS2*/ #include @@ -1245,6 +1275,13 @@ vips_icc_ac2rc( VipsImage *in, VipsImage **out, const char *profile_filename ) return( -1 ); } +gboolean +vips_icc_is_compatible_profile( VipsImage *image, + void *data, size_t data_length ) +{ + return( TRUE ); +} + #endif /*HAVE_LCMS*/ /** diff --git a/libvips/foreign/foreign.c b/libvips/foreign/foreign.c index 61c87e03..f32302b9 100644 --- a/libvips/foreign/foreign.c +++ b/libvips/foreign/foreign.c @@ -22,6 +22,8 @@ * - META_SEQ support moved here * 5/3/18 * - block _start if one start fails, see #893 + * 1/4/18 + * - drop incompatible ICC profiles before save */ /* @@ -1504,6 +1506,21 @@ vips__foreign_convert_saveable( VipsImage *in, VipsImage **ready, in = out; } + /* Some format libraries, like libpng, will throw a hard error if the + * profile is inappropriate for this image type. With profiles inherited + * from a source image, this can happen all the time, so we + * want to just drop the profile in this case. + */ + if( vips_image_get_typeof( in, VIPS_META_ICC_NAME ) ) { + void *data; + size_t length; + + if( !vips_image_get_blob( in, VIPS_META_ICC_NAME, + &data, &length ) && + !vips_icc_is_compatible_profile( in, data, length ) ) + vips_image_remove( in, VIPS_META_ICC_NAME ); + } + *ready = in; return( 0 ); diff --git a/libvips/foreign/vipspng.c b/libvips/foreign/vipspng.c index b645da3a..a7aaf963 100644 --- a/libvips/foreign/vipspng.c +++ b/libvips/foreign/vipspng.c @@ -992,7 +992,8 @@ write_vips( Write *write, /* If we're an intel byte order CPU and this is a 16bit image, we need * to swap bytes. */ - if( bit_depth > 8 && !vips_amiMSBfirst() ) + if( bit_depth > 8 && + !vips_amiMSBfirst() ) png_set_swap( write->pPng ); if( interlace ) diff --git a/libvips/include/vips/colour.h b/libvips/include/vips/colour.h index 77404b9c..7978d325 100644 --- a/libvips/include/vips/colour.h +++ b/libvips/include/vips/colour.h @@ -177,6 +177,8 @@ int vips_icc_export( VipsImage *in, VipsImage **out, ... ) __attribute__((sentinel)); int vips_icc_ac2rc( VipsImage *in, VipsImage **out, const char *profile_filename ); +gboolean vips_icc_is_compatible_profile( VipsImage *image, + void *data, size_t data_length ); int vips_dE76( VipsImage *left, VipsImage *right, VipsImage **out, ... ) __attribute__((sentinel)); From 0dd6b095aa1366e20709e29b64da928299b63a6c Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Tue, 3 Apr 2018 14:36:43 +0100 Subject: [PATCH 3/6] more conservative hasalpha The result of hasalpha is used to turn on things like premultiplication, so we should be rather conservative about when we signal this. We don't want to premultiply things that should not be premultiplied. Check Type as well as bands. See: https://github.com/jcupitt/libvips/issues/918 --- ChangeLog | 1 + libvips/iofuncs/image.c | 45 ++++++++++++++++++++++++++++++++++------- 2 files changed, 39 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index ff184274..83949abd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,6 +10,7 @@ - svgload was missing is_a [lovell] - better header sniffing for small files - drop incompatible ICC profiles before save +- better hasalpha rules 12/3/18 started 8.6.4 - better fitting of fonts with overhanging edges, thanks Adrià diff --git a/libvips/iofuncs/image.c b/libvips/iofuncs/image.c index 411e0b15..9045449f 100644 --- a/libvips/iofuncs/image.c +++ b/libvips/iofuncs/image.c @@ -12,8 +12,10 @@ * - vips_image_write() does not ref input for non-partial images * 29/10/16 * - add vips_image_hasalpha() - * 11/10/1 + * 11/10/17 * - more severing for vips_image_write() + * 3/4/18 + * - better rules for hasalpha */ /* @@ -2866,18 +2868,47 @@ vips_image_ispartial( VipsImage *image ) * vips_image_hasalpha: (method) * @image: image to check * - * libvips assumes an image has an alpha if it has two bands (ie. it is a - * monochrome image with an extra band), if it has four bands (unless it's been - * tagged as CMYK), or if it has more than four bands. + * Look at an image's interpretation and see if it has extra alpha bands. For + * example, a 4-band #VIPS_INTERPRETATION_RGB would, but a six-band + * #VIPS_INTERPRETATION_MULTIBAND would not. * * Return %TRUE if @image has an alpha channel. */ gboolean vips_image_hasalpha( VipsImage *image ) { - return( image->Bands == 2 || - (image->Bands == 4 && image->Type != VIPS_INTERPRETATION_CMYK) || - image->Bands > 4 ); + /* The result of hasalpha is used to turn on things like + * premultiplication, so we are rather conservative about when we + * signal this. We don't want to premultiply things that should not be + * premultiplied. + */ + switch( image->Type ) { + case VIPS_INTERPRETATION_B_W: + case VIPS_INTERPRETATION_GREY16: + return( image->Bands > 1 ); + + case VIPS_INTERPRETATION_RGB: + case VIPS_INTERPRETATION_CMC: + case VIPS_INTERPRETATION_LCH: + case VIPS_INTERPRETATION_LABS: + case VIPS_INTERPRETATION_sRGB: + case VIPS_INTERPRETATION_YXY: + case VIPS_INTERPRETATION_XYZ: + case VIPS_INTERPRETATION_LAB: + case VIPS_INTERPRETATION_RGB16: + case VIPS_INTERPRETATION_scRGB: + case VIPS_INTERPRETATION_HSV: + return( image->Bands > 3 ); + + case VIPS_INTERPRETATION_CMYK: + return( image->Bands > 4 ); + + default: + /* We can't really infer anything about bands from things like + * HISTOGRAM or FOURIER. + */ + return( FALSE ); + } } /** From aebb8af803a45b3b09f1b5cb9ebbd93787c36f8d Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Wed, 4 Apr 2018 09:22:57 +0100 Subject: [PATCH 4/6] create funcs always make MULTIBAND Before, they could make B_W for one-band output. This caused problems with (for example) two black image bandjoined: the second band then looked like an alpha to hasalpha() and enabled premultiply/unpremultiply for operations like affine. Now, it's always MULTIBAND. This is the generic multiband image type, so you don't get any unexpected alpha handling. --- ChangeLog | 1 + libvips/create/black.c | 6 ++++-- libvips/create/gaussmat.c | 3 ++- libvips/create/gaussnoise.c | 2 +- libvips/create/logmat.c | 3 ++- libvips/create/perlin.c | 2 +- libvips/create/point.c | 7 +++---- libvips/create/text.c | 3 ++- libvips/create/worley.c | 3 ++- 9 files changed, 18 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index 83949abd..2cde6127 100644 --- a/ChangeLog +++ b/ChangeLog @@ -11,6 +11,7 @@ - better header sniffing for small files - drop incompatible ICC profiles before save - better hasalpha rules +- create funcs always make MULTIBAND (ie. no alpha) 12/3/18 started 8.6.4 - better fitting of fonts with overhanging edges, thanks Adrià diff --git a/libvips/create/black.c b/libvips/create/black.c index c613a154..33c4ab1c 100644 --- a/libvips/create/black.c +++ b/libvips/create/black.c @@ -15,6 +15,9 @@ * - gtkdoc * 31/10/11 * - redo as a class + * 3/4/18 + * - always write MULTIBAND, otherwise when we join up these things it'll + * look like we have an alpha */ /* @@ -97,8 +100,7 @@ vips_black_build( VipsObject *object ) vips_image_init_fields( create->out, black->width, black->height, black->bands, VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, - black->bands == 1 ? - VIPS_INTERPRETATION_B_W : VIPS_INTERPRETATION_MULTIBAND, + VIPS_INTERPRETATION_MULTIBAND, 1.0, 1.0 ); vips_image_pipelinev( create->out, VIPS_DEMAND_STYLE_ANY, NULL ); diff --git a/libvips/create/gaussmat.c b/libvips/create/gaussmat.c index fa67c305..4ac21562 100644 --- a/libvips/create/gaussmat.c +++ b/libvips/create/gaussmat.c @@ -134,7 +134,8 @@ vips_gaussmat_build( VipsObject *object ) vips_image_init_fields( create->out, width, height, 1, - VIPS_FORMAT_DOUBLE, VIPS_CODING_NONE, VIPS_INTERPRETATION_B_W, + VIPS_FORMAT_DOUBLE, VIPS_CODING_NONE, + VIPS_INTERPRETATION_MULTIBAND, 1.0, 1.0 ); vips_image_pipelinev( create->out, VIPS_DEMAND_STYLE_ANY, NULL ); diff --git a/libvips/create/gaussnoise.c b/libvips/create/gaussnoise.c index 1566e39a..5ccf5510 100644 --- a/libvips/create/gaussnoise.c +++ b/libvips/create/gaussnoise.c @@ -134,7 +134,7 @@ vips_gaussnoise_build( VipsObject *object ) vips_image_init_fields( create->out, gaussnoise->width, gaussnoise->height, 1, VIPS_FORMAT_FLOAT, VIPS_CODING_NONE, - VIPS_INTERPRETATION_B_W, 1.0, 1.0 ); + VIPS_INTERPRETATION_MULTIBAND, 1.0, 1.0 ); vips_image_pipelinev( create->out, VIPS_DEMAND_STYLE_ANY, NULL ); diff --git a/libvips/create/logmat.c b/libvips/create/logmat.c index 5f15b3ea..43d753c7 100644 --- a/libvips/create/logmat.c +++ b/libvips/create/logmat.c @@ -153,7 +153,8 @@ vips_logmat_build( VipsObject *object ) vips_image_init_fields( create->out, width, height, 1, - VIPS_FORMAT_DOUBLE, VIPS_CODING_NONE, VIPS_INTERPRETATION_B_W, + VIPS_FORMAT_DOUBLE, VIPS_CODING_NONE, + VIPS_INTERPRETATION_MULTIBAND, 1.0, 1.0 ); vips_image_pipelinev( create->out, VIPS_DEMAND_STYLE_ANY, NULL ); diff --git a/libvips/create/perlin.c b/libvips/create/perlin.c index 5181f365..a6651f90 100644 --- a/libvips/create/perlin.c +++ b/libvips/create/perlin.c @@ -249,7 +249,7 @@ vips_perlin_build( VipsObject *object ) vips_image_init_fields( create->out, perlin->width, perlin->height, 1, perlin->uchar ? VIPS_FORMAT_UCHAR : VIPS_FORMAT_FLOAT, - VIPS_CODING_NONE, VIPS_INTERPRETATION_B_W, + VIPS_CODING_NONE, VIPS_INTERPRETATION_MULTIBAND, 1.0, 1.0 ); vips_image_pipelinev( create->out, VIPS_DEMAND_STYLE_ANY, NULL ); diff --git a/libvips/create/point.c b/libvips/create/point.c index 06e14229..f5f00841 100644 --- a/libvips/create/point.c +++ b/libvips/create/point.c @@ -109,10 +109,9 @@ vips_point_build( VipsObject *object ) return( -1 ); in = t[2]; - /* uchar mode always does B_W. We don't want FOURIER or - * whatever in this case. + /* We don't want FOURIER or whatever in this case. */ - in->Type = VIPS_INTERPRETATION_B_W; + in->Type = VIPS_INTERPRETATION_MULTIBAND; } if( vips_image_write( in, create->out ) ) @@ -137,7 +136,7 @@ vips_point_class_init( VipsPointClass *class ) class->point = NULL; class->min = -1.0; class->max = 1.0; - class->interpretation = VIPS_INTERPRETATION_B_W; + class->interpretation = VIPS_INTERPRETATION_MULTIBAND; VIPS_ARG_INT( class, "width", 2, _( "Width" ), diff --git a/libvips/create/text.c b/libvips/create/text.c index 8d26ed10..e8631638 100644 --- a/libvips/create/text.c +++ b/libvips/create/text.c @@ -379,7 +379,8 @@ vips_text_build( VipsObject *object ) vips_image_init_fields( create->out, text->bitmap.width, text->bitmap.rows, 1, - VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, VIPS_INTERPRETATION_B_W, + VIPS_FORMAT_UCHAR, VIPS_CODING_NONE, + VIPS_INTERPRETATION_MULTIBAND, 1.0, 1.0 ); vips_image_pipelinev( create->out, VIPS_DEMAND_STYLE_ANY, NULL ); diff --git a/libvips/create/worley.c b/libvips/create/worley.c index 520fdd47..e2cdf424 100644 --- a/libvips/create/worley.c +++ b/libvips/create/worley.c @@ -281,7 +281,8 @@ vips_worley_build( VipsObject *object ) vips_image_init_fields( create->out, worley->width, worley->height, 1, - VIPS_FORMAT_FLOAT, VIPS_CODING_NONE, VIPS_INTERPRETATION_B_W, + VIPS_FORMAT_FLOAT, VIPS_CODING_NONE, + VIPS_INTERPRETATION_MULTIBAND, 1.0, 1.0 ); vips_image_pipelinev( create->out, VIPS_DEMAND_STYLE_ANY, NULL ); From 632bce3c782c6725d460f784882cc35d8083d3f7 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Wed, 4 Apr 2018 16:25:35 +0100 Subject: [PATCH 5/6] reduce stack use for radsave fixes a crash on very low stack libcs like musl --- ChangeLog | 1 + libvips/foreign/radiance.c | 24 ++++++++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/ChangeLog b/ChangeLog index 482b0d4b..65a91921 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,6 @@ 12/3/18 started 8.6.4 - better fitting of fonts with overhanging edges, thanks Adrià +- lower stack use in radsave to help musl [Jacob Thrane Lund] 12/2/18 started 8.6.3 - use pkg-config to find libjpeg, if we can diff --git a/libvips/foreign/radiance.c b/libvips/foreign/radiance.c index 77b556b5..231d9b19 100644 --- a/libvips/foreign/radiance.c +++ b/libvips/foreign/radiance.c @@ -19,6 +19,8 @@ * - add buffer save functions * 28/2/17 * - use dbuf for buffer output + * 4/4/17 + * - reduce stack use to help musl */ /* @@ -885,10 +887,12 @@ rle_scanline_write( COLR *scanline, int width, } } -/* Write a single scanline. +/* Write a single scanline. buffer is at least MAX_LINE bytes and is used to + * construct the RLE scanline. Don't allocate this on the stack so we don't + * die too horribly on small-stack libc. */ static int -scanline_write( COLR *scanline, int width, FILE *fp ) +scanline_write( unsigned char *buffer, COLR *scanline, int width, FILE *fp ) { if( width < MINELEN || width > MAXELEN ) @@ -898,11 +902,12 @@ scanline_write( COLR *scanline, int width, FILE *fp ) else { /* An RLE scanline. */ - unsigned char buffer[MAX_LINE]; int length; rle_scanline_write( scanline, width, buffer, &length ); + g_assert( length <= MAX_LINE ); + return( fwrite( buffer, 1, length, fp ) - length ); } } @@ -1294,12 +1299,18 @@ static int vips2rad_put_data_block( VipsRegion *region, VipsRect *area, void *a ) { Write *write = (Write *) a; + size_t size; + unsigned char *buffer = vips_dbuf_get_write( &write->dbuf, &size ); + int i; + g_assert( size >= MAX_LINE ); + for( i = 0; i < area->height; i++ ) { VipsPel *p = VIPS_REGION_ADDR( region, 0, area->top + i ); - if( scanline_write( (COLR *) p, area->width, write->fout ) ) + if( scanline_write( buffer, + (COLR *) p, area->width, write->fout ) ) return( -1 ); } @@ -1333,6 +1344,11 @@ vips__rad_save( VipsImage *in, const char *filename ) write->filename = vips_strdup( NULL, filename ); write->fout = vips__file_open_write( filename, FALSE ); + /* scanline_write() needs a buffer to write compressed scanlines to. + * We use the dbuf ... why not. + */ + vips_dbuf_allocate( &write->dbuf, MAX_LINE ); + if( !write->filename || !write->fout || vips2rad_put_header( write ) || From 915226db212f684d6e2ba8bdcc1785c0630aff79 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Wed, 4 Apr 2018 17:46:14 +0100 Subject: [PATCH 6/6] oop missing a seek --- libvips/foreign/radiance.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/libvips/foreign/radiance.c b/libvips/foreign/radiance.c index 231d9b19..955d4c98 100644 --- a/libvips/foreign/radiance.c +++ b/libvips/foreign/radiance.c @@ -1299,11 +1299,16 @@ static int vips2rad_put_data_block( VipsRegion *region, VipsRect *area, void *a ) { Write *write = (Write *) a; - size_t size; - unsigned char *buffer = vips_dbuf_get_write( &write->dbuf, &size ); + size_t size; + unsigned char *buffer; int i; + /* You have to seek back after a write. + */ + buffer = vips_dbuf_get_write( &write->dbuf, &size ); + vips_dbuf_seek( &write->dbuf, 0, SEEK_SET ); + g_assert( size >= MAX_LINE ); for( i = 0; i < area->height; i++ ) {