Initial commit

This commit is contained in:
2026-03-31 13:17:21 +02:00
commit 7eeecff042
6821 changed files with 3514215 additions and 0 deletions

View File

@@ -0,0 +1,650 @@
/*******************************************************************************
* GIFDEC Wrapper Class
*
* Rewrite from: https://github.com/BasementCat/arduino-tft-gif
******************************************************************************/
#ifndef _GIFCLASS_H_
#define _GIFCLASS_H_
/* Wio Terminal */
#if defined(ARDUINO_ARCH_SAMD) && defined(SEEED_GROVE_UI_WIRELESS)
#include <Seeed_FS.h>
#elif defined(ESP32) || defined(ESP8266)
#include <FS.h>
#else
#include <SD.h>
#endif
#include <sys/types.h>
#ifndef MIN
#define MIN(A, B) ((A) < (B) ? (A) : (B))
#endif
#ifndef MAX
#define MAX(A, B) ((A) > (B) ? (A) : (B))
#endif
#define GIF_BUF_SIZE 1024
typedef struct gd_Palette
{
uint8_t size;
uint16_t colors[256];
} gd_Palette;
typedef struct gd_GCE
{
uint16_t delay;
uint8_t tindex;
uint8_t disposal;
uint8_t input;
uint8_t transparency;
} gd_GCE;
typedef struct gd_Entry
{
int32_t length;
uint16_t prefix;
uint8_t suffix;
} gd_Entry;
typedef struct gd_Table
{
int16_t bulk;
int16_t nentries;
gd_Entry *entries;
} gd_Table;
typedef struct gd_GIF
{
File *fd;
off_t anim_start;
uint16_t width, height;
uint16_t depth;
uint16_t loop_count;
gd_GCE gce;
gd_Palette *palette;
gd_Palette lct, gct;
void (*plain_text)(
struct gd_GIF *gif, uint16_t tx, uint16_t ty,
uint16_t tw, uint16_t th, uint8_t cw, uint8_t ch,
uint8_t fg, uint8_t bg);
void (*comment)(struct gd_GIF *gif);
void (*application)(struct gd_GIF *gif, char id[8], char auth[3]);
uint16_t fx, fy, fw, fh;
uint8_t bgindex;
gd_Table *table;
} gd_GIF;
class GifClass
{
public:
gd_GIF *gd_open_gif(File *fd)
{
uint8_t sigver[3];
uint16_t width, height, depth;
uint8_t fdsz, bgidx, aspect;
int32_t gct_sz;
gd_GIF *gif;
// init global variables
gif_buf_last_idx = GIF_BUF_SIZE;
gif_buf_idx = gif_buf_last_idx; // no buffer yet
file_pos = 0;
/* Header */
gif_buf_read(fd, sigver, 3);
if (memcmp(sigver, "GIF", 3) != 0)
{
Serial.println(F("invalid signature"));
return NULL;
}
/* Version */
gif_buf_read(fd, sigver, 3);
if (memcmp(sigver, "89a", 3) != 0)
{
Serial.println(F("invalid version"));
return NULL;
}
/* Width x Height */
width = gif_buf_read16(fd);
height = gif_buf_read16(fd);
/* FDSZ */
gif_buf_read(fd, &fdsz, 1);
/* Presence of GCT */
if (!(fdsz & 0x80))
{
Serial.println(F("no global color table"));
return NULL;
}
/* Color Space's Depth */
depth = ((fdsz >> 4) & 7) + 1;
/* Ignore Sort Flag. */
/* GCT Size */
gct_sz = 1 << ((fdsz & 0x07) + 1);
/* Background Color Index */
gif_buf_read(fd, &bgidx, 1);
/* Aspect Ratio */
gif_buf_read(fd, &aspect, 1);
/* Create gd_GIF Structure. */
gif = (gd_GIF *)calloc(1, sizeof(*gif));
gif->fd = fd;
gif->width = width;
gif->height = height;
gif->depth = depth;
/* Read GCT */
read_palette(fd, &gif->gct, gct_sz);
gif->palette = &gif->gct;
gif->bgindex = bgidx;
gif->anim_start = file_pos; // fd->position();
gif->table = new_table();
return gif;
}
/* Return 1 if got a frame; 0 if got GIF trailer; -1 if error. */
int32_t gd_get_frame(gd_GIF *gif, uint8_t *frame)
{
char sep;
while (1)
{
gif_buf_read(gif->fd, (uint8_t *)&sep, 1);
if (sep == 0)
{
gif_buf_read(gif->fd, (uint8_t *)&sep, 1);
}
if (sep == ',')
{
break;
}
if (sep == ';')
{
return 0;
}
if (sep == '!')
{
read_ext(gif);
}
else
{
Serial.print(F("Read sep: ["));
Serial.print(sep);
Serial.println(F("].\n"));
return -1;
}
}
// Serial.println("Do read image");
if (read_image(gif, frame) == -1)
return -1;
return 1;
}
void gd_rewind(gd_GIF *gif)
{
#if defined(ESP32) || defined(ESP8266)
gif->fd->seek(gif->anim_start, SeekSet);
#else
gif->fd->seek(gif->anim_start);
#endif
file_pos = gif->anim_start;
gif_buf_idx = gif_buf_last_idx; // reset buffer
}
void gd_close_gif(gd_GIF *gif)
{
gif->fd->close();
free(gif->table);
free(gif);
}
private:
bool gif_buf_seek(File *fd, int16_t len)
{
if (len > (gif_buf_last_idx - gif_buf_idx))
{
#if defined(ESP32) || defined(ESP8266)
// fd->seek(len - (gif_buf_last_idx - gif_buf_idx), SeekCur);
fd->seek(file_pos + len - (gif_buf_last_idx - gif_buf_idx), SeekSet);
#else
fd->seek(file_pos + len - (gif_buf_last_idx - gif_buf_idx));
#endif
gif_buf_idx = gif_buf_last_idx;
}
else
{
gif_buf_idx += len;
}
file_pos += len;
return true;
}
int16_t gif_buf_read(File *fd, uint8_t *dest, int16_t len)
{
while (len--)
{
if (gif_buf_idx == gif_buf_last_idx)
{
gif_buf_last_idx = fd->read(gif_buf, GIF_BUF_SIZE);
gif_buf_idx = 0;
}
file_pos++;
*(dest++) = gif_buf[gif_buf_idx++];
}
return len;
}
uint8_t gif_buf_read(File *fd)
{
if (gif_buf_idx == gif_buf_last_idx)
{
gif_buf_last_idx = fd->read(gif_buf, GIF_BUF_SIZE);
gif_buf_idx = 0;
}
file_pos++;
return gif_buf[gif_buf_idx++];
}
uint16_t gif_buf_read16(File *fd)
{
return gif_buf_read(fd) + (((uint16_t)gif_buf_read(fd)) << 8);
}
void read_palette(File *fd, gd_Palette *dest, int32_t num_colors)
{
uint8_t r, g, b;
dest->size = num_colors;
for (int32_t i = 0; i < num_colors; i++)
{
r = gif_buf_read(fd);
g = gif_buf_read(fd);
b = gif_buf_read(fd);
dest->colors[i] = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | ((b & 0xF8) >> 3);
}
}
void discard_sub_blocks(gd_GIF *gif)
{
uint8_t size;
do
{
gif_buf_read(gif->fd, &size, 1);
gif_buf_seek(gif->fd, size);
} while (size);
}
void read_plain_text_ext(gd_GIF *gif)
{
if (gif->plain_text)
{
uint16_t tx, ty, tw, th;
uint8_t cw, ch, fg, bg;
gif_buf_seek(gif->fd, 1); /* block size = 12 */
tx = gif_buf_read16(gif->fd);
ty = gif_buf_read16(gif->fd);
tw = gif_buf_read16(gif->fd);
th = gif_buf_read16(gif->fd);
cw = gif_buf_read(gif->fd);
ch = gif_buf_read(gif->fd);
fg = gif_buf_read(gif->fd);
bg = gif_buf_read(gif->fd);
gif->plain_text(gif, tx, ty, tw, th, cw, ch, fg, bg);
}
else
{
/* Discard plain text metadata. */
gif_buf_seek(gif->fd, 13);
}
/* Discard plain text sub-blocks. */
discard_sub_blocks(gif);
}
void read_graphic_control_ext(gd_GIF *gif)
{
uint8_t rdit;
/* Discard block size (always 0x04). */
gif_buf_seek(gif->fd, 1);
gif_buf_read(gif->fd, &rdit, 1);
gif->gce.disposal = (rdit >> 2) & 3;
gif->gce.input = rdit & 2;
gif->gce.transparency = rdit & 1;
gif->gce.delay = gif_buf_read16(gif->fd);
gif_buf_read(gif->fd, &gif->gce.tindex, 1);
/* Skip block terminator. */
gif_buf_seek(gif->fd, 1);
}
void read_comment_ext(gd_GIF *gif)
{
if (gif->comment)
{
gif->comment(gif);
}
/* Discard comment sub-blocks. */
discard_sub_blocks(gif);
}
void read_application_ext(gd_GIF *gif)
{
char app_id[8];
char app_auth_code[3];
/* Discard block size (always 0x0B). */
gif_buf_seek(gif->fd, 1);
/* Application Identifier. */
gif_buf_read(gif->fd, (uint8_t *)app_id, 8);
/* Application Authentication Code. */
gif_buf_read(gif->fd, (uint8_t *)app_auth_code, 3);
if (!strncmp(app_id, "NETSCAPE", sizeof(app_id)))
{
/* Discard block size (0x03) and constant byte (0x01). */
gif_buf_seek(gif->fd, 2);
gif->loop_count = gif_buf_read16(gif->fd);
/* Skip block terminator. */
gif_buf_seek(gif->fd, 1);
}
else if (gif->application)
{
gif->application(gif, app_id, app_auth_code);
discard_sub_blocks(gif);
}
else
{
discard_sub_blocks(gif);
}
}
void read_ext(gd_GIF *gif)
{
uint8_t label;
gif_buf_read(gif->fd, &label, 1);
switch (label)
{
case 0x01:
read_plain_text_ext(gif);
break;
case 0xF9:
read_graphic_control_ext(gif);
break;
case 0xFE:
read_comment_ext(gif);
break;
case 0xFF:
read_application_ext(gif);
break;
default:
Serial.print("unknown extension: ");
Serial.println(label, HEX);
}
}
gd_Table *new_table()
{
// uint16_t key;
// int16_t init_bulk = MAX(1 << (key_size + 1), 0x100);
// Table *table = (Table*) malloc(sizeof(*table) + sizeof(Entry) * init_bulk);
// if (table) {
// table->bulk = init_bulk;
// table->nentries = (1 << key_size) + 2;
// table->entries = (Entry *) &table[1];
// for (key = 0; key < (1 << key_size); key++)
// table->entries[key] = (Entry) {1, 0xFFF, key};
// }
// return table;
int32_t s = sizeof(gd_Table) + (sizeof(gd_Entry) * 4096);
gd_Table *table = (gd_Table *)malloc(s);
if (table)
{
Serial.print(F("new_table() malloc: "));
Serial.println(s);
}
else
{
Serial.print(F("new_table() malloc failed: "));
Serial.println(s);
}
table->entries = (gd_Entry *)&table[1];
return table;
}
void reset_table(gd_Table *table, uint16_t key_size)
{
table->nentries = (1 << key_size) + 2;
for (uint16_t key = 0; key < (1 << key_size); key++)
{
table->entries[key] = (gd_Entry){1, 0xFFF, (uint8_t)key};
}
}
/* Add table entry. Return value:
* 0 on success
* +1 if key size must be incremented after this addition
* -1 if could not realloc table */
int32_t add_entry(gd_Table *table, int32_t length, uint16_t prefix, uint8_t suffix)
{
// Table *table = *tablep;
// if (table->nentries == table->bulk) {
// table->bulk *= 2;
// table = (Table*) realloc(table, sizeof(*table) + sizeof(Entry) * table->bulk);
// if (!table) return -1;
// table->entries = (Entry *) &table[1];
// *tablep = table;
// }
table->entries[table->nentries] = (gd_Entry){length, prefix, suffix};
table->nentries++;
if ((table->nentries & (table->nentries - 1)) == 0)
return 1;
return 0;
}
uint16_t get_key(gd_GIF *gif, uint16_t key_size, uint8_t *sub_len, uint8_t *shift, uint8_t *byte)
{
int16_t bits_read;
int16_t rpad;
int16_t frag_size;
uint16_t key;
key = 0;
for (bits_read = 0; bits_read < key_size; bits_read += frag_size)
{
rpad = (*shift + bits_read) % 8;
if (rpad == 0)
{
/* Update byte. */
if (*sub_len == 0)
gif_buf_read(gif->fd, sub_len, 1); /* Must be nonzero! */
gif_buf_read(gif->fd, byte, 1);
(*sub_len)--;
}
frag_size = MIN(key_size - bits_read, 8 - rpad);
key |= ((uint16_t)((*byte) >> rpad)) << bits_read;
}
/* Clear extra bits to the left. */
key &= (1 << key_size) - 1;
*shift = (*shift + key_size) % 8;
return key;
}
/* Compute output index of y-th input line, in frame of height h. */
int16_t interlaced_line_index(int16_t h, int16_t y)
{
int16_t p; /* number of lines in current pass */
p = (h - 1) / 8 + 1;
if (y < p) /* pass 1 */
return y * 8;
y -= p;
p = (h - 5) / 8 + 1;
if (y < p) /* pass 2 */
return y * 8 + 4;
y -= p;
p = (h - 3) / 4 + 1;
if (y < p) /* pass 3 */
return y * 4 + 2;
y -= p;
/* pass 4 */
return y * 2 + 1;
}
/* Decompress image pixels.
* Return 0 on success or -1 on out-of-memory (w.r.t. LZW code table). */
int8_t read_image_data(gd_GIF *gif, int16_t interlace, uint8_t *frame)
{
uint8_t sub_len, shift, byte, table_is_full = 0;
uint16_t init_key_size, key_size;
int32_t frm_off, str_len = 0, p, x, y;
uint16_t key, clear, stop;
int32_t ret;
gd_Entry entry = {0, 0, 0};
// Serial.println("Read key size");
gif_buf_read(gif->fd, &byte, 1);
key_size = (uint16_t)byte;
// Serial.println("Set pos, discard sub blocks");
// start = gif->fd->position();
// discard_sub_blocks(gif);
// end = gif->fd->position();
// gif_buf_seek(gif->fd, start, SeekSet);
clear = 1 << key_size;
stop = clear + 1;
// Serial.println("New LZW table");
// table = new_table(key_size);
reset_table(gif->table, key_size);
key_size++;
init_key_size = key_size;
sub_len = shift = 0;
// Serial.println("Get init key");
key = get_key(gif, key_size, &sub_len, &shift, &byte); /* clear code */
frm_off = 0;
ret = 0;
while (1)
{
if (key == clear)
{
// Serial.println("Clear key, reset nentries");
key_size = init_key_size;
gif->table->nentries = (1 << (key_size - 1)) + 2;
table_is_full = 0;
}
else if (!table_is_full)
{
// Serial.println("Add entry to table");
ret = add_entry(gif->table, str_len + 1, key, entry.suffix);
// if (ret == -1) {
// // Serial.println("Table entry add failure");
// free(table);
// return -1;
// }
if (gif->table->nentries == 0x1000)
{
// Serial.println("Table is full");
ret = 0;
table_is_full = 1;
}
}
// Serial.println("Get key");
key = get_key(gif, key_size, &sub_len, &shift, &byte);
if (key == clear)
continue;
if (key == stop)
break;
if (ret == 1)
key_size++;
entry = gif->table->entries[key];
str_len = entry.length;
uint8_t tindex = gif->gce.tindex;
// Serial.println("Interpret key");
while (1)
{
p = frm_off + entry.length - 1;
x = p % gif->fw;
y = p / gif->fw;
if (interlace)
{
y = interlaced_line_index((int16_t)gif->fh, y);
}
if (tindex != entry.suffix)
{
frame[(gif->fy + y) * gif->width + gif->fx + x] = entry.suffix;
}
if (entry.prefix == 0xFFF)
break;
else
entry = gif->table->entries[entry.prefix];
}
frm_off += str_len;
if (key < gif->table->nentries - 1 && !table_is_full)
gif->table->entries[gif->table->nentries - 1].suffix = entry.suffix;
}
// Serial.println("Done w/ img data, free table and seek to end");
// free(table);
gif_buf_read(gif->fd, &sub_len, 1); /* Must be zero! */
// gif_buf_seek(gif->fd, end, SeekSet);
return 0;
}
/* Read image.
* Return 0 on success or -1 on out-of-memory (w.r.t. LZW code table). */
int8_t read_image(gd_GIF *gif, uint8_t *frame)
{
uint8_t fisrz;
int16_t interlace;
/* Image Descriptor. */
// Serial.println("Read image descriptor");
gif->fx = gif_buf_read16(gif->fd);
gif->fy = gif_buf_read16(gif->fd);
gif->fw = gif_buf_read16(gif->fd);
gif->fh = gif_buf_read16(gif->fd);
// Serial.println("Read fisrz?");
gif_buf_read(gif->fd, &fisrz, 1);
interlace = fisrz & 0x40;
/* Ignore Sort Flag. */
/* Local Color Table? */
if (fisrz & 0x80)
{
/* Read LCT */
// Serial.println("Read LCT");
read_palette(gif->fd, &gif->lct, 1 << ((fisrz & 0x07) + 1));
gif->palette = &gif->lct;
}
else
{
gif->palette = &gif->gct;
}
/* Image Data. */
// Serial.println("Read image data");
return read_image_data(gif, interlace, frame);
}
void render_frame_rect(gd_GIF *gif, uint16_t *buffer, uint8_t *frame)
{
int16_t i, j, k;
uint8_t index;
i = gif->fy * gif->width + gif->fx;
for (j = 0; j < gif->fh; j++)
{
for (k = 0; k < gif->fw; k++)
{
index = frame[(gif->fy + j) * gif->width + gif->fx + k];
// color = &gif->palette->colors[index*2];
// if (!gif->gce.transparency || index != gif->gce.tindex)
buffer[(i + k)] = gif->palette->colors[index];
// memcpy(&buffer[(i+k)*2], color, 2);
}
i += gif->width;
}
}
int16_t gif_buf_last_idx, gif_buf_idx, file_pos;
uint8_t gif_buf[GIF_BUF_SIZE];
};
#endif /* _GIFCLASS_H_ */

View File

@@ -0,0 +1,301 @@
/*******************************************************************************
* Animated GIF Image Viewer
* This is a simple Animated GIF image viewer exsample
* Image Source: https://www.geocities.ws/finalfantasyfive/ff5animations.html
* optimized with ezgif.com
*
* Setup steps:
* 1. Change your LCD parameters in Arduino_GFX setting
* 2. Upload Animated GIF file
* FFat (ESP32):
* upload FFat (FatFS) data with ESP32 Sketch Data Upload:
* ESP32: https://github.com/lorol/arduino-esp32fs-plugin
* LittleFS (ESP32 / ESP8266 / Pico):
* upload LittleFS data with ESP8266 LittleFS Data Upload:
* ESP32: https://github.com/lorol/arduino-esp32fs-plugin
* ESP8266: https://github.com/earlephilhower/arduino-esp8266littlefs-plugin
* Pico: https://github.com/earlephilhower/arduino-pico-littlefs-plugin.git
* SPIFFS (ESP32):
* upload SPIFFS data with ESP32 Sketch Data Upload:
* ESP32: https://github.com/lorol/arduino-esp32fs-plugin
******************************************************************************/
#define GIF_FILENAME1 "/jobs.gif"
#define GIF_FILENAME2 "/archer.gif"
#define GIF_FILENAME3 "/white.gif"
#define GIF_FILENAME4 "/lancer.gif"
/*******************************************************************************
* Start of Arduino_GFX setting
******************************************************************************/
#include <Arduino_GFX_Library.h>
/* all display share same SPI Data Bus with individual CS, RST pins connected to MCU RST pin */
Arduino_DataBus *bus1 = new Arduino_HWSPI(DF_GFX_DC, 21 /* CS */);
Arduino_GFX *gfx1 = new Arduino_SSD1331(bus1, GFX_NOT_DEFINED /* RST */, 0 /* rotation */);
Arduino_DataBus *bus2 = new Arduino_HWSPI(DF_GFX_DC, 32 /* CS */);
Arduino_GFX *gfx2 = new Arduino_ST7735(bus2, GFX_NOT_DEFINED /* RST */, 3 /* rotation */, true /* IPS */, 80 /* width */, 160 /* height */, 26 /* col offset 1 */, 1 /* row offset 1 */, 26 /* col offset 2 */, 1 /* row offset 2 */);
Arduino_DataBus *bus3 = new Arduino_HWSPI(DF_GFX_DC, 22 /* CS */);
Arduino_GFX *gfx3 = new Arduino_ST7789(bus3, GFX_NOT_DEFINED /* RST */, 0 /* rotation */, true /* IPS */, 240 /* width */, 240 /* height */, 0 /* col offset 1 */, 0 /* row offset 1 */, 0 /* col offset 2 */, 80 /* row offset 2 */);
Arduino_DataBus *bus4 = new Arduino_HWSPI(DF_GFX_DC, 5 /* CS */);
Arduino_GFX *gfx4 = new Arduino_ILI9341(bus4, GFX_NOT_DEFINED /* RST */, 0 /* rotation */, false /* IPS */);
/*******************************************************************************
* End of Arduino_GFX setting
******************************************************************************/
#if defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <LittleFS.h>
#include <SD.h>
#elif defined(ESP32)
#include <FFat.h>
#include <LittleFS.h>
#include <SPIFFS.h>
#include <SD.h>
#elif defined(ESP8266)
#include <LittleFS.h>
#include <SD.h>
#else
#include <SD.h>
#endif
#include "GifClass.h"
static GifClass gifClass1;
static GifClass gifClass2;
static GifClass gifClass3;
static GifClass gifClass4;
void setup()
{
Serial.begin(115200);
// while (!Serial);
Serial.println("Arduino_GFX library Multiple Device Test!");
gfx1->begin();
gfx1->fillScreen(RED);
delay(200);
gfx2->begin();
gfx2->fillScreen(YELLOW);
delay(200);
gfx3->begin();
gfx3->fillScreen(GREEN);
delay(200);
gfx4->begin();
gfx4->fillScreen(BLUE);
delay(200);
#if defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (!LittleFS.begin())
// if (!SD.begin(SS))
#elif defined(ESP32)
// if (!FFat.begin())
if (!LittleFS.begin())
// if (!SPIFFS.begin())
// if (!SD.begin(SS))
#elif defined(ESP8266)
if (!LittleFS.begin())
// if (!SD.begin(SS))
#else
if (!SD.begin())
#endif
{
Serial.println(F("ERROR: File System Mount Failed!"));
gfx4->println(F("ERROR: File System Mount Failed!"));
exit(0);
}
}
void loop()
{
#if defined(ARDUINO_RASPBERRY_PI_PICO) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
File gifFile1 = LittleFS.open(GIF_FILENAME1, "r");
File gifFile2 = LittleFS.open(GIF_FILENAME2, "r");
File gifFile3 = LittleFS.open(GIF_FILENAME3, "r");
File gifFile4 = LittleFS.open(GIF_FILENAME4, "r");
#elif defined(ESP32)
File gifFile1 = LittleFS.open(GIF_FILENAME1, "r");
File gifFile2 = LittleFS.open(GIF_FILENAME2, "r");
File gifFile3 = LittleFS.open(GIF_FILENAME3, "r");
File gifFile4 = LittleFS.open(GIF_FILENAME4, "r");
#elif defined(ESP8266)
File gifFile1 = LittleFS.open(GIF_FILENAME1, "r");
File gifFile2 = LittleFS.open(GIF_FILENAME2, "r");
File gifFile3 = LittleFS.open(GIF_FILENAME3, "r");
File gifFile4 = LittleFS.open(GIF_FILENAME4, "r");
#else
File gifFile1 = SD.open(GIF_FILENAME1, FILE_READ);
File gifFile2 = SD.open(GIF_FILENAME2, FILE_READ);
File gifFile3 = SD.open(GIF_FILENAME3, FILE_READ);
File gifFile4 = SD.open(GIF_FILENAME4, FILE_READ);
#endif
if (!gifFile1 || gifFile1.isDirectory())
{
Serial.println(F("ERROR: open gifFile1 Failed!"));
gfx1->println(F("ERROR: open gifFile1 Failed!"));
}
else if (!gifFile2 || gifFile2.isDirectory())
{
Serial.println(F("ERROR: open gifFile2 Failed!"));
gfx2->println(F("ERROR: open gifFile2 Failed!"));
}
else if (!gifFile3 || gifFile3.isDirectory())
{
Serial.println(F("ERROR: open gifFile3 Failed!"));
gfx3->println(F("ERROR: open gifFile3 Failed!"));
}
else if (!gifFile4 || gifFile4.isDirectory())
{
Serial.println(F("ERROR: open gifFile4 Failed!"));
gfx4->println(F("ERROR: open gifFile4 Failed!"));
}
else
{
// read GIF file header
gd_GIF *gif1 = gifClass1.gd_open_gif(&gifFile1);
gd_GIF *gif2 = gifClass2.gd_open_gif(&gifFile2);
gd_GIF *gif3 = gifClass3.gd_open_gif(&gifFile3);
gd_GIF *gif4 = gifClass4.gd_open_gif(&gifFile4);
if (!gif1)
{
Serial.println(F("gd_open_gif(&gifFile1) failed!"));
}
else if (!gif2)
{
Serial.println(F("gd_open_gif(&gifFile2) failed!"));
}
else if (!gif3)
{
Serial.println(F("gd_open_gif(&gifFile3) failed!"));
}
else if (!gif4)
{
Serial.println(F("gd_open_gif(&gifFile4) failed!"));
}
else
{
uint8_t *buf1 = (uint8_t *)malloc(gif1->width * gif1->height);
uint8_t *buf2 = (uint8_t *)malloc(gif2->width * gif2->height);
uint8_t *buf3 = (uint8_t *)malloc(gif3->width * gif3->height);
uint8_t *buf4 = (uint8_t *)malloc(gif4->width * gif4->height);
if (!buf1)
{
Serial.println(F("buf1 malloc failed!"));
}
if (!buf2)
{
Serial.println(F("buf2 malloc failed!"));
}
if (!buf3)
{
Serial.println(F("buf3 malloc failed!"));
}
if (!buf4)
{
Serial.println(F("buf4 malloc failed!"));
}
else
{
int16_t x1 = (gfx1->width() - gif1->width) / 2;
int16_t y1 = (gfx1->height() - gif1->height) / 2;
int16_t x2 = (gfx2->width() - gif2->width) / 2;
int16_t y2 = (gfx2->height() - gif2->height) / 2;
int16_t x3 = (gfx3->width() - gif3->width) / 2;
int16_t y3 = (gfx3->height() - gif3->height) / 2;
int16_t x4 = (gfx4->width() - gif4->width) / 2;
int16_t y4 = (gfx4->height() - gif4->height) / 2;
Serial.println(F("GIF video start"));
int32_t res1, res2, res3, res4;
uint32_t duration = 0, remain = 0;
while (1)
{
res1 = gifClass1.gd_get_frame(gif1, buf1);
res2 = gifClass2.gd_get_frame(gif2, buf2);
res3 = gifClass3.gd_get_frame(gif3, buf3);
res4 = gifClass4.gd_get_frame(gif4, buf4);
if (res1 < 0)
{
Serial.println(F("ERROR: gd_get_frame(gif1, buf1) failed!"));
break;
}
else if (res1 == 0)
{
Serial.println(F("rewind gif1"));
gifClass1.gd_rewind(gif1);
}
else
{
gfx1->drawIndexedBitmap(x1, y1, buf1, gif1->palette->colors, gif1->width, gif1->height);
}
if (res2 < 0)
{
Serial.println(F("ERROR: gd_get_frame(gif2, buf2) failed!"));
break;
}
else if (res2 == 0)
{
Serial.println(F("rewind gif2"));
gifClass2.gd_rewind(gif2);
}
else
{
gfx2->drawIndexedBitmap(x2, y2, buf2, gif2->palette->colors, gif2->width, gif2->height);
}
if (res3 < 0)
{
Serial.println(F("ERROR: gd_get_frame(gif3, buf3) failed!"));
break;
}
else if (res3 == 0)
{
Serial.println(F("rewind gif3"));
gifClass3.gd_rewind(gif3);
}
else
{
gfx3->drawIndexedBitmap(x3, y3, buf3, gif3->palette->colors, gif3->width, gif3->height);
}
if (res4 < 0)
{
Serial.println(F("ERROR: gd_get_frame(gif4, buf4) failed!"));
break;
}
else if (res4 == 0)
{
Serial.println(F("rewind gif4"));
gifClass4.gd_rewind(gif4);
}
else
{
gfx4->drawIndexedBitmap(x4, y4, buf4, gif4->palette->colors, gif4->width, gif4->height);
}
}
Serial.println(F("GIF video end"));
Serial.print(F("duration: "));
Serial.print(duration);
Serial.print(F(", remain: "));
Serial.print(remain);
Serial.print(F(" ("));
Serial.print(100.0 * remain / duration);
Serial.println(F("%)"));
gifClass1.gd_close_gif(gif1);
gifClass2.gd_close_gif(gif2);
gifClass3.gd_close_gif(gif3);
gifClass4.gd_close_gif(gif4);
free(buf1);
free(buf2);
free(buf3);
free(buf4);
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB