]> 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 b403d6fa5963d39921ac4ea8afabcf1d646ca0ee..d414d782013def3a6dd29ed42c26ef88fd8af66d 100644 (file)
@@ -53,7 +53,7 @@
 
 \f
 
-#include <config.h>
+#include "config.h"
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
@@ -117,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;
@@ -213,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) {
@@ -407,8 +411,8 @@ 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;
@@ -486,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;
                }
@@ -569,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
@@ -629,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 cannot 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) {
@@ -658,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];
@@ -856,10 +860,10 @@ gif_get_lzw (GifContext *context)
                                                 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;
                 }
 
@@ -870,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" */
@@ -904,6 +912,11 @@ gif_get_lzw (GifContext *context)
 
                 /* 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),
@@ -941,10 +954,10 @@ gif_get_lzw (GifContext *context)
                                 g_list_free (context->animation->frames);
                                 context->animation->frames = NULL;
                                 
-                                g_set_error (context->error,
-                                             GDK_PIXBUF_ERROR,
-                                             GDK_PIXBUF_ERROR_INSUFFICIENT_MEMORY,
-                                             _("Not enough memory to composite a frame in GIF file"));
+                                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;
                         }
                     
@@ -1088,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;
@@ -1110,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;
         }
 
@@ -1160,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;
        }
 
@@ -1281,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;
         }
@@ -1328,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)
@@ -1415,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;
@@ -1430,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;
 }
@@ -1445,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));
@@ -1491,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;
         }
         
@@ -1512,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;
         }
@@ -1606,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;
         }
         
@@ -1618,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;
@@ -1640,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;
@@ -1650,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 },