| @@ -18,7 +18,11 @@ |
| 18 | 18 | | |
| 19 | 19 | | #define _IMAGE_CONFIG |
| 20 | 20 | | |
| 21 | + | #include <stdlib.h> |
| 22 | + | #include <string.h> |
| 21 | 23 | | #include <unistd.h> |
| 24 | + | #include <sys/types.h> |
| 25 | + | #include <gif_lib.h> |
| 22 | 26 | | |
| 23 | 27 | | #include "image.h" |
| 24 | 28 | | #include "options.h" |
| @@ -36,6 +40,7 @@ void img_init(img_t *img, win_t *win) { |
| 36 | 40 | | |
| 37 | 41 | | if (img) { |
| 38 | 42 | | img->im = NULL; |
| 43 | + | img->multi.cap = img->multi.cnt = 0; |
| 39 | 44 | | img->zoom = options->zoom; |
| 40 | 45 | | img->zoom = MAX(img->zoom, zoom_min); |
| 41 | 46 | | img->zoom = MIN(img->zoom, zoom_max); |
| @@ -50,7 +55,153 @@ void img_init(img_t *img, win_t *win) { |
| 50 | 55 | | } |
| 51 | 56 | | } |
| 52 | 57 | | |
| 58 | + | int img_load_gif(img_t *img, const fileinfo_t *file) { |
| 59 | + | DATA32 *data, *ptr; |
| 60 | + | DATA32 *prev_frame = NULL; |
| 61 | + | Imlib_Image *im; |
| 62 | + | GifFileType *gif; |
| 63 | + | GifRowType *rows = NULL; |
| 64 | + | GifRecordType rec; |
| 65 | + | ColorMapObject *cmap; |
| 66 | + | int i, j; |
| 67 | + | int bg, r, g, b; |
| 68 | + | int w = 0, h = 0; |
| 69 | + | int intoffset[] = { 0, 4, 2, 1 }; |
| 70 | + | int intjump[] = { 8, 8, 4, 2 }; |
| 71 | + | int transp = -1; |
| 72 | + | int err = 0; |
| 73 | + | |
| 74 | + | if (img->multi.cap == 0) { |
| 75 | + | img->multi.cap = 8; |
| 76 | + | img->multi.frames = (Imlib_Image**) |
| 77 | + | s_malloc(sizeof(Imlib_Image*) * img->multi.cap); |
| 78 | + | } |
| 79 | + | img->multi.cnt = 0; |
| 80 | + | img->multi.cur = 0; |
| 81 | + | |
| 82 | + | gif = DGifOpenFileName(file->path); |
| 83 | + | if (!gif) { |
| 84 | + | warn("could not open gif file: %s", file->name); |
| 85 | + | return 0; |
| 86 | + | } |
| 87 | + | |
| 88 | + | do { |
| 89 | + | if (DGifGetRecordType(gif, &rec) == GIF_ERROR) { |
| 90 | + | warn("could not open gif file: %s", file->name); |
| 91 | + | err = 1; |
| 92 | + | break; |
| 93 | + | } |
| 94 | + | if (rec == EXTENSION_RECORD_TYPE) { |
| 95 | + | int ext_code; |
| 96 | + | GifByteType *ext = NULL; |
| 97 | + | |
| 98 | + | DGifGetExtension(gif, &ext_code, &ext); |
| 99 | + | while (ext) { |
| 100 | + | if ((ext_code == 0xf9) && (ext[1] & 1) && (transp < 0)) |
| 101 | + | transp = (int) ext[4]; |
| 102 | + | ext = NULL; |
| 103 | + | DGifGetExtensionNext(gif, &ext); |
| 104 | + | } |
| 105 | + | } else if (rec == IMAGE_DESC_RECORD_TYPE) { |
| 106 | + | if (DGifGetImageDesc(gif) == GIF_ERROR) { |
| 107 | + | warn("could not open gif frame # %d: %s", img->multi.cnt, file->name); |
| 108 | + | err = 1; |
| 109 | + | break; |
| 110 | + | } |
| 111 | + | w = gif->Image.Width; |
| 112 | + | h = gif->Image.Height; |
| 113 | + | rows = (GifRowType*) s_malloc(h * sizeof(GifRowType)); |
| 114 | + | for (i = 0; i < h; i++) |
| 115 | + | rows[i] = (GifRowType) s_malloc(w * sizeof(GifPixelType)); |
| 116 | + | if (gif->Image.Interlace) { |
| 117 | + | for (i = 0; i < 4; i++) { |
| 118 | + | for (j = intoffset[i]; j < h; j += intjump[i]) |
| 119 | + | DGifGetLine(gif, rows[j], w); |
| 120 | + | } |
| 121 | + | } else { |
| 122 | + | for (i = 0; i < h; i++) |
| 123 | + | DGifGetLine(gif, rows[i], w); |
| 124 | + | } |
| 125 | + | |
| 126 | + | bg = gif->SBackGroundColor; |
| 127 | + | cmap = gif->Image.ColorMap ? gif->Image.ColorMap : gif->SColorMap; |
| 128 | + | ptr = data = (DATA32*) s_malloc(sizeof(DATA32) * w * h); |
| 129 | + | |
| 130 | + | if (img->multi.cnt) { |
| 131 | + | imlib_context_set_image(img->multi.frames[img->multi.cnt - 1]); |
| 132 | + | prev_frame = imlib_image_get_data_for_reading_only(); |
| 133 | + | } |
| 134 | + | |
| 135 | + | for (i = 0; i < h; i++) { |
| 136 | + | for (j = 0; j < w; j++) { |
| 137 | + | if (rows[i][j] == transp) { |
| 138 | + | if (prev_frame) { |
| 139 | + | *ptr++ = prev_frame[i * w + j]; |
| 140 | + | } else { |
| 141 | + | r = cmap->Colors[bg].Red; |
| 142 | + | g = cmap->Colors[bg].Green; |
| 143 | + | b = cmap->Colors[bg].Blue; |
| 144 | + | *ptr++ = 0x00ffffff & ((r << 16) | (g << 8) | b); |
| 145 | + | } |
| 146 | + | } else { |
| 147 | + | r = cmap->Colors[rows[i][j]].Red; |
| 148 | + | g = cmap->Colors[rows[i][j]].Green; |
| 149 | + | b = cmap->Colors[rows[i][j]].Blue; |
| 150 | + | *ptr++ = (0xff << 24) | (r << 16) | (g << 8) | b; |
| 151 | + | } |
| 152 | + | } |
| 153 | + | } |
| 154 | + | |
| 155 | + | im = imlib_create_image_using_copied_data(w, h, data); |
| 156 | + | |
| 157 | + | for (i = 0; i < h; i++) |
| 158 | + | free(rows[i]); |
| 159 | + | free(rows); |
| 160 | + | free(data); |
| 161 | + | |
| 162 | + | if (!im) { |
| 163 | + | warn("could not open gif frame # %d: %s", img->multi.cnt, file->name); |
| 164 | + | err = 1; |
| 165 | + | break; |
| 166 | + | } |
| 167 | + | |
| 168 | + | imlib_context_set_image(im); |
| 169 | + | imlib_image_set_format("gif"); |
| 170 | + | if (transp >= 0) |
| 171 | + | imlib_image_set_has_alpha(1); |
| 172 | + | |
| 173 | + | if (img->multi.cnt == img->multi.cap) { |
| 174 | + | img->multi.cap *= 2; |
| 175 | + | img->multi.frames = (Imlib_Image**) |
| 176 | + | s_realloc(img->multi.frames, |
| 177 | + | img->multi.cap * sizeof(Imlib_Image*)); |
| 178 | + | } |
| 179 | + | img->multi.frames[img->multi.cnt++] = im; |
| 180 | + | } |
| 181 | + | } while (rec != TERMINATE_RECORD_TYPE); |
| 182 | + | |
| 183 | + | DGifCloseFile(gif); |
| 184 | + | |
| 185 | + | if (!err && img->multi.cnt > 1) { |
| 186 | + | imlib_context_set_image(img->im); |
| 187 | + | imlib_free_image(); |
| 188 | + | img->im = img->multi.frames[0]; |
| 189 | + | } else { |
| 190 | + | for (i = 0; i < img->multi.cnt; i++) { |
| 191 | + | imlib_context_set_image(img->multi.frames[i]); |
| 192 | + | imlib_free_image(); |
| 193 | + | } |
| 194 | + | img->multi.cnt = 0; |
| 195 | + | } |
| 196 | + | |
| 197 | + | imlib_context_set_image(img->im); |
| 198 | + | |
| 199 | + | return !err; |
| 200 | + | } |
| 201 | + | |
| 53 | 202 | | int img_load(img_t *img, const fileinfo_t *file) { |
| 203 | + | char *fmt; |
| 204 | + | |
| 54 | 205 | | if (!img || !file || !file->name || !file->path) |
| 55 | 206 | | return 0; |
| 56 | 207 | | |
| @@ -63,6 +214,10 @@ int img_load(img_t *img, const fileinfo_t *file) { |
| 63 | 214 | | imlib_image_set_changes_on_disk(); |
| 64 | 215 | | imlib_context_set_anti_alias(img->aa); |
| 65 | 216 | | |
| 217 | + | fmt = imlib_image_format(); |
| 218 | + | if (!strcmp(fmt, "gif")) |
| 219 | + | img_load_gif(img, file); |
| 220 | + | |
| 66 | 221 | | img->scalemode = options->scalemode; |
| 67 | 222 | | img->re = 0; |
| 68 | 223 | | img->checkpan = 0; |
| @@ -191,6 +346,27 @@ void img_render(img_t *img, win_t *win) { |
| 191 | 346 | | win_draw(win); |
| 192 | 347 | | } |
| 193 | 348 | | |
| 349 | + | int img_change_frame(img_t *img, int d) { |
| 350 | + | if (!img || !img->multi.cnt || !d) |
| 351 | + | return 0; |
| 352 | + | |
| 353 | + | d += img->multi.cur; |
| 354 | + | if (d < 0) |
| 355 | + | d = 0; |
| 356 | + | else if (d >= img->multi.cnt) |
| 357 | + | d = img->multi.cnt - 1; |
| 358 | + | |
| 359 | + | img->multi.cur = d; |
| 360 | + | img->im = img->multi.frames[d]; |
| 361 | + | |
| 362 | + | imlib_context_set_image(img->im); |
| 363 | + | img->w = imlib_image_get_width(); |
| 364 | + | img->h = imlib_image_get_height(); |
| 365 | + | img->checkpan = 1; |
| 366 | + | |
| 367 | + | return 1; |
| 368 | + | } |
| 369 | + | |
| 194 | 370 | | int img_fit_win(img_t *img, win_t *win) { |
| 195 | 371 | | if (!img || !img->im || !win) |
| 196 | 372 | | return 0; |