diff --git a/ChangeLog b/ChangeLog index 9ca27c60..a2f9c057 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,7 @@ constant image - add new_from_image() to Python as well - slight change to cpp new_from_image() to match py/C behaviour +- add FORCE resize mode to break aspect ratio 23/4/17 started 8.5.5 - doc polishing diff --git a/TODO b/TODO index 95698e30..d572537f 100644 --- a/TODO +++ b/TODO @@ -1,4 +1,6 @@ -- cpp bandjoin should use bandjoin_const() where possibel ... currently +- need tests for new thumbnail mode + +- cpp bandjoin should use bandjoin_const() where possible ... currently uses new_from_image - not sure about utf8 error messages on win diff --git a/doc/How-it-opens-files.md b/doc/How-it-opens-files.md index 3e4e4165..cdc68440 100644 --- a/doc/How-it-opens-files.md +++ b/doc/How-it-opens-files.md @@ -102,7 +102,7 @@ example: $ vips shrink fred.png jim.png 10 10 ``` -meaning shrink `fred.png` by a factor of 10 in both axies and write as +meaning shrink `fred.png` by a factor of 10 in both axes and write as `jim.png`. You can imagine this operation running without needing `fred.png` to be diff --git a/libvips/iofuncs/enumtypes.c b/libvips/iofuncs/enumtypes.c index ae0a18b8..d0b3f445 100644 --- a/libvips/iofuncs/enumtypes.c +++ b/libvips/iofuncs/enumtypes.c @@ -831,6 +831,7 @@ vips_size_get_type( void ) {VIPS_SIZE_BOTH, "VIPS_SIZE_BOTH", "both"}, {VIPS_SIZE_UP, "VIPS_SIZE_UP", "up"}, {VIPS_SIZE_DOWN, "VIPS_SIZE_DOWN", "down"}, + {VIPS_SIZE_FORCE, "VIPS_SIZE_FORCE", "force"}, {VIPS_SIZE_LAST, "VIPS_SIZE_LAST", "last"}, {0, NULL, NULL} }; diff --git a/libvips/resample/thumbnail.c b/libvips/resample/thumbnail.c index e3982522..788c1199 100644 --- a/libvips/resample/thumbnail.c +++ b/libvips/resample/thumbnail.c @@ -5,6 +5,8 @@ * - from vipsthumbnail.c * 6/1/17 * - add @size parameter + * 4/5/17 + * - add FORCE */ /* @@ -156,17 +158,17 @@ vips_thumbnail_calculate_shrink( VipsThumbnail *thumbnail, * In crop mode, we aim to fill the bounding box, so we must use the * smaller axis. */ - double horizontal = (double) width / thumbnail->width; - double vertical = (double) height / thumbnail->height; + *hshrink = (double) width / thumbnail->width; + *vshrink = (double) height / thumbnail->height; if( thumbnail->crop != VIPS_INTERESTING_NONE ) { - if( horizontal < vertical ) + if( *hshrink < *vshrink ) direction = VIPS_DIRECTION_HORIZONTAL; else direction = VIPS_DIRECTION_VERTICAL; } else { - if( horizontal < vertical ) + if( *hshrink < *vshrink ) direction = VIPS_DIRECTION_VERTICAL; else direction = VIPS_DIRECTION_HORIZONTAL; @@ -174,24 +176,27 @@ vips_thumbnail_calculate_shrink( VipsThumbnail *thumbnail, if( thumbnail->size != VIPS_SIZE_FORCE ) { if( direction == VIPS_DIRECTION_HORIZONTAL ) - vertical = horizontal; + *vshrink = *hshrink; else - horizontal = vertical; + *hshrink = *vshrink; } - else if( thumbnail->size == VIPS_SIZE_UP ) - shrink = VIPS_MIN( 1, shrink ); - else if( thumbnail->size == VIPS_SIZE_DOWN ) - shrink = VIPS_MAX( 1, shrink ); - + if( thumbnail->size == VIPS_SIZE_UP ) { + *hshrink = VIPS_MIN( 1, *hshrink ); + *vshrink = VIPS_MIN( 1, *vshrink ); + } + else if( thumbnail->size == VIPS_SIZE_DOWN ) { + *hshrink = VIPS_MAX( 1, *hshrink ); + *vshrink = VIPS_MAX( 1, *vshrink ); + } } -/* Just the common part of the shrink: the bit by which both axies must be +/* Just the common part of the shrink: the bit by which both axes must be * shrunk. */ static double vips_thumbnail_calculate_common_shrink( VipsThumbnail *thumbnail, - int input_width, int input_height ) + int width, int height ) { double hshrink; double vshrink; @@ -244,7 +249,7 @@ vips_thumbnail_open( VipsThumbnail *thumbnail ) VipsThumbnailClass *class = VIPS_THUMBNAIL_GET_CLASS( thumbnail ); VipsImage *im; - int shrink; + double shrink; double scale; if( class->get_info( thumbnail ) ) @@ -253,25 +258,26 @@ vips_thumbnail_open( VipsThumbnail *thumbnail ) g_info( "input size is %d x %d", thumbnail->input_width, thumbnail->input_height ); - shrink = 1; + shrink = 1.0; scale = 1.0; if( vips_isprefix( "VipsForeignLoadJpeg", thumbnail->loader ) ) { shrink = vips_thumbnail_find_jpegshrink( thumbnail, thumbnail->input_width, thumbnail->input_height ); + g_info( "loading jpeg with factor %g pre-shrink", shrink ); } else if( vips_isprefix( "VipsForeignLoadPdf", thumbnail->loader ) || vips_isprefix( "VipsForeignLoadSvg", thumbnail->loader ) ) { - scale = 1.0 / - vips_thumbnail_calculate_common_shrink( thumbnail, - width, height ); + shrink = vips_thumbnail_calculate_common_shrink( thumbnail, + thumbnail->input_width, thumbnail->input_height ); + scale = 1.0 / shrink; g_info( "loading PDF/SVG with factor %g pre-scale", scale ); } else if( vips_isprefix( "VipsForeignLoadWebp", thumbnail->loader ) ) { shrink = vips_thumbnail_calculate_common_shrink( thumbnail, - width, height ); + thumbnail->input_width, thumbnail->input_height ); g_info( "loading webp with factor %g pre-shrink", shrink ); } @@ -393,12 +399,13 @@ vips_thumbnail_build( VipsObject *object ) in = t[3]; } - shrink = vips_thumbnail_calculate_shrink( thumbnail, - in->Xsize, in->Ysize ); + vips_thumbnail_calculate_shrink( thumbnail, + in->Xsize, in->Ysize, &hshrink, &vshrink ); /* Use centre convention to better match imagemagick. */ - if( vips_resize( in, &t[4], 1.0 / shrink, + if( vips_resize( in, &t[4], 1.0 / hshrink, + "vscale", 1.0 / vshrink, "centre", TRUE, NULL ) ) return( -1 ); @@ -659,8 +666,6 @@ vips_thumbnail_file_open( VipsThumbnail *thumbnail, int shrink, double scale ) { VipsThumbnailFile *file = (VipsThumbnailFile *) thumbnail; - /* We can't use UNBUFERRED safely on very-many-core systems. - */ if( shrink != 1 ) return( vips_image_new_from_file( file->filename, "access", VIPS_ACCESS_SEQUENTIAL, diff --git a/man/vipsthumbnail.1 b/man/vipsthumbnail.1 index e83046b5..a57873a5 100644 --- a/man/vipsthumbnail.1 +++ b/man/vipsthumbnail.1 @@ -94,7 +94,7 @@ option. .TP .B -c, --crop Crop the output image down. The image is shrunk so as to completely fill the -bounding box in both axies, then any excess is cropped off. +bounding box in both axes, then any excess is cropped off. .TP .B -d, --delete diff --git a/tools/vipsthumbnail.c b/tools/vipsthumbnail.c index 5c5f5f00..b41fc47e 100644 --- a/tools/vipsthumbnail.c +++ b/tools/vipsthumbnail.c @@ -90,6 +90,8 @@ * 6/1/17 * - fancy geometry strings * - support VipSize restrictions + * 4/5/17 + * - add ! geo modifier */ #ifdef HAVE_CONFIG_H @@ -333,7 +335,7 @@ thumbnail_parse_geometry( const char *geometry ) p++; } - /* Get the final < or >. + /* Get the final <>! */ while( isspace( *p ) ) p++; @@ -341,6 +343,8 @@ thumbnail_parse_geometry( const char *geometry ) size_restriction = VIPS_SIZE_UP; else if( *p == '>' ) size_restriction = VIPS_SIZE_DOWN; + else if( *p == '!' ) + size_restriction = VIPS_SIZE_FORCE; else if( *p != '\0' || (thumbnail_width == VIPS_MAX_COORD && thumbnail_height == VIPS_MAX_COORD) ) { @@ -348,18 +352,30 @@ thumbnail_parse_geometry( const char *geometry ) return( -1 ); } - /* If --crop is set, both width and height must be specified, - * since we'll need a complete bounding box to fill. + /* If force is set and one of width or height isn't set, copy from the + * one that is. */ - if( (crop_image || smartcrop_image) && - (thumbnail_width == VIPS_MAX_COORD || - thumbnail_height == VIPS_MAX_COORD) ) { - vips_error( "thumbnail", - "both width and height must be given if " - "crop is enabled" ); - return( -1 ); + if( size_restriction == VIPS_SIZE_FORCE ) { + if( thumbnail_width == VIPS_MAX_COORD ) + thumbnail_width = thumbnail_height; + if( thumbnail_height == VIPS_MAX_COORD ) + thumbnail_height = thumbnail_width; } + /* If --crop is set or force is set, both width and height must be + * specified, since we'll need a complete bounding box to fill. + */ + if( crop_image || + smartcrop_image || + size_restriction == VIPS_SIZE_FORCE ) + if( thumbnail_width == VIPS_MAX_COORD || + thumbnail_height == VIPS_MAX_COORD ) { + vips_error( "thumbnail", + "both width and height must be given if " + "crop is enabled" ); + return( -1 ); + } + return( 0 ); }