add dispose handling

see https://github.com/jcupitt/php-vips/issues/59
This commit is contained in:
John Cupitt 2017-11-22 17:37:31 +00:00
parent 27621733f2
commit 6a4b249445
2 changed files with 48 additions and 16 deletions

View File

@ -38,6 +38,7 @@
- vips_affine() and vips_similarity() have a "background" parameter - vips_affine() and vips_similarity() have a "background" parameter
- fix nasty jaggies on the edges of affine output, thanks chregu - fix nasty jaggies on the edges of affine output, thanks chregu
- add gif-delay, gif-comment and gif-loop metadata - add gif-delay, gif-comment and gif-loop metadata
- add dispose handling to gifload
29/8/17 started 8.5.9 29/8/17 started 8.5.9
- make --fail stop jpeg read on any libjpeg warning, thanks @mceachen - make --fail stop jpeg read on any libjpeg warning, thanks @mceachen

View File

@ -17,6 +17,7 @@
* - colormap can be missing thanks Kleis * - colormap can be missing thanks Kleis
* 21/11/17 * 21/11/17
* - add "gif-delay", "gif-loop", "gif-comment" metadata * - add "gif-delay", "gif-loop", "gif-comment" metadata
* - add dispose handling
*/ */
/* /*
@ -134,6 +135,10 @@ typedef struct _VipsForeignLoadGif {
*/ */
char *comment; char *comment;
/* The current dispose method.
*/
int dispose;
/* The FILE* we read from. /* The FILE* we read from.
*/ */
FILE *fp; FILE *fp;
@ -404,7 +409,14 @@ vips_foreign_load_gif_render_line( VipsForeignLoadGif *gif,
q[2] = v; q[2] = v;
q[3] = 255; q[3] = 255;
} }
else if( gif->dispose == DISPOSE_DO_NOT ) {
/* Transparent pixels let the previous frame show
* through, ie., do nothing.
*/
}
else { else {
/* All other modes are just transparent.
*/
q[0] = 0; q[0] = 0;
q[1] = 0; q[1] = 0;
q[2] = 0; q[2] = 0;
@ -415,12 +427,12 @@ vips_foreign_load_gif_render_line( VipsForeignLoadGif *gif,
} }
} }
/* Render the current gif frame into an RGBA buffer. GIFs /* Render the current gif frame into an RGBA buffer. GIFs can accumulate,
* accumulate, so don't clear the buffer first, we need to paint a * depending on the current dispose mode.
* series of frames on top of each other.
*/ */
static int static int
vips_foreign_load_gif_render( VipsForeignLoadGif *gif, VipsImage *out ) vips_foreign_load_gif_render( VipsForeignLoadGif *gif,
VipsImage *previous, VipsImage *out )
{ {
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( gif ); VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( gif );
GifFileType *file = gif->file; GifFileType *file = gif->file;
@ -544,10 +556,16 @@ vips_foreign_load_gif_graphics_ext( VipsForeignLoadGif *gif,
if( extension[1] & 0x1 ) { if( extension[1] & 0x1 ) {
gif->transparency = extension[4]; gif->transparency = extension[4];
gif->has_transparency = TRUE; gif->has_transparency = TRUE;
VIPS_DEBUG_MSG( "gifload: " VIPS_DEBUG_MSG( "gifload: transparency %d\n",
"seen transparency %d\n", gif->transparency ); 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( "gifload: dispose %d\n", gif->dispose );
if( !gif->has_delay ) { if( !gif->has_delay ) {
gif->has_delay = TRUE; gif->has_delay = TRUE;
gif->delay = extension[2] | (extension[3] << 8); gif->delay = extension[2] | (extension[3] << 8);
@ -662,10 +680,12 @@ vips_foreign_load_gif_extension( VipsForeignLoadGif *gif )
} }
/* Write the next page, if there is one, to @page. Set EOF if we hit the end of /* Write the next page, if there is one, to @page. Set EOF if we hit the end of
* the file. @page must be a memory image of the right size. * the file. @page must be a memory image of the right size. @previous is the
* previous frame, if any.
*/ */
static int static int
vips_foreign_load_gif_page( VipsForeignLoadGif *gif, VipsImage *out ) vips_foreign_load_gif_page( VipsForeignLoadGif *gif,
VipsImage *previous, VipsImage *out )
{ {
GifRecordType record; GifRecordType record;
int n_pages; int n_pages;
@ -687,7 +707,7 @@ vips_foreign_load_gif_page( VipsForeignLoadGif *gif, VipsImage *out )
return( -1 ); return( -1 );
} }
if( vips_foreign_load_gif_render( gif, out ) ) if( vips_foreign_load_gif_render( gif, previous, out ) )
return( -1 ); return( -1 );
n_pages += 1; n_pages += 1;
@ -795,7 +815,7 @@ vips_foreign_load_gif_pages( VipsForeignLoadGif *gif, VipsImage **out )
if( !(frame = vips_foreign_load_gif_new_page( gif )) ) if( !(frame = vips_foreign_load_gif_new_page( gif )) )
return( -1 ); return( -1 );
do { do {
if( vips_foreign_load_gif_page( gif, frame ) ) { if( vips_foreign_load_gif_page( gif, NULL, frame ) ) {
g_object_unref( frame ); g_object_unref( frame );
return( -1 ); return( -1 );
} }
@ -821,14 +841,19 @@ vips_foreign_load_gif_pages( VipsForeignLoadGif *gif, VipsImage **out )
return( -1 ); return( -1 );
} }
/* And init with the previous frame, if any. if( gif->dispose == DISPOSE_BACKGROUND )
*/ /* BACKGROUND means the bg shows through, ie. (in web
if( previous ) * terms) everything is transparent.
*/
memset( VIPS_IMAGE_ADDR( frame, 0, 0 ),
0,
VIPS_IMAGE_SIZEOF_IMAGE( frame ) );
else
memcpy( VIPS_IMAGE_ADDR( frame, 0, 0 ), memcpy( VIPS_IMAGE_ADDR( frame, 0, 0 ),
VIPS_IMAGE_ADDR( previous, 0, 0 ), VIPS_IMAGE_ADDR( previous, 0, 0 ),
VIPS_IMAGE_SIZEOF_IMAGE( frame ) ); VIPS_IMAGE_SIZEOF_IMAGE( frame ) );
if( vips_foreign_load_gif_page( gif, frame ) ) { if( vips_foreign_load_gif_page( gif, previous, frame ) ) {
g_object_unref( frame ); g_object_unref( frame );
unref_array( frames ); unref_array( frames );
return( -1 ); return( -1 );
@ -842,7 +867,12 @@ vips_foreign_load_gif_pages( VipsForeignLoadGif *gif, VipsImage **out )
} }
else { else {
frames = g_slist_append( frames, frame ); frames = g_slist_append( frames, frame );
previous = frame;
/* These two dispose modes set new background frames.
*/
if( gif->dispose == DISPOSAL_UNSPECIFIED ||
gif->dispose == DISPOSE_DO_NOT )
previous = frame;
} }
} }
@ -985,6 +1015,7 @@ vips_foreign_load_gif_init( VipsForeignLoadGif *gif )
gif->delay = 4; gif->delay = 4;
gif->loop = 0; gif->loop = 0;
gif->comment = NULL; gif->comment = NULL;
gif->dispose = 0;
} }
typedef struct _VipsForeignLoadGifFile { typedef struct _VipsForeignLoadGifFile {