cgifsave: add support for interlaced GIF write (#2984)

* cgifsave: add support for interlaced GIF write

note: cgif >= v0.3.0 is required

* switch to warning instead of error

* add test

* fix test
This commit is contained in:
Daniel Löbl 2022-08-15 13:14:02 +02:00 committed by GitHub
parent 0029b3c416
commit 0b70145d99
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 40 additions and 0 deletions

View File

@ -83,6 +83,7 @@ typedef struct _VipsForeignSaveCgif {
int bitdepth;
double interframe_maxerror;
gboolean reoptimise;
gboolean interlace;
double interpalette_maxerror;
VipsTarget *target;
@ -601,6 +602,16 @@ vips_foreign_save_cgif_write_frame( VipsForeignSaveCgif *cgif )
frame_config.numLocalPaletteEntries = n_colours;
}
/* Write an interlaced GIF, if requested.
*/
if( cgif->interlace ) {
#ifdef HAVE_CGIF_FRAME_ATTR_INTERLACED
frame_config.attrFlags |= CGIF_FRAME_ATTR_INTERLACED;
#else /*!HAVE_CGIF_FRAME_ATTR_INTERLACED*/
g_warning( "%s: cgif >= v0.3.0 required for interlaced GIF write", class->nickname );
#endif /*HAVE_CGIF_FRAME_ATTR_INTERLACED*/
}
/* Write frame to cgif.
*/
frame_config.pImageData = cgif->index;
@ -893,6 +904,14 @@ vips_foreign_save_cgif_class_init( VipsForeignSaveCgifClass *class )
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignSaveCgif, interpalette_maxerror ),
0, 256, 3.0 );
VIPS_ARG_BOOL( class, "interlace", 16,
_( "Interlaced" ),
_( "Generate an interlaced (progressive) GIF" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsForeignSaveCgif, interlace ),
FALSE );
}
static void
@ -903,6 +922,7 @@ vips_foreign_save_cgif_init( VipsForeignSaveCgif *gif )
gif->bitdepth = 8;
gif->interframe_maxerror = 0.0;
gif->reoptimise = FALSE;
gif->interlace = FALSE;
gif->interpalette_maxerror = 3.0;
gif->mode = VIPS_FOREIGN_SAVE_CGIF_MODE_GLOBAL;
}
@ -1087,6 +1107,7 @@ vips_foreign_save_cgif_buffer_init( VipsForeignSaveCgifBuffer *buffer )
* * @bitdepth: %gint, number of bits per pixel
* * @interframe_maxerror: %gdouble, maximum inter-frame error for transparency
* * @reoptimise: %gboolean, reoptimise colour palettes
* * @interlace: %gboolean, write an interlaced (progressive) GIF
* * @interpalette_maxerror: %gdouble, maximum inter-palette error for palette
* reusage
*
@ -1110,6 +1131,10 @@ vips_foreign_save_cgif_buffer_init( VipsForeignSaveCgifBuffer *buffer )
* @interpalette_maxerror to set the threshold below which one of the previously
* generated palettes will be reused.
*
* If @interlace is TRUE, the GIF file will be interlaced (progressive GIF).
* These files may be better for display over a slow network
* conection, but need more memory to encode.
*
* See also: vips_image_new_from_file().
*
* Returns: 0 on success, -1 on error.
@ -1141,6 +1166,7 @@ vips_gifsave( VipsImage *in, const char *filename, ... )
* * @bitdepth: %gint, number of bits per pixel
* * @interframe_maxerror: %gdouble, maximum inter-frame error for transparency
* * @reoptimise: %gboolean, reoptimise colour palettes
* * @interlace: %gboolean, write an interlaced (progressive) GIF
* * @interpalette_maxerror: %gdouble, maximum inter-palette error for palette
* reusage
*
@ -1195,6 +1221,7 @@ vips_gifsave_buffer( VipsImage *in, void **buf, size_t *len, ... )
* * @bitdepth: %gint, number of bits per pixel
* * @interframe_maxerror: %gdouble, maximum inter-frame error for transparency
* * @reoptimise: %gboolean, reoptimise colour palettes
* * @interlace: %gboolean, write an interlaced (progressive) GIF
* * @interpalette_maxerror: %gdouble, maximum inter-palette error for palette
* reusage
*

View File

@ -259,6 +259,9 @@ if quantisation_package.found()
if cc.compiles('#include <cgif.h>\nint i = CGIF_ATTR_NO_LOOP;', name: 'Has CGIF_ATTR_NO_LOOP', dependencies: cgif_dep)
cfg_var.set('HAVE_CGIF_ATTR_NO_LOOP', '1')
endif
if cc.compiles('#include <cgif.h>\nint i = CGIF_FRAME_ATTR_INTERLACED;', name: 'Has CGIF_FRAME_ATTR_INTERLACED', dependencies: cgif_dep)
cfg_var.set('HAVE_CGIF_FRAME_ATTR_INTERLACED', '1')
endif
endif
endif

View File

@ -1478,6 +1478,16 @@ class TestForeign:
# FIXME ... this requires cgif0.3 or later for fixed loop support
# assert x1.get("loop") == x2.get("loop")
# Interlaced write
x1 = pyvips.Image.new_from_file(GIF_FILE, n=-1)
b1 = x1.gifsave_buffer(interlace=False)
b2 = x1.gifsave_buffer(interlace=True)
# Interlaced GIFs are usually larger in file size
# FIXME ... cgif v0.3 or later required for interlaced write.
# If interlaced write is not supported b2 and b1 are expected to be
# of the same file size.
assert len(b2) >= len(b1)
# Reducing dither will typically reduce file size (and quality)
little_dither = self.colour.gifsave_buffer(dither=0.1, effort=1)
large_dither = self.colour.gifsave_buffer(dither=0.9, effort=1)