Patch for io-gif.c



I ported this patch to the 2.2 branch.  With it you can load broken
animations as output by old versions of GifBuilder.

More importantly, you can also load the staring Wilber at the top of
www.gimp.org :)

This patch has been in place for about 2 months in the 1.4 branch and it
seems to work fine.

Is it OK to commit?

  Federico
--- io-gif.c.noclip	Wed Nov  6 14:26:27 2002
+++ io-gif.c	Fri Feb 21 15:25:15 2003
@@ -709,29 +709,57 @@
 	context->draw_pass = 0;
 }
 
+/* Clips the current frame to the base dimensions.  Returns the clipped offsets and width/height. */
+static void
+clip_frame (GifContext *context, int *x, int *y, int *w, int *h)
+{
+	*x = MAX (0, context->x_offset);
+	*y = MAX (0, context->y_offset);
+	*w = MIN (context->width, context->x_offset + context->frame_len) - *x;
+	*h = MIN (context->height, context->y_offset + context->frame_height) - *y;
+
+	if (w > 0 && h > 0)
+		return;
+
+	/* The frame is completely off-bounds */
+
+	*x = 0;
+	*y = 0;
+	*w = 0;
+	*h = 0;
+}
+
 static void
 gif_fill_in_pixels (GifContext *context, guchar *dest, gint offset, guchar v)
 {
 	guchar *pixel = NULL;
         guchar (*cmap)[MAXCOLORMAPSIZE];
+	int frame_x, frame_y, frame_width, frame_height;
+	int xpos, ypos;
+
+        g_assert (gdk_pixbuf_get_has_alpha (context->frame->pixbuf));
+
+	clip_frame (context, &frame_x, &frame_y, &frame_width, &frame_height);
 
         if (context->frame_cmap_active)
                 cmap = context->frame_color_map;
         else
                 cmap = context->global_color_map;
         
-	if (context->gif89.transparent != -1) {
-		pixel = dest + (context->draw_ypos + offset) * gdk_pixbuf_get_rowstride (context->frame->pixbuf) + context->draw_xpos * 4;
-		*pixel = cmap [0][(guchar) v];
-		*(pixel+1) = cmap [1][(guchar) v];
-		*(pixel+2) = cmap [2][(guchar) v];
-		*(pixel+3) = (guchar) ((v == context->gif89.transparent) ? 0 : 255);
-	} else {
-		pixel = dest + (context->draw_ypos + offset) * gdk_pixbuf_get_rowstride (context->frame->pixbuf) + context->draw_xpos * 3;
-		*pixel = cmap [0][(guchar) v];
-		*(pixel+1) = cmap [1][(guchar) v];
-		*(pixel+2) = cmap [2][(guchar) v];
-	}
+	xpos = context->draw_xpos + context->x_offset;
+	ypos = context->draw_ypos + offset + context->y_offset;
+
+	if (xpos >= frame_x && xpos < frame_x + frame_width &&
+	    ypos >= frame_y && ypos < frame_y + frame_height) {
+		xpos -= frame_x;
+		ypos -= frame_y;
+
+                pixel = dest + ypos * gdk_pixbuf_get_rowstride (context->frame->pixbuf) + xpos * 4;
+                *pixel = cmap [0][(guchar) v];
+                *(pixel+1) = cmap [1][(guchar) v];
+                *(pixel+2) = cmap [2][(guchar) v];
+                *(pixel+3) = (guchar) ((v == context->gif89.transparent) ? 0 : 255);
+        }
 }
 
 
@@ -785,19 +813,39 @@
 	gboolean bound_flag;
 	gint first_pass; /* bounds for emitting the area_updated signal */
 	gint v;
+	int frame_x, frame_y, frame_width, frame_height;
+	int rowstride;
+
+	clip_frame (context, &frame_x, &frame_y, &frame_width, &frame_height);
 
 	if (context->frame == NULL) {
                 context->frame = g_new (GdkPixbufFrame, 1);
 
                 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 (frame_width == 0 || frame_height == 0) {
+                        /* If it is a clipped-out frame, we just output a single
+                         * transparent pixel.
+                         */
+                        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,
+                                                frame_width,
+                                                frame_height);
+
                 if (!context->frame->pixbuf) {
                         g_free (context->frame);
                         g_set_error (context->error,
@@ -807,8 +855,8 @@
                         return -2;
                 }
 
-                context->frame->x_offset = context->x_offset;
-                context->frame->y_offset = context->y_offset;
+                context->frame->x_offset = frame_x;
+                context->frame->y_offset = frame_y;
                 context->frame->need_recomposite = TRUE;
                 
                 /* GIF delay is in hundredths, we want thousandths */
@@ -891,6 +939,7 @@
         }
 
 	dest = gdk_pixbuf_get_pixels (context->frame->pixbuf);
+        rowstride = gdk_pixbuf_get_rowstride (context->frame->pixbuf);
 
 	bound_flag = FALSE;
 	lower_bound = upper_bound = context->draw_ypos;
@@ -898,6 +947,7 @@
 
 	while (TRUE) {
                 guchar (*cmap)[MAXCOLORMAPSIZE];
+		int xpos, ypos;
 
                 if (context->frame_cmap_active)
                         cmap = context->frame_color_map;
@@ -912,11 +962,20 @@
 
                 g_assert (gdk_pixbuf_get_has_alpha (context->frame->pixbuf));
                 
-                temp = dest + context->draw_ypos * gdk_pixbuf_get_rowstride (context->frame->pixbuf) + context->draw_xpos * 4;
-                *temp = cmap [0][(guchar) v];
-                *(temp+1) = cmap [1][(guchar) v];
-                *(temp+2) = cmap [2][(guchar) v];
-                *(temp+3) = (guchar) ((v == context->gif89.transparent) ? 0 : 255);
+		xpos = context->draw_xpos + context->x_offset;
+		ypos = context->draw_ypos + context->y_offset;
+
+		if (xpos >= frame_x && xpos < frame_x + frame_width &&
+		    ypos >= frame_y && ypos < frame_y + frame_height) {
+			xpos -= frame_x;
+			ypos -= frame_y;
+
+                        temp = dest + ypos * rowstride + xpos * 4;
+                        *temp = cmap [0][(guchar) v];
+                        *(temp+1) = cmap [1][(guchar) v];
+                        *(temp+2) = cmap [2][(guchar) v];
+                        *(temp+3) = (guchar) ((v == context->gif89.transparent) ? 0 : 255);
+                }
 
 		if (context->prepare_func && context->frame_interlace)
 			gif_fill_in_lines (context, dest, v);
@@ -984,13 +1043,23 @@
                 context->frame->need_recomposite = TRUE;
         
 	if (bound_flag && context->update_func) {
+                int y, height;
+
 		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);
+			y = lower_bound + context->y_offset;
+			height = upper_bound - lower_bound;
+
+			y = MAX (frame_y, y);
+			height = MIN (frame_height, lower_bound + context->y_offset + height);
+
+                        if (height > 0)
+                                (* context->update_func)
+                                        (context->frame->pixbuf,
+                                         0,
+                                         y - frame_y,
+                                         gdk_pixbuf_get_width (context->frame->pixbuf),
+                                         height,
+                                         context->user_data);
 		} else {
 			if (lower_bound <= upper_bound) {
 				(* context->update_func)
@@ -1001,20 +1070,23 @@
 					 gdk_pixbuf_get_height (context->frame->pixbuf),
 					 context->user_data);
 			} 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);
+				height = MAX (frame_height, upper_bound + context->y_offset);
+				if (height > 0)
+                                        (* context->update_func)
+                                                (context->frame->pixbuf,
+                                                 0, 0,
+                                                 gdk_pixbuf_get_width (context->frame->pixbuf),
+                                                 height,
+                                                 context->user_data);
+
+				y = MAX (0, lower_bound + context->y_offset);
+                                if (y < frame_height)
+                                        (* context->update_func)
+                                                (context->frame->pixbuf,
+                                                 0, y,
+                                                 gdk_pixbuf_get_width (context->frame->pixbuf),
+                                                 gdk_pixbuf_get_height (context->frame->pixbuf),
+                                                 context->user_data);
 			}
 		}
 	}
@@ -1179,13 +1251,13 @@
 	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)) {
+        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."));
+                             _("GIF image contained a frame with height or width less than 0."));
                 
 		return -2;
         }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]