1 #include "gifdec.h"
2 #include "../../misc/lv_log.h"
3 #include "../../stdlib/lv_mem.h"
4 #include "../../misc/lv_color.h"
5 #if LV_USE_GIF
6
7 #include <stdlib.h>
8 #include <string.h>
9 #include <stdbool.h>
10
11 #define MIN(A, B) ((A) < (B) ? (A) : (B))
12 #define MAX(A, B) ((A) > (B) ? (A) : (B))
13
14 typedef struct Entry {
15 uint16_t length;
16 uint16_t prefix;
17 uint8_t suffix;
18 } Entry;
19
20 typedef struct Table {
21 int bulk;
22 int nentries;
23 Entry * entries;
24 } Table;
25
26 #if LV_GIF_CACHE_DECODE_DATA
27 #define LZW_MAXBITS 12
28 #define LZW_TABLE_SIZE (1 << LZW_MAXBITS)
29 #define LZW_CACHE_SIZE (LZW_TABLE_SIZE * 4)
30 #endif
31
32 static gd_GIF * gif_open(gd_GIF * gif);
33 static bool f_gif_open(gd_GIF * gif, const void * path, bool is_file);
34 static void f_gif_read(gd_GIF * gif, void * buf, size_t len);
35 static int f_gif_seek(gd_GIF * gif, size_t pos, int k);
36 static void f_gif_close(gd_GIF * gif);
37
38 #if LV_USE_DRAW_SW_ASM == LV_DRAW_SW_ASM_HELIUM
39 #include "gifdec_mve.h"
40 #endif
41
42 static uint16_t
read_num(gd_GIF * gif)43 read_num(gd_GIF * gif)
44 {
45 uint8_t bytes[2];
46
47 f_gif_read(gif, bytes, 2);
48 return bytes[0] + (((uint16_t) bytes[1]) << 8);
49 }
50
51 gd_GIF *
gd_open_gif_file(const char * fname)52 gd_open_gif_file(const char * fname)
53 {
54 gd_GIF gif_base;
55 memset(&gif_base, 0, sizeof(gif_base));
56
57 bool res = f_gif_open(&gif_base, fname, true);
58 if(!res) return NULL;
59
60 return gif_open(&gif_base);
61 }
62
63 gd_GIF *
gd_open_gif_data(const void * data)64 gd_open_gif_data(const void * data)
65 {
66 gd_GIF gif_base;
67 memset(&gif_base, 0, sizeof(gif_base));
68
69 bool res = f_gif_open(&gif_base, data, false);
70 if(!res) return NULL;
71
72 return gif_open(&gif_base);
73 }
74
gif_open(gd_GIF * gif_base)75 static gd_GIF * gif_open(gd_GIF * gif_base)
76 {
77 uint8_t sigver[3];
78 uint16_t width, height, depth;
79 uint8_t fdsz, bgidx, aspect;
80 uint8_t * bgcolor;
81 int gct_sz;
82 gd_GIF * gif = NULL;
83
84 /* Header */
85 f_gif_read(gif_base, sigver, 3);
86 if(memcmp(sigver, "GIF", 3) != 0) {
87 LV_LOG_WARN("invalid signature");
88 goto fail;
89 }
90 /* Version */
91 f_gif_read(gif_base, sigver, 3);
92 if(memcmp(sigver, "89a", 3) != 0) {
93 LV_LOG_WARN("invalid version");
94 goto fail;
95 }
96 /* Width x Height */
97 width = read_num(gif_base);
98 height = read_num(gif_base);
99 /* FDSZ */
100 f_gif_read(gif_base, &fdsz, 1);
101 /* Presence of GCT */
102 if(!(fdsz & 0x80)) {
103 LV_LOG_WARN("no global color table");
104 goto fail;
105 }
106 /* Color Space's Depth */
107 depth = ((fdsz >> 4) & 7) + 1;
108 /* Ignore Sort Flag. */
109 /* GCT Size */
110 gct_sz = 1 << ((fdsz & 0x07) + 1);
111 /* Background Color Index */
112 f_gif_read(gif_base, &bgidx, 1);
113 /* Aspect Ratio */
114 f_gif_read(gif_base, &aspect, 1);
115 /* Create gd_GIF Structure. */
116 if(0 == width || 0 == height){
117 LV_LOG_WARN("Zero size image");
118 goto fail;
119 }
120 #if LV_GIF_CACHE_DECODE_DATA
121 if(0 == (INT_MAX - sizeof(gd_GIF) - LZW_CACHE_SIZE) / width / height / 5){
122 LV_LOG_WARN("Image dimensions are too large");
123 goto fail;
124 }
125 gif = lv_malloc(sizeof(gd_GIF) + 5 * width * height + LZW_CACHE_SIZE);
126 #else
127 if(0 == (INT_MAX - sizeof(gd_GIF)) / width / height / 5){
128 LV_LOG_WARN("Image dimensions are too large");
129 goto fail;
130 }
131 gif = lv_malloc(sizeof(gd_GIF) + 5 * width * height);
132 #endif
133 if(!gif) goto fail;
134 memcpy(gif, gif_base, sizeof(gd_GIF));
135 gif->width = width;
136 gif->height = height;
137 gif->depth = depth;
138 /* Read GCT */
139 gif->gct.size = gct_sz;
140 f_gif_read(gif, gif->gct.colors, 3 * gif->gct.size);
141 gif->palette = &gif->gct;
142 gif->bgindex = bgidx;
143 gif->canvas = (uint8_t *) &gif[1];
144 gif->frame = &gif->canvas[4 * width * height];
145 if(gif->bgindex) {
146 memset(gif->frame, gif->bgindex, gif->width * gif->height);
147 }
148 bgcolor = &gif->palette->colors[gif->bgindex * 3];
149 #if LV_GIF_CACHE_DECODE_DATA
150 gif->lzw_cache = gif->frame + width * height;
151 #endif
152
153 #ifdef GIFDEC_FILL_BG
154 GIFDEC_FILL_BG(gif->canvas, gif->width * gif->height, 1, gif->width * gif->height, bgcolor, 0xff);
155 #else
156 for(int i = 0; i < gif->width * gif->height; i++) {
157 gif->canvas[i * 4 + 0] = *(bgcolor + 2);
158 gif->canvas[i * 4 + 1] = *(bgcolor + 1);
159 gif->canvas[i * 4 + 2] = *(bgcolor + 0);
160 gif->canvas[i * 4 + 3] = 0xff;
161 }
162 #endif
163 gif->anim_start = f_gif_seek(gif, 0, LV_FS_SEEK_CUR);
164 gif->loop_count = -1;
165 goto ok;
166 fail:
167 f_gif_close(gif_base);
168 ok:
169 return gif;
170 }
171
172 static void
discard_sub_blocks(gd_GIF * gif)173 discard_sub_blocks(gd_GIF * gif)
174 {
175 uint8_t size;
176
177 do {
178 f_gif_read(gif, &size, 1);
179 f_gif_seek(gif, size, LV_FS_SEEK_CUR);
180 } while(size);
181 }
182
183 static void
read_plain_text_ext(gd_GIF * gif)184 read_plain_text_ext(gd_GIF * gif)
185 {
186 if(gif->plain_text) {
187 uint16_t tx, ty, tw, th;
188 uint8_t cw, ch, fg, bg;
189 size_t sub_block;
190 f_gif_seek(gif, 1, LV_FS_SEEK_CUR); /* block size = 12 */
191 tx = read_num(gif);
192 ty = read_num(gif);
193 tw = read_num(gif);
194 th = read_num(gif);
195 f_gif_read(gif, &cw, 1);
196 f_gif_read(gif, &ch, 1);
197 f_gif_read(gif, &fg, 1);
198 f_gif_read(gif, &bg, 1);
199 sub_block = f_gif_seek(gif, 0, LV_FS_SEEK_CUR);
200 gif->plain_text(gif, tx, ty, tw, th, cw, ch, fg, bg);
201 f_gif_seek(gif, sub_block, LV_FS_SEEK_SET);
202 }
203 else {
204 /* Discard plain text metadata. */
205 f_gif_seek(gif, 13, LV_FS_SEEK_CUR);
206 }
207 /* Discard plain text sub-blocks. */
208 discard_sub_blocks(gif);
209 }
210
211 static void
read_graphic_control_ext(gd_GIF * gif)212 read_graphic_control_ext(gd_GIF * gif)
213 {
214 uint8_t rdit;
215
216 /* Discard block size (always 0x04). */
217 f_gif_seek(gif, 1, LV_FS_SEEK_CUR);
218 f_gif_read(gif, &rdit, 1);
219 gif->gce.disposal = (rdit >> 2) & 3;
220 gif->gce.input = rdit & 2;
221 gif->gce.transparency = rdit & 1;
222 gif->gce.delay = read_num(gif);
223 f_gif_read(gif, &gif->gce.tindex, 1);
224 /* Skip block terminator. */
225 f_gif_seek(gif, 1, LV_FS_SEEK_CUR);
226 }
227
228 static void
read_comment_ext(gd_GIF * gif)229 read_comment_ext(gd_GIF * gif)
230 {
231 if(gif->comment) {
232 size_t sub_block = f_gif_seek(gif, 0, LV_FS_SEEK_CUR);
233 gif->comment(gif);
234 f_gif_seek(gif, sub_block, LV_FS_SEEK_SET);
235 }
236 /* Discard comment sub-blocks. */
237 discard_sub_blocks(gif);
238 }
239
240 static void
read_application_ext(gd_GIF * gif)241 read_application_ext(gd_GIF * gif)
242 {
243 char app_id[8];
244 char app_auth_code[3];
245 uint16_t loop_count;
246
247 /* Discard block size (always 0x0B). */
248 f_gif_seek(gif, 1, LV_FS_SEEK_CUR);
249 /* Application Identifier. */
250 f_gif_read(gif, app_id, 8);
251 /* Application Authentication Code. */
252 f_gif_read(gif, app_auth_code, 3);
253 if(!strncmp(app_id, "NETSCAPE", sizeof(app_id))) {
254 /* Discard block size (0x03) and constant byte (0x01). */
255 f_gif_seek(gif, 2, LV_FS_SEEK_CUR);
256 loop_count = read_num(gif);
257 if(gif->loop_count < 0) {
258 if(loop_count == 0) {
259 gif->loop_count = 0;
260 }
261 else {
262 gif->loop_count = loop_count + 1;
263 }
264 }
265 /* Skip block terminator. */
266 f_gif_seek(gif, 1, LV_FS_SEEK_CUR);
267 }
268 else if(gif->application) {
269 size_t sub_block = f_gif_seek(gif, 0, LV_FS_SEEK_CUR);
270 gif->application(gif, app_id, app_auth_code);
271 f_gif_seek(gif, sub_block, LV_FS_SEEK_SET);
272 discard_sub_blocks(gif);
273 }
274 else {
275 discard_sub_blocks(gif);
276 }
277 }
278
279 static void
read_ext(gd_GIF * gif)280 read_ext(gd_GIF * gif)
281 {
282 uint8_t label;
283
284 f_gif_read(gif, &label, 1);
285 switch(label) {
286 case 0x01:
287 read_plain_text_ext(gif);
288 break;
289 case 0xF9:
290 read_graphic_control_ext(gif);
291 break;
292 case 0xFE:
293 read_comment_ext(gif);
294 break;
295 case 0xFF:
296 read_application_ext(gif);
297 break;
298 default:
299 LV_LOG_WARN("unknown extension: %02X\n", label);
300 }
301 }
302
303 static uint16_t
get_key(gd_GIF * gif,int key_size,uint8_t * sub_len,uint8_t * shift,uint8_t * byte)304 get_key(gd_GIF *gif, int key_size, uint8_t *sub_len, uint8_t *shift, uint8_t *byte)
305 {
306 int bits_read;
307 int rpad;
308 int frag_size;
309 uint16_t key;
310
311 key = 0;
312 for (bits_read = 0; bits_read < key_size; bits_read += frag_size) {
313 rpad = (*shift + bits_read) % 8;
314 if (rpad == 0) {
315 /* Update byte. */
316 if (*sub_len == 0) {
317 f_gif_read(gif, sub_len, 1); /* Must be nonzero! */
318 if (*sub_len == 0) return 0x1000;
319 }
320 f_gif_read(gif, byte, 1);
321 (*sub_len)--;
322 }
323 frag_size = MIN(key_size - bits_read, 8 - rpad);
324 key |= ((uint16_t) ((*byte) >> rpad)) << bits_read;
325 }
326 /* Clear extra bits to the left. */
327 key &= (1 << key_size) - 1;
328 *shift = (*shift + key_size) % 8;
329 return key;
330 }
331
332 #if LV_GIF_CACHE_DECODE_DATA
333 /* Decompress image pixels.
334 * Return 0 on success or -1 on out-of-memory (w.r.t. LZW code table) or parse error. */
335 static int
read_image_data(gd_GIF * gif,int interlace)336 read_image_data(gd_GIF *gif, int interlace)
337 {
338 uint8_t sub_len, shift, byte;
339 int ret = 0;
340 int key_size;
341 int y, pass, linesize;
342 uint8_t *ptr = NULL;
343 uint8_t *ptr_row_start = NULL;
344 uint8_t *ptr_base = NULL;
345 size_t start, end;
346 uint16_t key, clear_code, stop_code, curr_code;
347 int frm_off, frm_size,curr_size,top_slot,new_codes,slot;
348 /* The first value of the value sequence corresponding to key */
349 int first_value;
350 int last_key;
351 uint8_t *sp = NULL;
352 uint8_t *p_stack = NULL;
353 uint8_t *p_suffix = NULL;
354 uint16_t *p_prefix = NULL;
355
356 /* get initial key size and clear code, stop code */
357 f_gif_read(gif, &byte, 1);
358 key_size = (int) byte;
359 clear_code = 1 << key_size;
360 stop_code = clear_code + 1;
361 key = 0;
362
363 start = f_gif_seek(gif, 0, LV_FS_SEEK_CUR);
364 discard_sub_blocks(gif);
365 end = f_gif_seek(gif, 0, LV_FS_SEEK_CUR);
366 f_gif_seek(gif, start, LV_FS_SEEK_SET);
367
368 linesize = gif->width;
369 ptr_base = &gif->frame[gif->fy * linesize + gif->fx];
370 ptr_row_start = ptr_base;
371 ptr = ptr_row_start;
372 sub_len = shift = 0;
373 /* decoder */
374 pass = 0;
375 y = 0;
376 p_stack = gif->lzw_cache;
377 p_suffix = gif->lzw_cache + LZW_TABLE_SIZE;
378 p_prefix = (uint16_t*)(gif->lzw_cache + LZW_TABLE_SIZE * 2);
379 frm_off = 0;
380 frm_size = gif->fw * gif->fh;
381 curr_size = key_size + 1;
382 top_slot = 1 << curr_size;
383 new_codes = clear_code + 2;
384 slot = new_codes;
385 first_value = -1;
386 last_key = -1;
387 sp = p_stack;
388
389 while (frm_off < frm_size) {
390 /* copy data to frame buffer */
391 while (sp > p_stack) {
392 if(frm_off >= frm_size){
393 LV_LOG_WARN("LZW table token overflows the frame buffer");
394 return -1;
395 }
396 *ptr++ = *(--sp);
397 frm_off += 1;
398 /* read one line */
399 if ((ptr - ptr_row_start) == gif->fw) {
400 if (interlace) {
401 switch(pass) {
402 case 0:
403 case 1:
404 y += 8;
405 ptr_row_start += linesize * 8;
406 break;
407 case 2:
408 y += 4;
409 ptr_row_start += linesize * 4;
410 break;
411 case 3:
412 y += 2;
413 ptr_row_start += linesize * 2;
414 break;
415 default:
416 break;
417 }
418 while (y >= gif->fh) {
419 y = 4 >> pass;
420 ptr_row_start = ptr_base + linesize * y;
421 pass++;
422 }
423 } else {
424 ptr_row_start += linesize;
425 }
426 ptr = ptr_row_start;
427 }
428 }
429
430 key = get_key(gif, curr_size, &sub_len, &shift, &byte);
431
432 if (key == stop_code || key >= LZW_TABLE_SIZE)
433 break;
434
435 if (key == clear_code) {
436 curr_size = key_size + 1;
437 slot = new_codes;
438 top_slot = 1 << curr_size;
439 first_value = last_key = -1;
440 sp = p_stack;
441 continue;
442 }
443
444 curr_code = key;
445 /*
446 * If the current code is a code that will be added to the decoding
447 * dictionary, it is composed of the data list corresponding to the
448 * previous key and its first data.
449 * */
450 if (curr_code == slot && first_value >= 0) {
451 *sp++ = first_value;
452 curr_code = last_key;
453 }else if(curr_code >= slot)
454 break;
455
456 while (curr_code >= new_codes) {
457 *sp++ = p_suffix[curr_code];
458 curr_code = p_prefix[curr_code];
459 }
460 *sp++ = curr_code;
461
462 /* Add code to decoding dictionary */
463 if (slot < top_slot && last_key >= 0) {
464 p_suffix[slot] = curr_code;
465 p_prefix[slot++] = last_key;
466 }
467 first_value = curr_code;
468 last_key = key;
469 if (slot >= top_slot) {
470 if (curr_size < LZW_MAXBITS) {
471 top_slot <<= 1;
472 curr_size += 1;
473 }
474 }
475 }
476
477 if (key == stop_code) f_gif_read(gif, &sub_len, 1); /* Must be zero! */
478 f_gif_seek(gif, end, LV_FS_SEEK_SET);
479 return ret;
480 }
481 #else
482 static Table *
new_table(int key_size)483 new_table(int key_size)
484 {
485 int key;
486 int init_bulk = MAX(1 << (key_size + 1), 0x100);
487 Table * table = lv_malloc(sizeof(*table) + sizeof(Entry) * init_bulk);
488 if(table) {
489 table->bulk = init_bulk;
490 table->nentries = (1 << key_size) + 2;
491 table->entries = (Entry *) &table[1];
492 for(key = 0; key < (1 << key_size); key++)
493 table->entries[key] = (Entry) {
494 1, 0xFFF, key
495 };
496 }
497 return table;
498 }
499
500 /* Add table entry. Return value:
501 * 0 on success
502 * +1 if key size must be incremented after this addition
503 * -1 if could not realloc table */
504 static int
add_entry(Table ** tablep,uint16_t length,uint16_t prefix,uint8_t suffix)505 add_entry(Table ** tablep, uint16_t length, uint16_t prefix, uint8_t suffix)
506 {
507 Table * table = *tablep;
508 if(table->nentries == table->bulk) {
509 table->bulk *= 2;
510 table = lv_realloc(table, sizeof(*table) + sizeof(Entry) * table->bulk);
511 if(!table) return -1;
512 table->entries = (Entry *) &table[1];
513 *tablep = table;
514 }
515 table->entries[table->nentries] = (Entry) {
516 length, prefix, suffix
517 };
518 table->nentries++;
519 if((table->nentries & (table->nentries - 1)) == 0)
520 return 1;
521 return 0;
522 }
523
524 /* Compute output index of y-th input line, in frame of height h. */
525 static int
interlaced_line_index(int h,int y)526 interlaced_line_index(int h, int y)
527 {
528 int p; /* number of lines in current pass */
529
530 p = (h - 1) / 8 + 1;
531 if(y < p) /* pass 1 */
532 return y * 8;
533 y -= p;
534 p = (h - 5) / 8 + 1;
535 if(y < p) /* pass 2 */
536 return y * 8 + 4;
537 y -= p;
538 p = (h - 3) / 4 + 1;
539 if(y < p) /* pass 3 */
540 return y * 4 + 2;
541 y -= p;
542 /* pass 4 */
543 return y * 2 + 1;
544 }
545
546 /* Decompress image pixels.
547 * Return 0 on success or -1 on out-of-memory (w.r.t. LZW code table) or parse error. */
548 static int
read_image_data(gd_GIF * gif,int interlace)549 read_image_data(gd_GIF * gif, int interlace)
550 {
551 uint8_t sub_len, shift, byte;
552 int init_key_size, key_size, table_is_full = 0;
553 int frm_off, frm_size, str_len = 0, i, p, x, y;
554 uint16_t key, clear, stop;
555 int ret;
556 Table * table;
557 Entry entry = {0};
558 size_t start, end;
559
560 f_gif_read(gif, &byte, 1);
561 key_size = (int) byte;
562 start = f_gif_seek(gif, 0, LV_FS_SEEK_CUR);
563 discard_sub_blocks(gif);
564 end = f_gif_seek(gif, 0, LV_FS_SEEK_CUR);
565 f_gif_seek(gif, start, LV_FS_SEEK_SET);
566 clear = 1 << key_size;
567 stop = clear + 1;
568 table = new_table(key_size);
569 key_size++;
570 init_key_size = key_size;
571 sub_len = shift = 0;
572 key = get_key(gif, key_size, &sub_len, &shift, &byte); /* clear code */
573 frm_off = 0;
574 ret = 0;
575 frm_size = gif->fw * gif->fh;
576 while(frm_off < frm_size) {
577 if(key == clear) {
578 key_size = init_key_size;
579 table->nentries = (1 << (key_size - 1)) + 2;
580 table_is_full = 0;
581 }
582 else if(!table_is_full) {
583 ret = add_entry(&table, str_len + 1, key, entry.suffix);
584 if(ret == -1) {
585 lv_free(table);
586 return -1;
587 }
588 if(table->nentries == 0x1000) {
589 ret = 0;
590 table_is_full = 1;
591 }
592 }
593 key = get_key(gif, key_size, &sub_len, &shift, &byte);
594 if(key == clear) continue;
595 if(key == stop || key == 0x1000) break;
596 if(ret == 1) key_size++;
597 entry = table->entries[key];
598 str_len = entry.length;
599 if(frm_off + str_len >= frm_size){
600 LV_LOG_WARN("LZW table token overflows the frame buffer");
601 return -1;
602 }
603 for(i = 0; i < str_len; i++) {
604 p = frm_off + entry.length - 1;
605 x = p % gif->fw;
606 y = p / gif->fw;
607 if(interlace)
608 y = interlaced_line_index((int) gif->fh, y);
609 gif->frame[(gif->fy + y) * gif->width + gif->fx + x] = entry.suffix;
610 if(entry.prefix == 0xFFF)
611 break;
612 else
613 entry = table->entries[entry.prefix];
614 }
615 frm_off += str_len;
616 if(key < table->nentries - 1 && !table_is_full)
617 table->entries[table->nentries - 1].suffix = entry.suffix;
618 }
619 lv_free(table);
620 if(key == stop) f_gif_read(gif, &sub_len, 1); /* Must be zero! */
621 f_gif_seek(gif, end, LV_FS_SEEK_SET);
622 return 0;
623 }
624
625 #endif
626
627 /* Read image.
628 * Return 0 on success or -1 on out-of-memory (w.r.t. LZW code table) or parse error. */
629 static int
read_image(gd_GIF * gif)630 read_image(gd_GIF * gif)
631 {
632 uint8_t fisrz;
633 int interlace;
634
635 /* Image Descriptor. */
636 gif->fx = read_num(gif);
637 gif->fy = read_num(gif);
638 gif->fw = read_num(gif);
639 gif->fh = read_num(gif);
640 if(gif->fx + (uint32_t)gif->fw > gif->width || gif->fy + (uint32_t)gif->fh > gif->height){
641 LV_LOG_WARN("Frame coordinates out of image bounds");
642 return -1;
643 }
644 f_gif_read(gif, &fisrz, 1);
645 interlace = fisrz & 0x40;
646 /* Ignore Sort Flag. */
647 /* Local Color Table? */
648 if(fisrz & 0x80) {
649 /* Read LCT */
650 gif->lct.size = 1 << ((fisrz & 0x07) + 1);
651 f_gif_read(gif, gif->lct.colors, 3 * gif->lct.size);
652 gif->palette = &gif->lct;
653 }
654 else
655 gif->palette = &gif->gct;
656 /* Image Data. */
657 return read_image_data(gif, interlace);
658 }
659
660 static void
render_frame_rect(gd_GIF * gif,uint8_t * buffer)661 render_frame_rect(gd_GIF * gif, uint8_t * buffer)
662 {
663 int i = gif->fy * gif->width + gif->fx;
664 #ifdef GIFDEC_RENDER_FRAME
665 GIFDEC_RENDER_FRAME(&buffer[i * 4], gif->fw, gif->fh, gif->width,
666 &gif->frame[i], gif->palette->colors,
667 gif->gce.transparency ? gif->gce.tindex : 0x100);
668 #else
669 int j, k;
670 uint8_t index, * color;
671
672 for(j = 0; j < gif->fh; j++) {
673 for(k = 0; k < gif->fw; k++) {
674 index = gif->frame[(gif->fy + j) * gif->width + gif->fx + k];
675 color = &gif->palette->colors[index * 3];
676 if(!gif->gce.transparency || index != gif->gce.tindex) {
677 buffer[(i + k) * 4 + 0] = *(color + 2);
678 buffer[(i + k) * 4 + 1] = *(color + 1);
679 buffer[(i + k) * 4 + 2] = *(color + 0);
680 buffer[(i + k) * 4 + 3] = 0xFF;
681 }
682 }
683 i += gif->width;
684 }
685 #endif
686 }
687
688 static void
dispose(gd_GIF * gif)689 dispose(gd_GIF * gif)
690 {
691 int i;
692 uint8_t * bgcolor;
693 switch(gif->gce.disposal) {
694 case 2: /* Restore to background color. */
695 bgcolor = &gif->palette->colors[gif->bgindex * 3];
696
697 uint8_t opa = 0xff;
698 if(gif->gce.transparency) opa = 0x00;
699
700 i = gif->fy * gif->width + gif->fx;
701 #ifdef GIFDEC_FILL_BG
702 GIFDEC_FILL_BG(&(gif->canvas[i * 4]), gif->fw, gif->fh, gif->width, bgcolor, opa);
703 #else
704 int j, k;
705 for(j = 0; j < gif->fh; j++) {
706 for(k = 0; k < gif->fw; k++) {
707 gif->canvas[(i + k) * 4 + 0] = *(bgcolor + 2);
708 gif->canvas[(i + k) * 4 + 1] = *(bgcolor + 1);
709 gif->canvas[(i + k) * 4 + 2] = *(bgcolor + 0);
710 gif->canvas[(i + k) * 4 + 3] = opa;
711 }
712 i += gif->width;
713 }
714 #endif
715 break;
716 case 3: /* Restore to previous, i.e., don't update canvas.*/
717 break;
718 default:
719 /* Add frame non-transparent pixels to canvas. */
720 render_frame_rect(gif, gif->canvas);
721 }
722 }
723
724 /* Return 1 if got a frame; 0 if got GIF trailer; -1 if error. */
725 int
gd_get_frame(gd_GIF * gif)726 gd_get_frame(gd_GIF * gif)
727 {
728 char sep;
729
730 dispose(gif);
731 f_gif_read(gif, &sep, 1);
732 while(sep != ',') {
733 if(sep == ';') {
734 f_gif_seek(gif, gif->anim_start, LV_FS_SEEK_SET);
735 if(gif->loop_count == 1 || gif->loop_count < 0) {
736 return 0;
737 }
738 else if(gif->loop_count > 1) {
739 gif->loop_count--;
740 }
741 }
742 else if(sep == '!')
743 read_ext(gif);
744 else return -1;
745 f_gif_read(gif, &sep, 1);
746 }
747 if(read_image(gif) == -1)
748 return -1;
749 return 1;
750 }
751
752 void
gd_render_frame(gd_GIF * gif,uint8_t * buffer)753 gd_render_frame(gd_GIF * gif, uint8_t * buffer)
754 {
755 render_frame_rect(gif, buffer);
756 }
757
758 void
gd_rewind(gd_GIF * gif)759 gd_rewind(gd_GIF * gif)
760 {
761 gif->loop_count = -1;
762 f_gif_seek(gif, gif->anim_start, LV_FS_SEEK_SET);
763 }
764
765 void
gd_close_gif(gd_GIF * gif)766 gd_close_gif(gd_GIF * gif)
767 {
768 f_gif_close(gif);
769 lv_free(gif);
770 }
771
f_gif_open(gd_GIF * gif,const void * path,bool is_file)772 static bool f_gif_open(gd_GIF * gif, const void * path, bool is_file)
773 {
774 gif->f_rw_p = 0;
775 gif->data = NULL;
776 gif->is_file = is_file;
777
778 if(is_file) {
779 lv_fs_res_t res = lv_fs_open(&gif->fd, path, LV_FS_MODE_RD);
780 if(res != LV_FS_RES_OK) return false;
781 else return true;
782 }
783 else {
784 gif->data = path;
785 return true;
786 }
787 }
788
f_gif_read(gd_GIF * gif,void * buf,size_t len)789 static void f_gif_read(gd_GIF * gif, void * buf, size_t len)
790 {
791 if(gif->is_file) {
792 lv_fs_read(&gif->fd, buf, len, NULL);
793 }
794 else {
795 memcpy(buf, &gif->data[gif->f_rw_p], len);
796 gif->f_rw_p += len;
797 }
798 }
799
f_gif_seek(gd_GIF * gif,size_t pos,int k)800 static int f_gif_seek(gd_GIF * gif, size_t pos, int k)
801 {
802 if(gif->is_file) {
803 lv_fs_seek(&gif->fd, pos, k);
804 uint32_t x;
805 lv_fs_tell(&gif->fd, &x);
806 return x;
807 }
808 else {
809 if(k == LV_FS_SEEK_CUR) gif->f_rw_p += pos;
810 else if(k == LV_FS_SEEK_SET) gif->f_rw_p = pos;
811 return gif->f_rw_p;
812 }
813 }
814
f_gif_close(gd_GIF * gif)815 static void f_gif_close(gd_GIF * gif)
816 {
817 if(gif->is_file) {
818 lv_fs_close(&gif->fd);
819 }
820 }
821
822 #endif /*LV_USE_GIF*/
823