diff --git a/TODO b/TODO index 63ebaf48..8d5a3d74 100644 --- a/TODO +++ b/TODO @@ -9,6 +9,8 @@ displacement error, I guess? + yes, reduceh output should move one to the right + - need more tests for reduce, test every kernel plus every numeric type - try orc version of reducev? and shrinkv? maybe shrinkh? diff --git a/libvips/resample/reduceh.cpp b/libvips/resample/reduceh.cpp index 81b447b6..de556ae4 100644 --- a/libvips/resample/reduceh.cpp +++ b/libvips/resample/reduceh.cpp @@ -496,7 +496,7 @@ vips_reduceh_build( VipsObject *object ) /* Add new pixels around the input so we can interpolate at the edges. */ if( vips_embed( in, &t[1], - reduceh->n_points / 2, 0, + reduceh->n_points / 2 - 1, 0, in->Xsize + reduceh->n_points - 1, in->Ysize, "extend", VIPS_EXTEND_COPY, NULL ) ) @@ -507,14 +507,14 @@ vips_reduceh_build( VipsObject *object ) VIPS_DEMAND_STYLE_THINSTRIP, in, NULL ) ) return( -1 ); - /* Size output. Note: we round the output width down! + /* Size output. Note: we round to nearest to hide rounding errors. * * Don't change xres/yres, leave that to the application layer. For * example, vipsthumbnail knows the true reduce factor (including the * fractional part), we just see the integer part here. */ - resample->out->Xsize = (in->Xsize - reduceh->n_points + 1) / - reduceh->xshrink; + resample->out->Xsize = VIPS_RINT( + (in->Xsize - reduceh->n_points + 1) / reduceh->xshrink ); if( resample->out->Xsize <= 0 ) { vips_error( object_class->nickname, "%s", _( "image has shrunk to nothing" ) ); diff --git a/libvips/resample/reducev.cpp b/libvips/resample/reducev.cpp index 6dd1537f..b5bd652d 100644 --- a/libvips/resample/reducev.cpp +++ b/libvips/resample/reducev.cpp @@ -411,7 +411,7 @@ vips_reducev_build( VipsObject *object ) /* Add new pixels around the input so we can interpolate at the edges. */ if( vips_embed( in, &t[1], - 0, reducev->n_points / 2, + 0, reducev->n_points / 2 - 1, in->Xsize, in->Ysize + reducev->n_points - 1, "extend", VIPS_EXTEND_COPY, NULL ) ) @@ -422,13 +422,14 @@ vips_reducev_build( VipsObject *object ) VIPS_DEMAND_STYLE_SMALLTILE, in, NULL ) ) return( -1 ); - /* Size output. Note: we round the output width down! + /* Size output. Note: we round to nearest to hide rounding errors. * * Don't change xres/yres, leave that to the application layer. For * example, vipsthumbnail knows the true reduce factor (including the * fractional part), we just see the integer part here. */ - resample->out->Ysize = (in->Ysize - reducev->n_points + 1) / reducev->yshrink; + resample->out->Ysize = VIPS_RINT( + (in->Ysize - reducev->n_points + 1) / reducev->yshrink ); if( resample->out->Ysize <= 0 ) { vips_error( object_class->nickname, "%s", _( "image has shrunk to nothing" ) ); diff --git a/libvips/resample/resize.c b/libvips/resample/resize.c index 590227b8..fc9651d5 100644 --- a/libvips/resample/resize.c +++ b/libvips/resample/resize.c @@ -135,13 +135,11 @@ vips_resize_build( VipsObject *object ) /* Do we need a further size adjustment? It's the difference * between our target size and the size we have after vips_shrink(). * - * Aim for a little above target so we can't round down below it. - * * This can break the aspect ratio slightly :/ but hopefully no one * will notice. */ - hresidual = ((double) target_width + 0.1) / in->Xsize; - vresidual = ((double) target_height + 0.1) / in->Ysize; + hresidual = (double) target_width / in->Xsize; + vresidual = (double) target_height / in->Ysize; /* We want to make sure we read the image sequentially. * However, the convolution we may be doing later will force us diff --git a/tools/vipsthumbnail.c b/tools/vipsthumbnail.c index f44dd206..a507d568 100644 --- a/tools/vipsthumbnail.c +++ b/tools/vipsthumbnail.c @@ -185,14 +185,13 @@ calculate_shrink( VipsImage *im ) VipsDirection direction; /* Calculate the horizontal and vertical shrink we'd need to fit the - * image to the bounding box, and pick the biggest. Aim for a little - * above the target so we can't round down below it. + * image to the bounding box, and pick the biggest. * * In crop mode we aim to fill the bounding box, so we must use the * smaller axis. */ - double horizontal = (double) width / (thumbnail_width + 0.1); - double vertical = (double) height / (thumbnail_height + 0.1); + double horizontal = (double) width / thumbnail_width; + double vertical = (double) height / thumbnail_height; if( crop_image ) { if( horizontal < vertical ) @@ -470,10 +469,7 @@ thumbnail_shrink( VipsObject *process, VipsImage *in ) shrink = calculate_shrink( in ); - /* Add a tiny amount to stop rounding below the target. - */ - if( vips_resize( in, &t[4], 1.0 / shrink + 0.0000000001, - NULL ) ) + if( vips_resize( in, &t[4], 1.0 / shrink, NULL ) ) return( NULL ); in = t[4];