diff --git a/examples/AnimatedGIF/AnimatedGIF.ino b/examples/AnimatedGIF/AnimatedGIF.ino index 77dd3ed..a5830d2 100644 --- a/examples/AnimatedGIF/AnimatedGIF.ino +++ b/examples/AnimatedGIF/AnimatedGIF.ino @@ -56,7 +56,7 @@ GifDecoder 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 diff --git a/examples/AnimatedGIFPanel/AnimatedGIFPanel/AnimatedGIFPanel.ino b/examples/AnimatedGIFPanel/AnimatedGIFPanel/AnimatedGIFPanel.ino new file mode 100644 index 0000000..0f08249 --- /dev/null +++ b/examples/AnimatedGIFPanel/AnimatedGIFPanel/AnimatedGIFPanel.ino @@ -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 +#include +#include + +// ---------------------------- + +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; xucTransparent) + 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; xiWidth; 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(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(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(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 +} diff --git a/examples/AnimatedGIFPanel/AnimatedGIFPanel/README.md b/examples/AnimatedGIFPanel/AnimatedGIFPanel/README.md new file mode 100644 index 0000000..aa55689 --- /dev/null +++ b/examples/AnimatedGIFPanel/AnimatedGIFPanel/README.md @@ -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. + diff --git a/examples/AnimatedGIFPanel/AnimatedGIFPanel/data/gifs/ezgif.com-pacmn.gif b/examples/AnimatedGIFPanel/AnimatedGIFPanel/data/gifs/ezgif.com-pacmn.gif new file mode 100644 index 0000000..0a219a4 Binary files /dev/null and b/examples/AnimatedGIFPanel/AnimatedGIFPanel/data/gifs/ezgif.com-pacmn.gif differ diff --git a/examples/AnimatedGIFPanel/AnimatedGIFPanel/data/gifs/loading.io-64x32px.gif b/examples/AnimatedGIFPanel/AnimatedGIFPanel/data/gifs/loading.io-64x32px.gif new file mode 100644 index 0000000..342f8ae Binary files /dev/null and b/examples/AnimatedGIFPanel/AnimatedGIFPanel/data/gifs/loading.io-64x32px.gif differ diff --git a/examples/AnimatedGIFPanel/AnimatedGIFPanel/data/gifs/matrix-spin.gif b/examples/AnimatedGIFPanel/AnimatedGIFPanel/data/gifs/matrix-spin.gif new file mode 100644 index 0000000..7925d68 Binary files /dev/null and b/examples/AnimatedGIFPanel/AnimatedGIFPanel/data/gifs/matrix-spin.gif differ diff --git a/examples/AnimatedGIFPanel/AnimatedGIFPanel/data/gifs/shock.gif b/examples/AnimatedGIFPanel/AnimatedGIFPanel/data/gifs/shock.gif new file mode 100644 index 0000000..b07d631 Binary files /dev/null and b/examples/AnimatedGIFPanel/AnimatedGIFPanel/data/gifs/shock.gif differ