add minimise to insert
This patch makes "insert" issue minimise signals for inputs in sequential mode. This can drop memory use in some programs, for example: ```python import sys import random import pyvips image = pyvips.Image.black(20000, 20000) for filename in sys.argv[2:]: tile = pyvips.Image.new_from_file(filename, access='sequential') x = random.randint(0, image.width - tile.width) y = random.randint(0, image.height - tile.height) image = image.insert(tile, x, y) image.write_to_file(sys.argv[1]) ``` Before this patch: ``` $ for i in {0..1000}; do cp ~/pics/k2.jpg $i.jpg; done $ /usr/bin/time -f %M:%e ../manyjoin.py ../x.jpg *.jpg 5456256:4.34 ``` With this patch: ``` $ /usr/bin/time -f %M:%e ../manyjoin.py ../x.jpg *.jpg 2475324:3.38 ```
This commit is contained in:
parent
41e92b9ada
commit
6f081de0a0
@ -19,6 +19,7 @@
|
|||||||
- add fail-on to give better control over loader error sensitivity
|
- add fail-on to give better control over loader error sensitivity
|
||||||
- add hyperbolic functions sinh, cosh, tanh, asinh, acosh, atanh [hroskes]
|
- add hyperbolic functions sinh, cosh, tanh, asinh, acosh, atanh [hroskes]
|
||||||
- add untiled jp2k load
|
- add untiled jp2k load
|
||||||
|
- "insert" will minimise in seq mode
|
||||||
|
|
||||||
16/8/21 started 8.11.4
|
16/8/21 started 8.11.4
|
||||||
- fix off-by-one error in new rank fast path
|
- fix off-by-one error in new rank fast path
|
||||||
|
@ -129,13 +129,15 @@ vips_arrayjoin_gen( VipsRegion *or, void *seq,
|
|||||||
*
|
*
|
||||||
* We don't lock for minimised[], but it's harmless.
|
* We don't lock for minimised[], but it's harmless.
|
||||||
*/
|
*/
|
||||||
for( i = 0; i < n; i++ )
|
for( i = 0; i < n; i++ ) {
|
||||||
|
int bottom_edge = VIPS_RECT_BOTTOM( &join->rects[i] );
|
||||||
|
|
||||||
if( !join->minimised[i] &&
|
if( !join->minimised[i] &&
|
||||||
r->top > VIPS_RECT_BOTTOM( &join->rects[i] ) +
|
r->top > bottom_edge + 1024 ) {
|
||||||
1024 ) {
|
|
||||||
join->minimised[i] = TRUE;
|
join->minimised[i] = TRUE;
|
||||||
vips_image_minimise_all( in[i] );
|
vips_image_minimise_all( in[i] );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,8 @@
|
|||||||
* 29/9/11
|
* 29/9/11
|
||||||
* - rewrite as a class
|
* - rewrite as a class
|
||||||
* - add expand, bg options
|
* - add expand, bg options
|
||||||
|
* 5/11/21
|
||||||
|
* - add minimise for seq pipelines
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -93,20 +95,19 @@ typedef struct _VipsInsert {
|
|||||||
*/
|
*/
|
||||||
VipsPel *ink;
|
VipsPel *ink;
|
||||||
|
|
||||||
/* Inputs cast and banded up.
|
/* Inputs cast and banded up, plus a NULL at the end.
|
||||||
*/
|
*/
|
||||||
VipsImage *main_processed;
|
VipsImage *processed[3];
|
||||||
VipsImage *sub_processed;
|
|
||||||
|
|
||||||
/* Geometry.
|
/* Geometry.
|
||||||
*/
|
*/
|
||||||
VipsRect rout; /* Output space */
|
VipsRect rout; /* Output space */
|
||||||
VipsRect rmain; /* Position of main in output */
|
VipsRect rimage[2]; /* Position of main in output */
|
||||||
VipsRect rsub; /* Position of sub in output */
|
|
||||||
|
|
||||||
/* TRUE if we've minimise sub.
|
/* TRUE if we've minimised an input.
|
||||||
*/
|
*/
|
||||||
gboolean sub_minimised;
|
gboolean minimised[2];
|
||||||
|
|
||||||
} VipsInsert;
|
} VipsInsert;
|
||||||
|
|
||||||
typedef VipsConversionClass VipsInsertClass;
|
typedef VipsConversionClass VipsInsertClass;
|
||||||
@ -174,47 +175,58 @@ vips_insert_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop )
|
|||||||
VipsRegion **ir = (VipsRegion **) seq;
|
VipsRegion **ir = (VipsRegion **) seq;
|
||||||
VipsRect *r = &or->valid;
|
VipsRect *r = &or->valid;
|
||||||
VipsInsert *insert = (VipsInsert *) b;
|
VipsInsert *insert = (VipsInsert *) b;
|
||||||
|
VipsConversion *conversion = VIPS_CONVERSION( insert );
|
||||||
|
|
||||||
VipsRect ovl;
|
int i;
|
||||||
|
|
||||||
/* The part of the subimage we will use.
|
/* First, does this request fall entirely inside one of our inputs? If
|
||||||
|
* it does, we can just redirect the request there. Test sub first.
|
||||||
*/
|
*/
|
||||||
vips_rect_intersectrect( &or->valid, &insert->rsub, &ovl );
|
for( i = 1; i >= 0; i-- ) {
|
||||||
|
VipsRect *rimage = &insert->rimage[i];
|
||||||
|
|
||||||
/* Three cases: we are generating entirely within the sub-image,
|
if( vips_rect_includesrect( rimage, r ) ) {
|
||||||
* entirely within the main image, or a mixture.
|
if( vips__insert_just_one( or, ir[i],
|
||||||
|
rimage->left, rimage->top ) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Otherwise, it requires both (or neither) input.
|
||||||
*/
|
*/
|
||||||
if( vips_rect_includesrect( &insert->rsub, &or->valid ) ) {
|
if( i < 0 ) {
|
||||||
if( vips__insert_just_one( or, ir[1],
|
|
||||||
insert->rsub.left, insert->rsub.top ) )
|
|
||||||
return( -1 );
|
|
||||||
}
|
|
||||||
else if( vips_rect_includesrect( &insert->rmain, &or->valid ) &&
|
|
||||||
vips_rect_isempty( &ovl ) ) {
|
|
||||||
if( vips__insert_just_one( or, ir[0],
|
|
||||||
insert->rmain.left, insert->rmain.top ) )
|
|
||||||
return( -1 );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* Output requires both (or neither) input. If it is not
|
/* Output requires both (or neither) input. If it is not
|
||||||
* entirely inside both the main and the sub, then there is
|
* entirely inside both the main and the sub, then there is
|
||||||
* going to be some background.
|
* going to be some background.
|
||||||
*/
|
*/
|
||||||
if( !(vips_rect_includesrect( &insert->rsub, &or->valid ) &&
|
vips_region_paint_pel( or, r, insert->ink );
|
||||||
vips_rect_includesrect( &insert->rmain, &or->valid )) )
|
|
||||||
vips_region_paint_pel( or, r, insert->ink );
|
|
||||||
|
|
||||||
/* Paste from main.
|
/* Paste the background first.
|
||||||
*/
|
*/
|
||||||
if( vips__insert_paste_region( or, ir[0], &insert->rmain ) )
|
for( i = 0; i < 2; i++ )
|
||||||
return( -1 );
|
if( vips__insert_paste_region( or, ir[i],
|
||||||
|
&insert->rimage[i] ) )
|
||||||
/* Paste from sub.
|
return( -1 );
|
||||||
*/
|
|
||||||
if( vips__insert_paste_region( or, ir[1], &insert->rsub ) )
|
|
||||||
return( -1 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* See arrayjoin for almost this code again. Move into conversion.c?
|
||||||
|
*/
|
||||||
|
if( vips_image_is_sequential( conversion->out ) )
|
||||||
|
for( i = 0; i < 2; i++ ) {
|
||||||
|
int bottom_edge =
|
||||||
|
VIPS_RECT_BOTTOM( &insert->rimage[i] );
|
||||||
|
|
||||||
|
/* 1024 is a generous margin. 256 is too small.
|
||||||
|
*/
|
||||||
|
if( !insert->minimised[i] &&
|
||||||
|
r->top > bottom_edge + 1024 ) {
|
||||||
|
insert->minimised[i] = TRUE;
|
||||||
|
vips_image_minimise_all( insert->processed[i] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -351,8 +363,6 @@ vips_insert_build( VipsObject *object )
|
|||||||
VipsInsert *insert = (VipsInsert *) object;
|
VipsInsert *insert = (VipsInsert *) object;
|
||||||
VipsImage **t = (VipsImage **) vips_object_local_array( object, 6 );
|
VipsImage **t = (VipsImage **) vips_object_local_array( object, 6 );
|
||||||
|
|
||||||
VipsImage **arry;
|
|
||||||
|
|
||||||
if( VIPS_OBJECT_CLASS( vips_insert_parent_class )->build( object ) )
|
if( VIPS_OBJECT_CLASS( vips_insert_parent_class )->build( object ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
@ -370,48 +380,46 @@ vips_insert_build( VipsObject *object )
|
|||||||
if( vips__formatalike( insert->main, insert->sub, &t[0], &t[1] ) ||
|
if( vips__formatalike( insert->main, insert->sub, &t[0], &t[1] ) ||
|
||||||
vips__bandalike( class->nickname, t[0], t[1], &t[2], &t[3] ) )
|
vips__bandalike( class->nickname, t[0], t[1], &t[2], &t[3] ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
insert->main_processed = t[2];
|
insert->processed[0] = t[2];
|
||||||
insert->sub_processed = t[3];
|
insert->processed[1] = t[3];
|
||||||
if( !(arry = vips_allocate_input_array( conversion->out,
|
|
||||||
insert->main_processed, insert->sub_processed, NULL )) )
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
/* Joins can get very wide (eg. consider joining a set of tiles
|
/* Joins can get very wide (eg. consider joining a set of tiles
|
||||||
* horizontally to make a large image), we don't want mem use to shoot
|
* horizontally to make a large image), we don't want mem use to shoot
|
||||||
* up. SMALLTILE will guarantee we keep small and local.
|
* up. SMALLTILE will guarantee we keep small and local.
|
||||||
*/
|
*/
|
||||||
if( vips_image_pipeline_array( conversion->out,
|
if( vips_image_pipeline_array( conversion->out,
|
||||||
VIPS_DEMAND_STYLE_SMALLTILE, arry ) )
|
VIPS_DEMAND_STYLE_SMALLTILE, insert->processed ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
/* Calculate geometry.
|
/* Calculate geometry.
|
||||||
*/
|
*/
|
||||||
insert->rmain.left = 0;
|
insert->rimage[0].left = 0;
|
||||||
insert->rmain.top = 0;
|
insert->rimage[0].top = 0;
|
||||||
insert->rmain.width = insert->main_processed->Xsize;
|
insert->rimage[0].width = insert->processed[0]->Xsize;
|
||||||
insert->rmain.height = insert->main_processed->Ysize;
|
insert->rimage[0].height = insert->processed[0]->Ysize;
|
||||||
insert->rsub.left = insert->x;
|
|
||||||
insert->rsub.top = insert->y;
|
insert->rimage[1].left = insert->x;
|
||||||
insert->rsub.width = insert->sub_processed->Xsize;
|
insert->rimage[1].top = insert->y;
|
||||||
insert->rsub.height = insert->sub_processed->Ysize;
|
insert->rimage[1].width = insert->processed[1]->Xsize;
|
||||||
|
insert->rimage[1].height = insert->processed[1]->Ysize;
|
||||||
|
|
||||||
if( insert->expand ) {
|
if( insert->expand ) {
|
||||||
/* Expand output to bounding box of these two.
|
/* Expand output to bounding box of these two.
|
||||||
*/
|
*/
|
||||||
vips_rect_unionrect( &insert->rmain, &insert->rsub,
|
vips_rect_unionrect( &insert->rimage[0], &insert->rimage[1],
|
||||||
&insert->rout );
|
&insert->rout );
|
||||||
|
|
||||||
/* Translate origin to top LH corner of rout.
|
/* Translate origin to top LH corner of rout.
|
||||||
*/
|
*/
|
||||||
insert->rmain.left -= insert->rout.left;
|
insert->rimage[0].left -= insert->rout.left;
|
||||||
insert->rmain.top -= insert->rout.top;
|
insert->rimage[0].top -= insert->rout.top;
|
||||||
insert->rsub.left -= insert->rout.left;
|
insert->rimage[1].left -= insert->rout.left;
|
||||||
insert->rsub.top -= insert->rout.top;
|
insert->rimage[1].top -= insert->rout.top;
|
||||||
insert->rout.left = 0;
|
insert->rout.left = 0;
|
||||||
insert->rout.top = 0;
|
insert->rout.top = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
insert->rout = insert->rmain;
|
insert->rout = insert->rimage[0];
|
||||||
|
|
||||||
conversion->out->Xsize = insert->rout.width;
|
conversion->out->Xsize = insert->rout.width;
|
||||||
conversion->out->Ysize = insert->rout.height;
|
conversion->out->Ysize = insert->rout.height;
|
||||||
@ -424,7 +432,7 @@ vips_insert_build( VipsObject *object )
|
|||||||
|
|
||||||
if( vips_image_generate( conversion->out,
|
if( vips_image_generate( conversion->out,
|
||||||
vips_start_many, vips_insert_gen, vips_stop_many,
|
vips_start_many, vips_insert_gen, vips_stop_many,
|
||||||
arry, insert ) )
|
insert->processed, insert ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
|
Loading…
Reference in New Issue
Block a user