]> Pileus Git - ~andy/gtk/blobdiff - gdk-pixbuf/io-gif.c
Add icc-profile option to gdk-pixbuf for the TIFF image format
[~andy/gtk] / gdk-pixbuf / io-gif.c
index 9da97f83669e2e97cc3e8bd8fb6126016ef23c2f..d414d782013def3a6dd29ed42c26ef88fd8af66d 100644 (file)
@@ -53,7 +53,7 @@
 
 \f
 
-#include <config.h>
+#include "config.h"
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
@@ -63,7 +63,8 @@
 
 \f
 
-#undef DUMP_IMAGE_DETAILS
+#undef DUMP_IMAGE_DETAILS 
+#undef IO_GIFDEBUG
 
 #define MAXCOLORMAPSIZE  256
 #define MAX_LZW_BITS     12
@@ -116,6 +117,7 @@ struct _GifContext
         unsigned int global_bit_pixel;
        unsigned int global_color_resolution;
         unsigned int background_index;
+        gboolean stop_after_first_frame;
 
         gboolean frame_cmap_active;
         CMap frame_color_map;
@@ -212,11 +214,14 @@ gif_read (GifContext *context, guchar *buffer, size_t len)
 #endif
                retval = (fread(buffer, len, 1, context->file) != 0);
 
-                if (!retval && ferror (context->file))
+                if (!retval && ferror (context->file)) {
+                        gint save_errno = errno;
                         g_set_error (context->error,
                                      G_FILE_ERROR,
-                                     g_file_error_from_errno (errno),
-                                     _("Failure reading GIF: %s"), strerror (errno));
+                                     g_file_error_from_errno (save_errno),
+                                     _("Failure reading GIF: %s"), 
+                                     g_strerror (save_errno));
+                }
                 
 #ifdef IO_GIFDEBUG
                if (len < 100) {
@@ -406,11 +411,11 @@ gif_get_extension (GifContext *context)
                                 retval = get_data_block (context, (unsigned char *) context->block_buf, NULL);
                                 if (retval != 0)
                                         return retval;
-                                if (!strncmp (context->block_buf, "NETSCAPE2.0", 11) ||
-                                    !strncmp (context->block_buf, "ANIMEXTS1.0", 11)) {
+                                if (!strncmp ((gchar *)context->block_buf, "NETSCAPE2.0", 11) ||
+                                    !strncmp ((gchar *)context->block_buf, "ANIMEXTS1.0", 11)) {
                                         context->in_loop_extension = TRUE;
-                                        context->block_count = 0;
                                 }
+                                context->block_count = 0;
                         }
                         if (context->in_loop_extension) {
                                 do {
@@ -485,10 +490,10 @@ gif_lzw_fill_buffer (GifContext *context)
 
        if (context->code_done) {
                if (context->code_curbit >= context->code_lastbit) {
-                        g_set_error (context->error,
-                                     GDK_PIXBUF_ERROR,
-                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
-                                     _("GIF file was missing some data (perhaps it was truncated somehow?)"));
+                        g_set_error_literal (context->error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                             _("GIF file was missing some data (perhaps it was truncated somehow?)"));
 
                        return -2;
                }
@@ -568,10 +573,10 @@ gif_lzw_clear_code (GifContext *context)
 #define CHECK_LZW_SP() G_STMT_START {                                           \
         if ((guchar *)context->lzw_sp >=                                        \
             (guchar *)context->lzw_stack + sizeof (context->lzw_stack)) {       \
-                 g_set_error (context->error,                                   \
-                             GDK_PIXBUF_ERROR,                                  \
-                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,                    \
-                             _("Stack overflow"));                              \
+                 g_set_error_literal (context->error,                           \
+                                      GDK_PIXBUF_ERROR,                         \
+                                      GDK_PIXBUF_ERROR_CORRUPT_IMAGE,           \
+                                      _("Stack overflow"));                     \
                 return -2;                                                      \
         }                                                                       \
 } G_STMT_END
@@ -628,10 +633,10 @@ lzw_read_byte (GifContext *context)
                        unsigned char buf[260];
 
                         /*  FIXME - we should handle this case */
-                        g_set_error (context->error,
-                                     GDK_PIXBUF_ERROR,
-                                     GDK_PIXBUF_ERROR_FAILED,
-                                     _("GIF image loader can't understand this image."));
+                        g_set_error_literal (context->error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_FAILED,
+                                             _("GIF image loader cannot understand this image."));
                         return -2;
                         
                        if (ZeroDataBlock) {
@@ -657,20 +662,20 @@ lzw_read_byte (GifContext *context)
 
                while (code >= context->lzw_clear_code) {
                         if (code >= (1 << MAX_LZW_BITS)) {
-                                g_set_error (context->error,
-                                             GDK_PIXBUF_ERROR,
-                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
-                                             _("Bad code encountered"));
+                                g_set_error_literal (context->error,
+                                                     GDK_PIXBUF_ERROR,
+                                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                                     _("Bad code encountered"));
                                return -2;
                         }
                         CHECK_LZW_SP ();
                        *(context->lzw_sp)++ = context->lzw_table[1][code];
 
                        if (code == context->lzw_table[0][code]) {
-                                g_set_error (context->error,
-                                             GDK_PIXBUF_ERROR,
-                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
-                                             _("Circular table entry in GIF file"));
+                                g_set_error_literal (context->error,
+                                                     GDK_PIXBUF_ERROR,
+                                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                                     _("Circular table entry in GIF file"));
                                return -2;
                        }
                        code = context->lzw_table[0][code];
@@ -769,13 +774,49 @@ gif_fill_in_lines (GifContext *context, guchar *dest, guchar v)
        }
 }
 
-static void
-set_need_recomposite (gpointer data, gpointer user_data)
+/* Clips a rectancle to the base dimensions. Returns TRUE if the clipped rectangle is non-empty. */
+static gboolean
+clip_frame (GifContext *context, 
+            gint       *x, 
+            gint       *y, 
+            gint       *width, 
+            gint       *height)
 {
-        GdkPixbufFrame *frame = (GdkPixbufFrame *)data;
-        frame->need_recomposite = TRUE;
+        gint orig_x, orig_y;
+        
+        orig_x = *x;
+        orig_y = *y;
+       *x = MAX (0, *x);
+       *y = MAX (0, *y);
+       *width = MIN (context->width, orig_x + *width) - *x;
+       *height = MIN (context->height, orig_y + *height) - *y;
+
+       if (*width > 0 && *height > 0)
+               return TRUE;
+
+       /* The frame is completely off-bounds */
+
+       *x = 0;
+       *y = 0;
+       *width = 0;
+       *height = 0;
+
+        return FALSE;
 }
 
+/* Call update_func on the given rectangle, unless it is completely off-bounds */
+static void
+maybe_update (GifContext *context,
+              gint        x,
+              gint        y,
+              gint        width,
+              gint        height)
+{
+        if (clip_frame (context, &x, &y, &width, &height))
+                (*context->update_func) (context->frame->pixbuf, 
+                                         x, y, width, height,
+                                         context->user_data);
+}
 
 static int
 gif_get_lzw (GifContext *context)
@@ -792,18 +833,37 @@ gif_get_lzw (GifContext *context)
                 context->frame->composited = NULL;
                 context->frame->revert = NULL;
                 
-                context->frame->pixbuf =
-                        gdk_pixbuf_new (GDK_COLORSPACE_RGB,
-                                        TRUE,
-                                        8,
-                                        context->frame_len,
-                                        context->frame_height);
+                if (context->frame_len == 0 || context->frame_height == 0) {
+                        /* An empty frame, we just output a single transparent
+                         * pixel at (0, 0).
+                         */
+                        context->x_offset = 0;
+                        context->y_offset = 0;
+                        context->frame_len = 1;
+                        context->frame_height = 1;
+                        context->frame->pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, 1, 1);
+                        if (context->frame->pixbuf) {
+                                guchar *pixels;
+
+                                pixels = gdk_pixbuf_get_pixels (context->frame->pixbuf);
+                                pixels[0] = 0;
+                                pixels[1] = 0;
+                                pixels[2] = 0;
+                                pixels[3] = 0;
+                        }
+                } else
+                        context->frame->pixbuf =
+                                gdk_pixbuf_new (GDK_COLORSPACE_RGB,
+                                                TRUE,
+                                                8,
+                                                context->frame_len,
+                                                context->frame_height);
                 if (!context->frame->pixbuf) {
                         g_free (context->frame);
-                        g_set_error (context->error,
-                                     GDK_PIXBUF_ERROR,
-                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
-                                     _("Not enough memory to load GIF file"));
+                        g_set_error_literal (context->error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                             _("Not enough memory to load GIF file"));
                         return -2;
                 }
 
@@ -814,10 +874,14 @@ gif_get_lzw (GifContext *context)
                 /* GIF delay is in hundredths, we want thousandths */
                 context->frame->delay_time = context->gif89.delay_time * 10;
 
-                /* Some GIFs apparently have delay time of 0,
-                 * that crashes everything so set it to "fast".
-                 * Also, timeouts less than 20 or so just lock up
-                 * the app or make the animation choppy, so fix them.
+                /* GIFs with delay time 0 are mostly broken, but they
+                 * just want a default, "not that fast" delay.
+                 */
+                if (context->frame->delay_time == 0)
+                        context->frame->delay_time = 100;
+
+                /* No GIFs gets to play faster than 50 fps. They just
+                 * lock up poor gtk.
                  */
                 if (context->frame->delay_time < 20)
                         context->frame->delay_time = 20; /* 20 = "fast" */
@@ -843,28 +907,16 @@ gif_get_lzw (GifContext *context)
 
                 context->frame->bg_transparent = (context->gif89.transparent == context->background_index);
                 
-                {
-                        /* Update animation size */
-                        int w, h;
-                        
-                        context->animation->n_frames ++;
-                        context->animation->frames = g_list_append (context->animation->frames, context->frame);
-
-                        w = context->frame->x_offset +
-                                gdk_pixbuf_get_width (context->frame->pixbuf);
-                        h = context->frame->y_offset +
-                                gdk_pixbuf_get_height (context->frame->pixbuf);
-                        if (w  > context->animation->width || h > context->animation->height) {
-                                g_list_foreach (context->animation->frames, set_need_recomposite, NULL);
-                        }
-                        if (w > context->animation->width)
-                                context->animation->width = w;
-                        if (h > context->animation->height)
-                                context->animation->height = h;
-                }
+                context->animation->n_frames ++;
+                context->animation->frames = g_list_append (context->animation->frames, context->frame);
 
                 /* Only call prepare_func for the first frame */
                if (context->animation->frames->next == NULL) { 
+                        if (context->animation->width == 0 )
+                                context->animation->width = gdk_pixbuf_get_width(context->frame->pixbuf);
+                        if (context->animation->height == 0)
+                                context->animation->height = gdk_pixbuf_get_height (context->frame->pixbuf);
+
                         if (context->prepare_func)
                                 (* context->prepare_func) (context->frame->pixbuf,
                                                            GDK_PIXBUF_ANIMATION (context->animation),
@@ -873,6 +925,7 @@ gif_get_lzw (GifContext *context)
                         /* Otherwise init frame with last frame */
                         GList *link;
                         GdkPixbufFrame *prev_frame;
+                        gint x, y, w, h;
                         
                         link = g_list_find (context->animation->frames, context->frame);
 
@@ -880,13 +933,43 @@ gif_get_lzw (GifContext *context)
 
                         gdk_pixbuf_gif_anim_frame_composite (context->animation, prev_frame);
 
-                        gdk_pixbuf_copy_area (prev_frame->composited,
-                                              context->frame->x_offset,
-                                              context->frame->y_offset,
-                                              gdk_pixbuf_get_width (context->frame->pixbuf),
-                                              gdk_pixbuf_get_height (context->frame->pixbuf),
-                                              context->frame->pixbuf,
-                                              0, 0);
+                        /* Composite failed */
+                        if (prev_frame->composited == NULL) {
+                                GdkPixbufFrame *frame = NULL;
+                                link = g_list_first (context->animation->frames);
+                                while (link != NULL) {
+                                        frame = (GdkPixbufFrame *)link->data;
+                                        if (frame != NULL) {
+                                                if (frame->pixbuf != NULL)
+                                                        g_object_unref (frame->pixbuf);
+                                                if (frame->composited != NULL)
+                                                        g_object_unref (frame->composited);
+                                                if (frame->revert != NULL)
+                                                        g_object_unref (frame->revert);
+                                                g_free (frame);
+                                        }
+                                        link = link->next;
+                                }
+                                
+                                g_list_free (context->animation->frames);
+                                context->animation->frames = NULL;
+                                
+                                g_set_error_literal (context->error,
+                                                     GDK_PIXBUF_ERROR,
+                                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                                     _("Not enough memory to composite a frame in GIF file"));
+                                return -2;
+                        }
+                    
+                        x = context->frame->x_offset;
+                        y = context->frame->y_offset;
+                        w = gdk_pixbuf_get_width (context->frame->pixbuf);
+                        h = gdk_pixbuf_get_height (context->frame->pixbuf);
+                        if (clip_frame (context, &x, &y, &w, &h))
+                                gdk_pixbuf_copy_area (prev_frame->composited,
+                                                      x, y, w, h,
+                                                      context->frame->pixbuf,
+                                                      0, 0);
                 }
         }
 
@@ -985,36 +1068,29 @@ gif_get_lzw (GifContext *context)
         
        if (bound_flag && context->update_func) {
                if (lower_bound <= upper_bound && first_pass == context->draw_pass) {
-                       (* context->update_func)
-                               (context->frame->pixbuf,
-                                0, lower_bound,
-                                gdk_pixbuf_get_width (context->frame->pixbuf),
-                                upper_bound - lower_bound,
-                                context->user_data);
+                        maybe_update (context, 
+                                      context->frame->x_offset,
+                                      context->frame->y_offset + lower_bound,
+                                      gdk_pixbuf_get_width (context->frame->pixbuf),
+                                      upper_bound - lower_bound);
                } else {
                        if (lower_bound <= upper_bound) {
-                               (* context->update_func)
-                                       (context->frame->pixbuf,
-                                        context->frame->x_offset,
-                                         context->frame->y_offset,
-                                        gdk_pixbuf_get_width (context->frame->pixbuf),
-                                        gdk_pixbuf_get_height (context->frame->pixbuf),
-                                        context->user_data);
+                                maybe_update (context,
+                                              context->frame->x_offset,
+                                              context->frame->y_offset,
+                                              gdk_pixbuf_get_width (context->frame->pixbuf),
+                                              gdk_pixbuf_get_height (context->frame->pixbuf));
                        } else {
-                               (* context->update_func)
-                                       (context->frame->pixbuf,
-                                        context->frame->x_offset,
-                                         context->frame->y_offset,
-                                        gdk_pixbuf_get_width (context->frame->pixbuf),
-                                        upper_bound,
-                                        context->user_data);
-                               (* context->update_func)
-                                       (context->frame->pixbuf,
-                                        context->frame->x_offset,
-                                         lower_bound + context->frame->y_offset,
-                                        gdk_pixbuf_get_width (context->frame->pixbuf),
-                                        gdk_pixbuf_get_height (context->frame->pixbuf),
-                                        context->user_data);
+                                maybe_update (context,
+                                              context->frame->x_offset,
+                                              context->frame->y_offset,
+                                              gdk_pixbuf_get_width (context->frame->pixbuf),
+                                              upper_bound);
+                                maybe_update (context,
+                                              context->frame->x_offset,
+                                              context->frame->y_offset + lower_bound,
+                                              gdk_pixbuf_get_width (context->frame->pixbuf),
+                                              gdk_pixbuf_get_height (context->frame->pixbuf) - lower_bound);
                        }
                }
        }
@@ -1025,6 +1101,9 @@ gif_get_lzw (GifContext *context)
                  */
                context->frame = NULL;
                 context->frame_cmap_active = FALSE;
+
+                if (context->stop_after_first_frame)
+                        context->state =  GIF_DONE;
        }
        
        return v;
@@ -1047,10 +1126,10 @@ gif_prepare_lzw (GifContext *context)
        }
         
         if (context->lzw_set_code_size > MAX_LZW_BITS) {
-                g_set_error (context->error,
-                             GDK_PIXBUF_ERROR,
-                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
-                             _("GIF image is corrupt (incorrect LZW compression)"));
+                g_set_error_literal (context->error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("GIF image is corrupt (incorrect LZW compression)"));
                 return -2;
         }
 
@@ -1097,10 +1176,10 @@ gif_init (GifContext *context)
 
        if (strncmp ((char *) buf, "GIF", 3) != 0) {
                /* Not a GIF file */
-                g_set_error (context->error,
-                             GDK_PIXBUF_ERROR,
-                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
-                             _("File does not appear to be a GIF file"));
+                g_set_error_literal (context->error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("File does not appear to be a GIF file"));
                return -2;
        }
 
@@ -1143,7 +1222,10 @@ gif_init (GifContext *context)
         context->animation->bg_red = 0;
         context->animation->bg_green = 0;
         context->animation->bg_blue = 0;
-        
+
+        context->animation->width = context->width;
+        context->animation->height = context->height;
+
        if (context->has_global_cmap) {
                gif_set_get_colormap (context);
        } else {
@@ -1179,53 +1261,22 @@ gif_get_frame_info (GifContext *context)
        context->x_offset = LM_to_uint (buf[0], buf[1]);
        context->y_offset = LM_to_uint (buf[2], buf[3]);
 
-        if ((context->frame_height == 0) || (context->frame_len == 0)) {
-               context->state = GIF_DONE;
-
-                g_set_error (context->error,
-                             GDK_PIXBUF_ERROR,
-                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
-                             _("GIF image contained a frame with height or width 0."));
-                
-               return -2;
-        }
-            
-       if (((context->frame_height + context->y_offset) > context->height) ||
-            ((context->frame_len + context->x_offset) > context->width)) {
-               /* All frames must fit in the image bounds */
-               context->state = GIF_DONE;
-
-                g_set_error (context->error,
-                             GDK_PIXBUF_ERROR,
-                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
-                             _("GIF image contained a frame appearing outside the image bounds."));
-                
-               return -2;
-       }
-        
        if (context->animation->frames == NULL &&
             context->gif89.disposal == 3) {
                 /* First frame can't have "revert to previous" as its
-                 * dispose mode.
+                 * dispose mode. Silently use "retain" instead.
                  */
-                
-               context->state = GIF_DONE;
-
-                g_set_error (context->error,
-                             GDK_PIXBUF_ERROR,
-                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
-                             _("First frame of GIF image had 'revert to previous' as its disposal mode."));
-                
-               return -2;
+                context->gif89.disposal = 0;
        }
 
+       context->frame_interlace = BitSet (buf[8], INTERLACE);
+
 #ifdef DUMP_IMAGE_DETAILS
-        g_print (">width: %d height: %d xoffset: %d yoffset: %d disposal: %d delay: %d transparent: %d\n",
+        g_print (">width: %d height: %d xoffset: %d yoffset: %d disposal: %d delay: %d transparent: %d interlace: %d\n",
                  context->frame_len, context->frame_height, context->x_offset, context->y_offset,
-                 context->gif89.disposal, context->gif89.delay_time, context->gif89.transparent);
+                 context->gif89.disposal, context->gif89.delay_time, context->gif89.transparent, context->frame_interlace);
 #endif
         
-       context->frame_interlace = BitSet (buf[8], INTERLACE);
        if (BitSet (buf[8], LOCALCOLORMAP)) {
 
 #ifdef DUMP_IMAGE_DETAILS
@@ -1246,10 +1297,10 @@ gif_get_frame_info (GifContext *context)
         if (!context->has_global_cmap) {
                 context->state = GIF_DONE;
                 
-                g_set_error (context->error,
-                             GDK_PIXBUF_ERROR,
-                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
-                             _("GIF image has no global colormap, and a frame inside it has no local colormap."));
+                g_set_error_literal (context->error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("GIF image has no global colormap, and a frame inside it has no local colormap."));
                 
                return -2;
         }
@@ -1276,7 +1327,7 @@ gif_get_next_step (GifContext *context)
                }
 
                if (c == '!') {
-                       /* Check the extention */
+                       /* Check the extension */
                        gif_set_get_extension (context);
                        return 0;
                }
@@ -1293,7 +1344,7 @@ gif_get_next_step (GifContext *context)
 }
 
 
-#define LOG(x) /* g_print ("%d: %s\n", __LINE__, x); */
+#define LOG(x) /* g_print ("%s: %s\n", G_STRLOC, x); */
 
 static gint
 gif_main_loop (GifContext *context)
@@ -1380,7 +1431,7 @@ new_context (void)
 
         memset (context, 0, sizeof (GifContext));
         
-        context->animation = g_object_new (GDK_TYPE_PIXBUF_GIF_ANIM, NULL);        
+        context->animation = g_object_new (GDK_TYPE_PIXBUF_GIF_ANIM, NULL);
        context->frame = NULL;
        context->file = NULL;
        context->state = GIF_START;
@@ -1395,6 +1446,7 @@ new_context (void)
        context->gif89.disposal = -1;
         context->animation->loop = 1;
         context->in_loop_extension = FALSE;
+        context->stop_after_first_frame = FALSE;
 
        return context;
 }
@@ -1410,22 +1462,23 @@ gdk_pixbuf__gif_image_load (FILE *file, GError **error)
        context = new_context ();
 
         if (context == NULL) {
-                g_set_error (error,
-                             GDK_PIXBUF_ERROR,
-                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
-                             _("Not enough memory to load GIF file"));
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                     _("Not enough memory to load GIF file"));
                 return NULL;
         }
         
        context->file = file;
         context->error = error;
-        
+        context->stop_after_first_frame = TRUE;
+
        if (gif_main_loop (context) == -1 || context->animation->frames == NULL) {
                 if (context->error && *(context->error) == NULL)
-                        g_set_error (context->error,
-                                     GDK_PIXBUF_ERROR,
-                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
-                                     _("GIF file was missing some data (perhaps it was truncated somehow?)"));
+                        g_set_error_literal (context->error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                             _("GIF file was missing some data (perhaps it was truncated somehow?)"));
         }
         
         pixbuf = gdk_pixbuf_animation_get_static_image (GDK_PIXBUF_ANIMATION (context->animation));
@@ -1456,10 +1509,10 @@ gdk_pixbuf__gif_image_begin_load (GdkPixbufModuleSizeFunc size_func,
        context = new_context ();
 
         if (context == NULL) {
-                g_set_error (error,
-                             GDK_PIXBUF_ERROR,
-                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
-                             _("Not enough memory to load GIF file"));
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                     _("Not enough memory to load GIF file"));
                 return NULL;
         }
         
@@ -1477,11 +1530,11 @@ gdk_pixbuf__gif_image_stop_load (gpointer data, GError **error)
        GifContext *context = (GifContext *) data;
         gboolean retval = TRUE;
         
-        if (context->state != GIF_DONE) {
-                g_set_error (error,
-                             GDK_PIXBUF_ERROR,
-                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
-                             _("GIF image was truncated or incomplete."));
+        if (context->state != GIF_DONE || context->animation->frames == NULL) {
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                     _("GIF image was truncated or incomplete."));
 
                 retval = FALSE;
         }
@@ -1541,7 +1594,7 @@ gdk_pixbuf__gif_image_load_increment (gpointer data,
                /* prepare for the next image_load_increment */
                if (context->buf == buf) {
                        g_assert (context->size == size);
-                       context->buf = (guchar *)g_new (guchar, context->amount_needed + (context->size - context->ptr));
+                       context->buf = g_new (guchar, context->amount_needed + (context->size - context->ptr));
                        memcpy (context->buf, buf + context->ptr, context->size - context->ptr);
                } else {
                        /* copy the left overs to the begining of the buffer */
@@ -1571,10 +1624,10 @@ gdk_pixbuf__gif_image_load_animation (FILE *file,
        context = new_context ();
 
         if (context == NULL) {
-                g_set_error (error,
-                             GDK_PIXBUF_ERROR,
-                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
-                             _("Not enough memory to load GIF file"));
+                g_set_error_literal (error,
+                                     GDK_PIXBUF_ERROR,
+                                     GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
+                                     _("Not enough memory to load GIF file"));
                 return NULL;
         }
         
@@ -1583,10 +1636,10 @@ gdk_pixbuf__gif_image_load_animation (FILE *file,
 
        if (gif_main_loop (context) == -1 || context->animation->frames == NULL) {
                 if (context->error && *(context->error) == NULL)
-                        g_set_error (context->error,
-                                     GDK_PIXBUF_ERROR,
-                                     GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
-                                     _("GIF file was missing some data (perhaps it was truncated somehow?)"));
+                        g_set_error_literal (context->error,
+                                             GDK_PIXBUF_ERROR,
+                                             GDK_PIXBUF_ERROR_CORRUPT_IMAGE,
+                                             _("GIF file was missing some data (perhaps it was truncated somehow?)"));
 
                 g_object_unref (context->animation);
                 context->animation = NULL;
@@ -1605,8 +1658,13 @@ gdk_pixbuf__gif_image_load_animation (FILE *file,
        return animation;
 }
 
-void
-MODULE_ENTRY (gif, fill_vtable) (GdkPixbufModule *module)
+#ifndef INCLUDE_gif
+#define MODULE_ENTRY(function) G_MODULE_EXPORT void function
+#else
+#define MODULE_ENTRY(function) void _gdk_pixbuf__gif_ ## function
+#endif
+
+MODULE_ENTRY (fill_vtable) (GdkPixbufModule *module)
 {
         module->load = gdk_pixbuf__gif_image_load;
         module->begin_load = gdk_pixbuf__gif_image_begin_load;
@@ -1615,8 +1673,7 @@ MODULE_ENTRY (gif, fill_vtable) (GdkPixbufModule *module)
         module->load_animation = gdk_pixbuf__gif_image_load_animation;
 }
 
-void
-MODULE_ENTRY (gif, fill_info) (GdkPixbufFormat *info)
+MODULE_ENTRY (fill_info) (GdkPixbufFormat *info)
 {
         static GdkPixbufModulePattern signature[] = {
                 { "GIF8", NULL, 100 },
@@ -1636,5 +1693,6 @@ MODULE_ENTRY (gif, fill_info) (GdkPixbufFormat *info)
        info->description = N_("The GIF image format");
        info->mime_types = mime_types;
        info->extensions = extensions;
-       info->flags = 0;
+       info->flags = GDK_PIXBUF_FORMAT_THREADSAFE;
+       info->license = "LGPL";
 }