1 #include "gifdec.h"
2 #include "../../../misc/lv_log.h"
3 #include "../../../misc/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 static gd_GIF *  gif_open(gd_GIF * gif);
27 static bool f_gif_open(gd_GIF * gif, const void * path, bool is_file);
28 static void f_gif_read(gd_GIF * gif, void * buf, size_t len);
29 static int f_gif_seek(gd_GIF * gif, size_t pos, int k);
30 static void f_gif_close(gd_GIF * gif);
31 
32 static uint16_t
read_num(gd_GIF * gif)33 read_num(gd_GIF * gif)
34 {
35     uint8_t bytes[2];
36 
37     f_gif_read(gif, bytes, 2);
38     return bytes[0] + (((uint16_t) bytes[1]) << 8);
39 }
40 
41 
42 
43 gd_GIF *
gd_open_gif_file(const char * fname)44 gd_open_gif_file(const char *fname)
45 {
46     gd_GIF gif_base;
47     memset(&gif_base, 0, sizeof(gif_base));
48 
49     bool res = f_gif_open(&gif_base, fname, true);
50     if(!res) return NULL;
51 
52     return gif_open(&gif_base);
53 }
54 
55 
56 gd_GIF *
gd_open_gif_data(const void * data)57 gd_open_gif_data(const void *data)
58 {
59     gd_GIF gif_base;
60     memset(&gif_base, 0, sizeof(gif_base));
61 
62     bool res = f_gif_open(&gif_base, data, false);
63     if(!res) return NULL;
64 
65     return gif_open(&gif_base);
66 }
67 
gif_open(gd_GIF * gif_base)68 static gd_GIF * gif_open(gd_GIF * gif_base)
69 {
70     uint8_t sigver[3];
71     uint16_t width, height, depth;
72     uint8_t fdsz, bgidx, aspect;
73     int i;
74     uint8_t *bgcolor;
75     int gct_sz;
76     gd_GIF *gif = NULL;
77 
78     /* Header */
79     f_gif_read(gif_base, sigver, 3);
80     if (memcmp(sigver, "GIF", 3) != 0) {
81         LV_LOG_WARN("invalid signature\n");
82         goto fail;
83     }
84     /* Version */
85     f_gif_read(gif_base, sigver, 3);
86     if (memcmp(sigver, "89a", 3) != 0) {
87         LV_LOG_WARN("invalid version\n");
88         goto fail;
89     }
90     /* Width x Height */
91     width  = read_num(gif_base);
92     height = read_num(gif_base);
93     /* FDSZ */
94     f_gif_read(gif_base, &fdsz, 1);
95     /* Presence of GCT */
96     if (!(fdsz & 0x80)) {
97         LV_LOG_WARN("no global color table\n");
98         goto fail;
99     }
100     /* Color Space's Depth */
101     depth = ((fdsz >> 4) & 7) + 1;
102     /* Ignore Sort Flag. */
103     /* GCT Size */
104     gct_sz = 1 << ((fdsz & 0x07) + 1);
105     /* Background Color Index */
106     f_gif_read(gif_base, &bgidx, 1);
107     /* Aspect Ratio */
108     f_gif_read(gif_base, &aspect, 1);
109     /* Create gd_GIF Structure. */
110 #if LV_COLOR_DEPTH == 32
111     gif = lv_mem_alloc(sizeof(gd_GIF) + 5 * width * height);
112 #elif LV_COLOR_DEPTH == 16
113     gif = lv_mem_alloc(sizeof(gd_GIF) + 4 * width * height);
114 #elif LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
115     gif = lv_mem_alloc(sizeof(gd_GIF) + 3 * width * height);
116 #endif
117 
118     if (!gif) goto fail;
119     memcpy(gif, gif_base, sizeof(gd_GIF));
120     gif->width  = width;
121     gif->height = height;
122     gif->depth  = depth;
123     /* Read GCT */
124     gif->gct.size = gct_sz;
125     f_gif_read(gif, gif->gct.colors, 3 * gif->gct.size);
126     gif->palette = &gif->gct;
127     gif->bgindex = bgidx;
128     gif->canvas = (uint8_t *) &gif[1];
129 #if LV_COLOR_DEPTH == 32
130     gif->frame = &gif->canvas[4 * width * height];
131 #elif LV_COLOR_DEPTH == 16
132     gif->frame = &gif->canvas[3 * width * height];
133 #elif LV_COLOR_DEPTH == 8 || LV_COLOR_DEPTH == 1
134     gif->frame = &gif->canvas[2 * width * height];
135 #endif
136     if (gif->bgindex) {
137         memset(gif->frame, gif->bgindex, gif->width * gif->height);
138     }
139     bgcolor = &gif->palette->colors[gif->bgindex*3];
140 
141     for (i = 0; i < gif->width * gif->height; i++) {
142 #if LV_COLOR_DEPTH == 32
143         gif->canvas[i*4 + 0] = *(bgcolor + 2);
144         gif->canvas[i*4 + 1] = *(bgcolor + 1);
145         gif->canvas[i*4 + 2] = *(bgcolor + 0);
146         gif->canvas[i*4 + 3] = 0xff;
147 #elif LV_COLOR_DEPTH == 16
148         lv_color_t c = lv_color_make(*(bgcolor + 0), *(bgcolor + 1), *(bgcolor + 2));
149         gif->canvas[i*3 + 0] = c.full & 0xff;
150         gif->canvas[i*3 + 1] = (c.full >> 8) & 0xff;
151         gif->canvas[i*3 + 2] = 0xff;
152 #elif LV_COLOR_DEPTH == 8
153         lv_color_t c = lv_color_make(*(bgcolor + 0), *(bgcolor + 1), *(bgcolor + 2));
154         gif->canvas[i*2 + 0] = c.full;
155         gif->canvas[i*2 + 1] = 0xff;
156 #elif LV_COLOR_DEPTH == 1
157         lv_color_t c = lv_color_make(*(bgcolor + 0), *(bgcolor + 1), *(bgcolor + 2));
158         gif->canvas[i*2 + 0] = c.ch.red > 128 ? 1 : 0;
159         gif->canvas[i*2 + 1] = 0xff;
160 #endif
161     }
162     gif->anim_start = f_gif_seek(gif, 0, LV_FS_SEEK_CUR);
163     gif->loop_count = -1;
164     goto ok;
165 fail:
166     f_gif_close(gif_base);
167 ok:
168     return gif;
169 }
170 
171 static void
discard_sub_blocks(gd_GIF * gif)172 discard_sub_blocks(gd_GIF *gif)
173 {
174     uint8_t size;
175 
176     do {
177         f_gif_read(gif, &size, 1);
178         f_gif_seek(gif, size, LV_FS_SEEK_CUR);
179     } while (size);
180 }
181 
182 static void
read_plain_text_ext(gd_GIF * gif)183 read_plain_text_ext(gd_GIF *gif)
184 {
185     if (gif->plain_text) {
186         uint16_t tx, ty, tw, th;
187         uint8_t cw, ch, fg, bg;
188         size_t sub_block;
189         f_gif_seek(gif, 1, LV_FS_SEEK_CUR); /* block size = 12 */
190         tx = read_num(gif);
191         ty = read_num(gif);
192         tw = read_num(gif);
193         th = read_num(gif);
194         f_gif_read(gif, &cw, 1);
195         f_gif_read(gif, &ch, 1);
196         f_gif_read(gif, &fg, 1);
197         f_gif_read(gif, &bg, 1);
198         sub_block = f_gif_seek(gif, 0, LV_FS_SEEK_CUR);
199         gif->plain_text(gif, tx, ty, tw, th, cw, ch, fg, bg);
200         f_gif_seek(gif, sub_block, LV_FS_SEEK_SET);
201     } else {
202         /* Discard plain text metadata. */
203         f_gif_seek(gif, 13, LV_FS_SEEK_CUR);
204     }
205     /* Discard plain text sub-blocks. */
206     discard_sub_blocks(gif);
207 }
208 
209 static void
read_graphic_control_ext(gd_GIF * gif)210 read_graphic_control_ext(gd_GIF *gif)
211 {
212     uint8_t rdit;
213 
214     /* Discard block size (always 0x04). */
215     f_gif_seek(gif, 1, LV_FS_SEEK_CUR);
216     f_gif_read(gif, &rdit, 1);
217     gif->gce.disposal = (rdit >> 2) & 3;
218     gif->gce.input = rdit & 2;
219     gif->gce.transparency = rdit & 1;
220     gif->gce.delay = read_num(gif);
221     f_gif_read(gif, &gif->gce.tindex, 1);
222     /* Skip block terminator. */
223     f_gif_seek(gif, 1, LV_FS_SEEK_CUR);
224 }
225 
226 static void
read_comment_ext(gd_GIF * gif)227 read_comment_ext(gd_GIF *gif)
228 {
229     if (gif->comment) {
230         size_t sub_block = f_gif_seek(gif, 0, LV_FS_SEEK_CUR);
231         gif->comment(gif);
232         f_gif_seek(gif, sub_block, LV_FS_SEEK_SET);
233     }
234     /* Discard comment sub-blocks. */
235     discard_sub_blocks(gif);
236 }
237 
238 static void
read_application_ext(gd_GIF * gif)239 read_application_ext(gd_GIF *gif)
240 {
241     char app_id[8];
242     char app_auth_code[3];
243     uint16_t loop_count;
244 
245     /* Discard block size (always 0x0B). */
246     f_gif_seek(gif, 1, LV_FS_SEEK_CUR);
247     /* Application Identifier. */
248     f_gif_read(gif, app_id, 8);
249     /* Application Authentication Code. */
250     f_gif_read(gif, app_auth_code, 3);
251     if (!strncmp(app_id, "NETSCAPE", sizeof(app_id))) {
252         /* Discard block size (0x03) and constant byte (0x01). */
253         f_gif_seek(gif, 2, LV_FS_SEEK_CUR);
254         loop_count = read_num(gif);
255         if(gif->loop_count < 0) {
256             if(loop_count == 0) {
257                 gif->loop_count = 0;
258             }
259             else{
260                 gif->loop_count = loop_count + 1;
261             }
262         }
263         /* Skip block terminator. */
264         f_gif_seek(gif, 1, LV_FS_SEEK_CUR);
265     } else if (gif->application) {
266         size_t sub_block = f_gif_seek(gif, 0, LV_FS_SEEK_CUR);
267         gif->application(gif, app_id, app_auth_code);
268         f_gif_seek(gif, sub_block, LV_FS_SEEK_SET);
269         discard_sub_blocks(gif);
270     } else {
271         discard_sub_blocks(gif);
272     }
273 }
274 
275 static void
read_ext(gd_GIF * gif)276 read_ext(gd_GIF *gif)
277 {
278     uint8_t label;
279 
280     f_gif_read(gif, &label, 1);
281     switch (label) {
282     case 0x01:
283         read_plain_text_ext(gif);
284         break;
285     case 0xF9:
286         read_graphic_control_ext(gif);
287         break;
288     case 0xFE:
289         read_comment_ext(gif);
290         break;
291     case 0xFF:
292         read_application_ext(gif);
293         break;
294     default:
295         LV_LOG_WARN("unknown extension: %02X\n", label);
296     }
297 }
298 
299 static Table *
new_table(int key_size)300 new_table(int key_size)
301 {
302     int key;
303     int init_bulk = MAX(1 << (key_size + 1), 0x100);
304     Table *table = lv_mem_alloc(sizeof(*table) + sizeof(Entry) * init_bulk);
305     if (table) {
306         table->bulk = init_bulk;
307         table->nentries = (1 << key_size) + 2;
308         table->entries = (Entry *) &table[1];
309         for (key = 0; key < (1 << key_size); key++)
310             table->entries[key] = (Entry) {1, 0xFFF, key};
311     }
312     return table;
313 }
314 
315 /* Add table entry. Return value:
316  *  0 on success
317  *  +1 if key size must be incremented after this addition
318  *  -1 if could not realloc table */
319 static int
add_entry(Table ** tablep,uint16_t length,uint16_t prefix,uint8_t suffix)320 add_entry(Table **tablep, uint16_t length, uint16_t prefix, uint8_t suffix)
321 {
322     Table *table = *tablep;
323     if (table->nentries == table->bulk) {
324         table->bulk *= 2;
325         table = lv_mem_realloc(table, sizeof(*table) + sizeof(Entry) * table->bulk);
326         if (!table) return -1;
327         table->entries = (Entry *) &table[1];
328         *tablep = table;
329     }
330     table->entries[table->nentries] = (Entry) {length, prefix, suffix};
331     table->nentries++;
332     if ((table->nentries & (table->nentries - 1)) == 0)
333         return 1;
334     return 0;
335 }
336 
337 static uint16_t
get_key(gd_GIF * gif,int key_size,uint8_t * sub_len,uint8_t * shift,uint8_t * byte)338 get_key(gd_GIF *gif, int key_size, uint8_t *sub_len, uint8_t *shift, uint8_t *byte)
339 {
340     int bits_read;
341     int rpad;
342     int frag_size;
343     uint16_t key;
344 
345     key = 0;
346     for (bits_read = 0; bits_read < key_size; bits_read += frag_size) {
347         rpad = (*shift + bits_read) % 8;
348         if (rpad == 0) {
349             /* Update byte. */
350             if (*sub_len == 0) {
351                 f_gif_read(gif, sub_len, 1); /* Must be nonzero! */
352                 if (*sub_len == 0) return 0x1000;
353             }
354             f_gif_read(gif, byte, 1);
355             (*sub_len)--;
356         }
357         frag_size = MIN(key_size - bits_read, 8 - rpad);
358         key |= ((uint16_t) ((*byte) >> rpad)) << bits_read;
359     }
360     /* Clear extra bits to the left. */
361     key &= (1 << key_size) - 1;
362     *shift = (*shift + key_size) % 8;
363     return key;
364 }
365 
366 /* Compute output index of y-th input line, in frame of height h. */
367 static int
interlaced_line_index(int h,int y)368 interlaced_line_index(int h, int y)
369 {
370     int p; /* number of lines in current pass */
371 
372     p = (h - 1) / 8 + 1;
373     if (y < p) /* pass 1 */
374         return y * 8;
375     y -= p;
376     p = (h - 5) / 8 + 1;
377     if (y < p) /* pass 2 */
378         return y * 8 + 4;
379     y -= p;
380     p = (h - 3) / 4 + 1;
381     if (y < p) /* pass 3 */
382         return y * 4 + 2;
383     y -= p;
384     /* pass 4 */
385     return y * 2 + 1;
386 }
387 
388 /* Decompress image pixels.
389  * Return 0 on success or -1 on out-of-memory (w.r.t. LZW code table). */
390 static int
read_image_data(gd_GIF * gif,int interlace)391 read_image_data(gd_GIF *gif, int interlace)
392 {
393     uint8_t sub_len, shift, byte;
394     int init_key_size, key_size, table_is_full=0;
395     int frm_off, frm_size, str_len=0, i, p, x, y;
396     uint16_t key, clear, stop;
397     int ret;
398     Table *table;
399     Entry entry = {0};
400     size_t start, end;
401 
402     f_gif_read(gif, &byte, 1);
403     key_size = (int) byte;
404     start = f_gif_seek(gif, 0, LV_FS_SEEK_CUR);
405     discard_sub_blocks(gif);
406     end = f_gif_seek(gif, 0, LV_FS_SEEK_CUR);
407     f_gif_seek(gif, start, LV_FS_SEEK_SET);
408     clear = 1 << key_size;
409     stop = clear + 1;
410     table = new_table(key_size);
411     key_size++;
412     init_key_size = key_size;
413     sub_len = shift = 0;
414     key = get_key(gif, key_size, &sub_len, &shift, &byte); /* clear code */
415     frm_off = 0;
416     ret = 0;
417     frm_size = gif->fw*gif->fh;
418     while (frm_off < frm_size) {
419         if (key == clear) {
420             key_size = init_key_size;
421             table->nentries = (1 << (key_size - 1)) + 2;
422             table_is_full = 0;
423         } else if (!table_is_full) {
424             ret = add_entry(&table, str_len + 1, key, entry.suffix);
425             if (ret == -1) {
426                 lv_mem_free(table);
427                 return -1;
428             }
429             if (table->nentries == 0x1000) {
430                 ret = 0;
431                 table_is_full = 1;
432             }
433         }
434         key = get_key(gif, key_size, &sub_len, &shift, &byte);
435         if (key == clear) continue;
436         if (key == stop || key == 0x1000) break;
437         if (ret == 1) key_size++;
438         entry = table->entries[key];
439         str_len = entry.length;
440         for (i = 0; i < str_len; i++) {
441             p = frm_off + entry.length - 1;
442             x = p % gif->fw;
443             y = p / gif->fw;
444             if (interlace)
445                 y = interlaced_line_index((int) gif->fh, y);
446             gif->frame[(gif->fy + y) * gif->width + gif->fx + x] = entry.suffix;
447             if (entry.prefix == 0xFFF)
448                 break;
449             else
450                 entry = table->entries[entry.prefix];
451         }
452         frm_off += str_len;
453         if (key < table->nentries - 1 && !table_is_full)
454             table->entries[table->nentries - 1].suffix = entry.suffix;
455     }
456     lv_mem_free(table);
457     if (key == stop) f_gif_read(gif, &sub_len, 1); /* Must be zero! */
458     f_gif_seek(gif, end, LV_FS_SEEK_SET);
459     return 0;
460 }
461 
462 /* Read image.
463  * Return 0 on success or -1 on out-of-memory (w.r.t. LZW code table). */
464 static int
read_image(gd_GIF * gif)465 read_image(gd_GIF *gif)
466 {
467     uint8_t fisrz;
468     int interlace;
469 
470     /* Image Descriptor. */
471     gif->fx = read_num(gif);
472     gif->fy = read_num(gif);
473     gif->fw = read_num(gif);
474     gif->fh = read_num(gif);
475     f_gif_read(gif, &fisrz, 1);
476     interlace = fisrz & 0x40;
477     /* Ignore Sort Flag. */
478     /* Local Color Table? */
479     if (fisrz & 0x80) {
480         /* Read LCT */
481         gif->lct.size = 1 << ((fisrz & 0x07) + 1);
482         f_gif_read(gif, gif->lct.colors, 3 * gif->lct.size);
483         gif->palette = &gif->lct;
484     } else
485         gif->palette = &gif->gct;
486     /* Image Data. */
487     return read_image_data(gif, interlace);
488 }
489 
490 static void
render_frame_rect(gd_GIF * gif,uint8_t * buffer)491 render_frame_rect(gd_GIF *gif, uint8_t *buffer)
492 {
493     int i, j, k;
494     uint8_t index, *color;
495     i = gif->fy * gif->width + gif->fx;
496     for (j = 0; j < gif->fh; j++) {
497         for (k = 0; k < gif->fw; k++) {
498             index = gif->frame[(gif->fy + j) * gif->width + gif->fx + k];
499             color = &gif->palette->colors[index*3];
500             if (!gif->gce.transparency || index != gif->gce.tindex) {
501 #if LV_COLOR_DEPTH == 32
502                 buffer[(i+k)*4 + 0] = *(color + 2);
503                 buffer[(i+k)*4 + 1] = *(color + 1);
504                 buffer[(i+k)*4 + 2] = *(color + 0);
505                 buffer[(i+k)*4 + 3] = 0xFF;
506 #elif LV_COLOR_DEPTH == 16
507                 lv_color_t c = lv_color_make(*(color + 0), *(color + 1), *(color + 2));
508                 buffer[(i+k)*3 + 0] = c.full & 0xff;
509                 buffer[(i+k)*3 + 1] = (c.full >> 8) & 0xff;
510                 buffer[(i+k)*3 + 2] = 0xff;
511 #elif LV_COLOR_DEPTH == 8
512                 lv_color_t c = lv_color_make(*(color + 0), *(color + 1), *(color + 2));
513                 buffer[(i+k)*2 + 0] = c.full;
514                 buffer[(i+k)*2 + 1] = 0xff;
515 #elif LV_COLOR_DEPTH == 1
516                 uint8_t b = (*(color + 0)) | (*(color + 1)) | (*(color + 2));
517                 buffer[(i+k)*2 + 0] = b > 128 ? 1 : 0;
518                 buffer[(i+k)*2 + 1] = 0xff;
519 #endif
520             }
521         }
522         i += gif->width;
523     }
524 }
525 
526 static void
dispose(gd_GIF * gif)527 dispose(gd_GIF *gif)
528 {
529     int i, j, k;
530     uint8_t *bgcolor;
531     switch (gif->gce.disposal) {
532     case 2: /* Restore to background color. */
533         bgcolor = &gif->palette->colors[gif->bgindex*3];
534 
535         uint8_t opa = 0xff;
536         if(gif->gce.transparency) opa = 0x00;
537 
538         i = gif->fy * gif->width + gif->fx;
539         for (j = 0; j < gif->fh; j++) {
540             for (k = 0; k < gif->fw; k++) {
541 #if LV_COLOR_DEPTH == 32
542                 gif->canvas[(i+k)*4 + 0] = *(bgcolor + 2);
543                 gif->canvas[(i+k)*4 + 1] = *(bgcolor + 1);
544                 gif->canvas[(i+k)*4 + 2] = *(bgcolor + 0);
545                 gif->canvas[(i+k)*4 + 3] = opa;
546 #elif LV_COLOR_DEPTH == 16
547                 lv_color_t c = lv_color_make(*(bgcolor + 0), *(bgcolor + 1), *(bgcolor + 2));
548                 gif->canvas[(i+k)*3 + 0] = c.full & 0xff;
549                 gif->canvas[(i+k)*3 + 1] = (c.full >> 8) & 0xff;
550                 gif->canvas[(i+k)*3 + 2] = opa;
551 #elif LV_COLOR_DEPTH == 8
552                 lv_color_t c = lv_color_make(*(bgcolor + 0), *(bgcolor + 1), *(bgcolor + 2));
553                 gif->canvas[(i+k)*2 + 0] = c.full;
554                 gif->canvas[(i+k)*2 + 1] = opa;
555 #elif LV_COLOR_DEPTH == 1
556                 uint8_t b = (*(bgcolor + 0)) | (*(bgcolor + 1)) | (*(bgcolor + 2));
557                 gif->canvas[(i+k)*2 + 0] = b > 128 ? 1 : 0;
558                 gif->canvas[(i+k)*2 + 1] = opa;
559 #endif
560             }
561             i += gif->width;
562         }
563         break;
564     case 3: /* Restore to previous, i.e., don't update canvas.*/
565         break;
566     default:
567         /* Add frame non-transparent pixels to canvas. */
568         render_frame_rect(gif, gif->canvas);
569     }
570 }
571 
572 /* Return 1 if got a frame; 0 if got GIF trailer; -1 if error. */
573 int
gd_get_frame(gd_GIF * gif)574 gd_get_frame(gd_GIF *gif)
575 {
576     char sep;
577 
578     dispose(gif);
579     f_gif_read(gif, &sep, 1);
580     while (sep != ',') {
581         if (sep == ';') {
582             f_gif_seek(gif, gif->anim_start, LV_FS_SEEK_SET);
583             if(gif->loop_count == 1 || gif->loop_count < 0) {
584                 return 0;
585             }
586             else if(gif->loop_count > 1) {
587                 gif->loop_count--;
588             }
589         }
590         else if (sep == '!')
591             read_ext(gif);
592         else return -1;
593         f_gif_read(gif, &sep, 1);
594     }
595     if (read_image(gif) == -1)
596         return -1;
597     return 1;
598 }
599 
600 void
gd_render_frame(gd_GIF * gif,uint8_t * buffer)601 gd_render_frame(gd_GIF *gif, uint8_t *buffer)
602 {
603 //    uint32_t i;
604 //    uint32_t j;
605 //    for(i = 0, j = 0; i < gif->width * gif->height * 3; i+= 3, j+=4) {
606 //        buffer[j + 0] = gif->canvas[i + 2];
607 //        buffer[j + 1] = gif->canvas[i + 1];
608 //        buffer[j + 2] = gif->canvas[i + 0];
609 //        buffer[j + 3] = 0xFF;
610 //    }
611 //    memcpy(buffer, gif->canvas, gif->width * gif->height * 3);
612     render_frame_rect(gif, buffer);
613 }
614 
615 void
gd_rewind(gd_GIF * gif)616 gd_rewind(gd_GIF *gif)
617 {
618     gif->loop_count = -1;
619     f_gif_seek(gif, gif->anim_start, LV_FS_SEEK_SET);
620 }
621 
622 void
gd_close_gif(gd_GIF * gif)623 gd_close_gif(gd_GIF *gif)
624 {
625     f_gif_close(gif);
626     lv_mem_free(gif);
627 }
628 
f_gif_open(gd_GIF * gif,const void * path,bool is_file)629 static bool f_gif_open(gd_GIF * gif, const void * path, bool is_file)
630 {
631     gif->f_rw_p = 0;
632     gif->data = NULL;
633     gif->is_file = is_file;
634 
635     if(is_file) {
636         lv_fs_res_t res = lv_fs_open(&gif->fd, path, LV_FS_MODE_RD);
637         if(res != LV_FS_RES_OK) return false;
638         else return true;
639     } else {
640         gif->data = path;
641         return true;
642     }
643 }
644 
f_gif_read(gd_GIF * gif,void * buf,size_t len)645 static void f_gif_read(gd_GIF * gif, void * buf, size_t len)
646 {
647     if(gif->is_file) {
648         lv_fs_read(&gif->fd, buf, len, NULL);
649     } else
650     {
651         memcpy(buf, &gif->data[gif->f_rw_p], len);
652         gif->f_rw_p += len;
653     }
654 }
655 
f_gif_seek(gd_GIF * gif,size_t pos,int k)656 static int f_gif_seek(gd_GIF * gif, size_t pos, int k)
657 {
658     if(gif->is_file) {
659         lv_fs_seek(&gif->fd, pos, k);
660         uint32_t x;
661         lv_fs_tell(&gif->fd, &x);
662         return x;
663     } else {
664         if(k == LV_FS_SEEK_CUR) gif->f_rw_p += pos;
665         else if(k == LV_FS_SEEK_SET) gif->f_rw_p = pos;
666         return gif->f_rw_p;
667     }
668 }
669 
f_gif_close(gd_GIF * gif)670 static void f_gif_close(gd_GIF * gif)
671 {
672     if(gif->is_file) {
673         lv_fs_close(&gif->fd);
674     }
675 }
676 
677 #endif /*LV_USE_GIF*/
678