better behaviour for vips_region_fetch()

we weren't clipping the fetch area against region valid, so in some
cases we could return many more pixels than expected

see https://github.com/libvips/pyvips/issues/103
This commit is contained in:
John Cupitt 2019-06-09 20:38:13 +01:00
parent eaaa203f0a
commit ad98222073
3 changed files with 26 additions and 19 deletions

View File

@ -7,6 +7,7 @@
- istiff attempts to read the first directory rather than just testing the - istiff attempts to read the first directory rather than just testing the
magic number [przemyslawpluta] magic number [przemyslawpluta]
- much faster ismagick() [jcupitt] - much faster ismagick() [jcupitt]
- better behaviour for vips_region_fetch() if request lies partly ouside image
21/9/18 started 8.8.0 21/9/18 started 8.8.0
- much faster smartcrop [lovell] - much faster smartcrop [lovell]

View File

@ -594,7 +594,7 @@ vips_composite_base_blend( VipsCompositeBase *composite,
case VIPS_BLEND_MODE_HARD_LIGHT: case VIPS_BLEND_MODE_HARD_LIGHT:
for( int b = 0; b < bands; b++ ) for( int b = 0; b < bands; b++ )
if( A[b] < 0.5 ) if( A[b] <= 0.5 )
f[b] = 2 * A[b] * B[b]; f[b] = 2 * A[b] * B[b];
else else
f[b] = 1 - 2 * (1 - A[b]) * (1 - B[b]); f[b] = 1 - 2 * (1 - A[b]) * (1 - B[b]);
@ -605,7 +605,8 @@ vips_composite_base_blend( VipsCompositeBase *composite,
double g; double g;
if( B[b] <= 0.25 ) if( B[b] <= 0.25 )
g = ((16 * B[b] - 12) * B[b] + 4) * B[b]; g = ((16 * B[b] - 12) *
B[b] + 4) * B[b];
else else
g = sqrt( B[b] ); g = sqrt( B[b] );

View File

@ -45,6 +45,9 @@
* - multiply transparent images through alpha in vips_region_shrink() * - multiply transparent images through alpha in vips_region_shrink()
* 13/6/18 harukizaemon * 13/6/18 harukizaemon
* - add VipsRegionShrink parameter to vips_region_shrink() * - add VipsRegionShrink parameter to vips_region_shrink()
* 9/6/19
* - saner behaviour for vips_region_fetch() if the request is partly
* outside the image
*/ */
/* /*
@ -1875,8 +1878,7 @@ vips_region_prepare_many( VipsRegion **reg, const VipsRect *r )
* @height: area of pixels to fetch * @height: area of pixels to fetch
* *
* Generate an area of pixels and return a copy. The result must be freed * Generate an area of pixels and return a copy. The result must be freed
* with g_free(). Use vips_region_width() and vips_region_height() to find the * with g_free(). The requested area must be completely inside the image.
* dimensions of the returned array.
* *
* This is equivalent to vips_region_prepare(), followed by a memcpy. It is * This is equivalent to vips_region_prepare(), followed by a memcpy. It is
* convenient for language bindings. * convenient for language bindings.
@ -1887,7 +1889,8 @@ VipsPel *
vips_region_fetch( VipsRegion *region, vips_region_fetch( VipsRegion *region,
int left, int top, int width, int height, size_t *len ) int left, int top, int width, int height, size_t *len )
{ {
VipsRect rect; VipsRect request;
VipsRect image;
int y; int y;
VipsPel *result; VipsPel *result;
VipsPel *p, *q; VipsPel *p, *q;
@ -1897,25 +1900,27 @@ vips_region_fetch( VipsRegion *region,
g_assert( width > 0 ); g_assert( width > 0 );
g_assert( height > 0 ); g_assert( height > 0 );
rect.left = left; image.left = 0;
rect.top = top; image.top = 0;
rect.width = width; image.width = region->im->Xsize;
rect.height = height; image.height = region->im->Ysize;
if( vips_region_prepare( region, &rect ) ) request.left = left;
request.top = top;
request.width = width;
request.height = height;
if( !vips_rect_includesrect( &image, &request ) )
return( NULL );
if( vips_region_prepare( region, &request ) )
return( NULL ); return( NULL );
/* vips_region_prepare() will clip rect against the size of the image,
* so we must use region->valid instead.
*/
skip = VIPS_REGION_LSKIP( region ); skip = VIPS_REGION_LSKIP( region );
line = VIPS_REGION_SIZEOF_LINE( region ); line = VIPS_IMAGE_SIZEOF_PEL( region->im ) * request.width;
if( !(result = (VipsPel *) vips_malloc( NULL, if( !(result = (VipsPel *) vips_malloc( NULL, line * request.height )) )
region->valid.height * line )) )
return( NULL ); return( NULL );
p = VIPS_REGION_ADDR( region, region->valid.left, region->valid.top ); p = VIPS_REGION_ADDR( region, request.left, request.top );
q = result; q = result;
for( y = 0; y < region->valid.height; y++ ) { for( y = 0; y < request.height; y++ ) {
memcpy( q, p, line ); memcpy( q, p, line );
p += skip; p += skip;
@ -1923,7 +1928,7 @@ vips_region_fetch( VipsRegion *region,
} }
if( len ) if( len )
*len = region->valid.height * line; *len = request.height * line;
return( result ); return( result );
} }