experiment with svgload as a sequential loader

see https://github.com/libvips/libvips/issues/1425
This commit is contained in:
John Cupitt 2019-09-11 16:58:20 +01:00
parent d290c971ab
commit e505d56079

View File

@ -17,6 +17,8 @@
* 28/6/19
* - add "unlimited"
* - requires us to use the gio API to librsvg
* 11/9/19
* - rework as a sequential loader to reduce overcomputation
*/
/*
@ -239,15 +241,13 @@ vips_foreign_load_svg_dispose( GObject *gobject )
static VipsForeignFlags
vips_foreign_load_svg_get_flags_filename( const char *filename )
{
/* We can render any part of the page on demand.
*/
return( VIPS_FOREIGN_PARTIAL );
return( VIPS_FOREIGN_SEQUENTIAL );
}
static VipsForeignFlags
vips_foreign_load_svg_get_flags( VipsForeignLoad *load )
{
return( VIPS_FOREIGN_PARTIAL );
return( VIPS_FOREIGN_SEQUENTIAL );
}
static void
@ -328,6 +328,12 @@ vips_foreign_load_svg_generate( VipsRegion *or,
cairo_t *cr;
int y;
#ifdef DEBUG
printf( "vips_foreign_load_svg_generate:\n "
"left = %d, top = %d, width = %d, height = %d\n",
r->left, r->top, r->width, r->height );
#endif /*DEBUG*/
/* rsvg won't always paint the background.
*/
vips_region_black( or );
@ -371,44 +377,30 @@ vips_foreign_load_svg_load( VipsForeignLoad *load )
{
VipsForeignLoadSvg *svg = (VipsForeignLoadSvg *) load;
VipsImage **t = (VipsImage **)
vips_object_local_array( (VipsObject *) load, 2 );
vips_object_local_array( (VipsObject *) load, 3 );
int tile_width;
int tile_height;
int max_tiles;
/* Read to this image, then cache to out, see below.
/* librsvg starts to fail if any axis in a single render call is over
* RSVG_MAX_WIDTH pixels. vips_sequential() will use a tilecache where
* each tile is a strip the width of the image and (in this case)
* 2000 pixels high. To be able to render images wider than
* RSVG_MAX_WIDTH pixels, we need to chop these strips up.
* We use a small tilecache between the seq and our gen to do this.
*
* Make tiles 2000 pixels high to limit overcomputation.
*/
t[0] = vips_image_new();
vips_foreign_load_svg_parse( svg, t[0] );
if( vips_image_generate( t[0],
NULL, vips_foreign_load_svg_generate, NULL, svg, NULL ) )
return( -1 );
/* librsvg starts to fail if any axis in a single render call is over
* 32767. Use a tilecache so we can render very wide images, though we
* set it up like a linecache.
*
* Don't thread the cache: we rely on this to keep calls to rsvg
* single-threaded.
*
* Make tiles 2000 pixels high to limit overcomputation. Make sure we
* have two rows of tiles so we don't recompute requests that cross
* tile boundaries.
*/
tile_width = VIPS_MIN( t[0]->Xsize, RSVG_MAX_WIDTH );
max_tiles = 2 * VIPS_ROUND_UP( t[0]->Xsize, RSVG_MAX_WIDTH ) /
RSVG_MAX_WIDTH;
tile_height = 2000;
if( vips_tilecache( t[0], &t[1],
"tile_width", tile_width,
"tile_height", tile_height,
"max_tiles", max_tiles,
"access", VIPS_ACCESS_SEQUENTIAL,
NULL ) )
return( -1 );
if( vips_image_write( t[1], load->real ) )
NULL, vips_foreign_load_svg_generate, NULL, svg, NULL ) ||
vips_tilecache( t[0], &t[1],
"tile_width", VIPS_MIN( t[0]->Xsize, RSVG_MAX_WIDTH ),
"tile_height", 2000,
"max_tiles", 1,
NULL ) ||
vips_sequential( t[1], &t[2],
"tile_height", 2000,
NULL ) ||
vips_image_write( t[2], load->real ) )
return( -1 );
return( 0 );