New GIF animation example based on AnimatedGIF library for better performance.

This commit is contained in:
mrfaptastic 2020-08-10 21:44:25 +01:00
parent ee186006a3
commit 1ffce4e60c
7 changed files with 252 additions and 1 deletions

View file

@ -56,7 +56,7 @@ GifDecoder<GIFWidth, GIFHeight, 12> decoder;
int num_files;
void screenClearCallback(void) {
matrix.fillScreen(matrix.color565(0,0,0));
//matrix.fillScreen(matrix.color565(0,0,0));
}
void updateScreenCallback(void) {
@ -88,6 +88,8 @@ void setup() {
decoder.setFileReadCallback(fileReadCallback);
decoder.setFileReadBlockCallback(fileReadBlockCallback);
matrix.begin();
// Clear screen

View file

@ -0,0 +1,240 @@
// Example sketch which shows how to display a 64x32
// animated GIF image stored in FLASH memory
// on a 64x32 LED matrix
//
// To display a GIF from memory, a single callback function
// must be provided - GIFDRAW
// This function is called after each scan line is decoded
// and is passed the 8-bit pixels, RGB565 palette and info
// about how and where to display the line. The palette entries
// can be in little-endian or big-endian order; this is specified
// in the begin() method.
//
// The AnimatedGIF class doesn't allocate or free any memory, but the
// instance data occupies about 22.5K of RAM.
//
// Credits: https://github.com/bitbank2/AnimatedGIF/tree/master/examples/ESP32_LEDMatrix_I2S
//
#define FILESYSTEM SPIFFS
#include <SPIFFS.h>
#include <AnimatedGIF.h>
#include <ESP32-RGB64x32MatrixPanel-I2S-DMA.h>
// ----------------------------
RGB64x32MatrixPanel_I2S_DMA dma_display;
AnimatedGIF gif;
File f;
int x_offset, y_offset;
// Draw a line of image directly on the LED Matrix
void GIFDraw(GIFDRAW *pDraw)
{
uint8_t *s;
uint16_t *d, *usPalette, usTemp[320];
int x, y, iWidth;
iWidth = pDraw->iWidth;
if (iWidth > MATRIX_WIDTH)
iWidth = MATRIX_WIDTH;
usPalette = pDraw->pPalette;
y = pDraw->iY + pDraw->y; // current line
s = pDraw->pPixels;
if (pDraw->ucDisposalMethod == 2) // restore to background color
{
for (x=0; x<iWidth; x++)
{
if (s[x] == pDraw->ucTransparent)
s[x] = pDraw->ucBackground;
}
pDraw->ucHasTransparency = 0;
}
// Apply the new pixels to the main image
if (pDraw->ucHasTransparency) // if transparency used
{
uint8_t *pEnd, c, ucTransparent = pDraw->ucTransparent;
int x, iCount;
pEnd = s + pDraw->iWidth;
x = 0;
iCount = 0; // count non-transparent pixels
while(x < pDraw->iWidth)
{
c = ucTransparent-1;
d = usTemp;
while (c != ucTransparent && s < pEnd)
{
c = *s++;
if (c == ucTransparent) // done, stop
{
s--; // back up to treat it like transparent
}
else // opaque
{
*d++ = usPalette[c];
iCount++;
}
} // while looking for opaque pixels
if (iCount) // any opaque pixels?
{
for(int xOffset = 0; xOffset < iCount; xOffset++ ){
dma_display.drawPixelRGB565(x + xOffset, y, usTemp[xOffset]);
}
x += iCount;
iCount = 0;
}
// no, look for a run of transparent pixels
c = ucTransparent;
while (c == ucTransparent && s < pEnd)
{
c = *s++;
if (c == ucTransparent)
iCount++;
else
s--;
}
if (iCount)
{
x += iCount; // skip these
iCount = 0;
}
}
}
else // does not have transparency
{
s = pDraw->pPixels;
// Translate the 8-bit pixels through the RGB565 palette (already byte reversed)
for (x=0; x<pDraw->iWidth; x++)
{
dma_display.drawPixelRGB565(x, y, usPalette[*s++]);
}
}
} /* GIFDraw() */
void * GIFOpenFile(char *fname, int32_t *pSize)
{
f = FILESYSTEM.open(fname);
if (f)
{
*pSize = f.size();
return (void *)&f;
}
return NULL;
} /* GIFOpenFile() */
void GIFCloseFile(void *pHandle)
{
File *f = static_cast<File *>(pHandle);
if (f != NULL)
f->close();
} /* GIFCloseFile() */
int32_t GIFReadFile(GIFFILE *pFile, uint8_t *pBuf, int32_t iLen)
{
int32_t iBytesRead;
iBytesRead = iLen;
File *f = static_cast<File *>(pFile->fHandle);
// Note: If you read a file all the way to the last byte, seek() stops working
if ((pFile->iSize - pFile->iPos) < iLen)
iBytesRead = pFile->iSize - pFile->iPos - 1; // <-- ugly work-around
if (iBytesRead <= 0)
return 0;
iBytesRead = (int32_t)f->read(pBuf, iBytesRead);
pFile->iPos = f->position();
return iBytesRead;
} /* GIFReadFile() */
int32_t GIFSeekFile(GIFFILE *pFile, int32_t iPosition)
{
int i = micros();
File *f = static_cast<File *>(pFile->fHandle);
f->seek(iPosition);
pFile->iPos = (int32_t)f->position();
i = micros() - i;
// Serial.printf("Seek time = %d us\n", i);
return pFile->iPos;
} /* GIFSeekFile() */
unsigned long start_tick = 0;
void ShowGIF(char *name)
{
start_tick = millis();
if (gif.open(name, GIFOpenFile, GIFCloseFile, GIFReadFile, GIFSeekFile, GIFDraw))
{
x_offset = (MATRIX_WIDTH - gif.getCanvasWidth())/2;
if (x_offset < 0) x_offset = 0;
y_offset = (MATRIX_HEIGHT - gif.getCanvasHeight())/2;
if (y_offset < 0) y_offset = 0;
Serial.printf("Successfully opened GIF; Canvas size = %d x %d\n", gif.getCanvasWidth(), gif.getCanvasHeight());
Serial.flush();
while (gif.playFrame(true, NULL))
{
if ( (millis() - start_tick) > 8000) { // we'll get bored after about 8 seconds of the same looping gif
break;
}
}
gif.close();
}
} /* ShowGIF() */
/************************* Arduino Sketch Setup and Loop() *******************************/
void setup() {
Serial.begin(115200);
Serial.println("Starting AnimatedGIFs Sketch");
// Start filesystem
Serial.println(" * Loading SPIFFS");
if(!SPIFFS.begin()){
Serial.println("SPIFFS Mount Failed");
}
dma_display.setPanelBrightness(32);
dma_display.setMinRefreshRate(200);
dma_display.begin();
dma_display.fillScreen(dma_display.color565(0, 0, 0));
gif.begin(LITTLE_ENDIAN_PIXELS);
}
void loop() {
char *szDir = "/gifs"; // play all GIFs in this directory on the SD card
char fname[256];
File root, temp;
while (1) // run forever
{
root = FILESYSTEM.open(szDir);
if (root)
{
temp = root.openNextFile();
while (temp)
{
if (!temp.isDirectory()) // play it
{
strcpy(fname, temp.name());
Serial.printf("Playing %s\n", temp.name());
Serial.flush();
ShowGIF((char *)temp.name());
}
temp.close();
temp = root.openNextFile();
}
root.close();
} // root
delay(4000); // pause before restarting
} // while
}

View file

@ -0,0 +1,9 @@
=== Animated GIF Decoding Example ===
==== Prerequisite ====
1. The excellent 'AnimatedGIF' library by Larry Bank needs to be installed: https://github.com/bitbank2/AnimatedGIF
This is available via the Arduino Library manager, or can be placed in the 'libs' directory with PlatformIO.
2. The files in the 'data' folder are written to the ESP32's SPIFFS file system.

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB