FastLED 3.9.15
Loading...
Searching...
No Matches
gif.cpp.hpp
Go to the documentation of this file.
1/*
2 * Copyright 2004 Richard Wilson <richard.wilson@netsurf-browser.org>
3 * Copyright 2008 Sean Fox <dyntryx@gmail.com>
4 * Copyright 2013-2022 Michael Drake <tlsa@netsurf-browser.org>
5 *
6 * This file is part of NetSurf's libnsgif, http://www.netsurf-browser.org/
7 * Licenced under the MIT License,
8 * http://www.opensource.org/licenses/mit-license.php
9 */
10
11#include "fl/stl/cstddef.h"
12#include "fl/stl/assert.h"
13#include "fl/stl/int.h"
14#include "fl/stl/limits.h"
15#include "fl/stl/allocator.h"
16#include "fl/stl/cstring.h"
17#include "fl/stl/string.h"
18#include "fl/stl/noexcept.h"
19
20#include "lzw.h"
22
23namespace fl {
24namespace third_party {
25
27#define NSGIF_FRAME_DELAY_MIN 2
28
34#define NSGIF_FRAME_DELAY_DEFAULT 10
35
37typedef struct nsgif_frame {
39
41 fl::size frame_offset;
43 bool decoded;
45 bool opaque;
48
51
54
57
58 /* Frame flags */
59 fl::u32 flags;
61
69
138
145#define NSGIF_ARRAY_LEN(_a) ((sizeof(_a)) / (sizeof(*_a)))
146
157
159#define NSGIF_PROCESS_COLOURS 0xaa000000
160
162#define NSGIF_FRAME_INVALID (fl::numeric_limits<fl::u32>::max)()
163
165#define NSGIF_TRANSPARENT_COLOUR 0x00
166
168#define NSGIF_NO_TRANSPARENCY (0xFFFFFFFFu)
169
170/* GIF Flags */
171#define NSGIF_COLOUR_TABLE_MASK 0x80
172#define NSGIF_COLOUR_TABLE_SIZE_MASK 0x07
173#define NSGIF_BLOCK_TERMINATOR 0x00
174#define NSGIF_TRAILER 0x3b
175
183{
184 static const nsgif_error g_res[] = {
185 NSGIF_OK, /* LZW_OK */
186 NSGIF_ERR_END_OF_DATA, /* LZW_OK_EOD */
187 NSGIF_ERR_OOM, /* LZW_NO_MEM */
188 NSGIF_ERR_END_OF_DATA, /* LZW_NO_DATA */
189 NSGIF_ERR_DATA_FRAME, /* LZW_EOI_CODE */
190 NSGIF_ERR_DATA_FRAME, /* LZW_NO_COLOUR */
191 NSGIF_ERR_DATA_FRAME, /* LZW_BAD_ICODE */
192 NSGIF_ERR_DATA_FRAME, /* LZW_BAD_PARAM */
193 NSGIF_ERR_DATA_FRAME, /* LZW_BAD_CODE */
194 };
195 FL_ASSERT(l_res != LZW_BAD_PARAM, "LZW bad parameter");
196 FL_ASSERT(l_res != LZW_NO_COLOUR, "LZW no colour");
197 return g_res[l_res];
198}
199
209 struct nsgif *gif,
210 fl::u32 width,
211 fl::u32 height) FL_NOEXCEPT
212{
213 /* Already allocated? */
214 if (gif->frame_image) {
215 return NSGIF_OK;
216 }
217
218 FL_ASSERT(gif->bitmap.create, "GIF bitmap create function required");
219 gif->frame_image = gif->bitmap.create(width, height);
220 if (gif->frame_image == nullptr) {
221 return NSGIF_ERR_OOM;
222 }
223
224 return NSGIF_OK;
225}
226
233static inline fl::u32* nsgif__bitmap_get(
234 struct nsgif *gif) FL_NOEXCEPT
235{
236 nsgif_error ret;
237
238 /* Make sure we have a buffer to decode to. */
239 ret = nsgif__initialise_sprite(gif, gif->info.width, gif->info.height);
240 if (ret != NSGIF_OK) {
241 return nullptr;
242 }
243
244 gif->rowspan = gif->info.width;
245 if (gif->bitmap.get_rowspan) {
246 gif->rowspan = gif->bitmap.get_rowspan(gif->frame_image);
247 }
248
249 /* Get the frame data */
250 FL_ASSERT(gif->bitmap.get_buffer, "GIF bitmap get_buffer function required");
251 return reinterpret_cast<fl::u32*>(gif->bitmap.get_buffer(gif->frame_image));
252}
253
259static inline void nsgif__bitmap_modified(
260 const struct nsgif *gif) FL_NOEXCEPT
261{
262 if (gif->bitmap.modified) {
263 gif->bitmap.modified(gif->frame_image);
264 }
265}
266
273static inline void nsgif__bitmap_set_opaque(
274 const struct nsgif *gif,
275 const struct nsgif_frame *frame) FL_NOEXCEPT
276{
277 if (gif->bitmap.set_opaque) {
278 gif->bitmap.set_opaque(
279 gif->frame_image, frame->opaque);
280 }
281}
282
291static inline bool nsgif__bitmap_get_opaque(
292 const struct nsgif *gif) FL_NOEXCEPT
293{
294 if (gif->bitmap.test_opaque) {
295 return gif->bitmap.test_opaque(
296 gif->frame_image);
297 }
298
299 return false;
300}
301
303 struct nsgif *gif,
304 const fl::u32 *bitmap) FL_NOEXCEPT
305{
306 fl::size pixel_bytes = sizeof(*bitmap);
307 fl::size height = gif->info.height;
308 fl::size width = gif->info.width;
309 fl::u32 *prev_frame;
310
311 if (gif->decoded_frame == NSGIF_FRAME_INVALID ||
312 gif->decoded_frame == gif->prev_index) {
313 /* No frame to copy, or already have this frame recorded. */
314 return;
315 }
316
317 bitmap = nsgif__bitmap_get(gif);
318 if (bitmap == nullptr) {
319 return;
320 }
321
322 if (gif->prev_frame == nullptr) {
323 prev_frame = static_cast<fl::u32*>(fl::Malloc(width * height * pixel_bytes));
324 if (prev_frame == nullptr) {
325 return;
326 }
327 gif->prev_frame = prev_frame;
328 } else {
329 prev_frame = static_cast<fl::u32*>(gif->prev_frame);
330 }
331
332 fl::memcpy(prev_frame, bitmap, width * height * pixel_bytes);
333
334 gif->prev_frame = prev_frame;
335 gif->prev_index = gif->decoded_frame;
336}
337
339 const struct nsgif *gif,
340 fl::u32 *bitmap) FL_NOEXCEPT
341{
342 const fl::u32 *prev_frame = static_cast<const fl::u32*>(gif->prev_frame);
343 fl::size pixel_bytes = sizeof(*bitmap);
344 fl::size height = gif->info.height;
345 fl::size width = gif->info.width;
346
347 fl::memcpy(bitmap, prev_frame, height * width * pixel_bytes);
348
349 return NSGIF_OK;
350}
351
365static inline bool nsgif__deinterlace(fl::u32 height, fl::u32 *y, fl::u8 *step) FL_NOEXCEPT
366{
367 *y += *step & 0xf;
368
369 if (*y < height) return true;
370
371 switch (*step) {
372 case 24: *y = 4; *step = 8; if (*y < height) return true;
373 /* Fall through. */
374 case 8: *y = 2; *step = 4; if (*y < height) return true;
375 /* Fall through. */
376 case 4: *y = 1; *step = 2; if (*y < height) return true;
377 /* Fall through. */
378 default:
379 break;
380 }
381
382 return false;
383}
384
394static inline bool nsgif__next_row(fl::u32 interlace,
395 fl::u32 height, fl::u32 *y, fl::u8 *step) FL_NOEXCEPT
396{
397 if (!interlace) {
398 return (++*y != height);
399 } else {
401 }
402}
403
413static inline fl::u32 gif__clip(
414 fl::u32 frame_off,
415 fl::u32 frame_dim,
416 fl::u32 image_ext) FL_NOEXCEPT
417{
418 fl::u32 frame_ext = frame_off + frame_dim;
419
420 if (frame_ext <= image_ext) {
421 return 0;
422 }
423
424 return frame_ext - image_ext;
425}
426
434static inline void gif__jump_data(
435 fl::u32 *skip,
436 fl::u32 *available,
437 const fl::u8 **pos) FL_NOEXCEPT
438{
439 fl::u32 jump = (*skip < *available) ? *skip : *available;
440
441 *skip -= jump;
442 *available -= jump;
443 *pos += jump;
444}
445
447 struct nsgif *gif,
448 fl::u32 width,
449 fl::u32 height,
450 fl::u32 offset_x,
451 fl::u32 offset_y,
452 fl::u32 interlace,
453 const fl::u8 *data,
454 fl::u32 transparency_index,
455 fl::u32 * frame_data,
456 fl::u32 * colour_table) FL_NOEXCEPT
457{
458 lzw_result res;
459 nsgif_error ret = NSGIF_OK;
460 fl::u32 clip_x = gif__clip(offset_x, width, gif->info.width);
461 fl::u32 clip_y = gif__clip(offset_y, height, gif->info.height);
462 const fl::u8 *uncompressed;
463 fl::u32 available = 0;
464 fl::u8 step = 24;
465 fl::u32 skip = 0;
466 fl::u32 y = 0;
467
468 if (offset_x >= gif->info.width ||
469 offset_y >= gif->info.height) {
470 return NSGIF_OK;
471 }
472
473 width -= clip_x;
474 height -= clip_y;
475
476 if (width == 0 || height == 0) {
477 return NSGIF_OK;
478 }
479
480 /* Initialise the LZW decoding */
481 res = lzw_decode_init(static_cast<struct lzw_ctx*>(gif->lzw_ctx), data[0],
482 gif->buf, gif->buf_len,
483 data + 1 - gif->buf);
484 if (res != LZW_OK) {
485 return nsgif__error_from_lzw(res);
486 }
487
488 do {
489 fl::u32 x;
490 fl::u32 *frame_scanline;
491
492 frame_scanline = frame_data + offset_x +
493 (y + offset_y) * gif->rowspan;
494
495 x = width;
496 while (x > 0) {
497 unsigned row_available;
498 while (available == 0) {
499 if (res != LZW_OK) {
500 /* Unexpected end of frame, try to recover */
501 if (res == LZW_OK_EOD ||
502 res == LZW_EOI_CODE) {
503 ret = NSGIF_OK;
504 } else {
505 ret = nsgif__error_from_lzw(res);
506 }
507 return ret;
508 }
509 res = lzw_decode(static_cast<struct lzw_ctx*>(gif->lzw_ctx),
510 &uncompressed, &available);
511
512 if (available == 0) {
513 return NSGIF_OK;
514 }
515 gif__jump_data(&skip, &available, &uncompressed);
516 }
517
518 row_available = x < available ? x : available;
519 x -= row_available;
520 available -= row_available;
521 if (transparency_index > 0xFF) {
522 while (row_available-- > 0) {
523 *frame_scanline++ =
524 colour_table[*uncompressed++];
525 }
526 } else {
527 while (row_available-- > 0) {
528 fl::u32 colour;
529 colour = *uncompressed++;
530 if (colour != transparency_index) {
531 *frame_scanline =
532 colour_table[colour];
533 }
534 frame_scanline++;
535 }
536 }
537 }
538
539 skip = clip_x;
540 gif__jump_data(&skip, &available, &uncompressed);
541 } while (nsgif__next_row(interlace, height, &y, &step));
542
543 return ret;
544}
545
547 struct nsgif *gif,
548 fl::u32 height,
549 fl::u32 offset_y,
550 const fl::u8 *data,
551 fl::u32 transparency_index,
552 fl::u32 * frame_data,
553 fl::u32 * colour_table) FL_NOEXCEPT
554{
555 fl::u32 pixels;
556 fl::u32 written = 0;
557 nsgif_error ret = NSGIF_OK;
558 lzw_result res;
559
560 if (offset_y >= gif->info.height) {
561 return NSGIF_OK;
562 }
563
564 height -= gif__clip(offset_y, height, gif->info.height);
565
566 if (height == 0) {
567 return NSGIF_OK;
568 }
569
570 /* Initialise the LZW decoding */
571 res = lzw_decode_init_map(static_cast<struct lzw_ctx*>(gif->lzw_ctx), data[0],
572 transparency_index, colour_table,
573 gif->buf, gif->buf_len,
574 data + 1 - gif->buf);
575 if (res != LZW_OK) {
576 return nsgif__error_from_lzw(res);
577 }
578
579 frame_data += (offset_y * gif->info.width);
580 pixels = gif->info.width * height;
581
582 while (pixels > 0) {
583 res = lzw_decode_map(static_cast<struct lzw_ctx*>(gif->lzw_ctx),
584 frame_data, pixels, &written);
585 pixels -= written;
586 frame_data += written;
587 if (res != LZW_OK) {
588 /* Unexpected end of frame, try to recover */
589 if (res == LZW_OK_EOD || res == LZW_EOI_CODE) {
590 ret = NSGIF_OK;
591 } else {
592 ret = nsgif__error_from_lzw(res);
593 }
594 break;
595 }
596 }
597
598 if (pixels == 0) {
599 ret = NSGIF_OK;
600 }
601
602 return ret;
603}
604
606 struct nsgif *gif,
607 struct nsgif_frame *frame,
608 const fl::u8 *data,
609 fl::u32 * frame_data) FL_NOEXCEPT
610{
611 nsgif_error ret;
612 fl::u32 width = frame->info.rect.x1 - frame->info.rect.x0;
613 fl::u32 height = frame->info.rect.y1 - frame->info.rect.y0;
614 fl::u32 offset_x = frame->info.rect.x0;
615 fl::u32 offset_y = frame->info.rect.y0;
616 fl::u32 transparency_index = frame->transparency_index;
617 fl::u32 * colour_table = gif->colour_table;
618
619 if (frame->info.interlaced == false && offset_x == 0 &&
620 width == gif->info.width &&
621 width == gif->rowspan) {
622 ret = nsgif__decode_simple(gif, height, offset_y,
623 data, transparency_index,
624 frame_data, colour_table);
625 } else {
627 offset_x, offset_y, frame->info.interlaced,
628 data, transparency_index,
629 frame_data, colour_table);
630 }
631
632 if (gif->data_complete && ret == NSGIF_ERR_END_OF_DATA) {
633 /* This is all the data there is, so make do. */
634 ret = NSGIF_OK;
635 }
636
637 return ret;
638}
639
648 struct nsgif *gif,
649 struct nsgif_frame *frame,
650 fl::u32 *bitmap) FL_NOEXCEPT
651{
652 fl::size pixel_bytes = sizeof(*bitmap);
653
654 if (frame == nullptr) {
655 fl::size width = gif->info.width;
656 fl::size height = gif->info.height;
657
659 width * height * pixel_bytes);
660 } else {
661 fl::u32 width = frame->info.rect.x1 - frame->info.rect.x0;
662 fl::u32 height = frame->info.rect.y1 - frame->info.rect.y0;
663 fl::u32 offset_x = frame->info.rect.x0;
664 fl::u32 offset_y = frame->info.rect.y0;
665
666 if (frame->info.display == false ||
667 frame->info.rect.x0 >= gif->info.width ||
668 frame->info.rect.y0 >= gif->info.height) {
669 return;
670 }
671
672 width -= gif__clip(offset_x, width, gif->info.width);
673 height -= gif__clip(offset_y, height, gif->info.height);
674
675 if (frame->info.transparency) {
676 for (fl::u32 y = 0; y < height; y++) {
677 fl::u32 *scanline = bitmap + offset_x +
678 (offset_y + y) * gif->info.width;
680 width * pixel_bytes);
681 }
682 } else {
683 for (fl::u32 y = 0; y < height; y++) {
684 fl::u32 *scanline = bitmap + offset_x +
685 (offset_y + y) * gif->info.width;
686 for (fl::u32 x = 0; x < width; x++) {
687 scanline[x] = gif->info.background;
688 }
689 }
690 }
691 }
692}
693
695 struct nsgif *gif,
696 struct nsgif_frame *frame,
697 const fl::u8 *data,
698 fl::u32 frame_idx) FL_NOEXCEPT
699{
700 nsgif_error ret;
701 fl::u32 *bitmap;
702
703 gif->decoded_frame = frame_idx;
704
705 bitmap = nsgif__bitmap_get(gif);
706 if (bitmap == nullptr) {
707 return NSGIF_ERR_OOM;
708 }
709
710 /* Handle any bitmap clearing/restoration required before decoding this
711 * frame. */
712 if (frame_idx == 0 || gif->decoded_frame == NSGIF_FRAME_INVALID) {
713 nsgif__restore_bg(gif, nullptr, bitmap);
714
715 } else {
716 struct nsgif_frame *prev = &gif->frames[frame_idx - 1];
717
719 nsgif__restore_bg(gif, prev, bitmap);
720
721 } else if (prev->info.disposal == NSGIF_DISPOSAL_RESTORE_PREV) {
722 ret = nsgif__recover_frame(gif, bitmap);
723 if (ret != NSGIF_OK) {
724 nsgif__restore_bg(gif, prev, bitmap);
725 }
726 }
727 }
728
729 if (frame->info.disposal == NSGIF_DISPOSAL_RESTORE_PREV) {
730 /* Store the previous frame for later restoration */
731 nsgif__record_frame(gif, bitmap);
732 }
733
734 ret = nsgif__decode(gif, frame, data, bitmap);
735
737
738 if (!frame->decoded) {
739 frame->opaque = nsgif__bitmap_get_opaque(gif);
740 frame->decoded = true;
741 }
742 nsgif__bitmap_set_opaque(gif, frame);
743
744 return ret;
745}
746
757 struct nsgif_frame *frame,
758 const fl::u8 *data,
759 fl::size len) FL_NOEXCEPT
760{
761 enum {
762 GIF_MASK_TRANSPARENCY = 0x01,
763 GIF_MASK_DISPOSAL = 0x1c,
764 };
765
766 /* 6-byte Graphic Control Extension is:
767 *
768 * +0 CHAR Graphic Control Label
769 * +1 CHAR Block Size
770 * +2 CHAR __Packed Fields__
771 * 3BITS Reserved
772 * 3BITS Disposal Method
773 * 1BIT User Input Flag
774 * 1BIT Transparent Color Flag
775 * +3 SHORT Delay Time
776 * +5 CHAR Transparent Color Index
777 */
778 if (len < 6) {
780 }
781
782 frame->info.delay = data[3] | (data[4] << 8);
783
784 if (data[2] & GIF_MASK_TRANSPARENCY) {
785 frame->info.transparency = true;
786 frame->transparency_index = data[5];
787 }
788
789 frame->info.disposal = ((data[2] & GIF_MASK_DISPOSAL) >> 2);
790 /* I have encountered documentation and GIFs in the
791 * wild that use 0x04 to restore the previous frame,
792 * rather than the officially documented 0x03. I
793 * believe some (older?) software may even actually
794 * export this way. We handle this as a type of
795 * "quirks" mode. */
796 if (frame->info.disposal == NSGIF_DISPOSAL_RESTORE_QUIRK) {
797 frame->info.disposal = NSGIF_DISPOSAL_RESTORE_PREV;
798 }
799
800 /* if we are clearing the background then we need to
801 * redraw enough to cover the previous frame too. */
802 frame->redraw_required =
803 frame->info.disposal == NSGIF_DISPOSAL_RESTORE_BG ||
804 frame->info.disposal == NSGIF_DISPOSAL_RESTORE_PREV;
805
806 return NSGIF_OK;
807}
808
817 const fl::u8 *data,
818 fl::size len) FL_NOEXCEPT
819{
820 enum {
821 EXT_LOOP_COUNT_BLOCK_SIZE = 0x0b,
822 };
823
824 FL_ASSERT(len > 13, "Extension data too short");
825 (void)(len);
826
827 if (data[1] == EXT_LOOP_COUNT_BLOCK_SIZE) {
828 if (strncmp((const char *)data + 2, "NETSCAPE2.0", 11) == 0 ||
829 strncmp((const char *)data + 2, "ANIMEXTS1.0", 11) == 0) {
830 return true;
831 }
832 }
833
834 return false;
835}
836
847 struct nsgif *gif,
848 const fl::u8 *data,
849 fl::size len) FL_NOEXCEPT
850{
851 /* 14-byte+ Application Extension is:
852 *
853 * +0 CHAR Application Extension Label
854 * +1 CHAR Block Size
855 * +2 8CHARS Application Identifier
856 * +10 3CHARS Appl. Authentication Code
857 * +13 1-256 Application Data (Data sub-blocks)
858 */
859 if (len < 17) {
861 }
862
863 if (nsgif__app_ext_is_loop_count(data, len)) {
864 enum {
865 EXT_LOOP_COUNT_SUB_BLOCK_SIZE = 0x03,
866 EXT_LOOP_COUNT_SUB_BLOCK_ID = 0x01,
867 };
868 if ((data[13] == EXT_LOOP_COUNT_SUB_BLOCK_SIZE) &&
869 (data[14] == EXT_LOOP_COUNT_SUB_BLOCK_ID)) {
870 gif->info.loop_max = data[15] | (data[16] << 8);
871
872 /* The value in the source data means repeat N times
873 * after the first implied play. A value of zero has
874 * the special meaning of loop forever. (The only way
875 * to play the animation once is not to have this
876 * extension at all. */
877 if (gif->info.loop_max > 0) {
878 gif->info.loop_max++;
879 }
880 }
881 }
882
883 return NSGIF_OK;
884}
885
897 struct nsgif *gif,
898 struct nsgif_frame *frame,
899 const fl::u8 **pos,
900 bool decode) FL_NOEXCEPT
901{
902 enum {
903 GIF_EXT_INTRODUCER = 0x21,
904 GIF_EXT_GRAPHIC_CONTROL = 0xf9,
905 GIF_EXT_COMMENT = 0xfe,
906 GIF_EXT_PLAIN_TEXT = 0x01,
907 GIF_EXT_APPLICATION = 0xff,
908 };
909 const fl::u8 *nsgif_data = *pos;
910 const fl::u8 *nsgif_end = gif->buf + gif->buf_len;
911 int nsgif_bytes = nsgif_end - nsgif_data;
912
913 /* Initialise the extensions */
914 while (nsgif_bytes > 0 && nsgif_data[0] == GIF_EXT_INTRODUCER) {
915 bool block_step = true;
916 nsgif_error ret;
917
918 nsgif_data++;
919 nsgif_bytes--;
920
921 if (nsgif_bytes == 0) {
923 }
924
925 /* Switch on extension label */
926 switch (nsgif_data[0]) {
927 case GIF_EXT_GRAPHIC_CONTROL:
928 if (decode) {
930 frame,
931 nsgif_data,
932 nsgif_bytes);
933 if (ret != NSGIF_OK) {
934 return ret;
935 }
936 }
937 break;
938
939 case GIF_EXT_APPLICATION:
940 if (decode) {
942 gif, nsgif_data, nsgif_bytes);
943 if (ret != NSGIF_OK) {
944 return ret;
945 }
946 }
947 break;
948
949 case GIF_EXT_COMMENT:
950 /* Move the pointer to the first data sub-block Skip 1
951 * byte for the extension label. */
952 ++nsgif_data;
953 block_step = false;
954 break;
955
956 default:
957 break;
958 }
959
960 if (block_step) {
961 /* Move the pointer to the first data sub-block Skip 2
962 * bytes for the extension label and size fields Skip
963 * the extension size itself
964 */
965 if (nsgif_bytes < 2) {
967 }
968 nsgif_data += 2 + nsgif_data[1];
969 }
970
971 /* Repeatedly skip blocks until we get a zero block or run out
972 * of data. This data is ignored by this gif decoder. */
973 while (nsgif_data < nsgif_end && nsgif_data[0] != NSGIF_BLOCK_TERMINATOR) {
974 nsgif_data += nsgif_data[0] + 1;
975 if (nsgif_data >= nsgif_end) {
977 }
978 }
979 nsgif_data++;
980 nsgif_bytes = nsgif_end - nsgif_data;
981 }
982
983 if (nsgif_data > nsgif_end) {
984 nsgif_data = nsgif_end;
985 }
986
987 /* Set buffer position and return */
988 *pos = nsgif_data;
989 return NSGIF_OK;
990}
991
1016 struct nsgif *gif,
1017 struct nsgif_frame *frame,
1018 const fl::u8 **pos,
1019 bool decode) FL_NOEXCEPT
1020{
1021 const fl::u8 *data = *pos;
1022 fl::size len = gif->buf + gif->buf_len - data;
1023 enum {
1024 NSGIF_IMAGE_DESCRIPTOR_LEN = 10u,
1025 NSGIF_IMAGE_SEPARATOR = 0x2Cu,
1026 NSGIF_MASK_INTERLACE = 0x40u,
1027 };
1028
1029 FL_ASSERT(gif != nullptr, "GIF object required");
1030 FL_ASSERT(frame != nullptr, "Frame object required");
1031
1032 if (len < NSGIF_IMAGE_DESCRIPTOR_LEN) {
1033 return NSGIF_ERR_END_OF_DATA;
1034 }
1035
1036 if (decode) {
1037 fl::u32 x, y, w, h;
1038
1039 if (data[0] != NSGIF_IMAGE_SEPARATOR) {
1040 return NSGIF_ERR_DATA_FRAME;
1041 }
1042
1043 x = data[1] | (data[2] << 8);
1044 y = data[3] | (data[4] << 8);
1045 w = data[5] | (data[6] << 8);
1046 h = data[7] | (data[8] << 8);
1047 frame->flags = data[9];
1048
1049 frame->info.rect.x0 = x;
1050 frame->info.rect.y0 = y;
1051 frame->info.rect.x1 = x + w;
1052 frame->info.rect.y1 = y + h;
1053
1054 frame->info.interlaced = frame->flags & NSGIF_MASK_INTERLACE;
1055
1056 /* Allow first frame to grow image dimensions. */
1057 if (gif->info.frame_count == 0) {
1058 if (x + w > gif->info.width) {
1059 gif->info.width = x + w;
1060 }
1061 if (y + h > gif->info.height) {
1062 gif->info.height = y + h;
1063 }
1064 }
1065 }
1066
1067 *pos += NSGIF_IMAGE_DESCRIPTOR_LEN;
1068 return NSGIF_OK;
1069}
1070
1080 fl::u32 colour_table[NSGIF_MAX_COLOURS],
1081 const struct nsgif_colour_layout *layout,
1082 fl::size colour_table_entries,
1083 const fl::u8 *data) FL_NOEXCEPT
1084{
1085 fl::u8 *entry = (fl::u8 *)colour_table;
1086
1087 while (colour_table_entries--) {
1088 /* Gif colour map contents are r,g,b.
1089 *
1090 * We want to pack them bytewise into the colour table,
1091 * according to the client colour layout.
1092 */
1093
1094 entry[layout->r] = *data++;
1095 entry[layout->g] = *data++;
1096 entry[layout->b] = *data++;
1097 entry[layout->a] = 0xff;
1098
1099 entry += sizeof(fl::u32);
1100 }
1101}
1102
1116 fl::u32 colour_table[NSGIF_MAX_COLOURS],
1117 const struct nsgif_colour_layout *layout,
1118 fl::size colour_table_entries,
1119 const fl::u8 *data,
1120 fl::size data_len,
1121 fl::size *used,
1122 bool decode) FL_NOEXCEPT
1123{
1124 if (data_len < colour_table_entries * 3) {
1125 return NSGIF_ERR_END_OF_DATA;
1126 }
1127
1128 if (decode) {
1129 nsgif__colour_table_decode(colour_table, layout,
1130 colour_table_entries, data);
1131 }
1132
1133 *used = colour_table_entries * 3;
1134 return NSGIF_OK;
1135}
1136
1149 struct nsgif *gif,
1150 struct nsgif_frame *frame,
1151 const fl::u8 **pos,
1152 bool decode) FL_NOEXCEPT
1153{
1154 nsgif_error ret;
1155 const fl::u8 *data = *pos;
1156 fl::size len = gif->buf + gif->buf_len - data;
1157 fl::size used_bytes;
1158
1159 FL_ASSERT(gif != nullptr, "GIF object required");
1160 FL_ASSERT(frame != nullptr, "Frame object required");
1161
1162 if ((frame->flags & NSGIF_COLOUR_TABLE_MASK) == 0) {
1163 gif->colour_table = gif->global_colour_table;
1164 return NSGIF_OK;
1165 }
1166
1167 if (decode == false) {
1168 frame->colour_table_offset = *pos - gif->buf;
1169 }
1170
1172 gif->local_colour_table, &gif->colour_layout,
1173 2 << (frame->flags & NSGIF_COLOUR_TABLE_SIZE_MASK),
1174 data, len, &used_bytes, decode);
1175 if (ret != NSGIF_OK) {
1176 return ret;
1177 }
1178 *pos += used_bytes;
1179
1180 if (decode) {
1181 gif->colour_table = gif->local_colour_table;
1182 } else {
1183 frame->info.local_palette = true;
1184 }
1185
1186 return NSGIF_OK;
1187}
1188
1201 struct nsgif *gif,
1202 struct nsgif_frame *frame,
1203 const fl::u8 **pos,
1204 bool decode) FL_NOEXCEPT
1205{
1206 const fl::u8 *data = *pos;
1207 fl::size len = gif->buf + gif->buf_len - data;
1208 fl::u32 frame_idx = frame - gif->frames;
1209 fl::u8 minimum_code_size;
1210 nsgif_error ret;
1211
1212 FL_ASSERT(gif != nullptr, "GIF object required");
1213 FL_ASSERT(frame != nullptr, "Frame object required");
1214
1215 if (!decode) {
1216 gif->frame_count_partial = frame_idx + 1;
1217 }
1218
1219 /* Ensure sufficient data remains. A gif trailer or a minimum lzw code
1220 * followed by a gif trailer is treated as OK, although without any
1221 * image data. */
1222 switch (len) {
1223 default: if (data[0] == NSGIF_TRAILER) return NSGIF_OK;
1224 break;
1225 case 2: if (data[1] == NSGIF_TRAILER) return NSGIF_OK;
1226 /* Fall through. */
1227 case 1: if (data[0] == NSGIF_TRAILER) return NSGIF_OK;
1228 /* Fall through. */
1229 case 0: return NSGIF_ERR_END_OF_DATA;
1230 }
1231
1232 minimum_code_size = data[0];
1233 if (minimum_code_size >= LZW_CODE_MAX) {
1234 return NSGIF_ERR_DATA_FRAME;
1235 }
1236
1237 if (decode) {
1238 ret = nsgif__update_bitmap(gif, frame, data, frame_idx);
1239 } else {
1240 fl::u32 block_size = 0;
1241
1242 /* Skip the minimum code size. */
1243 data++;
1244 len--;
1245
1246 while (block_size != 1) {
1247 if (len < 1) {
1248 return NSGIF_ERR_END_OF_DATA;
1249 }
1250 block_size = data[0] + 1;
1251 /* Check if the frame data runs off the end of the file */
1252 if (block_size > len) {
1253 frame->lzw_data_length += len;
1254 return NSGIF_ERR_END_OF_DATA;
1255 }
1256
1257 len -= block_size;
1258 data += block_size;
1259 frame->lzw_data_length += block_size;
1260 }
1261
1262 *pos = data;
1263
1264 gif->info.frame_count = frame_idx + 1;
1265 gif->frames[frame_idx].info.display = true;
1266
1267 return NSGIF_OK;
1268 }
1269
1270 return ret;
1271}
1272
1274 struct nsgif *gif,
1275 fl::u32 frame_idx) FL_NOEXCEPT
1276{
1277 struct nsgif_frame *frame;
1278
1279 if (gif->frame_holders > frame_idx) {
1280 frame = &gif->frames[frame_idx];
1281 } else {
1282 /* Allocate more memory */
1283 fl::size count = frame_idx + 1;
1284 struct nsgif_frame *temp;
1285
1286 temp = static_cast<struct nsgif_frame*>(fl::Malloc(count * sizeof(*frame)));
1287 if (temp == nullptr) {
1288 return nullptr;
1289 }
1290 if (gif->frames) {
1291 fl::memcpy(temp, gif->frames, gif->frame_holders * sizeof(*frame));
1292 fl::Free(gif->frames);
1293 }
1294 gif->frames = temp;
1295 gif->frame_holders = count;
1296
1297 frame = &gif->frames[frame_idx];
1298
1299 frame->info.local_palette = false;
1300 frame->info.transparency = false;
1301 frame->info.display = false;
1302 frame->info.disposal = 0;
1303 frame->info.delay = 10;
1304
1306 frame->frame_offset = gif->buf_pos;
1307 frame->redraw_required = false;
1308 frame->lzw_data_length = 0;
1309 frame->decoded = false;
1310 }
1311
1312 return frame;
1313}
1314
1324 struct nsgif *gif,
1325 fl::u32 frame_idx,
1326 bool decode) FL_NOEXCEPT
1327{
1328 nsgif_error ret;
1329 const fl::u8 *pos;
1330 const fl::u8 *end;
1331 struct nsgif_frame *frame;
1332
1333 frame = nsgif__get_frame(gif, frame_idx);
1334 if (frame == nullptr) {
1335 return NSGIF_ERR_OOM;
1336 }
1337
1338 end = gif->buf + gif->buf_len;
1339
1340 if (decode) {
1341 pos = gif->buf + frame->frame_offset;
1342
1343 /* Ensure this frame is supposed to be decoded */
1344 if (frame->info.display == false) {
1345 return NSGIF_OK;
1346 }
1347
1348 /* Ensure the frame is in range to decode */
1349 if (frame_idx > gif->frame_count_partial) {
1350 return NSGIF_ERR_END_OF_DATA;
1351 }
1352
1353 /* Done if frame is already decoded */
1354 if (frame_idx == gif->decoded_frame) {
1355 return NSGIF_OK;
1356 }
1357 } else {
1358 pos = gif->buf + gif->buf_pos;
1359
1360 /* Check if we've finished */
1361 if (pos < end && pos[0] == NSGIF_TRAILER) {
1362 return NSGIF_OK;
1363 }
1364 }
1365
1366 ret = nsgif__parse_frame_extensions(gif, frame, &pos, !decode);
1367 if (ret != NSGIF_OK) {
1368 goto cleanup;
1369 }
1370
1371 ret = nsgif__parse_image_descriptor(gif, frame, &pos, !decode);
1372 if (ret != NSGIF_OK) {
1373 goto cleanup;
1374 }
1375
1376 ret = nsgif__parse_colour_table(gif, frame, &pos, decode);
1377 if (ret != NSGIF_OK) {
1378 goto cleanup;
1379 }
1380
1381 ret = nsgif__parse_image_data(gif, frame, &pos, decode);
1382 if (ret != NSGIF_OK) {
1383 goto cleanup;
1384 }
1385
1386cleanup:
1387 if (!decode) {
1388 gif->buf_pos = pos - gif->buf;
1389 }
1390
1391 return ret;
1392}
1393
1394/* exported function documented in nsgif.h */
1396{
1397 if (gif == nullptr) {
1398 return;
1399 }
1400
1401 /* Release all our memory blocks */
1402 if (gif->frame_image) {
1403 FL_ASSERT(gif->bitmap.destroy, "GIF bitmap destroy function required");
1404 gif->bitmap.destroy(gif->frame_image);
1405 gif->frame_image = nullptr;
1406 }
1407
1408 fl::Free(gif->frames);
1409 gif->frames = nullptr;
1410
1411 fl::Free(gif->prev_frame);
1412 gif->prev_frame = nullptr;
1413
1414 lzw_context_destroy(static_cast<struct lzw_ctx*>(gif->lzw_ctx));
1415 gif->lzw_ctx = nullptr;
1416
1417 fl::Free(gif);
1418}
1419
1428{
1429 const fl::u16 test = 1;
1430
1431 return ((const fl::u8 *) &test)[0];
1432}
1433
1436{
1437 bool le = nsgif__host_is_little_endian();
1438
1439 /* Map endian-dependant formats to byte-wise format for the host. */
1440 switch (bitmap_fmt) {
1442 bitmap_fmt = (le) ? NSGIF_BITMAP_FMT_A8B8G8R8
1444 break;
1446 bitmap_fmt = (le) ? NSGIF_BITMAP_FMT_A8R8G8B8
1448 break;
1450 bitmap_fmt = (le) ? NSGIF_BITMAP_FMT_B8G8R8A8
1452 break;
1454 bitmap_fmt = (le) ? NSGIF_BITMAP_FMT_R8G8B8A8
1456 break;
1461 /* These are already byte-wise formats, no conversion needed */
1462 break;
1463 default:
1464 break;
1465 }
1466
1467 /* Set up colour component order for bitmap format. */
1468 switch (bitmap_fmt) {
1469 default:
1470 /* Fall through. */
1472 { struct nsgif_colour_layout result = {0, 1, 2, 3}; return result; }
1473
1475 { struct nsgif_colour_layout result = {2, 1, 0, 3}; return result; }
1476
1478 { struct nsgif_colour_layout result = {1, 2, 3, 0}; return result; }
1479
1481 { struct nsgif_colour_layout result = {3, 2, 1, 0}; return result; }
1482
1487 /* These should have been converted to byte-wise formats above */
1488 { struct nsgif_colour_layout result = {0, 1, 2, 3}; return result; }
1489 }
1490}
1491
1492/* exported function documented in nsgif.h */
1494 const nsgif_bitmap_cb_vt *bitmap_vt,
1495 nsgif_bitmap_fmt_t bitmap_fmt,
1496 nsgif_t **gif_out) FL_NOEXCEPT
1497{
1498 nsgif_t *gif;
1499
1500 gif = static_cast<nsgif_t*>(fl::Malloc(sizeof(*gif)));
1501 if (gif) {
1502 fl::memset(gif, 0, sizeof(*gif));
1503 }
1504 if (gif == nullptr) {
1505 return NSGIF_ERR_OOM;
1506 }
1507
1508 gif->bitmap = *bitmap_vt;
1511
1514
1516
1517 *gif_out = gif;
1518 return NSGIF_OK;
1519}
1520
1521/* exported function documented in nsgif.h */
1523 nsgif_t *gif,
1524 fl::u16 delay_min,
1525 fl::u16 delay_default) FL_NOEXCEPT
1526{
1527 gif->delay_min = delay_min;
1528 gif->delay_default = delay_default;
1529}
1530
1545 struct nsgif *gif,
1546 const fl::u8 **pos,
1547 bool strict) FL_NOEXCEPT
1548{
1549 const fl::u8 *data = *pos;
1550 fl::size len = gif->buf + gif->buf_len - data;
1551
1552 if (len < 6) {
1553 return NSGIF_ERR_END_OF_DATA;
1554 }
1555
1556 if (strncmp((const char *) data, "GIF", 3) != 0) {
1557 return NSGIF_ERR_DATA;
1558 }
1559 data += 3;
1560
1561 if (strict == true) {
1562 if ((strncmp((const char *) data, "87a", 3) != 0) &&
1563 (strncmp((const char *) data, "89a", 3) != 0)) {
1564 return NSGIF_ERR_DATA;
1565 }
1566 }
1567 data += 3;
1568
1569 *pos = data;
1570 return NSGIF_OK;
1571}
1572
1593 struct nsgif *gif,
1594 const fl::u8 **pos) FL_NOEXCEPT
1595{
1596 const fl::u8 *data = *pos;
1597 fl::size len = gif->buf + gif->buf_len - data;
1598
1599 if (len < 7) {
1600 return NSGIF_ERR_END_OF_DATA;
1601 }
1602
1603 gif->info.width = data[0] | (data[1] << 8);
1604 gif->info.height = data[2] | (data[3] << 8);
1605 gif->info.global_palette = data[4] & NSGIF_COLOUR_TABLE_MASK;
1606 gif->colour_table_size = 2 << (data[4] & NSGIF_COLOUR_TABLE_SIZE_MASK);
1607 gif->bg_index = data[5];
1608 gif->aspect_ratio = data[6];
1609 gif->info.loop_max = 1;
1610
1611 *pos += 7;
1612 return NSGIF_OK;
1613}
1614
1615/* exported function documented in nsgif.h */
1617 nsgif_t *gif,
1618 fl::size size,
1619 const fl::u8 *data) FL_NOEXCEPT
1620{
1621 const fl::u8 *nsgif_data;
1622 nsgif_error ret;
1623 fl::u32 frames;
1624
1625 if (gif->data_complete) {
1627 }
1628
1629 /* Initialize values */
1630 gif->buf_len = size;
1631 gif->buf = data;
1632
1633 /* Get our current processing position */
1634 nsgif_data = gif->buf + gif->buf_pos;
1635
1636 /* See if we should initialise the GIF */
1637 if (gif->buf_pos == 0) {
1638 /* We want everything to be NULL before we start so we've no
1639 * chance of freeing bad pointers (paranoia)
1640 */
1641 gif->frame_image = nullptr;
1642 gif->frames = nullptr;
1643 gif->frame_holders = 0;
1644
1645 /* The caller may have been lazy and not reset any values */
1646 gif->info.frame_count = 0;
1647 gif->frame_count_partial = 0;
1648 gif->decoded_frame = NSGIF_FRAME_INVALID;
1649 gif->frame = NSGIF_FRAME_INVALID;
1650
1651 ret = nsgif__parse_header(gif, &nsgif_data, false);
1652 if (ret != NSGIF_OK) {
1653 return ret;
1654 }
1655
1656 ret = nsgif__parse_logical_screen_descriptor(gif, &nsgif_data);
1657 if (ret != NSGIF_OK) {
1658 return ret;
1659 }
1660
1661 /* Remember we've done this now */
1662 gif->buf_pos = nsgif_data - gif->buf;
1663
1664 /* Some broken GIFs report the size as the screen size they
1665 * were created in. As such, we detect for the common cases and
1666 * set the sizes as 0 if they are found which results in the
1667 * GIF being the maximum size of the frames.
1668 */
1669 if (((gif->info.width == 640) && (gif->info.height == 480)) ||
1670 ((gif->info.width == 640) && (gif->info.height == 512)) ||
1671 ((gif->info.width == 800) && (gif->info.height == 600)) ||
1672 ((gif->info.width == 1024) && (gif->info.height == 768)) ||
1673 ((gif->info.width == 1280) && (gif->info.height == 1024)) ||
1674 ((gif->info.width == 1600) && (gif->info.height == 1200)) ||
1675 ((gif->info.width == 0) || (gif->info.height == 0)) ||
1676 ((gif->info.width > 2048) || (gif->info.height > 2048))) {
1677 gif->info.width = 1;
1678 gif->info.height = 1;
1679 }
1680
1681 /* Set the first colour to a value that will never occur in
1682 * reality so we know if we've processed it
1683 */
1684 gif->global_colour_table[0] = NSGIF_PROCESS_COLOURS;
1685
1686 /* Check if the GIF has no frame data (13-byte header + 1-byte
1687 * termination block) Although generally useless, the GIF
1688 * specification does not expressly prohibit this
1689 */
1690 if (gif->buf_len == gif->buf_pos + 1) {
1691 if (nsgif_data[0] == NSGIF_TRAILER) {
1692 return NSGIF_OK;
1693 }
1694 }
1695 }
1696
1697 /* Do the colour map if we haven't already. As the top byte is always
1698 * 0xff or 0x00 depending on the transparency we know if it's been
1699 * filled in.
1700 */
1701 if (gif->global_colour_table[0] == NSGIF_PROCESS_COLOURS) {
1702 /* Check for a global colour map signified by bit 7 */
1703 if (gif->info.global_palette) {
1704 fl::size remaining = gif->buf + gif->buf_len - nsgif_data;
1705 fl::size used;
1706
1708 gif->global_colour_table,
1709 &gif->colour_layout,
1710 gif->colour_table_size,
1711 nsgif_data, remaining, &used, true);
1712 if (ret != NSGIF_OK) {
1713 return ret;
1714 }
1715
1716 nsgif_data += used;
1717 gif->buf_pos = (nsgif_data - gif->buf);
1718 } else {
1719 /* Create a default colour table with the first two
1720 * colours as black and white. */
1721 fl::u8 *entry = (fl::u8 *)gif->global_colour_table;
1722
1723 /* Black */
1724 entry[gif->colour_layout.r] = 0x00;
1725 entry[gif->colour_layout.g] = 0x00;
1726 entry[gif->colour_layout.b] = 0x00;
1727 entry[gif->colour_layout.a] = 0xFF;
1728
1729 entry += sizeof(fl::u32);
1730
1731 /* White */
1732 entry[gif->colour_layout.r] = 0xFF;
1733 entry[gif->colour_layout.g] = 0xFF;
1734 entry[gif->colour_layout.b] = 0xFF;
1735 entry[gif->colour_layout.a] = 0xFF;
1736
1737 gif->colour_table_size = 2;
1738 }
1739
1740 if (gif->info.global_palette &&
1741 gif->bg_index < gif->colour_table_size) {
1742 fl::size bg_idx = gif->bg_index;
1743 gif->info.background = gif->global_colour_table[bg_idx];
1744 } else {
1745 gif->info.background = gif->global_colour_table[0];
1746 }
1747 }
1748
1749 if (gif->lzw_ctx == nullptr) {
1750 struct lzw_ctx *lzw_ctx_ptr = nullptr;
1751 lzw_result res = lzw_context_create(&lzw_ctx_ptr);
1752 gif->lzw_ctx = lzw_ctx_ptr;
1753 if (res != LZW_OK) {
1754 return nsgif__error_from_lzw(res);
1755 }
1756 }
1757
1758 /* Try to initialise all frames. */
1759 do {
1760 frames = gif->info.frame_count;
1761 ret = nsgif__process_frame(gif, frames, false);
1762 } while (gif->info.frame_count > frames);
1763
1764 if (ret == NSGIF_ERR_END_OF_DATA && gif->info.frame_count > 0) {
1765 ret = NSGIF_OK;
1766 }
1767
1768 return ret;
1769}
1770
1771/* exported function documented in nsgif.h */
1773 nsgif_t *gif) FL_NOEXCEPT
1774{
1775 if (gif->data_complete == false) {
1776 fl::u32 start = gif->info.frame_count;
1777 fl::u32 end = gif->frame_count_partial;
1778
1779 for (fl::u32 f = start; f < end; f++) {
1780 nsgif_frame *frame = &gif->frames[f];
1781
1782 if (frame->lzw_data_length > 0) {
1783 frame->info.display = true;
1784 gif->info.frame_count = f + 1;
1785
1786 if (f == 0) {
1787 frame->info.transparency = true;
1788 }
1789 break;
1790 }
1791 }
1792 }
1793
1794 gif->data_complete = true;
1795}
1796
1798 const nsgif_rect_t *frame,
1799 nsgif_rect_t *redraw) FL_NOEXCEPT
1800{
1801 if (redraw->x1 == 0 || redraw->y1 == 0) {
1802 *redraw = *frame;
1803 } else {
1804 if (redraw->x0 > frame->x0) {
1805 redraw->x0 = frame->x0;
1806 }
1807 if (redraw->x1 < frame->x1) {
1808 redraw->x1 = frame->x1;
1809 }
1810 if (redraw->y0 > frame->y0) {
1811 redraw->y0 = frame->y0;
1812 }
1813 if (redraw->y1 < frame->y1) {
1814 redraw->y1 = frame->y1;
1815 }
1816 }
1817}
1818
1819static fl::u32 nsgif__frame_next(
1820 const nsgif_t *gif,
1821 bool partial,
1822 fl::u32 frame) FL_NOEXCEPT
1823{
1824 fl::u32 frames = partial ?
1825 gif->frame_count_partial :
1826 gif->info.frame_count;
1827
1828 if (frames == 0) {
1829 return NSGIF_FRAME_INVALID;
1830 }
1831
1832 frame++;
1833 return (frame >= frames) ? 0 : frame;
1834}
1835
1837 const nsgif_t *gif,
1838 fl::u32 *frame,
1839 fl::u32 *delay) FL_NOEXCEPT
1840{
1841 fl::u32 next = *frame;
1842
1843 do {
1844 next = nsgif__frame_next(gif, false, next);
1845 if (next <= *frame && *frame != NSGIF_FRAME_INVALID &&
1846 gif->data_complete == false) {
1847 return NSGIF_ERR_END_OF_DATA;
1848
1849 } else if (next == *frame || next == NSGIF_FRAME_INVALID) {
1851 }
1852
1853 if (delay != nullptr) {
1854 *delay += gif->frames[next].info.delay;
1855 }
1856
1857 } while (gif->frames[next].info.display == false);
1858
1859 *frame = next;
1860 return NSGIF_OK;
1861}
1862
1863static inline bool nsgif__animation_complete(int count, int max) FL_NOEXCEPT
1864{
1865 if (max == 0) {
1866 return false;
1867 }
1868
1869 return (count >= max);
1870}
1871
1873 nsgif_t *gif) FL_NOEXCEPT
1874{
1875 gif->loop_count = 0;
1876 gif->frame = NSGIF_FRAME_INVALID;
1877
1878 return NSGIF_OK;
1879}
1880
1881/* exported function documented in nsgif.h */
1883 nsgif_t *gif,
1884 nsgif_rect_t *area,
1885 fl::u32 *delay_cs,
1886 fl::u32 *frame_new) FL_NOEXCEPT
1887{
1888 nsgif_error ret;
1889 nsgif_rect_t rect = {0, 0, 0, 0};
1890 fl::u32 delay = 0;
1891 fl::u32 frame = gif->frame;
1892
1893 if (gif->frame != NSGIF_FRAME_INVALID &&
1894 gif->frame < gif->info.frame_count &&
1895 gif->frames[gif->frame].info.display) {
1896 rect = gif->frames[gif->frame].info.rect;
1897 }
1898
1900 gif->loop_count,
1901 gif->info.loop_max)) {
1903 }
1904
1905 ret = nsgif__next_displayable_frame(gif, &frame, &delay);
1906 if (ret != NSGIF_OK) {
1907 return ret;
1908 }
1909
1910 if (gif->frame != NSGIF_FRAME_INVALID && frame < gif->frame) {
1911 gif->loop_count++;
1912 }
1913
1914 if (gif->data_complete) {
1915 /* Check for last frame, which has infinite delay. */
1916
1917 if (gif->info.frame_count == 1) {
1919 } else if (gif->info.loop_max != 0) {
1920 fl::u32 frame_next = frame;
1921
1923 &frame_next, nullptr);
1924 if (ret != NSGIF_OK) {
1925 return ret;
1926 }
1927
1928 if (gif->data_complete && frame_next < frame) {
1930 gif->loop_count + 1,
1931 gif->info.loop_max)) {
1933 }
1934 }
1935 }
1936 }
1937
1938 gif->frame = frame;
1939 nsgif__redraw_rect_extend(&gif->frames[frame].info.rect, &rect);
1940
1941 if (delay < gif->delay_min) {
1942 delay = gif->delay_default;
1943 }
1944
1945 *frame_new = gif->frame;
1946 *delay_cs = delay;
1947 *area = rect;
1948
1949 return NSGIF_OK;
1950}
1951
1952/* exported function documented in nsgif.h */
1954 nsgif_t *gif,
1955 fl::u32 frame,
1956 nsgif_bitmap_t **bitmap) FL_NOEXCEPT
1957{
1958 fl::u32 start_frame;
1959 nsgif_error ret = NSGIF_OK;
1960
1961 if (frame >= gif->info.frame_count) {
1962 return NSGIF_ERR_BAD_FRAME;
1963 }
1964
1965 if (gif->decoded_frame == frame) {
1966 *bitmap = gif->frame_image;
1967 return NSGIF_OK;
1968
1969 } else if (gif->decoded_frame >= frame ||
1970 gif->decoded_frame == NSGIF_FRAME_INVALID) {
1971 /* Can skip to first frame or restart. */
1972 start_frame = 0;
1973 } else {
1974 start_frame = nsgif__frame_next(
1975 gif, false, gif->decoded_frame);
1976 }
1977
1978 for (fl::u32 f = start_frame; f <= frame; f++) {
1979 ret = nsgif__process_frame(gif, f, true);
1980 if (ret != NSGIF_OK) {
1981 return ret;
1982 }
1983 }
1984
1985 *bitmap = gif->frame_image;
1986 return ret;
1987}
1988
1989/* exported function documented in nsgif.h */
1991{
1992 return &gif->info;
1993}
1994
1995/* exported function documented in nsgif.h */
1997 const nsgif_t *gif,
1998 fl::u32 frame) FL_NOEXCEPT
1999{
2000 if (frame >= gif->info.frame_count) {
2001 return nullptr;
2002 }
2003
2004 return &gif->frames[frame].info;
2005}
2006
2007/* exported function documented in nsgif.h */
2009 const nsgif_t *gif,
2010 fl::u32 table[NSGIF_MAX_COLOURS],
2011 fl::size *entries) FL_NOEXCEPT
2012{
2013 fl::size len = sizeof(*table) * NSGIF_MAX_COLOURS;
2014
2015 fl::memcpy(table, gif->global_colour_table, len);
2016 *entries = gif->colour_table_size;
2017}
2018
2019/* exported function documented in nsgif.h */
2021 const nsgif_t *gif,
2022 fl::u32 frame,
2023 fl::u32 table[NSGIF_MAX_COLOURS],
2024 fl::size *entries) FL_NOEXCEPT
2025{
2026 const nsgif_frame *f;
2027
2028 if (frame >= gif->frame_count_partial) {
2029 return false;
2030 }
2031
2032 f = &gif->frames[frame];
2033 if (f->info.local_palette == false) {
2034 return false;
2035 }
2036
2037 *entries = 2 << (f->flags & NSGIF_COLOUR_TABLE_SIZE_MASK);
2038 nsgif__colour_table_decode(table, &gif->colour_layout,
2039 *entries, gif->buf + f->colour_table_offset);
2040
2041 return true;
2042}
2043
2044/* exported function documented in nsgif.h */
2046{
2047 static const char *const str[] = {
2048 "Success", /* NSGIF_OK */
2049 "Out of memory", /* NSGIF_ERR_OOM */
2050 "Invalid source data", /* NSGIF_ERR_DATA */
2051 "Requested frame does not exist", /* NSGIF_ERR_BAD_FRAME */
2052 "Invalid frame data", /* NSGIF_ERR_DATA_FRAME */
2053 "Unexpected end of GIF source data", /* NSGIF_ERR_END_OF_DATA */
2054 "Can't add data to completed GIF", /* NSGIF_ERR_DATA_COMPLETE */
2055 "Frame can't be displayed", /* NSGIF_ERR_FRAME_DISPLAY */
2056 "Animation complete", /* NSGIF_ERR_ANIMATION_END */
2057 };
2058
2059 if (err >= NSGIF_ARRAY_LEN(str) || str[err] == nullptr) {
2060 return "Unknown error";
2061 }
2062
2063 return str[err];
2064}
2065
2066/* exported function documented in nsgif.h */
2068{
2069 static const char *const str[] = {
2070 "Unspecified", /* NSGIF_DISPOSAL_UNSPECIFIED */
2071 "None", /* NSGIF_DISPOSAL_NONE */
2072 "Restore background", /* NSGIF_DISPOSAL_RESTORE_BG */
2073 "Restore previous", /* NSGIF_DISPOSAL_RESTORE_PREV */
2074 "Restore quirk", /* NSGIF_DISPOSAL_RESTORE_QUIRK */
2075 };
2076
2077 if (disposal >= NSGIF_ARRAY_LEN(str) || str[disposal] == nullptr) {
2078 return "Unspecified";
2079 }
2080
2081 return str[disposal];
2082}
2083
2084} // namespace third_party
2085} // namespace fl
uint8_t pos
Definition Blur.ino:11
#define FL_ASSERT(x, MSG)
Definition assert.h:6
#define LZW_CODE_MAX
Maximum LZW code size in bits.
Definition lzw.h:27
LZW decompression (interface)
unsigned char u8
Definition coder.h:132
@ NSGIF_BITMAP_FMT_A8B8G8R8
Bite-wise ABGR: Byte order: 0xAA, 0xBB, 0xGG, 0xRR.
Definition nsgif.hpp:128
@ NSGIF_BITMAP_FMT_R8G8B8A8
Bite-wise RGBA: Byte order: 0xRR, 0xGG, 0xBB, 0xAA.
Definition nsgif.hpp:119
@ NSGIF_BITMAP_FMT_ARGB8888
32-bit ARGB (0xAARRGGBB).
Definition nsgif.hpp:152
@ NSGIF_BITMAP_FMT_RGBA8888
32-bit RGBA (0xRRGGBBAA).
Definition nsgif.hpp:136
@ NSGIF_BITMAP_FMT_B8G8R8A8
Bite-wise BGRA: Byte order: 0xBB, 0xGG, 0xRR, 0xAA.
Definition nsgif.hpp:122
@ NSGIF_BITMAP_FMT_ABGR8888
32-bit BGRA (0xAABBGGRR).
Definition nsgif.hpp:160
@ NSGIF_BITMAP_FMT_BGRA8888
32-bit BGRA (0xBBGGRRAA).
Definition nsgif.hpp:144
@ NSGIF_BITMAP_FMT_A8R8G8B8
Bite-wise ARGB: Byte order: 0xAA, 0xRR, 0xGG, 0xBB.
Definition nsgif.hpp:125
static nsgif_error nsgif__parse_image_descriptor(struct nsgif *gif, struct nsgif_frame *frame, const fl::u8 **pos, bool decode) FL_NOEXCEPT
Parse a GIF Image Descriptor.
Definition gif.cpp.hpp:1015
lzw_result lzw_decode_init(struct lzw_ctx *ctx, fl::u8 minimum_code_size, const fl::u8 *input_data, fl::size input_length, fl::size input_pos) FL_NOEXCEPT
Initialise an LZW decompression context for decoding.
Definition lzw.cpp.hpp:263
lzw_result lzw_context_create(struct lzw_ctx **ctx) FL_NOEXCEPT
Create an LZW decompression context.
Definition lzw.cpp.hpp:104
static nsgif_error nsgif__initialise_sprite(struct nsgif *gif, fl::u32 width, fl::u32 height) FL_NOEXCEPT
Updates the sprite memory size.
Definition gif.cpp.hpp:208
void lzw_context_destroy(struct lzw_ctx *ctx) FL_NOEXCEPT
Destroy an LZW decompression context.
Definition lzw.cpp.hpp:116
void nsgif_set_frame_delay_behaviour(nsgif_t *gif, fl::u16 delay_min, fl::u16 delay_default) FL_NOEXCEPT
Configure handling of small frame delays.
Definition gif.cpp.hpp:1522
static void nsgif__restore_bg(struct nsgif *gif, struct nsgif_frame *frame, fl::u32 *bitmap) FL_NOEXCEPT
Restore a GIF to the background colour.
Definition gif.cpp.hpp:647
static nsgif_error nsgif__parse_logical_screen_descriptor(struct nsgif *gif, const fl::u8 **pos) FL_NOEXCEPT
Read Logical Screen Descriptor.
Definition gif.cpp.hpp:1592
static fl::u32 * nsgif__bitmap_get(struct nsgif *gif) FL_NOEXCEPT
Helper to get the rendering bitmap for a gif.
Definition gif.cpp.hpp:233
struct fl::third_party::nsgif_frame nsgif_frame
GIF frame data.
static void nsgif__record_frame(struct nsgif *gif, const fl::u32 *bitmap) FL_NOEXCEPT
Definition gif.cpp.hpp:302
static nsgif_error nsgif__decode_simple(struct nsgif *gif, fl::u32 height, fl::u32 offset_y, const fl::u8 *data, fl::u32 transparency_index, fl::u32 *frame_data, fl::u32 *colour_table) FL_NOEXCEPT
Definition gif.cpp.hpp:546
nsgif_error
LibNSGIF return codes.
Definition nsgif.hpp:58
@ NSGIF_ERR_DATA_COMPLETE
Can't supply more data after calling nsgif_data_complete.
Definition nsgif.hpp:92
@ NSGIF_ERR_OOM
Out of memory error.
Definition nsgif.hpp:67
@ NSGIF_ERR_BAD_FRAME
Frame number is not valid.
Definition nsgif.hpp:77
@ NSGIF_ERR_END_OF_DATA
Unexpected end of GIF source data.
Definition nsgif.hpp:87
@ NSGIF_ERR_ANIMATION_END
Indicates an animation is complete, and nsgif_reset must be called to restart the animation from the ...
Definition nsgif.hpp:103
@ NSGIF_ERR_DATA_FRAME
GIF source data contained an error in a frame.
Definition nsgif.hpp:82
@ NSGIF_ERR_DATA
GIF source data is invalid, and no frames are recoverable.
Definition nsgif.hpp:72
@ NSGIF_ERR_FRAME_DISPLAY
The current frame cannot be displayed.
Definition nsgif.hpp:97
@ NSGIF_OK
Success.
Definition nsgif.hpp:62
static nsgif_error nsgif__parse_header(struct nsgif *gif, const fl::u8 **pos, bool strict) FL_NOEXCEPT
Read GIF header.
Definition gif.cpp.hpp:1544
struct fl::third_party::nsgif_rect nsgif_rect_t
LibNSGIF rectangle structure.
struct fl::third_party::nsgif_frame_info nsgif_frame_info_t
Information about a GIF frame.
nsgif_error nsgif_frame_prepare(nsgif_t *gif, nsgif_rect_t *area, fl::u32 *delay_cs, fl::u32 *frame_new) FL_NOEXCEPT
Prepare to show a frame.
Definition gif.cpp.hpp:1882
static struct nsgif_colour_layout nsgif__bitmap_fmt_to_colour_layout(nsgif_bitmap_fmt_t bitmap_fmt) FL_NOEXCEPT
Definition gif.cpp.hpp:1434
static void nsgif__colour_table_decode(fl::u32 colour_table[NSGIF_MAX_COLOURS], const struct nsgif_colour_layout *layout, fl::size colour_table_entries, const fl::u8 *data) FL_NOEXCEPT
Extract a GIF colour table into a LibNSGIF colour table buffer.
Definition gif.cpp.hpp:1079
static bool nsgif__bitmap_get_opaque(const struct nsgif *gif) FL_NOEXCEPT
Helper to get the client to determine if the bitmap is opaque.
Definition gif.cpp.hpp:291
static nsgif_error nsgif__parse_frame_extensions(struct nsgif *gif, struct nsgif_frame *frame, const fl::u8 **pos, bool decode) FL_NOEXCEPT
Parse the frame's extensions.
Definition gif.cpp.hpp:896
nsgif_error nsgif_data_scan(nsgif_t *gif, fl::size size, const fl::u8 *data) FL_NOEXCEPT
Scan the source image data.
Definition gif.cpp.hpp:1616
static bool nsgif__app_ext_is_loop_count(const fl::u8 *data, fl::size len) FL_NOEXCEPT
Check an app ext identifier and authentication code for loop count extension.
Definition gif.cpp.hpp:816
static fl::u32 gif__clip(fl::u32 frame_off, fl::u32 frame_dim, fl::u32 image_ext) FL_NOEXCEPT
Get any frame clip adjustment for the image extent.
Definition gif.cpp.hpp:413
lzw_result
LZW decoding response codes.
Definition lzw.h:33
@ LZW_EOI_CODE
Error: End of Information code.
Definition lzw.h:38
@ LZW_OK
Success.
Definition lzw.h:34
@ LZW_NO_COLOUR
Error: No colour map provided.
Definition lzw.h:39
@ LZW_BAD_PARAM
Error: Bad function parameter.
Definition lzw.h:41
@ LZW_OK_EOD
Success; reached zero-length sub-block.
Definition lzw.h:35
nsgif_error nsgif_frame_decode(nsgif_t *gif, fl::u32 frame, nsgif_bitmap_t **bitmap) FL_NOEXCEPT
Decodes a GIF frame.
Definition gif.cpp.hpp:1953
nsgif_disposal
Frame disposal method.
Definition nsgif.hpp:403
@ NSGIF_DISPOSAL_RESTORE_BG
Clear frame to background colour.
Definition nsgif.hpp:406
@ NSGIF_DISPOSAL_RESTORE_PREV
Restore previous frame.
Definition nsgif.hpp:407
@ NSGIF_DISPOSAL_RESTORE_QUIRK
Alias for NSGIF_DISPOSAL_RESTORE_PREV.
Definition nsgif.hpp:408
static nsgif_error nsgif__colour_table_extract(fl::u32 colour_table[NSGIF_MAX_COLOURS], const struct nsgif_colour_layout *layout, fl::size colour_table_entries, const fl::u8 *data, fl::size data_len, fl::size *used, bool decode) FL_NOEXCEPT
Extract a GIF colour table into a LibNSGIF colour table buffer.
Definition gif.cpp.hpp:1115
nsgif_error nsgif_create(const nsgif_bitmap_cb_vt *bitmap_vt, nsgif_bitmap_fmt_t bitmap_fmt, nsgif_t **gif_out) FL_NOEXCEPT
Create the NSGIF object.
Definition gif.cpp.hpp:1493
const nsgif_info_t * nsgif_get_info(const nsgif_t *gif) FL_NOEXCEPT
Get information about a GIF from an nsgif_t object.
Definition gif.cpp.hpp:1990
void nsgif_data_complete(nsgif_t *gif) FL_NOEXCEPT
Tell libnsgif that all the gif data has been provided.
Definition gif.cpp.hpp:1772
static fl::u32 nsgif__frame_next(const nsgif_t *gif, bool partial, fl::u32 frame) FL_NOEXCEPT
Definition gif.cpp.hpp:1819
const char * nsgif_strerror(nsgif_error err) FL_NOEXCEPT
Convert an error code to a string.
Definition gif.cpp.hpp:2045
static nsgif_error nsgif__recover_frame(const struct nsgif *gif, fl::u32 *bitmap) FL_NOEXCEPT
Definition gif.cpp.hpp:338
static nsgif_error nsgif__parse_image_data(struct nsgif *gif, struct nsgif_frame *frame, const fl::u8 **pos, bool decode) FL_NOEXCEPT
Parse the image data for a gif frame.
Definition gif.cpp.hpp:1200
static bool nsgif__animation_complete(int count, int max) FL_NOEXCEPT
Definition gif.cpp.hpp:1863
nsgif_error nsgif_reset(nsgif_t *gif) FL_NOEXCEPT
Reset a GIF animation.
Definition gif.cpp.hpp:1872
const char * nsgif_str_disposal(enum nsgif_disposal disposal) FL_NOEXCEPT
Convert a disposal method to a string.
Definition gif.cpp.hpp:2067
void nsgif_bitmap_t
Client bitmap type.
Definition nsgif.hpp:175
static nsgif_error nsgif__parse_extension_graphic_control(struct nsgif_frame *frame, const fl::u8 *data, fl::size len) FL_NOEXCEPT
Parse the graphic control extension.
Definition gif.cpp.hpp:756
static nsgif_error nsgif__error_from_lzw(lzw_result l_res) FL_NOEXCEPT
Convert an LZW result code to equivalent GIF result code.
Definition gif.cpp.hpp:182
void nsgif_destroy(nsgif_t *gif) FL_NOEXCEPT
Free a NSGIF object.
Definition gif.cpp.hpp:1395
static nsgif_error nsgif__decode(struct nsgif *gif, struct nsgif_frame *frame, const fl::u8 *data, fl::u32 *frame_data) FL_NOEXCEPT
Definition gif.cpp.hpp:605
static void nsgif__redraw_rect_extend(const nsgif_rect_t *frame, nsgif_rect_t *redraw) FL_NOEXCEPT
Definition gif.cpp.hpp:1797
static nsgif_error nsgif__next_displayable_frame(const nsgif_t *gif, fl::u32 *frame, fl::u32 *delay) FL_NOEXCEPT
Definition gif.cpp.hpp:1836
static nsgif_error nsgif__process_frame(struct nsgif *gif, fl::u32 frame_idx, bool decode) FL_NOEXCEPT
Attempts to initialise the next frame.
Definition gif.cpp.hpp:1323
lzw_result lzw_decode_init_map(struct lzw_ctx *ctx, fl::u8 minimum_code_size, fl::u32 transparency_idx, const fl::u32 *colour_table, const fl::u8 *input_data, fl::size input_length, fl::size input_pos) FL_NOEXCEPT
Initialise an LZW decompression context for decoding to colour map values.
Definition lzw.cpp.hpp:323
void nsgif_global_palette(const nsgif_t *gif, fl::u32 table[NSGIF_MAX_COLOURS], fl::size *entries) FL_NOEXCEPT
Get the global colour palette.
Definition gif.cpp.hpp:2008
static nsgif_error nsgif__update_bitmap(struct nsgif *gif, struct nsgif_frame *frame, const fl::u8 *data, fl::u32 frame_idx) FL_NOEXCEPT
Definition gif.cpp.hpp:694
static void nsgif__bitmap_modified(const struct nsgif *gif) FL_NOEXCEPT
Helper to tell the client that their bitmap was modified.
Definition gif.cpp.hpp:259
struct fl::third_party::nsgif_info nsgif_info_t
Information about a GIF.
static bool nsgif__next_row(fl::u32 interlace, fl::u32 height, fl::u32 *y, fl::u8 *step) FL_NOEXCEPT
Get the next line for GIF decode.
Definition gif.cpp.hpp:394
const nsgif_frame_info_t * nsgif_get_frame_info(const nsgif_t *gif, fl::u32 frame) FL_NOEXCEPT
Get information about a GIF from an nsgif_t object.
Definition gif.cpp.hpp:1996
static struct nsgif_frame * nsgif__get_frame(struct nsgif *gif, fl::u32 frame_idx) FL_NOEXCEPT
Definition gif.cpp.hpp:1273
static bool nsgif__host_is_little_endian(void) FL_NOEXCEPT
Check whether the host is little endian.
Definition gif.cpp.hpp:1427
lzw_result lzw_decode(struct lzw_ctx *ctx, const fl::u8 **const output_data, fl::u32 *output_written) FL_NOEXCEPT
Read input codes until end of LZW context owned output buffer.
Definition lzw.cpp.hpp:500
static void gif__jump_data(fl::u32 *skip, fl::u32 *available, const fl::u8 **pos) FL_NOEXCEPT
Perform any jump over decoded data, to accommodate clipped portion of frame.
Definition gif.cpp.hpp:434
static nsgif_error nsgif__parse_extension_application(struct nsgif *gif, const fl::u8 *data, fl::size len) FL_NOEXCEPT
Parse the application extension.
Definition gif.cpp.hpp:846
lzw_result lzw_decode_map(struct lzw_ctx *ctx, fl::u32 *output_data, fl::u32 output_length, fl::u32 *output_written) FL_NOEXCEPT
Read LZW codes into client buffer, mapping output to colours.
Definition lzw.cpp.hpp:591
struct nsgif nsgif_t
Opaque type used by LibNSGIF to represent a GIF object in memory.
Definition nsgif.hpp:34
static void nsgif__bitmap_set_opaque(const struct nsgif *gif, const struct nsgif_frame *frame) FL_NOEXCEPT
Helper to tell the client that whether the bitmap is opaque.
Definition gif.cpp.hpp:273
static bool nsgif__deinterlace(fl::u32 height, fl::u32 *y, fl::u8 *step) FL_NOEXCEPT
Get the next line for GIF decode.
Definition gif.cpp.hpp:365
bool nsgif_local_palette(const nsgif_t *gif, fl::u32 frame, fl::u32 table[NSGIF_MAX_COLOURS], fl::size *entries) FL_NOEXCEPT
Get the local colour palette for a frame.
Definition gif.cpp.hpp:2020
static nsgif_error nsgif__decode_complex(struct nsgif *gif, fl::u32 width, fl::u32 height, fl::u32 offset_x, fl::u32 offset_y, fl::u32 interlace, const fl::u8 *data, fl::u32 transparency_index, fl::u32 *frame_data, fl::u32 *colour_table) FL_NOEXCEPT
Definition gif.cpp.hpp:446
static nsgif_error nsgif__parse_colour_table(struct nsgif *gif, struct nsgif_frame *frame, const fl::u8 **pos, bool decode) FL_NOEXCEPT
Get a frame's colour table.
Definition gif.cpp.hpp:1148
enum fl::third_party::nsgif_bitmap_fmt nsgif_bitmap_fmt_t
NSGIF nsgif_bitmap_t pixel format.
fl::size frame_offset
offset (in bytes) to the GIF frame data
Definition gif.cpp.hpp:41
bool redraw_required
whether a full image redraw is required
Definition gif.cpp.hpp:47
bool opaque
whether the frame is totally opaque
Definition gif.cpp.hpp:45
fl::u32 colour_table_size
size of global colour table (in entries)
Definition gif.cpp.hpp:122
bool transparency
whether the frame may have transparency
Definition nsgif.hpp:426
bool local_palette
whether the frame has a local colour table
Definition nsgif.hpp:428
nsgif_bitmap_t * frame_image
currently decoded image; stored as bitmap from bitmap_create callback
Definition gif.cpp.hpp:86
fl::u32 global_colour_table[NSGIF_MAX_COLOURS]
global colour table
Definition gif.cpp.hpp:129
fl::u8 b
Byte offset within pixel to blue component.
Definition gif.cpp.hpp:66
fl::u32 rowspan
Row span of frame_image in pixels.
Definition gif.cpp.hpp:88
fl::u32 aspect_ratio
image aspect ratio (ignored)
Definition gif.cpp.hpp:120
fl::u32 * colour_table
current colour table
Definition gif.cpp.hpp:125
nsgif_frame * frames
decoded frames
Definition gif.cpp.hpp:79
fl::u32 colour_table_offset
offset to frame colour table
Definition gif.cpp.hpp:56
fl::u32 prev_index
previous frame index
Definition gif.cpp.hpp:136
fl::u8 g
Byte offset within pixel to green component.
Definition gif.cpp.hpp:65
fl::u16 delay_min
Minimum allowable frame delay.
Definition gif.cpp.hpp:91
fl::u32 decoded_frame
current frame decoded to bitmap
Definition gif.cpp.hpp:83
nsgif_bitmap_cb_vt bitmap
callbacks for bitmap functions
Definition gif.cpp.hpp:77
bool display
whether the frame should be displayed/animated
Definition nsgif.hpp:424
fl::size buf_pos
current index into GIF data
Definition gif.cpp.hpp:111
fl::u8 r
Byte offset within pixel to red component.
Definition gif.cpp.hpp:64
fl::size buf_len
total number of bytes of GIF data available
Definition gif.cpp.hpp:113
fl::u32 delay
delay (in cs) before animating the frame
Definition nsgif.hpp:434
struct nsgif_colour_layout colour_layout
Client's colour component order.
Definition gif.cpp.hpp:127
fl::u32 lzw_data_length
Amount of LZW data found in scan.
Definition gif.cpp.hpp:50
void * lzw_ctx
LZW decode context.
Definition gif.cpp.hpp:75
fl::u32 transparency_index
the index designating a transparent pixel
Definition gif.cpp.hpp:53
fl::u16 delay_default
Frame delay to apply when delay is less than delay_min.
Definition gif.cpp.hpp:94
fl::u32 frame
current frame
Definition gif.cpp.hpp:81
fl::u32 bg_index
background index
Definition gif.cpp.hpp:118
struct nsgif_info info
Definition gif.cpp.hpp:72
bool decoded
whether the frame has previously been decoded.
Definition gif.cpp.hpp:43
fl::u32 frame_count_partial
number of frames partially decoded
Definition gif.cpp.hpp:100
fl::u8 a
Byte offset within pixel to alpha component.
Definition gif.cpp.hpp:67
struct nsgif_frame_info info
Definition gif.cpp.hpp:38
bool data_complete
Whether all the GIF data has been supplied, or if there may be more to come.
Definition gif.cpp.hpp:106
const fl::u8 * buf
pointer to GIF data
Definition gif.cpp.hpp:109
fl::u32 frame_holders
current number of frame holders
Definition gif.cpp.hpp:116
fl::u32 local_colour_table[NSGIF_MAX_COLOURS]
local colour table
Definition gif.cpp.hpp:131
fl::u8 disposal
Disposal method for previous frame; affects plotting.
Definition nsgif.hpp:432
void * prev_frame
previous frame for NSGIF_FRAME_RESTORE
Definition gif.cpp.hpp:134
int loop_count
number of animation loops so far
Definition gif.cpp.hpp:97
Information about a GIF.
Definition nsgif.hpp:382
Pixel format: colour component order.
Definition gif.cpp.hpp:63
Information about a GIF frame.
Definition nsgif.hpp:422
GIF animation data.
Definition gif.cpp.hpp:71
LZW decompression context.
Definition lzw.cpp.hpp:72
Bitmap callbacks function table.
Definition nsgif.hpp:178
int available()
void Free(void *ptr)
void * memcpy(void *dest, const void *src, size_t n) FL_NOEXCEPT
int strncmp(const char *s1, const char *s2, size_t n) FL_NOEXCEPT
constexpr common_type_t< T, U > max(T a, U b) FL_NOEXCEPT
Definition math.h:75
u8 u8 height
Definition blur.h:186
constexpr T * end(T(&array)[N]) FL_NOEXCEPT
void * memset(void *s, int c, size_t n) FL_NOEXCEPT
void delay(u32 ms, bool run_async=true) FL_NOEXCEPT
Public delay wrapper that keeps bare Arduino delay() preferred after using fl::delay; while still all...
Definition delay.h:98
u8 width
Definition blur.h:186
expected< T, E > result
Alias for expected (Rust-style naming)
Definition result.h:31
void * Malloc(fl::size size)
constexpr enable_if< is_fixed_point< T >::value, T >::type step(T edge, T x) FL_NOEXCEPT
Base definition for an LED controller.
Definition crgb.hpp:179
#define NSGIF_INFINITE
Representation of infinity.
Definition nsgif.hpp:26
#define NSGIF_MAX_COLOURS
Maximum colour table size.
Definition nsgif.hpp:29
Interface to progressive animated GIF file decoding - FastLED namespace wrapped version.
#define FL_NOEXCEPT
rect() FL_NOEXCEPT=default
#define NSGIF_FRAME_DELAY_MIN
Default minimum allowable frame delay in cs.
Definition gif.cpp.hpp:27
#define NSGIF_COLOUR_TABLE_SIZE_MASK
Definition gif.cpp.hpp:172
#define NSGIF_TRAILER
Definition gif.cpp.hpp:174
#define NSGIF_FRAME_DELAY_DEFAULT
Default frame delay to apply.
Definition gif.cpp.hpp:34
#define NSGIF_COLOUR_TABLE_MASK
Definition gif.cpp.hpp:171
#define NSGIF_TRANSPARENT_COLOUR
Transparent colour.
Definition gif.cpp.hpp:165
#define NSGIF_BLOCK_TERMINATOR
Definition gif.cpp.hpp:173
#define NSGIF_ARRAY_LEN(_a)
Helper macro to get number of elements in an array.
Definition gif.cpp.hpp:145
#define NSGIF_NO_TRANSPARENCY
No transparency.
Definition gif.cpp.hpp:168
#define NSGIF_FRAME_INVALID
Internal flag that a frame is invalid/unprocessed.
Definition gif.cpp.hpp:162
#define NSGIF_PROCESS_COLOURS
Internal flag that the colour table needs to be processed.
Definition gif.cpp.hpp:159