almost loading
This commit is contained in:
parent
e12b44e790
commit
617d910379
@ -50,8 +50,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
#define VIPS_DEBUG
|
|
||||||
*/
|
*/
|
||||||
|
#define VIPS_DEBUG
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
@ -93,19 +93,6 @@
|
|||||||
#define DISPOSE_PREVIOUS 3
|
#define DISPOSE_PREVIOUS 3
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* TODO:
|
|
||||||
*
|
|
||||||
* - once we know this, we can set the header of the output image
|
|
||||||
*
|
|
||||||
* - second slow scan driven by _generate to render pages as required, with a
|
|
||||||
* single page held as a memory image
|
|
||||||
*
|
|
||||||
* Try the fast scan idea first -- can we get everything we need quickly?
|
|
||||||
*
|
|
||||||
* Need vmethods for open/close/rewind in base class, implement in file and
|
|
||||||
* buffer.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define VIPS_TYPE_FOREIGN_LOAD_GIF (vips_foreign_load_gif_get_type())
|
#define VIPS_TYPE_FOREIGN_LOAD_GIF (vips_foreign_load_gif_get_type())
|
||||||
#define VIPS_FOREIGN_LOAD_GIF( obj ) \
|
#define VIPS_FOREIGN_LOAD_GIF( obj ) \
|
||||||
(G_TYPE_CHECK_INSTANCE_CAST( (obj), \
|
(G_TYPE_CHECK_INSTANCE_CAST( (obj), \
|
||||||
@ -157,6 +144,10 @@ typedef struct _VipsForeignLoadGif {
|
|||||||
*/
|
*/
|
||||||
char *comment;
|
char *comment;
|
||||||
|
|
||||||
|
/* The number of pages (frame) in the image.
|
||||||
|
*/
|
||||||
|
int n_pages;
|
||||||
|
|
||||||
/* A memory image the sized of one frame ... we accumulate to this as
|
/* A memory image the sized of one frame ... we accumulate to this as
|
||||||
* we scan the image, and copy lines to the output on generate.
|
* we scan the image, and copy lines to the output on generate.
|
||||||
*/
|
*/
|
||||||
@ -404,12 +395,28 @@ vips_foreign_load_gif_code_next( VipsForeignLoadGif *gif,
|
|||||||
static int
|
static int
|
||||||
vips_foreign_load_gif_scan_image_record( VipsForeignLoadGif *gif )
|
vips_foreign_load_gif_scan_image_record( VipsForeignLoadGif *gif )
|
||||||
{
|
{
|
||||||
|
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( gif );
|
||||||
GifFileType *file = gif->file;
|
GifFileType *file = gif->file;
|
||||||
ColorMapObject *map = file->Image.ColorMap ?
|
ColorMapObject *map = file->Image.ColorMap ?
|
||||||
file->Image.ColorMap : file->SColorMap;
|
file->Image.ColorMap : file->SColorMap;
|
||||||
|
|
||||||
GifByteType *extension;
|
GifByteType *extension;
|
||||||
|
|
||||||
|
/* Check that the frame looks sane. Perhaps giflib checks
|
||||||
|
* this for us.
|
||||||
|
*/
|
||||||
|
if( file->Image.Left < 0 ||
|
||||||
|
file->Image.Width < 1 ||
|
||||||
|
file->Image.Width > 10000 ||
|
||||||
|
file->Image.Left + file->Image.Width > file->SWidth ||
|
||||||
|
file->Image.Top < 0 ||
|
||||||
|
file->Image.Height < 1 ||
|
||||||
|
file->Image.Height > 10000 ||
|
||||||
|
file->Image.Top + file->Image.Height > file->SHeight ) {
|
||||||
|
vips_error( class->nickname, "%s", _( "bad frame size" ) );
|
||||||
|
return( -1 );
|
||||||
|
}
|
||||||
|
|
||||||
/* Test for a non-greyscale colourmap for this frame.
|
/* Test for a non-greyscale colourmap for this frame.
|
||||||
*/
|
*/
|
||||||
if( !gif->has_colour &&
|
if( !gif->has_colour &&
|
||||||
@ -508,10 +515,13 @@ vips_foreign_load_gif_scan_extension( VipsForeignLoadGif *gif )
|
|||||||
switch( ext_code ) {
|
switch( ext_code ) {
|
||||||
case GRAPHICS_EXT_FUNC_CODE:
|
case GRAPHICS_EXT_FUNC_CODE:
|
||||||
if( extension[0] == 4 &&
|
if( extension[0] == 4 &&
|
||||||
extension[1] & 0x1 )
|
extension[1] & 0x1 ) {
|
||||||
|
VIPS_DEBUG_MSG( "gifload: has transp.\n" );
|
||||||
gif->has_transparency = TRUE;
|
gif->has_transparency = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
if( !gif->has_delay ) {
|
if( !gif->has_delay ) {
|
||||||
|
VIPS_DEBUG_MSG( "gifload: has delay\n" );
|
||||||
gif->has_delay = TRUE;
|
gif->has_delay = TRUE;
|
||||||
gif->delay = extension[2] | (extension[3] << 8);
|
gif->delay = extension[2] | (extension[3] << 8);
|
||||||
}
|
}
|
||||||
@ -548,29 +558,52 @@ vips_foreign_load_gif_scan_extension( VipsForeignLoadGif *gif )
|
|||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Attempt to quickly scan a GIF and discover:
|
static int
|
||||||
* - number of frames (pages)
|
vips_foreign_load_gif_set_header( VipsForeignLoadGif *gif, VipsImage *image )
|
||||||
* - mono or colour (check colourmap on each page)
|
{
|
||||||
* - has transparency (check bit in ext block on every page)
|
vips_image_init_fields( image,
|
||||||
|
gif->file->SWidth, gif->file->SHeight * gif->n,
|
||||||
|
(gif->has_colour ? 3 : 1) + (gif->has_transparency ? 1 : 0),
|
||||||
|
VIPS_FORMAT_UCHAR, VIPS_CODING_NONE,
|
||||||
|
gif->has_colour ?
|
||||||
|
VIPS_INTERPRETATION_sRGB : VIPS_INTERPRETATION_B_W,
|
||||||
|
1.0, 1.0 );
|
||||||
|
vips_image_pipelinev( image, VIPS_DEMAND_STYLE_THINSTRIP, NULL );
|
||||||
|
|
||||||
|
if( gif->n_pages > 1 ) {
|
||||||
|
vips_image_set_int( image,
|
||||||
|
VIPS_META_PAGE_HEIGHT, gif->file->SHeight );
|
||||||
|
vips_image_set_int( image, VIPS_META_N_PAGES, gif->n_pages );
|
||||||
|
}
|
||||||
|
vips_image_set_int( image, "gif-delay", gif->delay );
|
||||||
|
vips_image_set_int( image, "gif-loop", gif->loop );
|
||||||
|
if( gif->comment )
|
||||||
|
vips_image_set_string( image, "gif-comment", gif->comment );
|
||||||
|
|
||||||
|
return( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Attempt to quickly scan a GIF and discover what we need for our header. We
|
||||||
|
* need to scan the whole file to get n_pages, transparency and colour.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
vips_foreign_load_gif_header( VipsForeignLoad *load )
|
vips_foreign_load_gif_header( VipsForeignLoad *load )
|
||||||
{
|
{
|
||||||
VipsForeignLoadGifClass *class =
|
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( load );
|
||||||
|
VipsForeignLoadGifClass *gif_class =
|
||||||
(VipsForeignLoadGifClass *) VIPS_OBJECT_GET_CLASS( load );
|
(VipsForeignLoadGifClass *) VIPS_OBJECT_GET_CLASS( load );
|
||||||
VipsForeignLoadGif *gif = (VipsForeignLoadGif *) load;
|
VipsForeignLoadGif *gif = (VipsForeignLoadGif *) load;
|
||||||
|
|
||||||
GifRecordType record;
|
GifRecordType record;
|
||||||
int n_pages;
|
|
||||||
|
|
||||||
printf( "vips_foreign_load_gif_header:\n" );
|
printf( "vips_foreign_load_gif_header:\n" );
|
||||||
|
|
||||||
if( class->open( gif ) )
|
if( gif_class->open( gif ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
printf( "vips_foreign_load_gif_header: starting page scan\n" );
|
printf( "vips_foreign_load_gif_header: starting page scan\n" );
|
||||||
|
|
||||||
n_pages = 0;
|
gif->n_pages = 0;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if( DGifGetRecordType( gif->file, &record ) == GIF_ERROR ) {
|
if( DGifGetRecordType( gif->file, &record ) == GIF_ERROR ) {
|
||||||
@ -592,7 +625,7 @@ vips_foreign_load_gif_header( VipsForeignLoad *load )
|
|||||||
if( vips_foreign_load_gif_scan_image_record( gif ) )
|
if( vips_foreign_load_gif_scan_image_record( gif ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
n_pages += 1;
|
gif->n_pages += 1;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -622,40 +655,23 @@ vips_foreign_load_gif_header( VipsForeignLoad *load )
|
|||||||
}
|
}
|
||||||
} while( !gif->eof );
|
} while( !gif->eof );
|
||||||
|
|
||||||
printf( "vips_foreign_load_gif_header: found %d pages\n", n_pages );
|
printf( "vips_foreign_load_gif_header: found %d pages\n",
|
||||||
|
gif->n_pages );
|
||||||
|
|
||||||
/* Make the memory image we accumulate pixels in. We always accumulate
|
if( gif->n == -1 )
|
||||||
* to RGBA, then trim down to whatever the output image needs on
|
gif->n = gif->n_pages - gif->page;
|
||||||
* _generate.
|
|
||||||
*/
|
|
||||||
gif->frame = vips_image_new_memory();
|
|
||||||
vips_image_init_fields( gif->frame,
|
|
||||||
gif->file->SWidth, gif->file->SHeight, 4, VIPS_FORMAT_UCHAR,
|
|
||||||
VIPS_CODING_NONE, VIPS_INTERPRETATION_sRGB, 1.0, 1.0 );
|
|
||||||
vips_image_pipelinev( gif->frame, VIPS_DEMAND_STYLE_ANY, NULL );
|
|
||||||
if( vips_image_write_prepare( gif->frame ) )
|
|
||||||
return( -1 );
|
|
||||||
|
|
||||||
/* The real output image is long, and made on demand in _generate.
|
if( gif->page < 0 ||
|
||||||
*/
|
gif->n <= 0 ||
|
||||||
vips_image_init_fields( load->out,
|
gif->page + gif->n > gif->n_pages ) {
|
||||||
gif->file->SWidth, gif->file->SHeight * n_pages,
|
vips_error( class->nickname, "%s", _( "bad page number" ) );
|
||||||
(gif->has_colour ? 3 : 1) + (gif->has_transparency ? 1 : 0),
|
return( -1 );
|
||||||
VIPS_FORMAT_UCHAR, VIPS_CODING_NONE,
|
|
||||||
gif->has_colour ?
|
|
||||||
VIPS_INTERPRETATION_sRGB : VIPS_INTERPRETATION_B_W,
|
|
||||||
1.0, 1.0 );
|
|
||||||
vips_image_pipelinev( load->out, VIPS_DEMAND_STYLE_THINSTRIP, NULL );
|
|
||||||
|
|
||||||
if( n_pages > 1 ) {
|
|
||||||
vips_image_set_int( load->out,
|
|
||||||
VIPS_META_PAGE_HEIGHT, gif->file->SHeight );
|
|
||||||
vips_image_set_int( load->out, VIPS_META_N_PAGES, n_pages );
|
|
||||||
}
|
}
|
||||||
vips_image_set_int( load->out, "gif-delay", gif->delay );
|
|
||||||
vips_image_set_int( load->out, "gif-loop", gif->loop );
|
/* And set the output vips header from what we've learned.
|
||||||
if( gif->comment )
|
*/
|
||||||
vips_image_set_string( load->out, "gif-comment", gif->comment );
|
if( vips_foreign_load_gif_set_header( gif, load->out ) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
@ -710,39 +726,9 @@ vips_foreign_load_gif_render_line( VipsForeignLoadGif *gif,
|
|||||||
* depending on the current dispose mode.
|
* depending on the current dispose mode.
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
vips_foreign_load_gif_render( VipsForeignLoadGif *gif,
|
vips_foreign_load_gif_render( VipsForeignLoadGif *gif )
|
||||||
VipsImage *previous, VipsImage *out )
|
|
||||||
{
|
{
|
||||||
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( gif );
|
|
||||||
GifFileType *file = gif->file;
|
GifFileType *file = gif->file;
|
||||||
ColorMapObject *map = file->Image.ColorMap ?
|
|
||||||
file->Image.ColorMap : file->SColorMap;
|
|
||||||
|
|
||||||
/* Check that the frame lies within our image.
|
|
||||||
*/
|
|
||||||
if( file->Image.Left < 0 ||
|
|
||||||
file->Image.Left + file->Image.Width > out->Xsize ||
|
|
||||||
file->Image.Top < 0 ||
|
|
||||||
file->Image.Top + file->Image.Height > out->Ysize ) {
|
|
||||||
vips_error( class->nickname,
|
|
||||||
"%s", _( "frame is outside image area" ) );
|
|
||||||
return( -1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check if we have a non-greyscale colourmap for this frame.
|
|
||||||
*/
|
|
||||||
if( !gif->has_colour &&
|
|
||||||
map ) {
|
|
||||||
int i;
|
|
||||||
|
|
||||||
for( i = 0; i < map->ColorCount; i++ )
|
|
||||||
if( map->Colors[i].Red != map->Colors[i].Green ||
|
|
||||||
map->Colors[i].Green != map->Colors[i].Blue ) {
|
|
||||||
VIPS_DEBUG_MSG( "gifload: not mono\n" );
|
|
||||||
gif->has_colour = TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if( file->Image.Interlace ) {
|
if( file->Image.Interlace ) {
|
||||||
int i;
|
int i;
|
||||||
@ -758,7 +744,7 @@ vips_foreign_load_gif_render( VipsForeignLoadGif *gif,
|
|||||||
for( y = InterlacedOffset[i];
|
for( y = InterlacedOffset[i];
|
||||||
y < file->Image.Height;
|
y < file->Image.Height;
|
||||||
y += InterlacedJumps[i] ) {
|
y += InterlacedJumps[i] ) {
|
||||||
VipsPel *q = VIPS_IMAGE_ADDR( out,
|
VipsPel *q = VIPS_IMAGE_ADDR( gif->frame,
|
||||||
file->Image.Left, file->Image.Top + y );
|
file->Image.Left, file->Image.Top + y );
|
||||||
|
|
||||||
if( DGifGetLine( gif->file, gif->line,
|
if( DGifGetLine( gif->file, gif->line,
|
||||||
@ -781,7 +767,7 @@ vips_foreign_load_gif_render( VipsForeignLoadGif *gif,
|
|||||||
file->Image.Left, file->Image.Top );
|
file->Image.Left, file->Image.Top );
|
||||||
|
|
||||||
for( y = 0; y < file->Image.Height; y++ ) {
|
for( y = 0; y < file->Image.Height; y++ ) {
|
||||||
VipsPel *q = VIPS_IMAGE_ADDR( out,
|
VipsPel *q = VIPS_IMAGE_ADDR( gif->frame,
|
||||||
file->Image.Left, file->Image.Top + y );
|
file->Image.Left, file->Image.Top + y );
|
||||||
|
|
||||||
if( DGifGetLine( gif->file, gif->line,
|
if( DGifGetLine( gif->file, gif->line,
|
||||||
@ -836,19 +822,15 @@ vips_foreign_load_gif_extension( VipsForeignLoadGif *gif )
|
|||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write the next page, if there is one, to @page. Set EOF if we hit the end of
|
/* Read the next page from the file into @frame.
|
||||||
* 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,
|
vips_foreign_load_gif_next_page( VipsForeignLoadGif *gif )
|
||||||
VipsImage *previous, VipsImage *out )
|
|
||||||
{
|
{
|
||||||
GifRecordType record;
|
GifRecordType record;
|
||||||
int n_pages;
|
gboolean have_read_frame;
|
||||||
|
|
||||||
n_pages = 0;
|
|
||||||
|
|
||||||
|
have_read_frame = FALSE;
|
||||||
do {
|
do {
|
||||||
if( DGifGetRecordType( gif->file, &record ) == GIF_ERROR ) {
|
if( DGifGetRecordType( gif->file, &record ) == GIF_ERROR ) {
|
||||||
vips_foreign_load_gif_error( gif );
|
vips_foreign_load_gif_error( gif );
|
||||||
@ -864,13 +846,10 @@ vips_foreign_load_gif_page( VipsForeignLoadGif *gif,
|
|||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( vips_foreign_load_gif_render( gif, previous, out ) )
|
if( vips_foreign_load_gif_render( gif ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
n_pages += 1;
|
have_read_frame = TRUE;
|
||||||
|
|
||||||
VIPS_DEBUG_MSG( "gifload: page %d\n",
|
|
||||||
gif->current_page + n_pages );
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -895,198 +874,40 @@ vips_foreign_load_gif_page( VipsForeignLoadGif *gif,
|
|||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while( n_pages < 1 &&
|
} while( !have_read_frame &&
|
||||||
!gif->eof );
|
!gif->eof );
|
||||||
|
|
||||||
gif->current_page += n_pages;
|
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
static VipsImage *
|
|
||||||
vips_foreign_load_gif_new_page( VipsForeignLoadGif *gif )
|
|
||||||
{
|
|
||||||
VipsImage *out;
|
|
||||||
|
|
||||||
out = vips_image_new_memory();
|
|
||||||
|
|
||||||
vips_image_init_fields( out,
|
|
||||||
gif->file->SWidth, gif->file->SHeight, 4, VIPS_FORMAT_UCHAR,
|
|
||||||
VIPS_CODING_NONE, VIPS_INTERPRETATION_sRGB, 1.0, 1.0 );
|
|
||||||
|
|
||||||
/* We will have the whole GIF frame in memory, so we can render any
|
|
||||||
* area.
|
|
||||||
*/
|
|
||||||
vips_image_pipelinev( out, VIPS_DEMAND_STYLE_ANY, NULL );
|
|
||||||
|
|
||||||
/* Turn out into a memory image which we then render the GIF frames
|
|
||||||
* into.
|
|
||||||
*/
|
|
||||||
if( vips_image_write_prepare( out ) ) {
|
|
||||||
g_object_unref( out );
|
|
||||||
return( NULL );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Some GIFs may not clear the background, so we must start
|
|
||||||
* transparent.
|
|
||||||
*/
|
|
||||||
memset( VIPS_IMAGE_ADDR( out, 0, 0 ),
|
|
||||||
0,
|
|
||||||
VIPS_IMAGE_SIZEOF_IMAGE( out ) );
|
|
||||||
|
|
||||||
return( out );
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *
|
|
||||||
unref_object( void *data, void *a, void *b )
|
|
||||||
{
|
|
||||||
g_object_unref( G_OBJECT( data ) );
|
|
||||||
|
|
||||||
return( NULL );
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
unref_array( GSList *list )
|
|
||||||
{
|
|
||||||
/* g_slist_free_full() was added in 2.28 and we have to work with
|
|
||||||
* 2.6 :(
|
|
||||||
*/
|
|
||||||
vips_slist_map2( list, unref_object, NULL, NULL );
|
|
||||||
g_slist_free( list );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We render each frame to a separate memory image held in a linked
|
|
||||||
* list, then assemble to out. We don't know the number of frames in advance,
|
|
||||||
* so we can't just allocate a large area.
|
|
||||||
*/
|
|
||||||
static int
|
static int
|
||||||
vips_foreign_load_gif_pages( VipsForeignLoadGif *gif, VipsImage **out )
|
vips_foreign_load_gif_generate( VipsRegion *or,
|
||||||
|
void *seq, void *a, void *b, gboolean *stop )
|
||||||
{
|
{
|
||||||
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( gif );
|
VipsRect *r = &or->valid;
|
||||||
|
VipsForeignLoadGif *gif = (VipsForeignLoadGif *) a;
|
||||||
|
|
||||||
GSList *frames;
|
/* The page for this generate, and the line number in page.
|
||||||
VipsImage *frame;
|
|
||||||
VipsImage *previous;
|
|
||||||
VipsImage **t;
|
|
||||||
int n_frames;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
frames = NULL;
|
|
||||||
previous = NULL;
|
|
||||||
|
|
||||||
/* Accumulate any start stuff up to the first frame we need.
|
|
||||||
*/
|
*/
|
||||||
if( !(frame = vips_foreign_load_gif_new_page( gif )) )
|
int page = r->top / gif->file->SHeight + gif->page;
|
||||||
return( -1 );
|
int line = r->top % gif->file->SHeight;
|
||||||
do {
|
|
||||||
if( vips_foreign_load_gif_page( gif, NULL, frame ) ) {
|
#ifdef DEBUG_VERBOSE
|
||||||
g_object_unref( frame );
|
printf( "vips_foreign_load_gif_generate: line %d\n", r->top );
|
||||||
|
#endif /*DEBUG_VERBOSE*/
|
||||||
|
|
||||||
|
g_assert( r->height == 1 );
|
||||||
|
|
||||||
|
while( gif->current_page < page ) {
|
||||||
|
if( vips_foreign_load_gif_next_page( gif ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
|
||||||
} while( !gif->eof &&
|
|
||||||
gif->current_page <= gif->page );
|
|
||||||
|
|
||||||
if( gif->eof ) {
|
gif->current_page += 1;
|
||||||
vips_error( class->nickname,
|
|
||||||
"%s", _( "too few frames in GIF file" ) );
|
|
||||||
g_object_unref( frame );
|
|
||||||
return( -1 );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
frames = g_slist_append( frames, frame );
|
memcpy( VIPS_REGION_ADDR( or, 0, r->top ),
|
||||||
previous = frame;
|
VIPS_IMAGE_ADDR( gif->frame, 0, line ),
|
||||||
|
VIPS_IMAGE_SIZEOF_LINE( gif->frame ) );
|
||||||
while( gif->n == -1 ||
|
|
||||||
gif->current_page < gif->page + gif->n ) {
|
|
||||||
/* We might need a frame for this read to render to.
|
|
||||||
*/
|
|
||||||
if( !(frame = vips_foreign_load_gif_new_page( gif )) ) {
|
|
||||||
unref_array( frames );
|
|
||||||
return( -1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( gif->dispose == DISPOSE_BACKGROUND )
|
|
||||||
/* BACKGROUND means the bg shows through, ie. (in web
|
|
||||||
* 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 ),
|
|
||||||
VIPS_IMAGE_ADDR( previous, 0, 0 ),
|
|
||||||
VIPS_IMAGE_SIZEOF_IMAGE( frame ) );
|
|
||||||
|
|
||||||
if( vips_foreign_load_gif_page( gif, previous, frame ) ) {
|
|
||||||
g_object_unref( frame );
|
|
||||||
unref_array( frames );
|
|
||||||
return( -1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
if( gif->eof ) {
|
|
||||||
/* Nope, didn't need the new frame.
|
|
||||||
*/
|
|
||||||
g_object_unref( frame );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
frames = g_slist_append( frames, frame );
|
|
||||||
|
|
||||||
/* These two dispose modes set new background frames.
|
|
||||||
*/
|
|
||||||
if( gif->dispose == DISPOSAL_UNSPECIFIED ||
|
|
||||||
gif->dispose == DISPOSE_DO_NOT )
|
|
||||||
previous = frame;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
n_frames = g_slist_length( frames );
|
|
||||||
|
|
||||||
if( gif->eof &&
|
|
||||||
gif->n != -1 &&
|
|
||||||
n_frames < gif->n ) {
|
|
||||||
unref_array( frames );
|
|
||||||
vips_error( class->nickname,
|
|
||||||
"%s", _( "too few frames in GIF file" ) );
|
|
||||||
return( -1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We've rendered to a set of memory images ... we can shut down the GIF
|
|
||||||
* reader now.
|
|
||||||
*/
|
|
||||||
vips_foreign_load_gif_close( gif );
|
|
||||||
|
|
||||||
if( !(t = VIPS_ARRAY( gif, n_frames, VipsImage * )) ) {
|
|
||||||
unref_array( frames );
|
|
||||||
return( -1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
for( i = 0; i < n_frames; i++ )
|
|
||||||
t[i] = (VipsImage *) g_slist_nth_data( frames, i );
|
|
||||||
|
|
||||||
if( vips_arrayjoin( t, out, n_frames,
|
|
||||||
"across", 1,
|
|
||||||
NULL ) ) {
|
|
||||||
unref_array( frames );
|
|
||||||
return( -1 );
|
|
||||||
}
|
|
||||||
|
|
||||||
unref_array( frames );
|
|
||||||
|
|
||||||
if( n_frames > 1 ) {
|
|
||||||
vips_image_set_int( *out, VIPS_META_PAGE_HEIGHT, t[0]->Ysize );
|
|
||||||
|
|
||||||
/* n-pages is supposed to be the number of pages in the file,
|
|
||||||
* but we'd need to scan the entire image to find that :( so
|
|
||||||
* just set it to the number of pages we've read so far.
|
|
||||||
*/
|
|
||||||
vips_image_set_int( *out, VIPS_META_N_PAGES,
|
|
||||||
gif->current_page );
|
|
||||||
}
|
|
||||||
vips_image_set_int( *out, "gif-delay", gif->delay );
|
|
||||||
vips_image_set_int( *out, "gif-loop", gif->loop );
|
|
||||||
if( gif->comment )
|
|
||||||
vips_image_set_string( *out, "gif-comment", gif->comment );
|
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
@ -1100,53 +921,35 @@ vips_foreign_load_gif_load( VipsForeignLoad *load )
|
|||||||
VipsImage **t = (VipsImage **)
|
VipsImage **t = (VipsImage **)
|
||||||
vips_object_local_array( VIPS_OBJECT( load ), 4 );
|
vips_object_local_array( VIPS_OBJECT( load ), 4 );
|
||||||
|
|
||||||
VipsImage *im;
|
printf( "vips_foreign_load_gif_load:\n" );
|
||||||
|
|
||||||
|
/* Rewind.
|
||||||
|
*/
|
||||||
if( class->open( gif ) )
|
if( class->open( gif ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
printf( "vips_foreign_load_gif_load:\n" );
|
/* Make the memory image we accumulate pixels in. We always accumulate
|
||||||
|
* to RGBA, then trim down to whatever the output image needs on
|
||||||
if( vips_foreign_load_gif_pages( gif, &t[0] ) )
|
* _generate.
|
||||||
return( -1 );
|
|
||||||
im = t[0];
|
|
||||||
|
|
||||||
/* Depending on what we found, transform and write to load->real.
|
|
||||||
*/
|
*/
|
||||||
if( gif->has_colour &&
|
gif->frame = vips_image_new_memory();
|
||||||
gif->has_transparency ) {
|
vips_image_init_fields( gif->frame,
|
||||||
/* Nothing to do.
|
gif->file->SWidth, gif->file->SHeight, 4, VIPS_FORMAT_UCHAR,
|
||||||
*/
|
VIPS_CODING_NONE, VIPS_INTERPRETATION_sRGB, 1.0, 1.0 );
|
||||||
}
|
vips_image_pipelinev( gif->frame, VIPS_DEMAND_STYLE_ANY, NULL );
|
||||||
else if( gif->has_colour ) {
|
if( vips_image_write_prepare( gif->frame ) )
|
||||||
/* RGB.
|
return( -1 );
|
||||||
*/
|
|
||||||
if( vips_extract_band( im, &t[1], 0,
|
|
||||||
"n", 3,
|
|
||||||
NULL ) )
|
|
||||||
return( -1 );
|
|
||||||
im = t[1];
|
|
||||||
}
|
|
||||||
else if( gif->has_transparency ) {
|
|
||||||
/* GA. Take BA so we have neighboring channels.
|
|
||||||
*/
|
|
||||||
if( vips_extract_band( im, &t[1], 2,
|
|
||||||
"n", 2,
|
|
||||||
NULL ) )
|
|
||||||
return( -1 );
|
|
||||||
im = t[1];
|
|
||||||
im->Type = VIPS_INTERPRETATION_B_W;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
/* G.
|
|
||||||
*/
|
|
||||||
if( vips_extract_band( im, &t[1], 0, NULL ) )
|
|
||||||
return( -1 );
|
|
||||||
im = t[1];
|
|
||||||
im->Type = VIPS_INTERPRETATION_B_W;
|
|
||||||
}
|
|
||||||
|
|
||||||
if( vips_image_write( im, load->out ) )
|
/* Make the output pipeline.
|
||||||
|
*/
|
||||||
|
t[0] = vips_image_new();
|
||||||
|
if( vips_foreign_load_gif_set_header( gif, t[0] ) )
|
||||||
|
return( -1 );
|
||||||
|
|
||||||
|
if( vips_image_generate( t[0],
|
||||||
|
NULL, vips_foreign_load_gif_generate, NULL, gif, NULL ) ||
|
||||||
|
vips_sequential( t[0], &t[1], NULL ) ||
|
||||||
|
vips_image_write( t[1], load->real ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
@ -1174,13 +977,14 @@ vips_foreign_load_gif_open( VipsForeignLoadGif *gif )
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
gif->eof = FALSE;
|
gif->eof = FALSE;
|
||||||
|
gif->current_page = 0;
|
||||||
|
|
||||||
/* Allocate a line buffer now that we have the GIF width.
|
/* Allocate a line buffer now that we have the GIF width.
|
||||||
*/
|
*/
|
||||||
if( !gif->line )
|
VIPS_FREE( gif->line )
|
||||||
if( !(gif->line = VIPS_ARRAY( gif,
|
if( !(gif->line = VIPS_ARRAY( gif,
|
||||||
gif->file->SWidth, GifPixelType )) )
|
gif->file->SWidth, GifPixelType )) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user