just one sink_disc() for magicksave

we used to cut the input image into tiles, then sink_disc() for each one
... instead, make a single sink_disc() and chop in _generate

simpler and faster
This commit is contained in:
John Cupitt 2019-02-17 12:28:13 +00:00
parent 30b5c49d0b
commit f41c1439c9

View File

@ -57,13 +57,19 @@ typedef struct _VipsForeignSaveMagick {
char *format;
int quality;
Image *images;
ImageInfo *image_info;
ExceptionInfo *exception;
Image *current_image;
char *map;
StorageType storage_type;
Image *images;
Image *current_image;
int page_height;
/* The position of current_image in the output.
*/
VipsRect position;
} VipsForeignSaveMagick;
typedef VipsForeignSaveClass VipsForeignSaveMagickClass;
@ -89,15 +95,48 @@ vips_foreign_save_magick_dispose( GObject *gobject )
dispose( gobject );
}
/* Move current_image on to the next image we will write.
*/
static int
vips_foreign_save_magick_set_properties( VipsForeignSaveMagick *magick,
Image *image, VipsImage *im )
vips_foreign_save_magick_next_image( VipsForeignSaveMagick *magick )
{
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( magick );
VipsForeignSave *save = (VipsForeignSave *) magick;
VipsImage *im = save->ready;
Image *image;
int status;
int number;
const char *str;
g_assert( !magick->current_image );
if( magick->images == NULL ) {
if( !(image = magick_acquire_image( magick->image_info,
magick->exception )) )
return( -1 );
magick->images = image;
magick->position.top = 0;
magick->position.left = 0;
magick->position.width = im->Xsize;
magick->position.height = magick->page_height;
}
else {
image = GetLastImageInList( magick->images );
magick_acquire_next_image( magick->image_info, image,
magick->exception );
if( GetNextImageInList( image ) == NULL )
return( -1 );
image = SyncNextImageInList( image );
magick->position.top += magick->page_height;
}
if( !magick_set_image_size( image,
im->Xsize, magick->page_height, magick->exception ) )
return( -1 );
if( vips_image_get_typeof( im, "gif-delay" ) &&
!vips_image_get_int( im, "gif-delay", &number ) )
image->delay = (size_t) number;
@ -120,96 +159,69 @@ vips_foreign_save_magick_set_properties( VipsForeignSaveMagick *magick,
return( -1 );
}
magick->current_image = image;
return( 0 );
}
/* We've written all the pixels to current_image ... finish it off ready to
* move on.
*/
static void
vips_foreign_save_magick_end_image( VipsForeignSaveMagick *magick )
{
if( magick->current_image ) {
magick_inherit_exception( magick->exception,
magick->current_image );
magick->current_image = NULL;
}
}
/* Another block of pixels have arrived from libvips.
*/
static int
magick_write_block( VipsRegion *region, VipsRect *area, void *a )
vips_foreign_save_magick_write_block( VipsRegion *region, VipsRect *area,
void *a )
{
VipsForeignSaveMagick *magick = (VipsForeignSaveMagick *) a;
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( magick );
int status;
VipsRect pixels;
pixels = region->valid;
do {
VipsRect hit;
void *p;
int status;
p = VIPS_REGION_ADDR( region, area->left, area->top );
if( !magick->current_image &&
vips_foreign_save_magick_next_image( magick ) )
return( -1 );
status = magick_import_pixels( magick->current_image,
area->left, area->top, area->width, area->height,
vips_rect_intersectrect( &pixels, &magick->position, &hit );
p = VIPS_REGION_ADDR( region, hit.left, hit.top );
if( !magick_import_pixels( magick->current_image,
hit.left, hit.top - magick->position.top,
hit.width, hit.height,
magick->map, magick->storage_type,
p,
magick->exception ) ) {
magick_vips_error( class->nickname,
magick->exception );
return( status == MagickFalse ? -1 : 0 );
return( -1 );
}
static int
vips_foreign_save_magick_create_one( VipsForeignSaveMagick *magick,
VipsImage *im )
{
Image *image;
int status;
/* Have we filled the page.
*/
if( VIPS_RECT_BOTTOM( &hit ) ==
VIPS_RECT_BOTTOM( &magick->position ) )
vips_foreign_save_magick_end_image( magick );
if( magick->images == NULL ) {
if( !(image = magick_acquire_image( magick->image_info,
magick->exception )) )
return( -1 );
pixels.top += hit.height;
pixels.height -= hit.height;
} while( pixels.height > 0 );
magick->images = image;
}
else {
image = GetLastImageInList( magick->images );
magick_acquire_next_image( magick->image_info, image,
magick->exception );
if( GetNextImageInList( image ) == NULL )
return( -1 );
image = SyncNextImageInList( image );
}
if( !magick_set_image_size( image, im->Xsize, im->Ysize,
magick->exception ) )
return( -1 );
if( vips_foreign_save_magick_set_properties( magick, image, im ) )
return( -1 );
magick->current_image = image;
status = vips_sink_disc( im, magick_write_block, magick );
magick_inherit_exception( magick->exception, image );
return( status );
}
static int
vips_foreign_save_magick_create( VipsForeignSaveMagick *magick, VipsImage *im )
{
int page_height;
int status;
int top;
page_height = 0;
if( vips_image_get_typeof( im, VIPS_META_PAGE_HEIGHT ) &&
vips_image_get_int( im, VIPS_META_PAGE_HEIGHT, &page_height ) )
;
if( page_height <= 0 )
page_height = im->Ysize;
status = 0;
for( top = 0; top < im->Ysize; top += page_height ) {
VipsImage *x;
if( vips_crop( im, &x, 0, top, im->Xsize, page_height, NULL ) )
return( -1 );
status = vips_foreign_save_magick_create_one( magick, x );
g_object_unref( x );
if( status )
break;
}
return( status );
return( 0 );
}
static int
@ -311,10 +323,17 @@ vips_foreign_save_magick_build( VipsObject *object )
if( magick->quality > 0 )
magick->image_info->quality = magick->quality;
if( vips_foreign_save_magick_create( magick, im ) ) {
magick_vips_error( class->nickname, magick->exception );
magick->page_height = 0;
if( vips_image_get_typeof( im, VIPS_META_PAGE_HEIGHT ) &&
vips_image_get_int( im, VIPS_META_PAGE_HEIGHT,
&magick->page_height ) )
return( -1 );
if( magick->page_height <= 0 )
magick->page_height = im->Ysize;
if( vips_sink_disc( im,
vips_foreign_save_magick_write_block, magick ) )
return( -1 );
}
return( 0 );
}