use round() rather than rint() where appropriate

rint() rounds to nearest even, rather than nearest ... in some cases,
like geometry transforms, we want strict nearest
This commit is contained in:
John Cupitt 2016-08-20 12:59:41 +01:00
parent 8503065faa
commit 271d8656e9
15 changed files with 63 additions and 94 deletions

View File

@ -37,8 +37,9 @@
- support --strip for pngsave
- add svgz support [Felix Bünemann]
- rename boostrap.sh -> autogen.sh to help snapcraft
- resize/reduce/shrink now round output size to nearest rather than rounding
down, thanks ioquatix
- added VIPS_ROUND as well as VIPS_RINT
- resize/reduce*/shrink*/affine now round output size to nearest rather than
rounding down, thanks ioquatix
30/7/16 started 8.3.3
- fix performance regression in 8.3.2, thanks Lovell

View File

@ -95,11 +95,9 @@ vips_Lab2LabQ_line( VipsColour *colour, VipsPel *out, VipsPel **in, int width )
int lsbs;
int intv;
/* Scale L up to 10 bits. Add 0.5 rather than call VIPS_RINT
* for speed. This will not round negatives correctly! But
* this does not matter, since L is >0. L*=100.0 -> 1023.
/* Scale L up to 10 bits.
*/
intv = 10.23 * p[0] + 0.5; /* scale L up to 10 bits */
intv = VIPS_ROUND_UINT( 10.23 * p[0] );
intv = VIPS_CLIP( 0, intv, 1023 );
lsbs = (intv & 0x3) << 6; /* 00000011 -> 11000000 */
q[0] = intv >> 2; /* drop bot 2 bits and store */

View File

@ -50,14 +50,6 @@
#include "pconversion.h"
/* Round N down to P boundary.
*/
#define ROUND_DOWN( N, P ) ((N) - ((N) % P))
/* Round N up to P boundary.
*/
#define ROUND_UP( N, P ) (ROUND_DOWN( (N) + (P) - 1, (P) ))
typedef struct _VipsArrayjoin {
VipsConversion parent_instance;
@ -179,7 +171,7 @@ vips_arrayjoin_build( VipsObject *object )
/* How many images down the grid?
*/
join->down = ROUND_UP( n, join->across ) / join->across;
join->down = VIPS_ROUND_UP( n, join->across ) / join->across;
/* The output size.
*/

View File

@ -98,14 +98,6 @@ typedef VipsConversionClass VipsZoomClass;
G_DEFINE_TYPE( VipsZoom, vips_zoom, VIPS_TYPE_CONVERSION );
/* Round N down to P boundary.
*/
#define ROUND_DOWN( N, P ) ((N) - ((N) % P))
/* Round N up to P boundary.
*/
#define ROUND_UP( N, P ) (ROUND_DOWN( (N) + (P) - 1, (P) ))
/* Paint the part of the region containing only whole pels.
*/
static void
@ -265,10 +257,10 @@ vips_zoom_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop )
/* Area of input we need. We have to round out, as we may have
* part-pixels all around the edges.
*/
left = ROUND_DOWN( r->left, zoom->xfac );
right = ROUND_UP( ri, zoom->xfac );
top = ROUND_DOWN( r->top, zoom->yfac );
bottom = ROUND_UP( bo, zoom->yfac );
left = VIPS_ROUND_DOWN( r->left, zoom->xfac );
right = VIPS_ROUND_UP( ri, zoom->xfac );
top = VIPS_ROUND_DOWN( r->top, zoom->yfac );
bottom = VIPS_ROUND_UP( bo, zoom->yfac );
width = right - left;
height = bottom - top;
s.left = left / zoom->xfac;
@ -280,10 +272,10 @@ vips_zoom_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop )
/* Find the part of the output (if any) which uses only whole pels.
*/
left = ROUND_UP( r->left, zoom->xfac );
right = ROUND_DOWN( ri, zoom->xfac );
top = ROUND_UP( r->top, zoom->yfac );
bottom = ROUND_DOWN( bo, zoom->yfac );
left = VIPS_ROUND_UP( r->left, zoom->xfac );
right = VIPS_ROUND_DOWN( ri, zoom->xfac );
top = VIPS_ROUND_UP( r->top, zoom->yfac );
bottom = VIPS_ROUND_DOWN( bo, zoom->yfac );
width = right - left;
height = bottom - top;

View File

@ -71,14 +71,6 @@ typedef struct _VipsPerlinClass {
G_DEFINE_TYPE( VipsPerlin, vips_perlin, VIPS_TYPE_CREATE );
/* Round N down to P boundary.
*/
#define ROUND_DOWN( N, P ) ((N) - ((N) % P))
/* Round N up to P boundary.
*/
#define ROUND_UP( N, P ) (ROUND_DOWN( (N) + (P) - 1, (P) ))
/* cos and sin from an angle in 0 - 255.
*/
float vips_perlin_cos[256];
@ -261,9 +253,11 @@ vips_perlin_build( VipsObject *object )
/* Be careful if width is a multiple of cell_size.
*/
perlin->cells_across = ROUND_UP( perlin->width, perlin->cell_size ) /
perlin->cells_across =
VIPS_ROUND_UP( perlin->width, perlin->cell_size ) /
perlin->cell_size;
perlin->cells_down = ROUND_UP( perlin->height, perlin->cell_size ) /
perlin->cells_down =
VIPS_ROUND_UP( perlin->height, perlin->cell_size ) /
perlin->cell_size;
perlin->seed = g_random_double() * 0xffffffffu;

View File

@ -75,14 +75,6 @@ G_DEFINE_TYPE( VipsWorley, vips_worley, VIPS_TYPE_CREATE );
#define MAX_FEATURES (10)
/* Round N down to P boundary.
*/
#define ROUND_DOWN( N, P ) ((N) - ((N) % P))
/* Round N up to P boundary.
*/
#define ROUND_UP( N, P ) (ROUND_DOWN( (N) + (P) - 1, (P) ))
typedef struct _Cell {
/* Cell position, in number of cells. Scale by cell_size to get
* absolute image cods.
@ -294,9 +286,11 @@ vips_worley_build( VipsObject *object )
/* Be careful if width is a multiple of cell_size.
*/
worley->cells_across = ROUND_UP( worley->width, worley->cell_size ) /
worley->cells_across =
VIPS_ROUND_UP( worley->width, worley->cell_size ) /
worley->cell_size;
worley->cells_down = ROUND_UP( worley->height, worley->cell_size ) /
worley->cells_down =
VIPS_ROUND_UP( worley->height, worley->cell_size ) /
worley->cell_size;
worley->seed = g_random_double() * 0xffffffffu;

View File

@ -285,14 +285,6 @@ vips__make_xml_metadata( const char *domain, VipsImage *image )
#include <gsf/gsf.h>
/* Round N down to P boundary.
*/
#define ROUND_DOWN( N, P ) ((N) - ((N) % P))
/* Round N up to P boundary.
*/
#define ROUND_UP( N, P ) (ROUND_DOWN( (N) + (P) - 1, (P) ))
/* Simple wrapper around libgsf.
*
* We need to be able to do scattered writes to structured files. So while
@ -672,8 +664,10 @@ pyramid_build( VipsForeignSaveDz *dz, Layer *above,
layer->width = width;
layer->height = height;
layer->tiles_across = ROUND_UP( width, dz->tile_size ) / dz->tile_size;
layer->tiles_down = ROUND_UP( height, dz->tile_size ) / dz->tile_size;
layer->tiles_across = VIPS_ROUND_UP( width, dz->tile_size ) /
dz->tile_size;
layer->tiles_down = VIPS_ROUND_UP( height, dz->tile_size ) /
dz->tile_size;
layer->real_pixels = *real_pixels;

View File

@ -322,14 +322,6 @@ tiff_openin( const char *name )
return( tif );
}
/* Round N down to P boundary.
*/
#define ROUND_DOWN(N,P) ((N) - ((N) % P))
/* Round N up to P boundary.
*/
#define ROUND_UP(N,P) (ROUND_DOWN( (N) + (P) - 1, (P) ))
static Layer *
pyramid_new( Write *write, Layer *above, int width, int height )
{
@ -975,7 +967,7 @@ write_new( VipsImage *im, const char *filename,
if( im->Coding == VIPS_CODING_LABQ )
write->tls = write->tilew * 3;
else if( write->onebit )
write->tls = ROUND_UP( write->tilew, 8 ) / 8;
write->tls = VIPS_ROUND_UP( write->tilew, 8 ) / 8;
else
write->tls = VIPS_IMAGE_SIZEOF_PEL( im ) * write->tilew;

View File

@ -53,11 +53,14 @@ extern "C" {
#define VIPS_MAX( A, B ) ((A) > (B) ? (A) : (B))
#define VIPS_MIN( A, B ) ((A) < (B) ? (A) : (B))
#define VIPS_ABS( X ) (((X) >= 0) ? (X) : -(X))
#define VIPS_CLIP( A, V, B ) VIPS_MAX( (A), VIPS_MIN( (B), (V) ) )
#define VIPS_FCLIP( A, V, B ) VIPS_FMAX( (A), VIPS_FMIN( (B), (V) ) )
#define VIPS_NUMBER( R ) ((int) (sizeof(R) / sizeof(R[0])))
#define VIPS_ABS( X ) (((X) >= 0) ? (X) : -(X))
/* The built-in isnan and isinf functions provided by gcc 4+ and clang are
* up to 7x faster than their libc equivalent included from <math.h>.
*/
@ -67,6 +70,7 @@ extern "C" {
#define VIPS_FLOOR( V ) __builtin_floor( V )
#define VIPS_CEIL( V ) __builtin_ceil( V )
#define VIPS_RINT( V ) __builtin_rint( V )
#define VIPS_ROUND( V ) __builtin_round( V )
#define VIPS_FABS( V ) __builtin_fabs( V )
#define VIPS_FMAX( A, B ) __builtin_fmax( A, B )
#define VIPS_FMIN( A, B ) __builtin_fmin( A, B )
@ -75,13 +79,25 @@ extern "C" {
#define VIPS_ISINF( V ) isinf( V )
#define VIPS_FLOOR( V ) floor( V )
#define VIPS_CEIL( V ) ceil( V )
#define VIPS_RINT( R ) ((int) ((R) > 0 ? ((R) + 0.5) : ((R) - 0.5)))
#define VIPS_RINT( R ) rint( V )
#define VIPS_ROUND( V ) round( V )
#define VIPS_FABS( V ) VIPS_ABS( V )
#define VIPS_FMAX( A, B ) VIPS_MAX( A, B )
#define VIPS_FMIN( A, B ) VIPS_MIN( A, B )
#endif
#define VIPS_FCLIP( A, V, B ) VIPS_FMAX( (A), VIPS_FMIN( (B), (V) ) )
/* VIPS_RINT() does "bankers rounding", it rounds to the nerarest even integer.
* For things like image geometry, we want strict nearest int.
*
* If you know it's unsigned, _UINT is a little faster.
*/
#define VIPS_ROUND_INT( R ) ((int) ((R) > 0 ? ((R) + 0.5) : ((R) - 0.5)))
#define VIPS_ROUND_UINT( R ) ((int) ((R) + 0.5))
/* Round N down and up to the nearest multiple of P.
*/
#define VIPS_ROUND_DOWN( N, P ) ((N) - ((N) % (P)))
#define VIPS_ROUND_UP( N, P ) (VIPS_ROUND_DOWN( N, P ) + (P))
#define VIPS_SWAP( TYPE, A, B ) \
G_STMT_START { \

View File

@ -922,14 +922,6 @@ vips_threadpool_run( VipsImage *im,
return( result );
}
/* Round N down to P boundary.
*/
#define ROUND_DOWN(N,P) ((N) - ((N) % P))
/* Round N up to P boundary.
*/
#define ROUND_UP(N,P) (ROUND_DOWN( (N) + (P) - 1, (P) ))
/**
* vips_get_tile_size:
* @im: image to guess for
@ -986,7 +978,7 @@ vips_get_tile_size( VipsImage *im,
(1 + nthr / VIPS_MAX( 1, im->Xsize / vips__tile_width )) * 2;
*n_lines = VIPS_MAX( *n_lines, vips__fatstrip_height * nthr * 2 );
*n_lines = VIPS_MAX( *n_lines, vips__thinstrip_height * nthr * 2 );
*n_lines = ROUND_UP( *n_lines, *tile_height );
*n_lines = VIPS_ROUND_UP( *n_lines, *tile_height );
/* We make this assumption in several places.
*/

View File

@ -498,13 +498,14 @@ vips_reduceh_build( VipsObject *object )
VIPS_DEMAND_STYLE_THINSTRIP, in, NULL ) )
return( -1 );
/* Size output. Note: we round to nearest to hide rounding errors.
/* Size output. We need to always round to nearest, so round(), not
* rint().
*
* 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 = VIPS_RINT(
resample->out->Xsize = VIPS_ROUND_UINT(
(in->Xsize - reduceh->n_point + 1) / reduceh->hshrink );
if( resample->out->Xsize <= 0 ) {
vips_error( object_class->nickname,

View File

@ -775,13 +775,14 @@ vips_reducev_raw( VipsReducev *reducev, VipsImage *in )
VIPS_DEMAND_STYLE_FATSTRIP, in, NULL ) )
return( -1 );
/* Size output. Note: we round to nearest to hide rounding errors.
/* Size output. We need to always round to nearest, so round(), not
* rint().
*
* 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 = VIPS_RINT(
resample->out->Ysize = VIPS_ROUND_UINT(
(in->Ysize - reducev->n_point + 1) / reducev->vshrink );
if( resample->out->Ysize <= 0 ) {
vips_error( object_class->nickname,

View File

@ -275,13 +275,14 @@ vips_shrinkh_build( VipsObject *object )
VIPS_DEMAND_STYLE_THINSTRIP, in, NULL ) )
return( -1 );
/* Size output. We need to rint() from the size of the original image.
/* Size output. We need to always round to nearest, so round(), not
* rint().
*
* Don't change xres/yres, leave that to the application layer. For
* example, vipsthumbnail knows the true shrink factor (including the
* fractional part), we just see the integer part here.
*/
resample->out->Xsize = VIPS_RINT(
resample->out->Xsize = VIPS_ROUND_UINT(
resample->in->Xsize / shrink->hshrink );
if( resample->out->Xsize <= 0 ) {
vips_error( class->nickname,

View File

@ -379,13 +379,14 @@ vips_shrinkv_build( VipsObject *object )
VIPS_DEMAND_STYLE_THINSTRIP, in, NULL ) )
return( -1 );
/* Size output. We need to rint() from the size of the original image.
/* Size output. We need to always round to nearest, so round(), not
* rint().
*
* Don't change xres/yres, leave that to the application layer. For
* example, vipsthumbnail knows the true shrink factor (including the
* fractional part), we just see the integer part here.
*/
resample->out->Ysize = VIPS_RINT(
resample->out->Ysize = VIPS_ROUND_UINT(
resample->in->Ysize / shrink->vshrink );
if( resample->out->Ysize <= 0 ) {
vips_error( class->nickname,

View File

@ -215,10 +215,10 @@ transform_rect( const VipsTransformation *trn, transform_fn transform,
top = VIPS_MIN( y1, VIPS_MIN( y2, VIPS_MIN( y3, y4 ) ) );
bottom = VIPS_MAX( y1, VIPS_MAX( y2, VIPS_MAX( y3, y4 ) ) );
out->left = VIPS_RINT( left );
out->top = VIPS_RINT( top );
out->width = VIPS_RINT( right - left );
out->height = VIPS_RINT( bottom - top );
out->left = VIPS_ROUND_INT( left );
out->top = VIPS_ROUND_INT( top );
out->width = VIPS_ROUND_INT( right - left );
out->height = VIPS_ROUND_INT( bottom - top );
}
/* Given an area in the input image, calculate the bounding box for those