Line data Source code
1 : #include "gifdec.h"
2 :
3 : #include <stdio.h>
4 : #include <stdlib.h>
5 : #include <string.h>
6 :
7 : #include <sys/types.h>
8 : #include <sys/stat.h>
9 : #include <fcntl.h>
10 : #ifdef _WIN32
11 : #include <io.h>
12 : #else
13 : #include <unistd.h>
14 : #endif
15 :
16 : #define MIN(A, B) ((A) < (B) ? (A) : (B))
17 : #define MAX(A, B) ((A) > (B) ? (A) : (B))
18 :
19 : typedef struct Entry {
20 : uint16_t length;
21 : uint16_t prefix;
22 : uint8_t suffix;
23 : } Entry;
24 :
25 : typedef struct Table {
26 : int bulk;
27 : int nentries;
28 : Entry *entries;
29 : } Table;
30 :
31 : static uint16_t
32 2328 : read_num(int fd)
33 : {
34 : uint8_t bytes[2];
35 :
36 2328 : read(fd, bytes, 2);
37 2328 : return bytes[0] + (((uint16_t) bytes[1]) << 8);
38 : }
39 :
40 : gd_GIF *
41 596 : gd_open_gif(const char *fname)
42 : {
43 : int fd;
44 : uint8_t sigver[3];
45 : uint16_t width, height, depth;
46 : uint8_t fdsz, bgidx, aspect;
47 : int i;
48 : uint8_t *bgcolor;
49 : int gct_sz;
50 : gd_GIF *gif;
51 :
52 596 : fd = open(fname, O_RDONLY);
53 596 : if (fd == -1) return NULL;
54 : #ifdef _WIN32
55 : setmode(fd, O_BINARY);
56 : #endif
57 : /* Header */
58 596 : read(fd, sigver, 3);
59 596 : if (memcmp(sigver, "GIF", 3) != 0) {
60 0 : fprintf(stderr, "invalid signature\n");
61 0 : goto fail;
62 : }
63 : /* Version */
64 596 : read(fd, sigver, 3);
65 596 : if (memcmp(sigver, "89a", 3) != 0) {
66 0 : fprintf(stderr, "invalid version\n");
67 0 : goto fail;
68 : }
69 : /* Width x Height */
70 596 : width = read_num(fd);
71 596 : height = read_num(fd);
72 : /* FDSZ */
73 596 : read(fd, &fdsz, 1);
74 : /* Presence of GCT */
75 596 : if (!(fdsz & 0x80)) {
76 0 : fprintf(stderr, "no global color table\n");
77 0 : goto fail;
78 : }
79 : /* Color Space's Depth */
80 596 : depth = ((fdsz >> 4) & 7) + 1;
81 : /* Ignore Sort Flag. */
82 : /* GCT Size */
83 596 : gct_sz = 1 << ((fdsz & 0x07) + 1);
84 : /* Background Color Index */
85 596 : read(fd, &bgidx, 1);
86 : /* Aspect Ratio */
87 596 : read(fd, &aspect, 1);
88 : /* Create gd_GIF Structure. */
89 596 : gif = calloc(1, sizeof(*gif));
90 596 : if (!gif) goto fail;
91 596 : gif->fd = fd;
92 596 : gif->width = width;
93 596 : gif->height = height;
94 596 : gif->depth = depth;
95 : /* Read GCT */
96 596 : gif->gct.size = gct_sz;
97 596 : read(fd, gif->gct.colors, 3 * gif->gct.size);
98 596 : gif->palette = &gif->gct;
99 596 : gif->bgindex = bgidx;
100 596 : gif->frame = calloc(4, width * height);
101 596 : if (!gif->frame) {
102 146 : free(gif);
103 146 : goto fail;
104 : }
105 450 : gif->canvas = &gif->frame[width * height];
106 450 : if (gif->bgindex)
107 447 : memset(gif->frame, gif->bgindex, gif->width * gif->height);
108 450 : bgcolor = &gif->palette->colors[gif->bgindex*3];
109 450 : if (bgcolor[0] || bgcolor[1] || bgcolor [2])
110 13672060818 : for (i = 0; i < gif->width * gif->height; i++)
111 13672060818 : memcpy(&gif->canvas[i*3], bgcolor, 3);
112 450 : gif->anim_start = lseek(fd, 0, SEEK_CUR);
113 450 : goto ok;
114 : fail:
115 146 : close(fd);
116 146 : return 0;
117 : ok:
118 450 : return gif;
119 596 : }
120 :
121 : static void
122 263 : discard_sub_blocks(gd_GIF *gif)
123 : {
124 : uint8_t size;
125 :
126 263 : do {
127 2107 : read(gif->fd, &size, 1);
128 2107 : lseek(gif->fd, size, SEEK_CUR);
129 2107 : } while (size);
130 263 : }
131 :
132 : static void
133 62 : read_plain_text_ext(gd_GIF *gif)
134 : {
135 62 : if (gif->plain_text) {
136 : uint16_t tx, ty, tw, th;
137 : uint8_t cw, ch, fg, bg;
138 : off_t sub_block;
139 62 : lseek(gif->fd, 1, SEEK_CUR); /* block size = 12 */
140 62 : tx = read_num(gif->fd);
141 62 : ty = read_num(gif->fd);
142 62 : tw = read_num(gif->fd);
143 62 : th = read_num(gif->fd);
144 62 : read(gif->fd, &cw, 1);
145 62 : read(gif->fd, &ch, 1);
146 62 : read(gif->fd, &fg, 1);
147 62 : read(gif->fd, &bg, 1);
148 62 : sub_block = lseek(gif->fd, 0, SEEK_CUR);
149 62 : gif->plain_text(gif, tx, ty, tw, th, cw, ch, fg, bg);
150 62 : lseek(gif->fd, sub_block, SEEK_SET);
151 62 : } else {
152 : /* Discard plain text metadata. */
153 0 : lseek(gif->fd, 13, SEEK_CUR);
154 : }
155 : /* Discard plain text sub-blocks. */
156 62 : discard_sub_blocks(gif);
157 62 : }
158 :
159 : static void
160 53 : read_graphic_control_ext(gd_GIF *gif)
161 : {
162 : uint8_t rdit;
163 :
164 : /* Discard block size (always 0x04). */
165 53 : lseek(gif->fd, 1, SEEK_CUR);
166 53 : read(gif->fd, &rdit, 1);
167 53 : gif->gce.disposal = (rdit >> 2) & 3;
168 53 : gif->gce.input = rdit & 2;
169 53 : gif->gce.transparency = rdit & 1;
170 53 : gif->gce.delay = read_num(gif->fd);
171 53 : read(gif->fd, &gif->gce.tindex, 1);
172 : /* Skip block terminator. */
173 53 : lseek(gif->fd, 1, SEEK_CUR);
174 53 : }
175 :
176 : static void
177 6 : read_comment_ext(gd_GIF *gif)
178 : {
179 6 : if (gif->comment) {
180 6 : off_t sub_block = lseek(gif->fd, 0, SEEK_CUR);
181 6 : gif->comment(gif);
182 6 : lseek(gif->fd, sub_block, SEEK_SET);
183 6 : }
184 : /* Discard comment sub-blocks. */
185 6 : discard_sub_blocks(gif);
186 6 : }
187 :
188 : static void
189 55 : read_application_ext(gd_GIF *gif)
190 : {
191 : char app_id[8];
192 : char app_auth_code[3];
193 :
194 : /* Discard block size (always 0x0B). */
195 55 : lseek(gif->fd, 1, SEEK_CUR);
196 : /* Application Identifier. */
197 55 : read(gif->fd, app_id, 8);
198 : /* Application Authentication Code. */
199 55 : read(gif->fd, app_auth_code, 3);
200 55 : if (!strncmp(app_id, "NETSCAPE", sizeof(app_id))) {
201 : /* Discard block size (0x03) and constant byte (0x01). */
202 55 : lseek(gif->fd, 2, SEEK_CUR);
203 55 : gif->loop_count = read_num(gif->fd);
204 : /* Skip block terminator. */
205 55 : lseek(gif->fd, 1, SEEK_CUR);
206 55 : } else if (gif->application) {
207 0 : off_t sub_block = lseek(gif->fd, 0, SEEK_CUR);
208 0 : gif->application(gif, app_id, app_auth_code);
209 0 : lseek(gif->fd, sub_block, SEEK_SET);
210 0 : discard_sub_blocks(gif);
211 0 : } else {
212 0 : discard_sub_blocks(gif);
213 : }
214 55 : }
215 :
216 : static void
217 176 : read_ext(gd_GIF *gif)
218 : {
219 : uint8_t label;
220 :
221 176 : read(gif->fd, &label, 1);
222 176 : switch (label) {
223 : case 0x01:
224 62 : read_plain_text_ext(gif);
225 62 : break;
226 : case 0xF9:
227 53 : read_graphic_control_ext(gif);
228 53 : break;
229 : case 0xFE:
230 6 : read_comment_ext(gif);
231 6 : break;
232 : case 0xFF:
233 55 : read_application_ext(gif);
234 55 : break;
235 : default:
236 0 : fprintf(stderr, "unknown extension: %02X\n", label);
237 0 : }
238 176 : }
239 :
240 : static Table *
241 195 : new_table(int key_size)
242 : {
243 : int key;
244 195 : int init_bulk = MAX(1 << (key_size + 1), 0x100);
245 195 : Table *table = malloc(sizeof(*table) + sizeof(Entry) * init_bulk);
246 195 : if (table) {
247 195 : table->bulk = init_bulk;
248 195 : table->nentries = (1 << key_size) + 2;
249 195 : table->entries = (Entry *) &table[1];
250 14119 : for (key = 0; key < (1 << key_size); key++)
251 13924 : table->entries[key] = (Entry) {1, 0xFFF, key};
252 195 : }
253 195 : return table;
254 : }
255 :
256 : /* Add table entry. Return value:
257 : * 0 on success
258 : * +1 if key size must be incremented after this addition
259 : * -1 if could not realloc table */
260 : static int
261 18042 : add_entry(Table **tablep, uint16_t length, uint16_t prefix, uint8_t suffix)
262 : {
263 18042 : Table *table = *tablep;
264 18042 : if (table->nentries == table->bulk) {
265 25 : table->bulk *= 2;
266 25 : table = realloc(table, sizeof(*table) + sizeof(Entry) * table->bulk);
267 25 : if (!table) return -1;
268 25 : table->entries = (Entry *) &table[1];
269 25 : *tablep = table;
270 25 : }
271 18042 : table->entries[table->nentries] = (Entry) {length, prefix, suffix};
272 18042 : table->nentries++;
273 18042 : if ((table->nentries & (table->nentries - 1)) == 0)
274 166 : return 1;
275 17876 : return 0;
276 18042 : }
277 :
278 : static uint16_t
279 24385 : get_key(gd_GIF *gif, int key_size, uint8_t *sub_len, uint8_t *shift, uint8_t *byte)
280 : {
281 : int bits_read;
282 : int rpad;
283 : int frag_size;
284 : uint16_t key;
285 :
286 24385 : key = 0;
287 67797 : for (bits_read = 0; bits_read < key_size; bits_read += frag_size) {
288 43436 : rpad = (*shift + bits_read) % 8;
289 43436 : if (rpad == 0) {
290 : /* Update byte. */
291 24978 : if (*sub_len == 0) {
292 371 : read(gif->fd, sub_len, 1); /* Must be nonzero! */
293 371 : if (*sub_len == 0)
294 24 : return 0x1000;
295 347 : }
296 24954 : read(gif->fd, byte, 1);
297 24954 : (*sub_len)--;
298 24954 : }
299 43412 : frag_size = MIN(key_size - bits_read, 8 - rpad);
300 43412 : key |= ((uint16_t) ((*byte) >> rpad)) << bits_read;
301 43412 : }
302 : /* Clear extra bits to the left. */
303 24361 : key &= (1 << key_size) - 1;
304 24361 : *shift = (*shift + key_size) % 8;
305 24361 : return key;
306 24385 : }
307 :
308 : /* Compute output index of y-th input line, in frame of height h. */
309 : static int
310 93758 : interlaced_line_index(int h, int y)
311 : {
312 : int p; /* number of lines in current pass */
313 :
314 93758 : p = (h - 1) / 8 + 1;
315 93758 : if (y < p) /* pass 1 */
316 93735 : return y * 8;
317 23 : y -= p;
318 23 : p = (h - 5) / 8 + 1;
319 23 : if (y < p) /* pass 2 */
320 22 : return y * 8 + 4;
321 1 : y -= p;
322 1 : p = (h - 3) / 4 + 1;
323 1 : if (y < p) /* pass 3 */
324 0 : return y * 4 + 2;
325 1 : y -= p;
326 : /* pass 4 */
327 1 : return y * 2 + 1;
328 93758 : }
329 :
330 : /* Decompress image pixels.
331 : * Return 0 on success or -1 on out-of-memory (w.r.t. LZW code table). */
332 : static int
333 195 : read_image_data(gd_GIF *gif, int interlace)
334 : {
335 : uint8_t sub_len, shift, byte;
336 : int init_key_size, key_size, table_is_full;
337 : int frm_off, frm_size, str_len, i, p, x, y;
338 : uint16_t key, clear, stop;
339 : int ret;
340 : Table *table;
341 : Entry entry;
342 : off_t start, end;
343 :
344 195 : read(gif->fd, &byte, 1);
345 195 : key_size = (int) byte;
346 195 : if (key_size < 2 || key_size > 8)
347 0 : return -1;
348 :
349 195 : start = lseek(gif->fd, 0, SEEK_CUR);
350 195 : discard_sub_blocks(gif);
351 195 : end = lseek(gif->fd, 0, SEEK_CUR);
352 195 : lseek(gif->fd, start, SEEK_SET);
353 195 : clear = 1 << key_size;
354 195 : stop = clear + 1;
355 195 : table = new_table(key_size);
356 195 : key_size++;
357 195 : init_key_size = key_size;
358 195 : sub_len = shift = 0;
359 195 : key = get_key(gif, key_size, &sub_len, &shift, &byte); /* clear code */
360 195 : frm_off = 0;
361 195 : ret = 0;
362 195 : frm_size = gif->fw*gif->fh;
363 24191 : while (frm_off < frm_size) {
364 24190 : if (key == clear) {
365 148 : key_size = init_key_size;
366 148 : table->nentries = (1 << (key_size - 1)) + 2;
367 148 : table_is_full = 0;
368 24190 : } else if (!table_is_full) {
369 18042 : ret = add_entry(&table, str_len + 1, key, entry.suffix);
370 18042 : if (ret == -1) {
371 0 : free(table);
372 0 : return -1;
373 : }
374 18042 : if (table->nentries == 0x1000) {
375 0 : ret = 0;
376 0 : table_is_full = 1;
377 0 : }
378 18042 : }
379 24190 : key = get_key(gif, key_size, &sub_len, &shift, &byte);
380 24190 : if (key == clear) continue;
381 24049 : if (key == stop || key == 0x1000) break;
382 23855 : if (ret == 1) key_size++;
383 23855 : entry = table->entries[key];
384 23855 : str_len = entry.length;
385 1257283 : for (i = 0; i < str_len; i++) {
386 1246639 : p = frm_off + entry.length - 1;
387 1246639 : x = p % gif->fw;
388 1246639 : y = p / gif->fw;
389 1246639 : if (interlace)
390 93758 : y = interlaced_line_index((int) gif->fh, y);
391 1246639 : gif->frame[(gif->fy + y) * gif->width + gif->fx + x] = entry.suffix;
392 1246639 : if (entry.prefix == 0xFFF)
393 13211 : break;
394 : else
395 1233428 : entry = table->entries[entry.prefix];
396 1233428 : }
397 23855 : frm_off += str_len;
398 23855 : if (key < table->nentries - 1 && !table_is_full)
399 12078 : table->entries[table->nentries - 1].suffix = entry.suffix;
400 : }
401 195 : free(table);
402 195 : if (key == stop)
403 170 : read(gif->fd, &sub_len, 1); /* Must be zero! */
404 195 : lseek(gif->fd, end, SEEK_SET);
405 195 : return 0;
406 195 : }
407 :
408 : /* Read image.
409 : * Return 0 on success or -1 on out-of-memory (w.r.t. LZW code table). */
410 : static int
411 195 : read_image(gd_GIF *gif)
412 : {
413 : uint8_t fisrz;
414 : int interlace;
415 :
416 : /* Image Descriptor. */
417 195 : gif->fx = read_num(gif->fd);
418 195 : gif->fy = read_num(gif->fd);
419 :
420 195 : if (gif->fx >= gif->width || gif->fy >= gif->height)
421 0 : return -1;
422 :
423 195 : gif->fw = read_num(gif->fd);
424 195 : gif->fh = read_num(gif->fd);
425 :
426 195 : gif->fw = MIN(gif->fw, gif->width - gif->fx);
427 195 : gif->fh = MIN(gif->fh, gif->height - gif->fy);
428 :
429 195 : read(gif->fd, &fisrz, 1);
430 195 : interlace = fisrz & 0x40;
431 : /* Ignore Sort Flag. */
432 : /* Local Color Table? */
433 195 : if (fisrz & 0x80) {
434 : /* Read LCT */
435 92 : gif->lct.size = 1 << ((fisrz & 0x07) + 1);
436 92 : read(gif->fd, gif->lct.colors, 3 * gif->lct.size);
437 92 : gif->palette = &gif->lct;
438 92 : } else
439 103 : gif->palette = &gif->gct;
440 : /* Image Data. */
441 195 : return read_image_data(gif, interlace);
442 195 : }
443 :
444 : static void
445 947 : render_frame_rect(gd_GIF *gif, uint8_t *buffer)
446 : {
447 : int i, j, k;
448 : uint8_t index, *color;
449 947 : i = gif->fy * gif->width + gif->fx;
450 2824515 : for (j = 0; j < gif->fh; j++) {
451 8378851194 : for (k = 0; k < gif->fw; k++) {
452 8376027626 : index = gif->frame[(gif->fy + j) * gif->width + gif->fx + k];
453 8376027626 : color = &gif->palette->colors[index*3];
454 8376027626 : if (!gif->gce.transparency || index != gif->gce.tindex)
455 8376027623 : memcpy(&buffer[(i+k)*3], color, 3);
456 8376027626 : }
457 2823568 : i += gif->width;
458 2823568 : }
459 947 : }
460 :
461 : static void
462 485 : dispose(gd_GIF *gif)
463 : {
464 : int i, j, k;
465 : uint8_t *bgcolor;
466 485 : switch (gif->gce.disposal) {
467 : case 2: /* Restore to background color. */
468 10 : bgcolor = &gif->palette->colors[gif->bgindex*3];
469 10 : i = gif->fy * gif->width + gif->fx;
470 30028 : for (j = 0; j < gif->fh; j++) {
471 93917196 : for (k = 0; k < gif->fw; k++)
472 93887178 : memcpy(&gif->canvas[(i+k)*3], bgcolor, 3);
473 30018 : i += gif->width;
474 30018 : }
475 10 : break;
476 : case 3: /* Restore to previous, i.e., don't update canvas.*/
477 10 : break;
478 : default:
479 : /* Add frame non-transparent pixels to canvas. */
480 465 : render_frame_rect(gif, gif->canvas);
481 465 : }
482 485 : }
483 :
484 : /* Return 1 if got a frame; 0 if got GIF trailer; -1 if error. */
485 : int
486 485 : gd_get_frame(gd_GIF *gif)
487 : {
488 : char sep;
489 :
490 485 : dispose(gif);
491 485 : read(gif->fd, &sep, 1);
492 661 : while (sep != ',') {
493 466 : if (sep == ';')
494 287 : return 0;
495 179 : if (sep == '!')
496 176 : read_ext(gif);
497 3 : else return -1;
498 176 : read(gif->fd, &sep, 1);
499 : }
500 195 : if (read_image(gif) == -1)
501 0 : return -1;
502 195 : return 1;
503 485 : }
504 :
505 : void
506 482 : gd_render_frame(gd_GIF *gif, uint8_t *buffer)
507 : {
508 482 : memcpy(buffer, gif->canvas, gif->width * gif->height * 3);
509 482 : render_frame_rect(gif, buffer);
510 482 : }
511 :
512 : int
513 >10232*10^7 : gd_is_bgcolor(gd_GIF *gif, uint8_t color[3])
514 : {
515 >10232*10^7 : return !memcmp(&gif->palette->colors[gif->bgindex*3], color, 3);
516 : }
517 :
518 : void
519 287 : gd_rewind(gd_GIF *gif)
520 : {
521 287 : lseek(gif->fd, gif->anim_start, SEEK_SET);
522 287 : }
523 :
524 : void
525 290 : gd_close_gif(gd_GIF *gif)
526 : {
527 290 : close(gif->fd);
528 290 : free(gif->frame);
529 290 : free(gif);
530 290 : }
|