Commit 4e7b5345 authored by Robert Ancell's avatar Robert Ancell
Browse files

gif: Render GIF frames on demand

The previous code loaded all the frames into memory, which causes a memory
and CPU explosion when a large GIF was loaded.

From the existing code:
/* The below reflects the "use hell of a lot of RAM" philosophy of coding */

The updated code now generates each image on demand by storing the compressed
data and decompressing and combining with the last image. This uses more CPU
than the old method, but allows arbitraritly large GIFs to play.

The stop_after_first_frame hack that worked around this is no longer required
and removed. This hack didn't work for progressive loading.

If a GIF was played with frames out of order (e.g. in reverse) this would be
quite slow, as repeated rendering would occur. This seems unlikely in the
GIF use case but if it was a problem storing some key frames that would
normally be discarded would reduce this while not using too much memory.

A render cache could also be helpful in making a CPU / RAM trade-off for
small repeating GIFs that have few frames.

Fixes #101
parent b88f1ce9
Pipeline #99856 passed with stage
in 5 minutes and 24 seconds
This diff is collapsed.
......@@ -59,23 +59,24 @@ typedef struct _GdkPixbufFrame GdkPixbufFrame;
struct _GdkPixbufGifAnim {
GdkPixbufAnimation parent_instance;
/* Number of frames */
int n_frames;
/* Total length of animation */
int total_time;
/* Color map */
guchar color_map[256 * 3];
/* List of GdkPixbufFrame structures */
GList *frames;
/* bounding box size */
int width, height;
guchar bg_red;
guchar bg_green;
guchar bg_blue;
int loop;
/* Last rendered frames */
GdkPixbuf *last_frame_data;
GdkPixbufFrame *last_frame;
GdkPixbuf *last_frame_revert_data;
struct _GdkPixbufGifAnimClass {
......@@ -127,12 +128,25 @@ GType gdk_pixbuf_gif_anim_iter_get_type (void) G_GNUC_CONST;
struct _GdkPixbufFrame {
/* The pixbuf with this frame's image data */
GdkPixbuf *pixbuf;
/* Compressed frame data */
GByteArray *lzw_data;
guint8 lzw_code_size;
/* Offsets for overlaying onto the GIF graphic area */
/* Position of frame data in image */
int x_offset;
int y_offset;
guint16 width;
guint16 height;
/* Layout of pixels */
gboolean interlace;
/* Color map */
gboolean color_map_allocated;
guchar *color_map;
/* Transparency */
int transparent_index;
/* Frame duration in ms */
int delay_time;
......@@ -142,30 +156,6 @@ struct _GdkPixbufFrame {
/* Overlay mode */
GdkPixbufFrameAction action;
/* TRUE if the pixbuf has been modified since
* the last frame composite operation
gboolean need_recomposite;
/* The below reflects the "use hell of a lot of RAM"
* philosophy of coding
/* Cached composite image (the image you actually display
* for this frame)
GdkPixbuf *composited;
/* Cached revert image (the contents of the area
* covered by the frame prior to compositing;
* same size as pixbuf, not as the composite image; only
* used for FRAME_REVERT frames)
GdkPixbuf *revert;
void gdk_pixbuf_gif_anim_frame_composite (GdkPixbufGifAnim *gif_anim,
GdkPixbufFrame *frame);
This diff is collapsed.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment