16 #define MIN(A, B) ((A) < (B) ? (A) : (B))
17 #define MAX(A, B) ((A) > (B) ? (A) : (B))
19 typedef struct Entry
{
25 typedef struct Table
{
37 return bytes
[0] + (((uint16_t) bytes
[1]) << 8);
41 gd_open_gif(const char *fname
)
45 uint16_t width
, height
, depth
;
46 uint8_t fdsz
, bgidx
, aspect
;
52 fd
= open(fname
, O_RDONLY
);
53 if (fd
== -1) return NULL
;
55 setmode(fd
, O_BINARY
);
59 if (memcmp(sigver
, "GIF", 3) != 0) {
60 fprintf(stderr
, "invalid signature\n");
65 if (memcmp(sigver
, "89a", 3) != 0) {
66 fprintf(stderr
, "invalid version\n");
71 height
= read_num(fd
);
76 fprintf(stderr
, "no global color table\n");
79 /* Color Space's Depth */
80 depth
= ((fdsz
>> 4) & 7) + 1;
81 /* Ignore Sort Flag. */
83 gct_sz
= 1 << ((fdsz
& 0x07) + 1);
84 /* Background Color Index */
88 /* Create gd_GIF Structure. */
89 gif
= calloc(1, sizeof(*gif
));
96 gif
->gct
.size
= gct_sz
;
97 read(fd
, gif
->gct
.colors
, 3 * gif
->gct
.size
);
98 gif
->palette
= &gif
->gct
;
100 gif
->frame
= calloc(4, width
* height
);
105 gif
->canvas
= &gif
->frame
[width
* height
];
107 memset(gif
->frame
, gif
->bgindex
, gif
->width
* gif
->height
);
108 bgcolor
= &gif
->palette
->colors
[gif
->bgindex
*3];
109 if (bgcolor
[0] || bgcolor
[1] || bgcolor
[2])
110 for (i
= 0; i
< gif
->width
* gif
->height
; i
++)
111 memcpy(&gif
->canvas
[i
*3], bgcolor
, 3);
112 gif
->anim_start
= lseek(fd
, 0, SEEK_CUR
);
122 discard_sub_blocks(gd_GIF
*gif
)
127 read(gif
->fd
, &size
, 1);
128 lseek(gif
->fd
, size
, SEEK_CUR
);
133 read_plain_text_ext(gd_GIF
*gif
)
135 if (gif
->plain_text
) {
136 uint16_t tx
, ty
, tw
, th
;
137 uint8_t cw
, ch
, fg
, bg
;
139 lseek(gif
->fd
, 1, SEEK_CUR
); /* block size = 12 */
140 tx
= read_num(gif
->fd
);
141 ty
= read_num(gif
->fd
);
142 tw
= read_num(gif
->fd
);
143 th
= read_num(gif
->fd
);
144 read(gif
->fd
, &cw
, 1);
145 read(gif
->fd
, &ch
, 1);
146 read(gif
->fd
, &fg
, 1);
147 read(gif
->fd
, &bg
, 1);
148 sub_block
= lseek(gif
->fd
, 0, SEEK_CUR
);
149 gif
->plain_text(gif
, tx
, ty
, tw
, th
, cw
, ch
, fg
, bg
);
150 lseek(gif
->fd
, sub_block
, SEEK_SET
);
152 /* Discard plain text metadata. */
153 lseek(gif
->fd
, 13, SEEK_CUR
);
155 /* Discard plain text sub-blocks. */
156 discard_sub_blocks(gif
);
160 read_graphic_control_ext(gd_GIF
*gif
)
164 /* Discard block size (always 0x04). */
165 lseek(gif
->fd
, 1, SEEK_CUR
);
166 read(gif
->fd
, &rdit
, 1);
167 gif
->gce
.disposal
= (rdit
>> 2) & 3;
168 gif
->gce
.input
= rdit
& 2;
169 gif
->gce
.transparency
= rdit
& 1;
170 gif
->gce
.delay
= read_num(gif
->fd
);
171 read(gif
->fd
, &gif
->gce
.tindex
, 1);
172 /* Skip block terminator. */
173 lseek(gif
->fd
, 1, SEEK_CUR
);
177 read_comment_ext(gd_GIF
*gif
)
180 off_t sub_block
= lseek(gif
->fd
, 0, SEEK_CUR
);
182 lseek(gif
->fd
, sub_block
, SEEK_SET
);
184 /* Discard comment sub-blocks. */
185 discard_sub_blocks(gif
);
189 read_application_ext(gd_GIF
*gif
)
192 char app_auth_code
[3];
194 /* Discard block size (always 0x0B). */
195 lseek(gif
->fd
, 1, SEEK_CUR
);
196 /* Application Identifier. */
197 read(gif
->fd
, app_id
, 8);
198 /* Application Authentication Code. */
199 read(gif
->fd
, app_auth_code
, 3);
200 if (!strncmp(app_id
, "NETSCAPE", sizeof(app_id
))) {
201 /* Discard block size (0x03) and constant byte (0x01). */
202 lseek(gif
->fd
, 2, SEEK_CUR
);
203 gif
->loop_count
= read_num(gif
->fd
);
204 /* Skip block terminator. */
205 lseek(gif
->fd
, 1, SEEK_CUR
);
206 } else if (gif
->application
) {
207 off_t sub_block
= lseek(gif
->fd
, 0, SEEK_CUR
);
208 gif
->application(gif
, app_id
, app_auth_code
);
209 lseek(gif
->fd
, sub_block
, SEEK_SET
);
210 discard_sub_blocks(gif
);
212 discard_sub_blocks(gif
);
217 read_ext(gd_GIF
*gif
)
221 read(gif
->fd
, &label
, 1);
224 read_plain_text_ext(gif
);
227 read_graphic_control_ext(gif
);
230 read_comment_ext(gif
);
233 read_application_ext(gif
);
236 fprintf(stderr
, "unknown extension: %02X\n", label
);
241 new_table(int key_size
)
244 int init_bulk
= MAX(1 << (key_size
+ 1), 0x100);
245 Table
*table
= malloc(sizeof(*table
) + sizeof(Entry
) * init_bulk
);
247 table
->bulk
= init_bulk
;
248 table
->nentries
= (1 << key_size
) + 2;
249 table
->entries
= (Entry
*) &table
[1];
250 for (key
= 0; key
< (1 << key_size
); key
++)
251 table
->entries
[key
] = (Entry
) {1, 0xFFF, key
};
256 /* Add table entry. Return value:
258 * +1 if key size must be incremented after this addition
259 * -1 if could not realloc table */
261 add_entry(Table
**tablep
, uint16_t length
, uint16_t prefix
, uint8_t suffix
)
263 Table
*table
= *tablep
;
264 if (table
->nentries
== table
->bulk
) {
266 table
= realloc(table
, sizeof(*table
) + sizeof(Entry
) * table
->bulk
);
267 if (!table
) return -1;
268 table
->entries
= (Entry
*) &table
[1];
271 table
->entries
[table
->nentries
] = (Entry
) {length
, prefix
, suffix
};
273 if ((table
->nentries
& (table
->nentries
- 1)) == 0)
279 get_key(gd_GIF
*gif
, int key_size
, uint8_t *sub_len
, uint8_t *shift
, uint8_t *byte
)
287 for (bits_read
= 0; bits_read
< key_size
; bits_read
+= frag_size
) {
288 rpad
= (*shift
+ bits_read
) % 8;
292 read(gif
->fd
, sub_len
, 1); /* Must be nonzero! */
296 read(gif
->fd
, byte
, 1);
299 frag_size
= MIN(key_size
- bits_read
, 8 - rpad
);
300 key
|= ((uint16_t) ((*byte
) >> rpad
)) << bits_read
;
302 /* Clear extra bits to the left. */
303 key
&= (1 << key_size
) - 1;
304 *shift
= (*shift
+ key_size
) % 8;
308 /* Compute output index of y-th input line, in frame of height h. */
310 interlaced_line_index(int h
, int y
)
312 int p
; /* number of lines in current pass */
315 if (y
< p
) /* pass 1 */
319 if (y
< p
) /* pass 2 */
323 if (y
< p
) /* pass 3 */
330 /* Decompress image pixels.
331 * Return 0 on success or -1 on out-of-memory (w.r.t. LZW code table). */
333 read_image_data(gd_GIF
*gif
, int interlace
)
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
;
344 read(gif
->fd
, &byte
, 1);
345 key_size
= (int) byte
;
346 if (key_size
< 2 || key_size
> 8)
349 start
= lseek(gif
->fd
, 0, SEEK_CUR
);
350 discard_sub_blocks(gif
);
351 end
= lseek(gif
->fd
, 0, SEEK_CUR
);
352 lseek(gif
->fd
, start
, SEEK_SET
);
353 clear
= 1 << key_size
;
355 table
= new_table(key_size
);
357 init_key_size
= key_size
;
359 key
= get_key(gif
, key_size
, &sub_len
, &shift
, &byte
); /* clear code */
362 frm_size
= gif
->fw
*gif
->fh
;
363 while (frm_off
< frm_size
) {
365 key_size
= init_key_size
;
366 table
->nentries
= (1 << (key_size
- 1)) + 2;
368 } else if (!table_is_full
) {
369 ret
= add_entry(&table
, str_len
+ 1, key
, entry
.suffix
);
374 if (table
->nentries
== 0x1000) {
379 key
= get_key(gif
, key_size
, &sub_len
, &shift
, &byte
);
380 if (key
== clear
) continue;
381 if (key
== stop
|| key
== 0x1000) break;
382 if (ret
== 1) key_size
++;
383 entry
= table
->entries
[key
];
384 str_len
= entry
.length
;
385 for (i
= 0; i
< str_len
; i
++) {
386 p
= frm_off
+ entry
.length
- 1;
390 y
= interlaced_line_index((int) gif
->fh
, y
);
391 gif
->frame
[(gif
->fy
+ y
) * gif
->width
+ gif
->fx
+ x
] = entry
.suffix
;
392 if (entry
.prefix
== 0xFFF)
395 entry
= table
->entries
[entry
.prefix
];
398 if (key
< table
->nentries
- 1 && !table_is_full
)
399 table
->entries
[table
->nentries
- 1].suffix
= entry
.suffix
;
403 read(gif
->fd
, &sub_len
, 1); /* Must be zero! */
404 lseek(gif
->fd
, end
, SEEK_SET
);
409 * Return 0 on success or -1 on out-of-memory (w.r.t. LZW code table). */
411 read_image(gd_GIF
*gif
)
416 /* Image Descriptor. */
417 gif
->fx
= read_num(gif
->fd
);
418 gif
->fy
= read_num(gif
->fd
);
420 if (gif
->fx
>= gif
->width
|| gif
->fy
>= gif
->height
)
423 gif
->fw
= read_num(gif
->fd
);
424 gif
->fh
= read_num(gif
->fd
);
426 gif
->fw
= MIN(gif
->fw
, gif
->width
- gif
->fx
);
427 gif
->fh
= MIN(gif
->fh
, gif
->height
- gif
->fy
);
429 read(gif
->fd
, &fisrz
, 1);
430 interlace
= fisrz
& 0x40;
431 /* Ignore Sort Flag. */
432 /* Local Color Table? */
435 gif
->lct
.size
= 1 << ((fisrz
& 0x07) + 1);
436 read(gif
->fd
, gif
->lct
.colors
, 3 * gif
->lct
.size
);
437 gif
->palette
= &gif
->lct
;
439 gif
->palette
= &gif
->gct
;
441 return read_image_data(gif
, interlace
);
445 render_frame_rect(gd_GIF
*gif
, uint8_t *buffer
)
448 uint8_t index
, *color
;
449 i
= gif
->fy
* gif
->width
+ gif
->fx
;
450 for (j
= 0; j
< gif
->fh
; j
++) {
451 for (k
= 0; k
< gif
->fw
; k
++) {
452 index
= gif
->frame
[(gif
->fy
+ j
) * gif
->width
+ gif
->fx
+ k
];
453 color
= &gif
->palette
->colors
[index
*3];
454 if (!gif
->gce
.transparency
|| index
!= gif
->gce
.tindex
)
455 memcpy(&buffer
[(i
+k
)*3], color
, 3);
466 switch (gif
->gce
.disposal
) {
467 case 2: /* Restore to background color. */
468 bgcolor
= &gif
->palette
->colors
[gif
->bgindex
*3];
469 i
= gif
->fy
* gif
->width
+ gif
->fx
;
470 for (j
= 0; j
< gif
->fh
; j
++) {
471 for (k
= 0; k
< gif
->fw
; k
++)
472 memcpy(&gif
->canvas
[(i
+k
)*3], bgcolor
, 3);
476 case 3: /* Restore to previous, i.e., don't update canvas.*/
479 /* Add frame non-transparent pixels to canvas. */
480 render_frame_rect(gif
, gif
->canvas
);
484 /* Return 1 if got a frame; 0 if got GIF trailer; -1 if error. */
486 gd_get_frame(gd_GIF
*gif
)
491 read(gif
->fd
, &sep
, 1);
498 read(gif
->fd
, &sep
, 1);
500 if (read_image(gif
) == -1)
506 gd_render_frame(gd_GIF
*gif
, uint8_t *buffer
)
508 memcpy(buffer
, gif
->canvas
, gif
->width
* gif
->height
* 3);
509 render_frame_rect(gif
, buffer
);
513 gd_is_bgcolor(gd_GIF
*gif
, uint8_t color
[3])
515 return !memcmp(&gif
->palette
->colors
[gif
->bgindex
*3], color
, 3);
519 gd_rewind(gd_GIF
*gif
)
521 lseek(gif
->fd
, gif
->anim_start
, SEEK_SET
);
525 gd_close_gif(gd_GIF
*gif
)