fix gif rendering for "waterfall.gif"

This GIF has dispose set to DISPOSAL_UNSPECIFIED and seems to mean
transparent.

This patch makes gifload use DISPOSAL_UNSPECIFIED as well as _DO_NOT to
mean reuse previous frame.

Thanks DarthSim.

See https://github.com/libvips/libvips/issues/1543
This commit is contained in:
John Cupitt 2020-01-31 15:51:44 +00:00
parent e4db74746a
commit 8a21f6ea52
2 changed files with 28 additions and 3 deletions

View File

@ -1,5 +1,6 @@
31/1/19 started 8.9.2
- fix a deadlock with --vips-leak [DarthSim]
- better gifload behaviour for DISPOSAL_UNSPECIFIED [DarthSim]
20/6/19 started 8.9.1
- don't use the new source loaders for new_from_file or new_from_buffer, it

View File

@ -34,6 +34,9 @@
* - check image and frame bounds, since giflib does not
* 1/9/19
* - improve early close again
* 31/1/20
* - treat DISPOSAL_UNSPECIFIED as _DO_NOT, since that's what many GIFs
* in the wild appear to do
*/
/*
@ -852,8 +855,12 @@ vips_foreign_load_gif_render_line( VipsForeignLoadGif *gif,
/* In DISPOSE_DO_NOT mode, the previous frame shows
* through (ie. we do nothing). In all other modes,
* it's just transparent.
*
* Many GIFs use DISPOSAL_UNSPECIFIED to mean DO_NOT,
* so use that for previous frame as well.
*/
if( gif->dispose != DISPOSE_DO_NOT )
if( gif->dispose != DISPOSE_DO_NOT &&
gif->dispose != DISPOSAL_UNSPECIFIED )
iq[x] = 0;
}
else
@ -976,6 +983,20 @@ vips_foreign_load_gif_render( VipsForeignLoadGif *gif )
return( 0 );
}
#ifdef VIPS_DEBUG
static const char *
dispose2str( int dispose )
{
switch( dispose ) {
case DISPOSAL_UNSPECIFIED: return( "DISPOSAL_UNSPECIFIED" );
case DISPOSE_DO_NOT: return( "DISPOSE_DO_NOT" );
case DISPOSE_BACKGROUND: return( "DISPOSE_BACKGROUND" );
case DISPOSE_PREVIOUS: return( "DISPOSE_PREVIOUS" );
default: return( "<unknown>" );
}
}
#endif /*VIPS_DEBUG*/
static int
vips_foreign_load_gif_extension( VipsForeignLoadGif *gif )
{
@ -998,15 +1019,18 @@ vips_foreign_load_gif_extension( VipsForeignLoadGif *gif )
* is being set.
*/
gif->transparency = -1;
if( extension[1] & 0x1 )
if( extension[1] & 0x1 ) {
gif->transparency = extension[4];
VIPS_DEBUG_MSG( "vips_foreign_load_gif_extension: "
"transparency = %d\n", gif->transparency );
}
/* Set the current dispose mode. This is read during frame load
* to set the meaning of background and transparent pixels.
*/
gif->dispose = (extension[1] >> 2) & 0x7;
VIPS_DEBUG_MSG( "vips_foreign_load_gif_extension: "
"dispose = %d\n", gif->dispose );
"dispose = %s\n", dispose2str( gif->dispose ) );
}
while( extension != NULL )