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 31/1/19 started 8.9.2
- fix a deadlock with --vips-leak [DarthSim] - fix a deadlock with --vips-leak [DarthSim]
- better gifload behaviour for DISPOSAL_UNSPECIFIED [DarthSim]
20/6/19 started 8.9.1 20/6/19 started 8.9.1
- don't use the new source loaders for new_from_file or new_from_buffer, it - 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 * - check image and frame bounds, since giflib does not
* 1/9/19 * 1/9/19
* - improve early close again * - 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 /* In DISPOSE_DO_NOT mode, the previous frame shows
* through (ie. we do nothing). In all other modes, * through (ie. we do nothing). In all other modes,
* it's just transparent. * 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; iq[x] = 0;
} }
else else
@ -976,6 +983,20 @@ vips_foreign_load_gif_render( VipsForeignLoadGif *gif )
return( 0 ); 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 static int
vips_foreign_load_gif_extension( VipsForeignLoadGif *gif ) vips_foreign_load_gif_extension( VipsForeignLoadGif *gif )
{ {
@ -998,15 +1019,18 @@ vips_foreign_load_gif_extension( VipsForeignLoadGif *gif )
* is being set. * is being set.
*/ */
gif->transparency = -1; gif->transparency = -1;
if( extension[1] & 0x1 ) if( extension[1] & 0x1 ) {
gif->transparency = extension[4]; 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 /* Set the current dispose mode. This is read during frame load
* to set the meaning of background and transparent pixels. * to set the meaning of background and transparent pixels.
*/ */
gif->dispose = (extension[1] >> 2) & 0x7; gif->dispose = (extension[1] >> 2) & 0x7;
VIPS_DEBUG_MSG( "vips_foreign_load_gif_extension: " VIPS_DEBUG_MSG( "vips_foreign_load_gif_extension: "
"dispose = %d\n", gif->dispose ); "dispose = %s\n", dispose2str( gif->dispose ) );
} }
while( extension != NULL ) while( extension != NULL )