Patch for io-gif.c
- From: Federico Mena Quintero <federico ximian com>
- To: gtk-devel-list gnome org
- Cc: lewing ximian com
- Subject: Patch for io-gif.c
- Date: 21 Feb 2003 18:11:13 -0600
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]