From 79bd86defb5c86a50e2def4c03129c4215c07ca5 Mon Sep 17 00:00:00 2001
From: Bert <ber.t@gmx.com>
Date: Wed, 17 Aug 2011 18:01:21 +0200
Subject: [PATCH] Refactored img_load_gif()

- Corrected handling of transparency settings for individual frames
- Corrected handling of different frame dimensions & offsets
---
 image.c | 98 +++++++++++++++++++++++++++++++++++----------------------
 image.h |  2 +-
 main.c  |  2 +-
 3 files changed, 62 insertions(+), 40 deletions(-)

diff --git a/image.c b/image.c
index ef78542..dfc7f14 100644
--- a/image.c
+++ b/image.c
@@ -56,20 +56,18 @@ void img_init(img_t *img, win_t *win) {
 }
 
 int img_load_gif(img_t *img, const fileinfo_t *file) {
-	DATA32 *data, *ptr;
-	DATA32 *prev_frame = NULL;
-	Imlib_Image *im;
 	GifFileType *gif;
 	GifRowType *rows = NULL;
 	GifRecordType rec;
 	ColorMapObject *cmap;
-	int i, j;
-	int bg, r, g, b;
-	int w = 0, h = 0;
+	DATA32 bgpixel, *data, *ptr;
+	DATA32 *prev_frame = NULL;
+	Imlib_Image *im;
+	int i, j, bg, r, g, b;
+	int x, y, w, h, sw, sh;
 	int intoffset[] = { 0, 4, 2, 1 };
 	int intjump[] = { 8, 8, 4, 2 };
-	int transp = -1;
-	int err = 0;
+	int err = 0, transp = -1;
 
 	if (img->multi.cap == 0) {
 		img->multi.cap = 8;
@@ -77,13 +75,16 @@ int img_load_gif(img_t *img, const fileinfo_t *file) {
 		                    s_malloc(sizeof(Imlib_Image*) * img->multi.cap);
 	}
 	img->multi.cnt = 0;
-	img->multi.cur = 0;
+	img->multi.sel = 0;
 
 	gif = DGifOpenFileName(file->path);
 	if (!gif) {
 		warn("could not open gif file: %s", file->name);
 		return 0;
 	}
+	bg = gif->SBackGroundColor;
+	sw = gif->SWidth;
+	sh = gif->SHeight;
 
 	do {
 		if (DGifGetRecordType(gif, &rec) == GIF_ERROR) {
@@ -97,8 +98,12 @@ int img_load_gif(img_t *img, const fileinfo_t *file) {
 
 			DGifGetExtension(gif, &ext_code, &ext);
 			while (ext) {
-				if ((ext_code == 0xf9) && (ext[1] & 1) && (transp < 0))
-					transp = (int) ext[4];
+				if (ext_code == 0xf9) {
+					if (ext[1] & 1)
+						transp = (int) ext[4];
+					else
+						transp = -1;
+				}
 				ext = NULL;
 				DGifGetExtensionNext(gif, &ext);
 			}
@@ -108,8 +113,11 @@ int img_load_gif(img_t *img, const fileinfo_t *file) {
 				err = 1;
 				break;
 			}
+			x = gif->Image.Left;
+			y = gif->Image.Top;
 			w = gif->Image.Width;
 			h = gif->Image.Height;
+
 			rows = (GifRowType*) s_malloc(h * sizeof(GifRowType));
 			for (i = 0; i < h; i++)
 				rows[i] = (GifRowType) s_malloc(w * sizeof(GifPixelType));
@@ -123,36 +131,36 @@ int img_load_gif(img_t *img, const fileinfo_t *file) {
 					DGifGetLine(gif, rows[i], w);
 			}
 
-			bg = gif->SBackGroundColor;
+			ptr = data = (DATA32*) s_malloc(sizeof(DATA32) * sw * sh);
 			cmap = gif->Image.ColorMap ? gif->Image.ColorMap : gif->SColorMap;
-			ptr = data = (DATA32*) s_malloc(sizeof(DATA32) * w * h);
+			r = cmap->Colors[bg].Red;
+			g = cmap->Colors[bg].Green;
+			b = cmap->Colors[bg].Blue;
+			bgpixel = 0x00ffffff & (r << 16 | g << 8 | b);
 
-			if (img->multi.cnt) {
-				imlib_context_set_image(img->multi.frames[img->multi.cnt - 1]);
-				prev_frame = imlib_image_get_data_for_reading_only();
-			}
-
-			for (i = 0; i < h; i++) {
-				for (j = 0; j < w; j++) {
-					if (rows[i][j] == transp) {
-						if (prev_frame) {
-							*ptr++ = prev_frame[i * w + j];
-						} else {
-							r = cmap->Colors[bg].Red;
-							g = cmap->Colors[bg].Green;
-							b = cmap->Colors[bg].Blue;
-							*ptr++ = 0x00ffffff & ((r << 16) | (g << 8) | b);
-						}
+			for (i = 0; i < sh; i++) {
+				for (j = 0; j < sw; j++) {
+					if (i < y || i >= y + h || j < x || j >= x + w) {
+						if (transp >= 0 && prev_frame)
+							*ptr = prev_frame[i * sw + j];
+						else
+							*ptr = bgpixel;
+					} else if (rows[i-y][j-x] == transp) {
+						if (prev_frame)
+							*ptr = prev_frame[i * sw + j];
+						else
+							*ptr = bgpixel;
 					} else {
-						r = cmap->Colors[rows[i][j]].Red;
-						g = cmap->Colors[rows[i][j]].Green;
-						b = cmap->Colors[rows[i][j]].Blue;
-						*ptr++ = (0xff << 24) | (r << 16) | (g << 8) | b;
+						r = cmap->Colors[rows[i-y][j-x]].Red;
+						g = cmap->Colors[rows[i-y][j-x]].Green;
+						b = cmap->Colors[rows[i-y][j-x]].Blue;
+						*ptr = 0xff << 24 | r << 16 | g << 8 | b;
 					}
+					ptr++;
 				}
 			}
 
-			im = imlib_create_image_using_copied_data(w, h, data);
+			im = imlib_create_image_using_copied_data(sw, sh, data);
 
 			for (i = 0; i < h; i++)
 				free(rows[i]);
@@ -166,6 +174,8 @@ int img_load_gif(img_t *img, const fileinfo_t *file) {
 			}
 
 			imlib_context_set_image(im);
+			prev_frame = imlib_image_get_data_for_reading_only();
+
 			imlib_image_set_format("gif");
 			if (transp >= 0)
 				imlib_image_set_has_alpha(1);
@@ -200,7 +210,7 @@ int img_load_gif(img_t *img, const fileinfo_t *file) {
 }
 
 int img_load(img_t *img, const fileinfo_t *file) {
-	char *fmt;
+	const char *fmt;
 
 	if (!img || !file || !file->name || !file->path)
 		return 0;
@@ -229,7 +239,19 @@ int img_load(img_t *img, const fileinfo_t *file) {
 }
 
 void img_close(img_t *img, int decache) {
-	if (img && img->im) {
+	int i;
+
+	if (!img)
+		return;
+
+	if (img->multi.cnt) {
+		for (i = 0; i < img->multi.cnt; i++) {
+			imlib_context_set_image(img->multi.frames[i]);
+			imlib_free_image();
+		}
+		img->multi.cnt = 0;
+		img->im = NULL;
+	} else if (img->im) {
 		imlib_context_set_image(img->im);
 		if (decache)
 			imlib_free_image_and_decache();
@@ -350,13 +372,13 @@ int img_change_frame(img_t *img, int d) {
 	if (!img || !img->multi.cnt || !d)
 		return 0;
 
-	d += img->multi.cur;
+	d += img->multi.sel;
 	if (d < 0)
 		d = 0;
 	else if (d >= img->multi.cnt)
 		d = img->multi.cnt - 1;
 
-	img->multi.cur = d;
+	img->multi.sel = d;
 	img->im = img->multi.frames[d];
 
 	imlib_context_set_image(img->im);
diff --git a/image.h b/image.h
index 37db7c8..408992e 100644
--- a/image.h
+++ b/image.h
@@ -27,7 +27,7 @@
 typedef struct {
 	int cap;
 	int cnt;
-	int cur;
+	int sel;
 	Imlib_Image **frames;
 } multi_img_t;
 
diff --git a/main.c b/main.c
index eb00c67..27788db 100644
--- a/main.c
+++ b/main.c
@@ -158,7 +158,7 @@ void update_title() {
 			n = snprintf(win_title, TITLE_LEN,
 			             "sxiv: [%d/%d] <%d%%> <%dx%d> (%.2f%s) {%d/%d} %s",
 			             fileidx + 1, filecnt, (int) (img.zoom * 100.0), img.w,
-			             img.h, size, unit, img.multi.cur + 1, img.multi.cnt,
+			             img.h, size, unit, img.multi.sel + 1, img.multi.cnt,
 			             files[fileidx].name);
 		else
 			n = snprintf(win_title, TITLE_LEN,