Merge branch 'loader-minimise-experiment'
This commit is contained in:
commit
6a75776272
@ -6,6 +6,7 @@
|
||||
- disable webp alpha output if all frames fill the canvas and are solid
|
||||
- add "compression" option to heifsave [lovell]
|
||||
- support webp and zstd compression in tiff
|
||||
- loaders use "minimise" to close input files earlier
|
||||
- integrate support for oss-fuzz [omira-sch]
|
||||
|
||||
9/7/19 started 8.8.2
|
||||
|
@ -34,7 +34,8 @@ equal_vector( std::vector<double> a, std::vector<double> b )
|
||||
printf( "%g", a[i] );
|
||||
}
|
||||
printf( "], is [" );
|
||||
for( unsigned int i = 0; i < a.size(); i++ ) { if( i > 0 )
|
||||
for( unsigned int i = 0; i < a.size(); i++ ) {
|
||||
if( i > 0 )
|
||||
printf( ", " );
|
||||
printf( "%g", a[i] );
|
||||
}
|
||||
|
@ -103,6 +103,10 @@ typedef struct _VipsInsert {
|
||||
VipsRect rout; /* Output space */
|
||||
VipsRect rmain; /* Position of main in output */
|
||||
VipsRect rsub; /* Position of sub in output */
|
||||
|
||||
/* TRUE if we've minimise sub.
|
||||
*/
|
||||
gboolean sub_minimised;
|
||||
} VipsInsert;
|
||||
|
||||
typedef VipsConversionClass VipsInsertClass;
|
||||
@ -164,8 +168,6 @@ vips__insert_paste_region( VipsRegion *or, VipsRegion *ir, VipsRect *pos )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Insert generate function.
|
||||
*/
|
||||
static int
|
||||
vips_insert_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop )
|
||||
{
|
||||
@ -175,39 +177,43 @@ vips_insert_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop )
|
||||
|
||||
VipsRect ovl;
|
||||
|
||||
/* Does the rect we have been asked for fall entirely inside the
|
||||
* sub-image?
|
||||
*/
|
||||
if( vips_rect_includesrect( &insert->rsub, &or->valid ) )
|
||||
return( vips__insert_just_one( or, ir[1],
|
||||
insert->rsub.left, insert->rsub.top ) );
|
||||
|
||||
/* Does it fall entirely inside the main, and not at all inside the
|
||||
* sub?
|
||||
/* The part of the subimage we will use.
|
||||
*/
|
||||
vips_rect_intersectrect( &or->valid, &insert->rsub, &ovl );
|
||||
if( vips_rect_includesrect( &insert->rmain, &or->valid ) &&
|
||||
vips_rect_isempty( &ovl ) )
|
||||
return( vips__insert_just_one( or, ir[0],
|
||||
insert->rmain.left, insert->rmain.top ) );
|
||||
|
||||
/* Output requires both (or neither) input. If it is not entirely
|
||||
* inside both the main and the sub, then there is going to be some
|
||||
* background.
|
||||
/* Three cases: we are generating entirely within the sub-image,
|
||||
* entirely within the main image, or a mixture.
|
||||
*/
|
||||
if( !(vips_rect_includesrect( &insert->rsub, &or->valid ) &&
|
||||
vips_rect_includesrect( &insert->rmain, &or->valid )) )
|
||||
vips_region_paint_pel( or, r, insert->ink );
|
||||
if( vips_rect_includesrect( &insert->rsub, &or->valid ) ) {
|
||||
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
|
||||
* entirely inside both the main and the sub, then there is
|
||||
* going to be some background.
|
||||
*/
|
||||
if( !(vips_rect_includesrect( &insert->rsub, &or->valid ) &&
|
||||
vips_rect_includesrect( &insert->rmain, &or->valid )) )
|
||||
vips_region_paint_pel( or, r, insert->ink );
|
||||
|
||||
/* Paste from main.
|
||||
*/
|
||||
if( vips__insert_paste_region( or, ir[0], &insert->rmain ) )
|
||||
return( -1 );
|
||||
/* Paste from main.
|
||||
*/
|
||||
if( vips__insert_paste_region( or, ir[0], &insert->rmain ) )
|
||||
return( -1 );
|
||||
|
||||
/* Paste from sub.
|
||||
*/
|
||||
if( vips__insert_paste_region( or, ir[1], &insert->rsub ) )
|
||||
return( -1 );
|
||||
/* Paste from sub.
|
||||
*/
|
||||
if( vips__insert_paste_region( or, ir[1], &insert->rsub ) )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
@ -838,7 +838,7 @@ vips_foreign_load_start( VipsImage *out, void *a, void *b )
|
||||
|
||||
/* Load the image and check the result.
|
||||
*
|
||||
* ->header() read the header into @out, load has read the
|
||||
* ->header() read the header into @out, load will read the
|
||||
* image into @real. They must match exactly in size, bands,
|
||||
* format and coding for the copy to work.
|
||||
*
|
||||
|
@ -24,6 +24,9 @@
|
||||
* - rework as a sequential loader ... simpler, much lower mem use
|
||||
* 6/7/19 [deftomat]
|
||||
* - support array of delays
|
||||
* 24/7/19
|
||||
* - close early on minimise
|
||||
* - close early on error
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -637,8 +640,6 @@ vips_foreign_load_gif_header( VipsForeignLoad *load )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
/* Read in the image record.
|
||||
*/
|
||||
if( vips_foreign_load_gif_scan_image_record( gif ) )
|
||||
return( -1 );
|
||||
|
||||
@ -647,7 +648,7 @@ vips_foreign_load_gif_header( VipsForeignLoad *load )
|
||||
break;
|
||||
|
||||
case EXTENSION_RECORD_TYPE:
|
||||
/* We will need to fetch the extensions to check for
|
||||
/* We need to fetch the extensions to check for
|
||||
* cmaps and transparency.
|
||||
*/
|
||||
if( vips_foreign_load_gif_scan_extension( gif ) )
|
||||
@ -1009,6 +1010,12 @@ vips_foreign_load_gif_generate( VipsRegion *or,
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_foreign_load_gif_minimise( VipsObject *object, VipsForeignLoadGif *gif )
|
||||
{
|
||||
vips_foreign_load_gif_close( gif );
|
||||
}
|
||||
|
||||
static int
|
||||
vips_foreign_load_gif_load( VipsForeignLoad *load )
|
||||
{
|
||||
@ -1052,6 +1059,11 @@ vips_foreign_load_gif_load( VipsForeignLoad *load )
|
||||
if( vips_foreign_load_gif_set_header( gif, t[0] ) )
|
||||
return( -1 );
|
||||
|
||||
/* Close input immediately at end of read.
|
||||
*/
|
||||
g_signal_connect( t[0], "minimise",
|
||||
G_CALLBACK( vips_foreign_load_gif_minimise ), gif );
|
||||
|
||||
/* Strips 8 pixels high to avoid too many tiny regions.
|
||||
*/
|
||||
if( vips_image_generate( t[0],
|
||||
@ -1189,6 +1201,26 @@ vips_giflib_file_read( GifFileType *file, GifByteType *buffer, int n )
|
||||
return( (int) fread( (void *) buffer, 1, n, fp ) );
|
||||
}
|
||||
|
||||
static int
|
||||
vips_foreign_load_gif_file_header( VipsForeignLoad *load )
|
||||
{
|
||||
VipsForeignLoadGifFile *file = (VipsForeignLoadGifFile *) load;
|
||||
|
||||
if( VIPS_FOREIGN_LOAD_CLASS(
|
||||
vips_foreign_load_gif_file_parent_class )->header( load ) ) {
|
||||
/* Close early if header read fails in our base class.
|
||||
*/
|
||||
VIPS_FREEF( fclose, file->fp );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* We have to have _open() as a vfunc since our base class needs to be able to
|
||||
* make two scans of the gif (scan for header, then scan for pixels), so we
|
||||
* must be able to close and reopen (or rewind).
|
||||
*/
|
||||
static int
|
||||
vips_foreign_load_gif_file_open( VipsForeignLoadGif *gif )
|
||||
{
|
||||
@ -1238,6 +1270,7 @@ vips_foreign_load_gif_file_class_init(
|
||||
foreign_class->suffs = vips_foreign_gif_suffs;
|
||||
|
||||
load_class->is_a = vips_foreign_load_gif_is_a;
|
||||
load_class->header = vips_foreign_load_gif_file_header;
|
||||
|
||||
gif_class->open = vips_foreign_load_gif_file_open;
|
||||
|
||||
|
@ -4,6 +4,9 @@
|
||||
* - from niftiload.c
|
||||
* 24/7/19 [zhoux2016]
|
||||
* - always fetch metadata from the main image (thumbs don't have it)
|
||||
* 24/7/19
|
||||
* - close early on minimise
|
||||
* - close early on error
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -130,14 +133,21 @@ typedef VipsForeignLoadClass VipsForeignLoadHeifClass;
|
||||
G_DEFINE_ABSTRACT_TYPE( VipsForeignLoadHeif, vips_foreign_load_heif,
|
||||
VIPS_TYPE_FOREIGN_LOAD );
|
||||
|
||||
static void
|
||||
vips_foreign_load_heif_close( VipsForeignLoadHeif *heif )
|
||||
{
|
||||
VIPS_FREEF( heif_image_release, heif->img );
|
||||
heif->data = NULL;
|
||||
VIPS_FREEF( heif_image_handle_release, heif->handle );
|
||||
VIPS_FREEF( heif_context_free, heif->ctx );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_foreign_load_heif_dispose( GObject *gobject )
|
||||
{
|
||||
VipsForeignLoadHeif *heif = (VipsForeignLoadHeif *) gobject;
|
||||
|
||||
VIPS_FREEF( heif_image_release, heif->img );
|
||||
VIPS_FREEF( heif_image_handle_release, heif->handle );
|
||||
VIPS_FREEF( heif_context_free, heif->ctx );
|
||||
vips_foreign_load_heif_close( heif );
|
||||
VIPS_FREE( heif->id );
|
||||
|
||||
G_OBJECT_CLASS( vips_foreign_load_heif_parent_class )->
|
||||
@ -707,6 +717,12 @@ vips_foreign_load_heif_generate( VipsRegion *or,
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_foreign_load_heif_minimise( VipsObject *object, VipsForeignLoadHeif *heif )
|
||||
{
|
||||
vips_foreign_load_heif_close( heif );
|
||||
}
|
||||
|
||||
static int
|
||||
vips_foreign_load_heif_load( VipsForeignLoad *load )
|
||||
{
|
||||
@ -722,6 +738,12 @@ vips_foreign_load_heif_load( VipsForeignLoad *load )
|
||||
t[0] = vips_image_new();
|
||||
if( vips_foreign_load_heif_set_header( heif, t[0] ) )
|
||||
return( -1 );
|
||||
|
||||
/* CLose input immediately at end of read.
|
||||
*/
|
||||
g_signal_connect( t[0], "minimise",
|
||||
G_CALLBACK( vips_foreign_load_heif_minimise ), heif );
|
||||
|
||||
if( vips_image_generate( t[0],
|
||||
NULL, vips_foreign_load_heif_generate, NULL, heif, NULL ) ||
|
||||
vips_sequential( t[0], &t[1], NULL ) ||
|
||||
@ -821,13 +843,20 @@ vips_foreign_load_heif_file_header( VipsForeignLoad *load )
|
||||
|
||||
error = heif_context_read_from_file( heif->ctx, file->filename, NULL );
|
||||
if( error.code ) {
|
||||
/* Make we close the fd as soon as we can on error.
|
||||
*/
|
||||
vips_foreign_load_heif_close( heif );
|
||||
vips__heif_error( &error );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
if( VIPS_FOREIGN_LOAD_CLASS(
|
||||
vips_foreign_load_heif_file_parent_class )->header( load ) )
|
||||
vips_foreign_load_heif_file_parent_class )->header( load ) ) {
|
||||
/* Close early if our base class fails to read.
|
||||
*/
|
||||
vips_foreign_load_heif_close( heif );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
VIPS_SETSTR( load->out->filename, file->filename );
|
||||
|
||||
|
@ -100,6 +100,8 @@
|
||||
* - strict round down on shrink-on-load
|
||||
* 16/8/18
|
||||
* - shut down the input file as soon as we can [kleisauke]
|
||||
* 20/7/19
|
||||
* - close input on minimise rather than Y read position
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -190,8 +192,7 @@ typedef struct _ReadJpeg {
|
||||
int output_height;
|
||||
} ReadJpeg;
|
||||
|
||||
/* This can be called many times. It's called directly at the end of image
|
||||
* read.
|
||||
/* This can be called many times.
|
||||
*/
|
||||
static void
|
||||
readjpeg_close_input( ReadJpeg *jpeg )
|
||||
@ -237,6 +238,12 @@ readjpeg_close_cb( VipsObject *object, ReadJpeg *jpeg )
|
||||
(void) readjpeg_free( jpeg );
|
||||
}
|
||||
|
||||
static void
|
||||
readjpeg_minimise_cb( VipsObject *object, ReadJpeg *jpeg )
|
||||
{
|
||||
readjpeg_close_input( jpeg );
|
||||
}
|
||||
|
||||
static ReadJpeg *
|
||||
readjpeg_new( VipsImage *out, int shrink, gboolean fail, gboolean autorotate )
|
||||
{
|
||||
@ -270,6 +277,8 @@ readjpeg_new( VipsImage *out, int shrink, gboolean fail, gboolean autorotate )
|
||||
|
||||
g_signal_connect( out, "close",
|
||||
G_CALLBACK( readjpeg_close_cb ), jpeg );
|
||||
g_signal_connect( out, "minimise",
|
||||
G_CALLBACK( readjpeg_minimise_cb ), jpeg );
|
||||
|
||||
return( jpeg );
|
||||
}
|
||||
@ -290,20 +299,17 @@ readjpeg_file( ReadJpeg *jpeg, const char *filename )
|
||||
static const char *
|
||||
find_chroma_subsample( struct jpeg_decompress_struct *cinfo )
|
||||
{
|
||||
gboolean has_subsample;
|
||||
|
||||
/* libjpeg only uses 4:4:4 and 4:2:0, confusingly.
|
||||
*
|
||||
* http://poynton.ca/PDFs/Chroma_subsampling_notation.pdf
|
||||
*/
|
||||
has_subsample = cinfo->max_h_samp_factor > 1 ||
|
||||
gboolean has_subsample = cinfo->max_h_samp_factor > 1 ||
|
||||
cinfo->max_v_samp_factor > 1;
|
||||
if( cinfo->num_components > 3 )
|
||||
/* A cmyk image.
|
||||
*/
|
||||
return( has_subsample ? "4:2:0:4" : "4:4:4:4" );
|
||||
else
|
||||
return( has_subsample ? "4:2:0" : "4:4:4" );
|
||||
gboolean is_cmyk = cinfo->num_components > 3;
|
||||
|
||||
return( is_cmyk ?
|
||||
(has_subsample ? "4:2:0:4" : "4:4:4:4" ) :
|
||||
(has_subsample ? "4:2:0" : "4:4:4") );
|
||||
}
|
||||
|
||||
static int
|
||||
@ -718,7 +724,7 @@ read_jpeg_generate( VipsRegion *or,
|
||||
jpeg->y_pos += 1;
|
||||
}
|
||||
|
||||
/* Shut down the input file as soon as we can.
|
||||
/* Shut down the input early if we can.
|
||||
*/
|
||||
if( jpeg->y_pos >= or->im->Ysize )
|
||||
readjpeg_close_input( jpeg );
|
||||
|
@ -348,11 +348,6 @@ vips__openexr_generate( VipsRegion *out,
|
||||
}
|
||||
}
|
||||
|
||||
/* We can't shut down the input file early for tile read, even if we
|
||||
* know load is in sequential mode, since we are not inside a
|
||||
* vips_sequential() and requests are not guaranteed to be in order.
|
||||
*/
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
|
@ -380,6 +380,15 @@ vips_foreign_load_pdf_header( VipsForeignLoad *load )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_foreign_load_pdf_minimise( VipsObject *object, VipsForeignLoadPdf *pdf )
|
||||
{
|
||||
/* In seq mode, we can shut down the input at the end of computation.
|
||||
*/
|
||||
if( VIPS_FOREIGN_LOAD( pdf )->access == VIPS_ACCESS_SEQUENTIAL )
|
||||
vips_foreign_load_pdf_close( pdf );
|
||||
}
|
||||
|
||||
static int
|
||||
vips_foreign_load_pdf_generate( VipsRegion *or,
|
||||
void *seq, void *a, void *b, gboolean *stop )
|
||||
@ -436,13 +445,6 @@ vips_foreign_load_pdf_generate( VipsRegion *or,
|
||||
i += 1;
|
||||
}
|
||||
|
||||
/* In seq mode, we can shut down the input when we render the last
|
||||
* row.
|
||||
*/
|
||||
if( top >= or->im->Ysize &&
|
||||
load->access == VIPS_ACCESS_SEQUENTIAL )
|
||||
vips_foreign_load_pdf_close( pdf );
|
||||
|
||||
/* PDFium writes BRGA, we must swap.
|
||||
*
|
||||
* FIXME ... this is a bit slow.
|
||||
@ -476,6 +478,11 @@ vips_foreign_load_pdf_load( VipsForeignLoad *load )
|
||||
*/
|
||||
t[0] = vips_image_new();
|
||||
|
||||
/* Close input immediately at end of read.
|
||||
*/
|
||||
g_signal_connect( t[0], "minimise",
|
||||
G_CALLBACK( vips_foreign_load_pdf_minimise ), pdf );
|
||||
|
||||
vips_foreign_load_pdf_set_image( pdf, t[0] );
|
||||
if( vips_image_generate( t[0],
|
||||
NULL, vips_foreign_load_pdf_generate, NULL, pdf, NULL ) )
|
||||
|
@ -334,12 +334,20 @@ vips_foreign_load_pdf_header( VipsForeignLoad *load )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_foreign_load_pdf_minimise( VipsObject *object, VipsForeignLoadPdf *pdf )
|
||||
{
|
||||
/* In seq mode, we can shut down the input at the end of computation.
|
||||
*/
|
||||
if( VIPS_FOREIGN_LOAD( pdf )->access == VIPS_ACCESS_SEQUENTIAL )
|
||||
vips_foreign_load_pdf_close( pdf );
|
||||
}
|
||||
|
||||
static int
|
||||
vips_foreign_load_pdf_generate( VipsRegion *or,
|
||||
void *seq, void *a, void *b, gboolean *stop )
|
||||
{
|
||||
VipsForeignLoadPdf *pdf = (VipsForeignLoadPdf *) a;
|
||||
VipsForeignLoad *load = (VipsForeignLoad *) pdf;
|
||||
VipsRect *r = &or->valid;
|
||||
|
||||
int top;
|
||||
@ -398,13 +406,6 @@ vips_foreign_load_pdf_generate( VipsRegion *or,
|
||||
i += 1;
|
||||
}
|
||||
|
||||
/* In seq mode, we can shut down the input when we render the last
|
||||
* row.
|
||||
*/
|
||||
if( top >= or->im->Ysize &&
|
||||
load->access == VIPS_ACCESS_SEQUENTIAL )
|
||||
vips_foreign_load_pdf_close( pdf );
|
||||
|
||||
/* Cairo makes pre-multipled BRGA, we must byteswap and unpremultiply.
|
||||
*/
|
||||
for( y = 0; y < r->height; y++ )
|
||||
@ -430,6 +431,11 @@ vips_foreign_load_pdf_load( VipsForeignLoad *load )
|
||||
*/
|
||||
t[0] = vips_image_new();
|
||||
|
||||
/* Close input immediately at end of read.
|
||||
*/
|
||||
g_signal_connect( t[0], "minimise",
|
||||
G_CALLBACK( vips_foreign_load_pdf_minimise ), pdf );
|
||||
|
||||
vips_foreign_load_pdf_set_image( pdf, t[0] );
|
||||
if( vips_image_generate( t[0],
|
||||
NULL, vips_foreign_load_pdf_generate, NULL, pdf, NULL ) )
|
||||
|
@ -984,12 +984,17 @@ vips__rad_israd( const char *filename )
|
||||
return( result == 1 );
|
||||
}
|
||||
|
||||
static void
|
||||
read_minimise( VipsObject *object, Read *read )
|
||||
{
|
||||
VIPS_FREEF( buffer_free, read->buffer );
|
||||
VIPS_FREEF( fclose, read->fin );
|
||||
}
|
||||
|
||||
static void
|
||||
read_destroy( VipsObject *object, Read *read )
|
||||
{
|
||||
VIPS_FREE( read->filename );
|
||||
VIPS_FREEF( fclose, read->fin );
|
||||
VIPS_FREEF( buffer_free, read->buffer );
|
||||
}
|
||||
|
||||
static Read *
|
||||
@ -1019,6 +1024,8 @@ read_new( const char *filename, VipsImage *out )
|
||||
read->prims[3][1] = CIE_y_w;
|
||||
read->buffer = NULL;
|
||||
|
||||
g_signal_connect( out, "minimise",
|
||||
G_CALLBACK( read_minimise ), read );
|
||||
g_signal_connect( out, "close",
|
||||
G_CALLBACK( read_destroy ), read );
|
||||
|
||||
|
@ -189,6 +189,8 @@
|
||||
* 7/6/19
|
||||
* - istiff reads the first directory rather than just testing the magic
|
||||
* number, so it ignores more TIFF-like, but not TIFF images
|
||||
* 20/7/19
|
||||
* - use "minimise" for early shutdown, rather than read Y position
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -494,6 +496,20 @@ rtiff_close_cb( VipsObject *object, Rtiff *rtiff )
|
||||
rtiff_free( rtiff );
|
||||
}
|
||||
|
||||
static void
|
||||
rtiff_minimise_cb( VipsObject *object, Rtiff *rtiff )
|
||||
{
|
||||
#ifdef DEBUG
|
||||
printf( "rtiff_minimise_cb: %p minimise\n", rtiff );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
/* Close early for non-tiled TIFFs. Tiled TIFFs are read randomly, so
|
||||
* the end of a loop doesn't mean the tiff won't be used again.
|
||||
*/
|
||||
if( !rtiff->header.tiled )
|
||||
rtiff_free( rtiff );
|
||||
}
|
||||
|
||||
static Rtiff *
|
||||
rtiff_new( VipsImage *out, int page, int n, gboolean autorotate )
|
||||
{
|
||||
@ -520,6 +536,9 @@ rtiff_new( VipsImage *out, int page, int n, gboolean autorotate )
|
||||
g_signal_connect( out, "close",
|
||||
G_CALLBACK( rtiff_close_cb ), rtiff );
|
||||
|
||||
g_signal_connect( out, "minimise",
|
||||
G_CALLBACK( rtiff_minimise_cb ), rtiff );
|
||||
|
||||
if( rtiff->page < 0 || rtiff->page > 1000000 ) {
|
||||
vips_error( "tiff2vips", _( "bad page number %d" ),
|
||||
rtiff->page );
|
||||
@ -1603,11 +1622,6 @@ rtiff_fill_region( VipsRegion *out,
|
||||
|
||||
VIPS_GATE_STOP( "rtiff_fill_region: work" );
|
||||
|
||||
/* We can't shut down the input file early for tile read, even if we
|
||||
* know load is in sequential mode, since we are not inside a
|
||||
* vips_sequential() and requests are not guaranteed to be in order.
|
||||
*/
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
@ -1949,11 +1963,11 @@ rtiff_stripwise_generate( VipsRegion *or,
|
||||
rtiff->y_pos += hit.height;
|
||||
}
|
||||
|
||||
/* Shut down the input file as soon as we can.
|
||||
/* Shut down the input file as soon as we can.
|
||||
*/
|
||||
if( rtiff->y_pos >= or->im->Ysize ) {
|
||||
#ifdef DEBUG
|
||||
printf( "rtiff_stripwise_generate: early shutdown\n" );
|
||||
printf( "rtiff_stripwise_generate: early shutdown\n" );
|
||||
#endif /*DEBUG*/
|
||||
rtiff_free( rtiff );
|
||||
}
|
||||
|
@ -196,6 +196,22 @@ read_close_cb( VipsImage *out, Read *read )
|
||||
read_destroy( read );
|
||||
}
|
||||
|
||||
static void
|
||||
read_minimise_cb( VipsImage *out, Read *read )
|
||||
{
|
||||
/* Catch errors from png_read_end(). This can fail on a truncated
|
||||
* file.
|
||||
*/
|
||||
if( read->pPng ) {
|
||||
/* Catch and ignore error returns from png_read_end().
|
||||
*/
|
||||
if( !setjmp( png_jmpbuf( read->pPng ) ) )
|
||||
png_read_end( read->pPng, NULL );
|
||||
}
|
||||
|
||||
read_destroy( read );
|
||||
}
|
||||
|
||||
static Read *
|
||||
read_new( VipsImage *out, gboolean fail )
|
||||
{
|
||||
@ -218,6 +234,8 @@ read_new( VipsImage *out, gboolean fail )
|
||||
|
||||
g_signal_connect( out, "close",
|
||||
G_CALLBACK( read_close_cb ), read );
|
||||
g_signal_connect( out, "minimise",
|
||||
G_CALLBACK( read_minimise_cb ), read );
|
||||
|
||||
if( !(read->pPng = png_create_read_struct(
|
||||
PNG_LIBPNG_VER_STRING, NULL,
|
||||
@ -643,22 +661,21 @@ png2vips_generate( VipsRegion *or,
|
||||
}
|
||||
|
||||
/* Catch errors from png_read_end(). This can fail on a truncated
|
||||
* file.
|
||||
* file.
|
||||
*/
|
||||
if( setjmp( png_jmpbuf( read->pPng ) ) ) {
|
||||
if( read->fail ) {
|
||||
vips_error( "vipspng", "%s", _( "libpng read error" ) );
|
||||
vips_error( "vipspng", "%s", _( "libpng read error" ) );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* We need to shut down the reader immediately at the end of read or
|
||||
* we won't detach ready for the next image.
|
||||
/* Early close to free the fd as soon as we can.
|
||||
*/
|
||||
if( read->y_pos >= read->out->Ysize ) {
|
||||
png_read_end( read->pPng, NULL );
|
||||
png_read_end( read->pPng, NULL );
|
||||
read_destroy( read );
|
||||
}
|
||||
|
||||
|
@ -342,8 +342,8 @@ vips__iswebp( const char *filename )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
read_free( Read *read )
|
||||
static void
|
||||
read_minimise( Read *read )
|
||||
{
|
||||
WebPDemuxReleaseIterator( &read->iter );
|
||||
VIPS_UNREF( read->frame );
|
||||
@ -359,6 +359,13 @@ read_free( Read *read )
|
||||
}
|
||||
|
||||
VIPS_FREEF( vips_tracked_close, read->fd );
|
||||
}
|
||||
|
||||
static int
|
||||
read_free( Read *read )
|
||||
{
|
||||
read_minimise( read );
|
||||
|
||||
VIPS_FREE( read->filename );
|
||||
VIPS_FREE( read->delays );
|
||||
VIPS_FREE( read );
|
||||
@ -793,6 +800,12 @@ read_webp_generate( VipsRegion *or,
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static void
|
||||
read_minimise_cb( VipsObject *object, Read *read )
|
||||
{
|
||||
read_minimise( read );
|
||||
}
|
||||
|
||||
static int
|
||||
read_image( Read *read, VipsImage *out )
|
||||
{
|
||||
@ -803,6 +816,9 @@ read_image( Read *read, VipsImage *out )
|
||||
if( read_header( read, t[0] ) )
|
||||
return( -1 );
|
||||
|
||||
g_signal_connect( t[0], "minimise",
|
||||
G_CALLBACK( read_minimise_cb ), read );
|
||||
|
||||
if( vips_image_generate( t[0],
|
||||
NULL, read_webp_generate, NULL, read, NULL ) ||
|
||||
vips_sequential( t[0], &t[1], NULL ) ||
|
||||
|
@ -426,6 +426,8 @@ void vips_image_invalidate_all( VipsImage *image );
|
||||
|
||||
void vips_image_minimise_all( VipsImage *image );
|
||||
|
||||
gboolean vips_image_is_sequential( VipsImage *image );
|
||||
|
||||
void vips_image_set_progress( VipsImage *image, gboolean progress );
|
||||
gboolean vips_image_iskilled( VipsImage *image );
|
||||
void vips_image_set_kill( VipsImage *image, gboolean kill );
|
||||
|
@ -451,11 +451,9 @@ vips_image_finalize( GObject *gobject )
|
||||
VIPS_FREE( image->time );
|
||||
}
|
||||
|
||||
/* Any image data?
|
||||
/* Free attached memory.
|
||||
*/
|
||||
if( image->data ) {
|
||||
/* Buffer image. Only free stuff we know we allocated.
|
||||
*/
|
||||
if( image->dtype == VIPS_IMAGE_SETBUF ) {
|
||||
VIPS_DEBUG_MSG( "vips_image_finalize: "
|
||||
"freeing buffer\n" );
|
||||
@ -466,7 +464,7 @@ vips_image_finalize( GObject *gobject )
|
||||
image->data = NULL;
|
||||
}
|
||||
|
||||
/* If this is a temp, delete it.
|
||||
/* Delete associated files.
|
||||
*/
|
||||
vips_image_delete( image );
|
||||
|
||||
@ -1454,6 +1452,22 @@ vips_image_minimise_all( VipsImage *image )
|
||||
(VipsSListMap2Fn) vips_image_minimise_all_cb, NULL, NULL );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_image_is_sequential: (method)
|
||||
* @image: #VipsImage to minimise
|
||||
*
|
||||
* TRUE if any of the images upstream from @image were opened in sequential
|
||||
* mode. Some operations change behaviour slightly in sequential mode to
|
||||
* optimise memory behaviour.
|
||||
*
|
||||
* Returns: %TRUE if @image is in sequential mode.
|
||||
*/
|
||||
gboolean
|
||||
vips_image_is_sequential( VipsImage *image )
|
||||
{
|
||||
return( vips_image_get_typeof( image, VIPS_META_SEQUENTIAL ) );
|
||||
}
|
||||
|
||||
/* Attach a new time struct, if necessary, and reset it.
|
||||
*/
|
||||
static int
|
||||
@ -2066,9 +2080,8 @@ vips_image_new_from_memory_copy_cb( VipsImage *image, void *data_copy )
|
||||
* @format: image format
|
||||
*
|
||||
* Like vips_image_new_from_memory(), but VIPS will make a copy of the memory
|
||||
* area. This
|
||||
* means more memory use and an extra copy operation, but is much simpler and
|
||||
* safer.
|
||||
* area. This means more memory use and an extra copy operation, but is much
|
||||
* simpler and safer.
|
||||
*
|
||||
* See also: vips_image_new_from_memory().
|
||||
*
|
||||
|
@ -45,8 +45,6 @@
|
||||
* - rename yshrink -> vshrink for greater consistency
|
||||
* 7/3/17
|
||||
* - add a seq line cache
|
||||
* 9/7/19
|
||||
* - read the tail of the input to force early shutdown in seq readers
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -101,7 +99,6 @@ typedef struct _VipsShrinkv {
|
||||
|
||||
int vshrink;
|
||||
size_t sizeof_line_buffer;
|
||||
gboolean sequential;
|
||||
|
||||
} VipsShrinkv;
|
||||
|
||||
@ -268,7 +265,6 @@ vips_shrinkv_gen( VipsRegion *or, void *vseq,
|
||||
{
|
||||
VipsShrinkvSequence *seq = (VipsShrinkvSequence *) vseq;
|
||||
VipsShrinkv *shrink = (VipsShrinkv *) b;
|
||||
VipsResample *resample = VIPS_RESAMPLE( shrink );
|
||||
VipsRegion *ir = seq->ir;
|
||||
VipsRect *r = &or->valid;
|
||||
|
||||
@ -319,38 +315,6 @@ vips_shrinkv_gen( VipsRegion *or, void *vseq,
|
||||
|
||||
VIPS_COUNT_PIXELS( or, "vips_shrinkv_gen" );
|
||||
|
||||
/* If we are in seq mode and we've just generated the last line of
|
||||
* the output, make sure we read all of the input.
|
||||
*
|
||||
* This will trigger the early shutdown logic in things like the
|
||||
* tiff loader.
|
||||
*/
|
||||
if( shrink->sequential &&
|
||||
r->top + r->height >= or->im->Ysize ) {
|
||||
/* First unused scanline. resample->in->Ysize because we want
|
||||
* the height before the embed.
|
||||
*/
|
||||
int first = or->im->Ysize * shrink->vshrink;
|
||||
int unused = resample->in->Ysize - first;
|
||||
|
||||
g_assert( unused >= 0 );
|
||||
|
||||
for( y = 0; y < unused; y++ ) {
|
||||
VipsRect s;
|
||||
|
||||
s.left = r->left;
|
||||
s.top = first + y;
|
||||
s.width = r->width;
|
||||
s.height = 1;
|
||||
#ifdef DEBUG
|
||||
printf( "shrink_gen: requesting tail %d\n", s.top );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
if( vips_region_prepare( ir, &s ) )
|
||||
return( -1 );
|
||||
}
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
@ -448,11 +412,9 @@ vips_shrinkv_build( VipsObject *object )
|
||||
* always have the previous XX lines of the shrunk image, and we won't
|
||||
* fetch out of order.
|
||||
*/
|
||||
if( vips_image_get_typeof( in, VIPS_META_SEQUENTIAL ) ) {
|
||||
if( vips_image_is_sequential( in ) ) {
|
||||
g_info( "shrinkv sequential line cache" );
|
||||
|
||||
shrink->sequential = TRUE;
|
||||
|
||||
if( vips_sequential( in, &t[3],
|
||||
"tile_height", 10,
|
||||
NULL ) )
|
||||
|
Loading…
Reference in New Issue
Block a user