27#define NSGIF_FRAME_DELAY_MIN 2
34#define NSGIF_FRAME_DELAY_DEFAULT 10
145#define NSGIF_ARRAY_LEN(_a) ((sizeof(_a)) / (sizeof(*_a)))
159#define NSGIF_PROCESS_COLOURS 0xaa000000
162#define NSGIF_FRAME_INVALID (fl::numeric_limits<fl::u32>::max)()
165#define NSGIF_TRANSPARENT_COLOUR 0x00
168#define NSGIF_NO_TRANSPARENCY (0xFFFFFFFFu)
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
214 if (gif->frame_image) {
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) {
244 gif->rowspan = gif->info.width;
245 if (gif->bitmap.get_rowspan) {
246 gif->rowspan = gif->bitmap.get_rowspan(gif->frame_image);
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));
262 if (gif->bitmap.modified) {
263 gif->bitmap.modified(gif->frame_image);
274 const struct nsgif *gif,
277 if (gif->bitmap.set_opaque) {
278 gif->bitmap.set_opaque(
279 gif->frame_image, frame->opaque);
294 if (gif->bitmap.test_opaque) {
295 return gif->bitmap.test_opaque(
306 fl::size pixel_bytes =
sizeof(*bitmap);
307 fl::size
height = gif->info.height;
308 fl::size
width = gif->info.width;
312 gif->decoded_frame == gif->prev_index) {
318 if (bitmap ==
nullptr) {
322 if (gif->prev_frame ==
nullptr) {
324 if (prev_frame ==
nullptr) {
327 gif->prev_frame = prev_frame;
329 prev_frame =
static_cast<fl::u32*
>(gif->prev_frame);
334 gif->prev_frame = prev_frame;
335 gif->prev_index = gif->decoded_frame;
339 const struct nsgif *gif,
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;
372 case 24: *
y = 4; *
step = 8;
if (*
y <
height)
return true;
374 case 8: *
y = 2; *
step = 4;
if (*
y <
height)
return true;
376 case 4: *
y = 1; *
step = 2;
if (*
y <
height)
return true;
418 fl::u32 frame_ext = frame_off + frame_dim;
420 if (frame_ext <= image_ext) {
424 return frame_ext - image_ext;
454 fl::u32 transparency_index,
455 fl::u32 * frame_data,
462 const fl::u8 *uncompressed;
468 if (offset_x >= gif->info.width ||
469 offset_y >= gif->info.height) {
482 gif->buf, gif->buf_len,
483 data + 1 - gif->buf);
490 fl::u32 *frame_scanline;
492 frame_scanline = frame_data + offset_x +
493 (
y + offset_y) * gif->rowspan;
497 unsigned row_available;
521 if (transparency_index > 0xFF) {
522 while (row_available-- > 0) {
524 colour_table[*uncompressed++];
527 while (row_available-- > 0) {
529 colour = *uncompressed++;
530 if (colour != transparency_index) {
532 colour_table[colour];
551 fl::u32 transparency_index,
552 fl::u32 * frame_data,
560 if (offset_y >= gif->info.height) {
572 transparency_index, colour_table,
573 gif->buf, gif->buf_len,
574 data + 1 - gif->buf);
579 frame_data += (offset_y * gif->info.width);
580 pixels = gif->info.width *
height;
584 frame_data, pixels, &written);
586 frame_data += written;
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;
619 if (frame->info.interlaced ==
false && offset_x == 0 &&
620 width == gif->info.width &&
621 width == gif->rowspan) {
623 data, transparency_index,
624 frame_data, colour_table);
627 offset_x, offset_y, frame->info.interlaced,
628 data, transparency_index,
629 frame_data, colour_table);
652 fl::size pixel_bytes =
sizeof(*bitmap);
654 if (frame ==
nullptr) {
655 fl::size
width = gif->info.width;
656 fl::size
height = gif->info.height;
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;
666 if (frame->info.display ==
false ||
667 frame->info.rect.x0 >= gif->info.width ||
668 frame->info.rect.y0 >= gif->info.height) {
675 if (frame->info.transparency) {
677 fl::u32 *scanline = bitmap + offset_x +
678 (offset_y +
y) * gif->info.width;
680 width * pixel_bytes);
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;
703 gif->decoded_frame = frame_idx;
706 if (bitmap ==
nullptr) {
716 struct nsgif_frame *prev = &gif->frames[frame_idx - 1];
738 if (!frame->decoded) {
740 frame->decoded =
true;
762 GIF_MASK_TRANSPARENCY = 0x01,
763 GIF_MASK_DISPOSAL = 0x1c,
782 frame->info.delay = data[3] | (data[4] << 8);
784 if (data[2] & GIF_MASK_TRANSPARENCY) {
785 frame->info.transparency =
true;
786 frame->transparency_index = data[5];
789 frame->info.disposal = ((data[2] & GIF_MASK_DISPOSAL) >> 2);
802 frame->redraw_required =
821 EXT_LOOP_COUNT_BLOCK_SIZE = 0x0b,
824 FL_ASSERT(len > 13,
"Extension data too short");
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) {
865 EXT_LOOP_COUNT_SUB_BLOCK_SIZE = 0x03,
866 EXT_LOOP_COUNT_SUB_BLOCK_ID = 0x01,
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);
877 if (gif->info.loop_max > 0) {
878 gif->info.loop_max++;
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,
910 const fl::u8 *nsgif_end = gif->buf + gif->buf_len;
911 int nsgif_bytes = nsgif_end - nsgif_data;
914 while (nsgif_bytes > 0 && nsgif_data[0] == GIF_EXT_INTRODUCER) {
915 bool block_step =
true;
921 if (nsgif_bytes == 0) {
926 switch (nsgif_data[0]) {
927 case GIF_EXT_GRAPHIC_CONTROL:
939 case GIF_EXT_APPLICATION:
942 gif, nsgif_data, nsgif_bytes);
949 case GIF_EXT_COMMENT:
965 if (nsgif_bytes < 2) {
968 nsgif_data += 2 + nsgif_data[1];
974 nsgif_data += nsgif_data[0] + 1;
975 if (nsgif_data >= nsgif_end) {
980 nsgif_bytes = nsgif_end - nsgif_data;
983 if (nsgif_data > nsgif_end) {
984 nsgif_data = nsgif_end;
1022 fl::size len = gif->buf + gif->buf_len - data;
1024 NSGIF_IMAGE_DESCRIPTOR_LEN = 10u,
1025 NSGIF_IMAGE_SEPARATOR = 0x2Cu,
1026 NSGIF_MASK_INTERLACE = 0x40u,
1029 FL_ASSERT(gif !=
nullptr,
"GIF object required");
1030 FL_ASSERT(frame !=
nullptr,
"Frame object required");
1032 if (len < NSGIF_IMAGE_DESCRIPTOR_LEN) {
1039 if (data[0] != NSGIF_IMAGE_SEPARATOR) {
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];
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;
1054 frame->info.interlaced = frame->flags & NSGIF_MASK_INTERLACE;
1057 if (gif->info.frame_count == 0) {
1058 if (
x + w > gif->info.width) {
1059 gif->info.width =
x + w;
1061 if (
y + h > gif->info.height) {
1062 gif->info.height =
y + h;
1067 *
pos += NSGIF_IMAGE_DESCRIPTOR_LEN;
1082 fl::size colour_table_entries,
1087 while (colour_table_entries--) {
1094 entry[layout->r] = *data++;
1095 entry[layout->g] = *data++;
1096 entry[layout->b] = *data++;
1097 entry[layout->a] = 0xff;
1099 entry +=
sizeof(fl::u32);
1118 fl::size colour_table_entries,
1124 if (data_len < colour_table_entries * 3) {
1130 colour_table_entries, data);
1133 *used = colour_table_entries * 3;
1156 fl::size len = gif->buf + gif->buf_len - data;
1157 fl::size used_bytes;
1159 FL_ASSERT(gif !=
nullptr,
"GIF object required");
1160 FL_ASSERT(frame !=
nullptr,
"Frame object required");
1163 gif->colour_table = gif->global_colour_table;
1167 if (decode ==
false) {
1168 frame->colour_table_offset = *
pos - gif->buf;
1172 gif->local_colour_table, &gif->colour_layout,
1174 data, len, &used_bytes, decode);
1181 gif->colour_table = gif->local_colour_table;
1183 frame->info.local_palette =
true;
1207 fl::size len = gif->buf + gif->buf_len - data;
1208 fl::u32 frame_idx = frame - gif->frames;
1209 fl::u8 minimum_code_size;
1212 FL_ASSERT(gif !=
nullptr,
"GIF object required");
1213 FL_ASSERT(frame !=
nullptr,
"Frame object required");
1216 gif->frame_count_partial = frame_idx + 1;
1232 minimum_code_size = data[0];
1240 fl::u32 block_size = 0;
1246 while (block_size != 1) {
1250 block_size = data[0] + 1;
1252 if (block_size > len) {
1253 frame->lzw_data_length += len;
1259 frame->lzw_data_length += block_size;
1264 gif->info.frame_count = frame_idx + 1;
1265 gif->frames[frame_idx].info.display =
true;
1279 if (gif->frame_holders > frame_idx) {
1280 frame = &gif->frames[frame_idx];
1283 fl::size count = frame_idx + 1;
1287 if (temp ==
nullptr) {
1291 fl::memcpy(temp, gif->frames, gif->frame_holders *
sizeof(*frame));
1295 gif->frame_holders = count;
1297 frame = &gif->frames[frame_idx];
1334 if (frame ==
nullptr) {
1338 end = gif->buf + gif->buf_len;
1349 if (frame_idx > gif->frame_count_partial) {
1354 if (frame_idx == gif->decoded_frame) {
1358 pos = gif->buf + gif->buf_pos;
1388 gif->buf_pos =
pos - gif->buf;
1397 if (gif ==
nullptr) {
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;
1409 gif->frames =
nullptr;
1412 gif->prev_frame =
nullptr;
1415 gif->lzw_ctx =
nullptr;
1429 const fl::u16
test = 1;
1440 switch (bitmap_fmt) {
1468 switch (bitmap_fmt) {
1504 if (gif ==
nullptr) {
1508 gif->
bitmap = *bitmap_vt;
1527 gif->delay_min = delay_min;
1528 gif->delay_default = delay_default;
1550 fl::size len = gif->buf + gif->buf_len - data;
1556 if (
strncmp((
const char *) data,
"GIF", 3) != 0) {
1561 if (strict ==
true) {
1562 if ((
strncmp((
const char *) data,
"87a", 3) != 0) &&
1563 (
strncmp((
const char *) data,
"89a", 3) != 0)) {
1597 fl::size len = gif->buf + gif->buf_len - data;
1603 gif->info.width = data[0] | (data[1] << 8);
1604 gif->info.height = data[2] | (data[3] << 8);
1607 gif->bg_index = data[5];
1608 gif->aspect_ratio = data[6];
1609 gif->info.loop_max = 1;
1621 const fl::u8 *nsgif_data;
1625 if (gif->data_complete) {
1630 gif->buf_len = size;
1634 nsgif_data = gif->buf + gif->buf_pos;
1637 if (gif->buf_pos == 0) {
1641 gif->frame_image =
nullptr;
1642 gif->frames =
nullptr;
1643 gif->frame_holders = 0;
1646 gif->info.frame_count = 0;
1647 gif->frame_count_partial = 0;
1662 gif->buf_pos = nsgif_data - gif->buf;
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;
1690 if (gif->buf_len == gif->buf_pos + 1) {
1703 if (gif->info.global_palette) {
1704 fl::size remaining = gif->buf + gif->buf_len - nsgif_data;
1708 gif->global_colour_table,
1709 &gif->colour_layout,
1710 gif->colour_table_size,
1711 nsgif_data, remaining, &used,
true);
1717 gif->buf_pos = (nsgif_data - gif->buf);
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;
1729 entry +=
sizeof(fl::u32);
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;
1737 gif->colour_table_size = 2;
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];
1745 gif->info.background = gif->global_colour_table[0];
1749 if (gif->lzw_ctx ==
nullptr) {
1750 struct lzw_ctx *lzw_ctx_ptr =
nullptr;
1752 gif->lzw_ctx = lzw_ctx_ptr;
1760 frames = gif->info.frame_count;
1762 }
while (gif->info.frame_count > frames);
1775 if (gif->data_complete ==
false) {
1776 fl::u32 start = gif->info.frame_count;
1777 fl::u32
end = gif->frame_count_partial;
1779 for (fl::u32 f = start; f <
end; f++) {
1784 gif->info.frame_count = f + 1;
1794 gif->data_complete =
true;
1801 if (redraw->x1 == 0 || redraw->y1 == 0) {
1804 if (redraw->x0 > frame->x0) {
1805 redraw->x0 = frame->x0;
1807 if (redraw->x1 < frame->x1) {
1808 redraw->x1 = frame->x1;
1810 if (redraw->y0 > frame->y0) {
1811 redraw->y0 = frame->y0;
1813 if (redraw->y1 < frame->y1) {
1814 redraw->y1 = frame->y1;
1824 fl::u32 frames = partial ?
1825 gif->frame_count_partial :
1826 gif->info.frame_count;
1833 return (frame >= frames) ? 0 : frame;
1841 fl::u32 next = *frame;
1846 gif->data_complete ==
false) {
1853 if (
delay !=
nullptr) {
1854 *
delay += gif->frames[next].info.delay;
1857 }
while (gif->frames[next].info.display ==
false);
1869 return (count >=
max);
1875 gif->loop_count = 0;
1891 fl::u32 frame = gif->frame;
1894 gif->frame < gif->info.frame_count &&
1895 gif->frames[gif->frame].info.display) {
1896 rect = gif->frames[gif->frame].info.
rect;
1901 gif->info.loop_max)) {
1914 if (gif->data_complete) {
1917 if (gif->info.frame_count == 1) {
1919 }
else if (gif->info.loop_max != 0) {
1920 fl::u32 frame_next = frame;
1923 &frame_next,
nullptr);
1928 if (gif->data_complete && frame_next < frame) {
1930 gif->loop_count + 1,
1931 gif->info.loop_max)) {
1942 delay = gif->delay_default;
1945 *frame_new = gif->frame;
1958 fl::u32 start_frame;
1961 if (frame >= gif->info.frame_count) {
1965 if (gif->decoded_frame == frame) {
1966 *bitmap = gif->frame_image;
1969 }
else if (gif->decoded_frame >= frame ||
1975 gif,
false, gif->decoded_frame);
1978 for (fl::u32 f = start_frame; f <= frame; f++) {
1985 *bitmap = gif->frame_image;
2000 if (frame >= gif->info.frame_count) {
2004 return &gif->frames[frame].info;
2015 fl::memcpy(table, gif->global_colour_table, len);
2016 *entries = gif->colour_table_size;
2028 if (frame >= gif->frame_count_partial) {
2032 f = &gif->frames[frame];
2047 static const char *
const str[] = {
2050 "Invalid source data",
2051 "Requested frame does not exist",
2052 "Invalid frame data",
2053 "Unexpected end of GIF source data",
2054 "Can't add data to completed GIF",
2055 "Frame can't be displayed",
2056 "Animation complete",
2060 return "Unknown error";
2069 static const char *
const str[] = {
2072 "Restore background",
2078 return "Unspecified";
2081 return str[disposal];
#define FL_ASSERT(x, MSG)
#define LZW_CODE_MAX
Maximum LZW code size in bits.
LZW decompression (interface)
@ NSGIF_BITMAP_FMT_A8B8G8R8
Bite-wise ABGR: Byte order: 0xAA, 0xBB, 0xGG, 0xRR.
@ NSGIF_BITMAP_FMT_R8G8B8A8
Bite-wise RGBA: Byte order: 0xRR, 0xGG, 0xBB, 0xAA.
@ NSGIF_BITMAP_FMT_ARGB8888
32-bit ARGB (0xAARRGGBB).
@ NSGIF_BITMAP_FMT_RGBA8888
32-bit RGBA (0xRRGGBBAA).
@ NSGIF_BITMAP_FMT_B8G8R8A8
Bite-wise BGRA: Byte order: 0xBB, 0xGG, 0xRR, 0xAA.
@ NSGIF_BITMAP_FMT_ABGR8888
32-bit BGRA (0xAABBGGRR).
@ NSGIF_BITMAP_FMT_BGRA8888
32-bit BGRA (0xBBGGRRAA).
@ NSGIF_BITMAP_FMT_A8R8G8B8
Bite-wise ARGB: Byte order: 0xAA, 0xRR, 0xGG, 0xBB.
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.
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.
lzw_result lzw_context_create(struct lzw_ctx **ctx) FL_NOEXCEPT
Create an LZW decompression context.
static nsgif_error nsgif__initialise_sprite(struct nsgif *gif, fl::u32 width, fl::u32 height) FL_NOEXCEPT
Updates the sprite memory size.
void lzw_context_destroy(struct lzw_ctx *ctx) FL_NOEXCEPT
Destroy an LZW decompression context.
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.
static void nsgif__restore_bg(struct nsgif *gif, struct nsgif_frame *frame, fl::u32 *bitmap) FL_NOEXCEPT
Restore a GIF to the background colour.
static nsgif_error nsgif__parse_logical_screen_descriptor(struct nsgif *gif, const fl::u8 **pos) FL_NOEXCEPT
Read Logical Screen Descriptor.
static fl::u32 * nsgif__bitmap_get(struct nsgif *gif) FL_NOEXCEPT
Helper to get the rendering bitmap for a gif.
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
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
nsgif_error
LibNSGIF return codes.
@ NSGIF_ERR_DATA_COMPLETE
Can't supply more data after calling nsgif_data_complete.
@ NSGIF_ERR_OOM
Out of memory error.
@ NSGIF_ERR_BAD_FRAME
Frame number is not valid.
@ NSGIF_ERR_END_OF_DATA
Unexpected end of GIF source data.
@ NSGIF_ERR_ANIMATION_END
Indicates an animation is complete, and nsgif_reset must be called to restart the animation from the ...
@ NSGIF_ERR_DATA_FRAME
GIF source data contained an error in a frame.
@ NSGIF_ERR_DATA
GIF source data is invalid, and no frames are recoverable.
@ NSGIF_ERR_FRAME_DISPLAY
The current frame cannot be displayed.
static nsgif_error nsgif__parse_header(struct nsgif *gif, const fl::u8 **pos, bool strict) FL_NOEXCEPT
Read GIF header.
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.
static struct nsgif_colour_layout nsgif__bitmap_fmt_to_colour_layout(nsgif_bitmap_fmt_t bitmap_fmt) FL_NOEXCEPT
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.
static bool nsgif__bitmap_get_opaque(const struct nsgif *gif) FL_NOEXCEPT
Helper to get the client to determine if the bitmap is opaque.
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.
nsgif_error nsgif_data_scan(nsgif_t *gif, fl::size size, const fl::u8 *data) FL_NOEXCEPT
Scan the source image data.
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.
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.
lzw_result
LZW decoding response codes.
@ LZW_EOI_CODE
Error: End of Information code.
@ LZW_NO_COLOUR
Error: No colour map provided.
@ LZW_BAD_PARAM
Error: Bad function parameter.
@ LZW_OK_EOD
Success; reached zero-length sub-block.
nsgif_error nsgif_frame_decode(nsgif_t *gif, fl::u32 frame, nsgif_bitmap_t **bitmap) FL_NOEXCEPT
Decodes a GIF frame.
nsgif_disposal
Frame disposal method.
@ NSGIF_DISPOSAL_RESTORE_BG
Clear frame to background colour.
@ NSGIF_DISPOSAL_RESTORE_PREV
Restore previous frame.
@ NSGIF_DISPOSAL_RESTORE_QUIRK
Alias for NSGIF_DISPOSAL_RESTORE_PREV.
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.
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.
const nsgif_info_t * nsgif_get_info(const nsgif_t *gif) FL_NOEXCEPT
Get information about a GIF from an nsgif_t object.
void nsgif_data_complete(nsgif_t *gif) FL_NOEXCEPT
Tell libnsgif that all the gif data has been provided.
static fl::u32 nsgif__frame_next(const nsgif_t *gif, bool partial, fl::u32 frame) FL_NOEXCEPT
const char * nsgif_strerror(nsgif_error err) FL_NOEXCEPT
Convert an error code to a string.
static nsgif_error nsgif__recover_frame(const struct nsgif *gif, fl::u32 *bitmap) FL_NOEXCEPT
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.
static bool nsgif__animation_complete(int count, int max) FL_NOEXCEPT
nsgif_error nsgif_reset(nsgif_t *gif) FL_NOEXCEPT
Reset a GIF animation.
const char * nsgif_str_disposal(enum nsgif_disposal disposal) FL_NOEXCEPT
Convert a disposal method to a string.
void nsgif_bitmap_t
Client bitmap type.
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.
static nsgif_error nsgif__error_from_lzw(lzw_result l_res) FL_NOEXCEPT
Convert an LZW result code to equivalent GIF result code.
void nsgif_destroy(nsgif_t *gif) FL_NOEXCEPT
Free a NSGIF object.
static nsgif_error nsgif__decode(struct nsgif *gif, struct nsgif_frame *frame, const fl::u8 *data, fl::u32 *frame_data) FL_NOEXCEPT
static void nsgif__redraw_rect_extend(const nsgif_rect_t *frame, nsgif_rect_t *redraw) FL_NOEXCEPT
static nsgif_error nsgif__next_displayable_frame(const nsgif_t *gif, fl::u32 *frame, fl::u32 *delay) FL_NOEXCEPT
static nsgif_error nsgif__process_frame(struct nsgif *gif, fl::u32 frame_idx, bool decode) FL_NOEXCEPT
Attempts to initialise the next frame.
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.
void nsgif_global_palette(const nsgif_t *gif, fl::u32 table[NSGIF_MAX_COLOURS], fl::size *entries) FL_NOEXCEPT
Get the global colour palette.
static nsgif_error nsgif__update_bitmap(struct nsgif *gif, struct nsgif_frame *frame, const fl::u8 *data, fl::u32 frame_idx) FL_NOEXCEPT
static void nsgif__bitmap_modified(const struct nsgif *gif) FL_NOEXCEPT
Helper to tell the client that their bitmap was modified.
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.
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.
static struct nsgif_frame * nsgif__get_frame(struct nsgif *gif, fl::u32 frame_idx) FL_NOEXCEPT
static bool nsgif__host_is_little_endian(void) FL_NOEXCEPT
Check whether the host is little endian.
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.
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.
static nsgif_error nsgif__parse_extension_application(struct nsgif *gif, const fl::u8 *data, fl::size len) FL_NOEXCEPT
Parse the application extension.
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.
struct nsgif nsgif_t
Opaque type used by LibNSGIF to represent a GIF object in memory.
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.
static bool nsgif__deinterlace(fl::u32 height, fl::u32 *y, fl::u8 *step) FL_NOEXCEPT
Get the next line for GIF decode.
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.
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
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.
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
bool redraw_required
whether a full image redraw is required
bool opaque
whether the frame is totally opaque
fl::u32 colour_table_size
size of global colour table (in entries)
bool transparency
whether the frame may have transparency
bool local_palette
whether the frame has a local colour table
nsgif_bitmap_t * frame_image
currently decoded image; stored as bitmap from bitmap_create callback
fl::u32 global_colour_table[NSGIF_MAX_COLOURS]
global colour table
fl::u8 b
Byte offset within pixel to blue component.
fl::u32 rowspan
Row span of frame_image in pixels.
fl::u32 aspect_ratio
image aspect ratio (ignored)
fl::u32 * colour_table
current colour table
nsgif_frame * frames
decoded frames
fl::u32 colour_table_offset
offset to frame colour table
fl::u32 prev_index
previous frame index
fl::u8 g
Byte offset within pixel to green component.
fl::u16 delay_min
Minimum allowable frame delay.
fl::u32 decoded_frame
current frame decoded to bitmap
nsgif_bitmap_cb_vt bitmap
callbacks for bitmap functions
bool display
whether the frame should be displayed/animated
fl::size buf_pos
current index into GIF data
fl::u8 r
Byte offset within pixel to red component.
fl::size buf_len
total number of bytes of GIF data available
fl::u32 delay
delay (in cs) before animating the frame
struct nsgif_colour_layout colour_layout
Client's colour component order.
fl::u32 lzw_data_length
Amount of LZW data found in scan.
void * lzw_ctx
LZW decode context.
fl::u32 transparency_index
the index designating a transparent pixel
fl::u16 delay_default
Frame delay to apply when delay is less than delay_min.
fl::u32 frame
current frame
fl::u32 bg_index
background index
bool decoded
whether the frame has previously been decoded.
fl::u32 frame_count_partial
number of frames partially decoded
fl::u8 a
Byte offset within pixel to alpha component.
struct nsgif_frame_info info
bool data_complete
Whether all the GIF data has been supplied, or if there may be more to come.
const fl::u8 * buf
pointer to GIF data
fl::u32 frame_holders
current number of frame holders
fl::u32 local_colour_table[NSGIF_MAX_COLOURS]
local colour table
fl::u8 disposal
Disposal method for previous frame; affects plotting.
void * prev_frame
previous frame for NSGIF_FRAME_RESTORE
int loop_count
number of animation loops so far
Pixel format: colour component order.
Information about a GIF frame.
LZW decompression context.
Bitmap callbacks function table.
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
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...
expected< T, E > result
Alias for expected (Rust-style naming)
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.
#define NSGIF_INFINITE
Representation of infinity.
#define NSGIF_MAX_COLOURS
Maximum colour table size.
Interface to progressive animated GIF file decoding - FastLED namespace wrapped version.
rect() FL_NOEXCEPT=default
#define NSGIF_FRAME_DELAY_MIN
Default minimum allowable frame delay in cs.
#define NSGIF_COLOUR_TABLE_SIZE_MASK
#define NSGIF_FRAME_DELAY_DEFAULT
Default frame delay to apply.
#define NSGIF_COLOUR_TABLE_MASK
#define NSGIF_TRANSPARENT_COLOUR
Transparent colour.
#define NSGIF_BLOCK_TERMINATOR
#define NSGIF_ARRAY_LEN(_a)
Helper macro to get number of elements in an array.
#define NSGIF_NO_TRANSPARENCY
No transparency.
#define NSGIF_FRAME_INVALID
Internal flag that a frame is invalid/unprocessed.
#define NSGIF_PROCESS_COLOURS
Internal flag that the colour table needs to be processed.