diff --git a/examples/AnimatedGIF/AnimatedGIF.ino b/examples/AnimatedGIF/AnimatedGIF.ino deleted file mode 100644 index a5830d2..0000000 --- a/examples/AnimatedGIF/AnimatedGIF.ino +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Written by: Craig A. Lindley - * - * Copyright (c) 2014 Craig A. Lindley - * Refactoring by Louis Beaudoin (Pixelmatix) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include -#include -#include - -RGB64x32MatrixPanel_I2S_DMA matrix; - - -#include "GifDecoder.h" -#include "FilenameFunctions.h" - -/* GIF files for this particular example need to be put into the 'data' directoy of the - * sketch and saved to the ESP32 using the "ESP32 Sketch Data Upload" tool in Arduino. - * - * URL: https://github.com/me-no-dev/arduino-esp32fs-plugin - * - */ -#define GIF_DIRECTORY "/" -#define DISPLAY_TIME_SECONDS 5 - -// Gif sizes should match exactly that of the RGB Matrix display. -const uint8_t GIFWidth = 64; -const uint8_t GIFHeight = 32; - -/* template parameters are maxGifWidth, maxGifHeight, lzwMaxBits - * - * The lzwMaxBits value of 12 supports all GIFs, but uses 16kB RAM - * lzwMaxBits can be set to 10 or 11 for small displays, 12 for large displays - * All 32x32-pixel GIFs tested work with 11, most work with 10 - */ -GifDecoder decoder; - -int num_files; - -void screenClearCallback(void) { - //matrix.fillScreen(matrix.color565(0,0,0)); -} - -void updateScreenCallback(void) { - //backgroundLayer.swapBuffers(); -} - -void drawPixelCallback(int16_t x, int16_t y, uint8_t red, uint8_t green, uint8_t blue) { - matrix.drawPixelRGB888(x, y, red, green, blue); -} - -// Setup method runs once, when the sketch starts -void setup() { - - Serial.begin(115200); - Serial.println("Starting AnimatedGIFs Sketch"); - - // Start filesystem - Serial.println(" * Loading SPIFFS"); - if(!SPIFFS.begin()){ - Serial.println("SPIFFS Mount Failed"); - } - - decoder.setScreenClearCallback(screenClearCallback); - decoder.setUpdateScreenCallback(updateScreenCallback); - decoder.setDrawPixelCallback(drawPixelCallback); - - decoder.setFileSeekCallback(fileSeekCallback); - decoder.setFilePositionCallback(filePositionCallback); - decoder.setFileReadCallback(fileReadCallback); - decoder.setFileReadBlockCallback(fileReadBlockCallback); - - - - matrix.begin(); - - // Clear screen - matrix.fillScreen(matrix.color565(0,0,0)); - - // Determine how many animated GIF files exist - num_files = enumerateGIFFiles(GIF_DIRECTORY, false); - - if(num_files < 0) { - Serial.println("No gifs directory"); - while(1); - } - - if(!num_files) { - Serial.println("Empty gifs directory"); - while(1); - } -} - -int file_index = -1; -void loop() { - static unsigned long futureTime; - - // int index = -1; //random(num_files); - - if(futureTime < millis()) { - if (++file_index >= num_files) { - file_index = 0; - } - - if (openGifFilenameByIndex(GIF_DIRECTORY, file_index) >= 0) { - // Can clear screen for new animation here, but this might cause flicker with short animations - // matrix.fillScreen(COLOR_BLACK); - // matrix.swapBuffers(); - - decoder.startDecoding(); - - // Calculate time in the future to terminate animation - futureTime = millis() + (DISPLAY_TIME_SECONDS * 1000); - } - } - - decoder.decodeFrame(); -} diff --git a/examples/AnimatedGIF/FSBrowser.h b/examples/AnimatedGIF/FSBrowser.h deleted file mode 100644 index c380226..0000000 --- a/examples/AnimatedGIF/FSBrowser.h +++ /dev/null @@ -1,179 +0,0 @@ -// ADAPTED FROM: https://github.com/espressif/arduino-esp32/blob/master/libraries/WebServer/examples/FSBrowser/FSBrowser.ino - -#define FILESYSTEM SPIFFS -#define FORMAT_FILESYSTEM true -#define DBG_OUTPUT_PORT Serial - - -//holds the current upload -File fsUploadFile; - -//format bytes -String formatBytes(size_t bytes) { - if (bytes < 1024) { - return String(bytes) + "B"; - } else if (bytes < (1024 * 1024)) { - return String(bytes / 1024.0) + "KB"; - } else if (bytes < (1024 * 1024 * 1024)) { - return String(bytes / 1024.0 / 1024.0) + "MB"; - } else { - return String(bytes / 1024.0 / 1024.0 / 1024.0) + "GB"; - } -} - -String getContentType(String filename) { - if (webServer.hasArg("download")) { - return "application/octet-stream"; - } else if (filename.endsWith(".htm")) { - return "text/html"; - } else if (filename.endsWith(".html")) { - return "text/html"; - } else if (filename.endsWith(".css")) { - return "text/css"; - } else if (filename.endsWith(".js")) { - return "application/javascript"; - } else if (filename.endsWith(".png")) { - return "image/png"; - } else if (filename.endsWith(".gif")) { - return "image/gif"; - } else if (filename.endsWith(".jpg")) { - return "image/jpeg"; - } else if (filename.endsWith(".ico")) { - return "image/x-icon"; - } else if (filename.endsWith(".xml")) { - return "text/xml"; - } else if (filename.endsWith(".pdf")) { - return "application/x-pdf"; - } else if (filename.endsWith(".zip")) { - return "application/x-zip"; - } else if (filename.endsWith(".gz")) { - return "application/x-gzip"; - } - return "text/plain"; -} - -bool exists(String path){ - bool yes = false; - File file = FILESYSTEM.open(path, "r"); - if(!file.isDirectory()){ - yes = true; - } - file.close(); - return yes; -} - -bool handleFileRead(String path) { - DBG_OUTPUT_PORT.println("handleFileRead: " + path); - if (path.endsWith("/")) { - path += "index.htm"; - } - String contentType = getContentType(path); - String pathWithGz = path + ".gz"; - if (exists(pathWithGz) || exists(path)) { - if (exists(pathWithGz)) { - path += ".gz"; - } - File file = FILESYSTEM.open(path, "r"); - webServer.streamFile(file, contentType); - file.close(); - return true; - } - return false; -} - -void handleFileUpload() { - if (webServer.uri() != "/edit") { - return; - } - HTTPUpload& upload = webServer.upload(); - if (upload.status == UPLOAD_FILE_START) { - String filename = upload.filename; - if (!filename.startsWith("/")) { - filename = "/" + filename; - } - DBG_OUTPUT_PORT.print("handleFileUpload Name: "); DBG_OUTPUT_PORT.println(filename); - fsUploadFile = FILESYSTEM.open(filename, "w"); - filename = String(); - } else if (upload.status == UPLOAD_FILE_WRITE) { - //DBG_OUTPUT_PORT.print("handleFileUpload Data: "); DBG_OUTPUT_PORT.println(upload.currentSize); - if (fsUploadFile) { - fsUploadFile.write(upload.buf, upload.currentSize); - } - } else if (upload.status == UPLOAD_FILE_END) { - if (fsUploadFile) { - fsUploadFile.close(); - } - DBG_OUTPUT_PORT.print("handleFileUpload Size: "); DBG_OUTPUT_PORT.println(upload.totalSize); - } -} - -void handleFileDelete() { - if (webServer.args() == 0) { - return webServer.send(500, "text/plain", "BAD ARGS"); - } - String path = webServer.arg(0); - DBG_OUTPUT_PORT.println("handleFileDelete: " + path); - if (path == "/") { - return webServer.send(500, "text/plain", "BAD PATH"); - } - if (!exists(path)) { - return webServer.send(404, "text/plain", "FileNotFound"); - } - FILESYSTEM.remove(path); - webServer.send(200, "text/plain", ""); - path = String(); -} - -void handleFileCreate() { - if (webServer.args() == 0) { - return webServer.send(500, "text/plain", "BAD ARGS"); - } - String path = webServer.arg(0); - DBG_OUTPUT_PORT.println("handleFileCreate: " + path); - if (path == "/") { - return webServer.send(500, "text/plain", "BAD PATH"); - } - if (exists(path)) { - return webServer.send(500, "text/plain", "FILE EXISTS"); - } - File file = FILESYSTEM.open(path, "w"); - if (file) { - file.close(); - } else { - return webServer.send(500, "text/plain", "CREATE FAILED"); - } - webServer.send(200, "text/plain", ""); - path = String(); -} - -void handleFileList() { - if (!webServer.hasArg("dir")) { - webServer.send(500, "text/plain", "BAD ARGS"); - return; - } - - String path = webServer.arg("dir"); - DBG_OUTPUT_PORT.println("handleFileList: " + path); - - - File root = FILESYSTEM.open(path); - path = String(); - - String output = "["; - if(root.isDirectory()){ - File file = root.openNextFile(); - while(file){ - if (output != "[") { - output += ','; - } - output += "{\"type\":\""; - output += (file.isDirectory()) ? "dir" : "file"; - output += "\",\"name\":\""; - output += String(file.name()).substring(1); - output += "\"}"; - file = root.openNextFile(); - } - } - output += "]"; - webServer.send(200, "text/json", output); -} diff --git a/examples/AnimatedGIF/FilenameFunctions.cpp b/examples/AnimatedGIF/FilenameFunctions.cpp deleted file mode 100644 index e8a8f04..0000000 --- a/examples/AnimatedGIF/FilenameFunctions.cpp +++ /dev/null @@ -1,169 +0,0 @@ -/* - * Animated GIFs Display Code for SmartMatrix and 32x32 RGB LED Panels - * - * This file contains code to enumerate and select animated GIF files by name - * - * Written by: Craig A. Lindley - * - * Other references: https://github.com/espressif/arduino-esp32/blob/master/libraries/WebServer/examples/FSBrowser/FSBrowser.ino - * - */ - -#include "FilenameFunctions.h" - -File file; - -int numberOfFiles; - -bool fileSeekCallback(unsigned long position) { - return file.seek(position); -} - -unsigned long filePositionCallback(void) { - return file.position(); -} - -int fileReadCallback(void) { - return file.read(); -} - -int fileReadBlockCallback(void * buffer, int numberOfBytes) { - return file.read((uint8_t*)buffer, numberOfBytes); -} - -bool isAnimationFile(const char filename []) { - String filenameString(filename); - -#if defined(ESP32) - // ESP32 filename includes the full path, so need to remove the path before looking at the filename - int pathindex = filenameString.lastIndexOf("/"); - if(pathindex >= 0) - filenameString.remove(0, pathindex + 1); -#endif - - DBG_OUTPUT_PORT.print(filenameString); - - if ((filenameString[0] == '_') || (filenameString[0] == '~') || (filenameString[0] == '.')) { - DBG_OUTPUT_PORT.println(" ignoring: leading _/~/. character"); - return false; - } - - filenameString.toUpperCase(); - if (filenameString.endsWith(".GIF") != 1) { - DBG_OUTPUT_PORT.println(" ignoring: doesn't end of .GIF"); - return false; - } - - DBG_OUTPUT_PORT.println(); - - return true; -} - -// Enumerate and possibly display the animated GIF filenames in GIFS directory -int enumerateGIFFiles(const char *directoryName, boolean displayFilenames) { - - numberOfFiles = 0; - - File directory = FILESYSTEM.open(directoryName); - if (!directory) { - return -1; - } - - File file = directory.openNextFile(); - while (file) { - if (isAnimationFile(file.name())) { - numberOfFiles++; - if (displayFilenames) { - DBG_OUTPUT_PORT.println(file.name()); - } - } - file.close(); - file = directory.openNextFile(); - } - - file.close(); - directory.close(); - - return numberOfFiles; -} - -// Get the full path/filename of the GIF file with specified index -void getGIFFilenameByIndex(const char *directoryName, int index, char *pnBuffer) { - - char* filename; - - // Make sure index is in range - if ((index < 0) || (index >= numberOfFiles)) - return; - - File directory = FILESYSTEM.open(directoryName); - if (!directory) - return; - - File file = directory.openNextFile(); - while (file && (index >= 0)) { - filename = (char*)file.name(); - - if (isAnimationFile(file.name())) { - index--; - -#if !defined(ESP32) - // Copy the directory name into the pathname buffer - ESP32 SD Library includes the full path name in the filename, so no need to add the directory name - strcpy(pnBuffer, directoryName); - // Append the filename to the pathname - strcat(pnBuffer, filename); -#else - strcpy(pnBuffer, filename); -#endif - } - - file.close(); - file = directory.openNextFile(); - } - - file.close(); - directory.close(); -} - -int openGifFilenameByIndex(const char *directoryName, int index) { - char pathname[30]; // long filename will break this... Smash the stack! i.e: - /* - * Stack smashing protect failure! - * - * abort() was called at PC 0x400d9a90 on core 1 - * - * Backtrace: 0x40088578:0x3ffb1ec0 0x4008877b:0x3ffb1ee0 0x400d9a90:0x3ffb1f00 0x400d1d62:0x3ffb1f20 0x400d182f:0x3ffb1f80 0x400ef86e:0x3ffb1fa0 - * - * Rebooting... - - */ - - getGIFFilenameByIndex(directoryName, index, pathname); - - DBG_OUTPUT_PORT.print("Pathname: "); - DBG_OUTPUT_PORT.println(pathname); - - if(file) - { - file.close(); - DBG_OUTPUT_PORT.print("Closing old file..."); - } - - // Attempt to open the file for reading - DBG_OUTPUT_PORT.print("Opening new file..."); - file = FILESYSTEM.open(pathname); - if (!file) { - DBG_OUTPUT_PORT.println("Error opening GIF file"); - return -1; - } - - return 0; -} - - -// Return a random animated gif path/filename from the specified directory -void chooseRandomGIFFilename(const char *directoryName, char *pnBuffer) { - - int index = random(numberOfFiles); - getGIFFilenameByIndex(directoryName, index, pnBuffer); -} diff --git a/examples/AnimatedGIF/FilenameFunctions.h b/examples/AnimatedGIF/FilenameFunctions.h deleted file mode 100644 index 2c92c10..0000000 --- a/examples/AnimatedGIF/FilenameFunctions.h +++ /dev/null @@ -1,21 +0,0 @@ -#ifndef FILENAME_FUNCTIONS_H -#define FILENAME_FUNCTIONS_H - -#include "FS.h" // for the 'File' class -#include - - -#define FILESYSTEM SPIFFS -#define DBG_OUTPUT_PORT Serial - - -int enumerateGIFFiles(const char *directoryName, boolean displayFilenames); -void getGIFFilenameByIndex(const char *directoryName, int index, char *pnBuffer); -int openGifFilenameByIndex(const char *directoryName, int index); - -bool fileSeekCallback(unsigned long position); -unsigned long filePositionCallback(void); -int fileReadCallback(void); -int fileReadBlockCallback(void * buffer, int numberOfBytes); - -#endif diff --git a/examples/AnimatedGIF/GifDecoder.h b/examples/AnimatedGIF/GifDecoder.h deleted file mode 100644 index 8a3d14a..0000000 --- a/examples/AnimatedGIF/GifDecoder.h +++ /dev/null @@ -1,148 +0,0 @@ -#ifndef _GIFDECODER_H_ -#define _GIFDECODER_H_ - -#include -#include - - -typedef void (*callback)(void); -typedef void (*pixel_callback)(int16_t x, int16_t y, uint8_t red, uint8_t green, uint8_t blue); -typedef void* (*get_buffer_callback)(void); - -typedef bool (*file_seek_callback)(unsigned long position); -typedef unsigned long (*file_position_callback)(void); -typedef int (*file_read_callback)(void); -typedef int (*file_read_block_callback)(void * buffer, int numberOfBytes); - -// LZW constants -// NOTE: LZW_MAXBITS should be set to 10 or 11 for small displays, 12 for large displays -// all 32x32-pixel GIFs tested work with 11, most work with 10 -// LZW_MAXBITS = 12 will support all GIFs, but takes 16kB RAM -#define LZW_SIZTABLE (1 << lzwMaxBits) - -template -class GifDecoder { -public: - int startDecoding(void); - int decodeFrame(void); - - void setScreenClearCallback(callback f); - void setUpdateScreenCallback(callback f); - void setDrawPixelCallback(pixel_callback f); - void setStartDrawingCallback(callback f); - - void setFileSeekCallback(file_seek_callback f); - void setFilePositionCallback(file_position_callback f); - void setFileReadCallback(file_read_callback f); - void setFileReadBlockCallback(file_read_block_callback f); - -private: - void parseTableBasedImage(void); - void decompressAndDisplayFrame(unsigned long filePositionAfter); - int parseData(void); - int parseGIFFileTerminator(void); - void parseCommentExtension(void); - void parseApplicationExtension(void); - void parseGraphicControlExtension(void); - void parsePlainTextExtension(void); - void parseGlobalColorTable(void); - void parseLogicalScreenDescriptor(void); - bool parseGifHeader(void); - void copyImageDataRect(uint8_t *dst, uint8_t *src, int x, int y, int width, int height); - void fillImageData(uint8_t colorIndex); - void fillImageDataRect(uint8_t colorIndex, int x, int y, int width, int height); - int readIntoBuffer(void *buffer, int numberOfBytes); - int readWord(void); - void backUpStream(int n); - int readByte(void); - - void lzw_decode_init(int csize); - int lzw_decode(uint8_t *buf, int len, uint8_t *bufend); - void lzw_setTempBuffer(uint8_t * tempBuffer); - int lzw_get_code(void); - - // Logical screen descriptor attributes - int lsdWidth; - int lsdHeight; - int lsdPackedField; - int lsdAspectRatio; - int lsdBackgroundIndex; - - // Table based image attributes - int tbiImageX; - int tbiImageY; - int tbiWidth; - int tbiHeight; - int tbiPackedBits; - bool tbiInterlaced; - - int frameDelay; - int transparentColorIndex; - int prevBackgroundIndex; - int prevDisposalMethod; - int disposalMethod; - int lzwCodeSize; - bool keyFrame; - int rectX; - int rectY; - int rectWidth; - int rectHeight; - - unsigned long nextFrameTime_ms; - - int colorCount; - rgb_24 palette[256]; - - char tempBuffer[260]; - - // Buffer image data is decoded into - uint8_t imageData[maxGifWidth * maxGifHeight]; - - // Backup image data buffer for saving portions of image disposal method == 3 - uint8_t imageDataBU[maxGifWidth * maxGifHeight]; - - callback screenClearCallback; - callback updateScreenCallback; - pixel_callback drawPixelCallback; - callback startDrawingCallback; - file_seek_callback fileSeekCallback; - file_position_callback filePositionCallback; - file_read_callback fileReadCallback; - file_read_block_callback fileReadBlockCallback; - - // LZW variables - int bbits; - int bbuf; - int cursize; // The current code size - int curmask; - int codesize; - int clear_code; - int end_code; - int newcodes; // First available code - int top_slot; // Highest code for current size - int extra_slot; - int slot; // Last read code - int fc, oc; - int bs; // Current buffer size for GIF - int bcnt; - uint8_t *sp; - uint8_t * temp_buffer; - - uint8_t stack [LZW_SIZTABLE]; - uint8_t suffix [LZW_SIZTABLE]; - uint16_t prefix [LZW_SIZTABLE]; - - // Masks for 0 .. 16 bits - unsigned int mask[17] = { - 0x0000, 0x0001, 0x0003, 0x0007, - 0x000F, 0x001F, 0x003F, 0x007F, - 0x00FF, 0x01FF, 0x03FF, 0x07FF, - 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, - 0xFFFF - }; -}; - -#include "GifDecoder_Impl.h" -#include "LzwDecoder_Impl.h" - -#endif diff --git a/examples/AnimatedGIF/GifDecoder_Impl.h b/examples/AnimatedGIF/GifDecoder_Impl.h deleted file mode 100644 index c7c5a5d..0000000 --- a/examples/AnimatedGIF/GifDecoder_Impl.h +++ /dev/null @@ -1,806 +0,0 @@ -/* - * This file contains code to parse animated GIF files - * - * Written by: Craig A. Lindley - * - * Copyright (c) 2014 Craig A. Lindley - * Minor modifications by Louis Beaudoin (pixelmatix) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#define GIFDEBUG 0 - -// This file contains C code, and ESP32 Arduino has changed to use the C++ template version of min()/max() which we can't use with C, so we can't depend on a #define min() from Arduino anymore -#ifndef min -#define min(a,b) ((a)<(b)?(a):(b)) -#endif - -#include "GifDecoder.h" - -#if GIFDEBUG == 1 -#define DEBUG_SCREEN_DESCRIPTOR 1 -#define DEBUG_GLOBAL_COLOR_TABLE 1 -#define DEBUG_PROCESSING_PLAIN_TEXT_EXT 1 -#define DEBUG_PROCESSING_GRAPHIC_CONTROL_EXT 1 -#define DEBUG_PROCESSING_APP_EXT 1 -#define DEBUG_PROCESSING_COMMENT_EXT 1 -#define DEBUG_PROCESSING_FILE_TERM 1 -#define DEBUG_PROCESSING_TABLE_IMAGE_DESC 1 -#define DEBUG_PROCESSING_TBI_DESC_START 1 -#define DEBUG_PROCESSING_TBI_DESC_INTERLACED 1 -#define DEBUG_PROCESSING_TBI_DESC_LOCAL_COLOR_TABLE 1 -#define DEBUG_PROCESSING_TBI_DESC_LZWCODESIZE 1 -#define DEBUG_PROCESSING_TBI_DESC_DATABLOCKSIZE 1 -#define DEBUG_PROCESSING_TBI_DESC_LZWIMAGEDATA_OVERFLOW 1 -#define DEBUG_PROCESSING_TBI_DESC_LZWIMAGEDATA_SIZE 1 -#define DEBUG_PARSING_DATA 1 -#define DEBUG_DECOMPRESS_AND_DISPLAY 1 - -#define DEBUG_WAIT_FOR_KEY_PRESS 0 - -#endif - -#include "GifDecoder.h" - - -// Error codes -#define ERROR_NONE 0 -#define ERROR_DONE_PARSING 1 -#define ERROR_WAITING 2 -#define ERROR_FILEOPEN -1 -#define ERROR_FILENOTGIF -2 -#define ERROR_BADGIFFORMAT -3 -#define ERROR_UNKNOWNCONTROLEXT -4 - -#define GIFHDRTAGNORM "GIF87a" // tag in valid GIF file -#define GIFHDRTAGNORM1 "GIF89a" // tag in valid GIF file -#define GIFHDRSIZE 6 - -// Global GIF specific definitions -#define COLORTBLFLAG 0x80 -#define INTERLACEFLAG 0x40 -#define TRANSPARENTFLAG 0x01 - -#define NO_TRANSPARENT_INDEX -1 - -// Disposal methods -#define DISPOSAL_NONE 0 -#define DISPOSAL_LEAVE 1 -#define DISPOSAL_BACKGROUND 2 -#define DISPOSAL_RESTORE 3 - - - -template -void GifDecoder::setStartDrawingCallback(callback f) { - startDrawingCallback = f; -} - -template -void GifDecoder::setUpdateScreenCallback(callback f) { - updateScreenCallback = f; -} - -template -void GifDecoder::setDrawPixelCallback(pixel_callback f) { - drawPixelCallback = f; -} - -template -void GifDecoder::setScreenClearCallback(callback f) { - screenClearCallback = f; -} - -template -void GifDecoder::setFileSeekCallback(file_seek_callback f) { - fileSeekCallback = f; -} - -template -void GifDecoder::setFilePositionCallback(file_position_callback f) { - filePositionCallback = f; -} - -template -void GifDecoder::setFileReadCallback(file_read_callback f) { - fileReadCallback = f; -} - -template -void GifDecoder::setFileReadBlockCallback(file_read_block_callback f) { - fileReadBlockCallback = f; -} - -// Backup the read stream by n bytes -template -void GifDecoder::backUpStream(int n) { - fileSeekCallback(filePositionCallback() - n); -} - -// Read a file byte -template -int GifDecoder::readByte() { - - int b = fileReadCallback(); - if (b == -1) { -#if GIFDEBUG == 1 - Serial.println("Read error or EOF occurred"); -#endif - } - return b; -} - -// Read a file word -template -int GifDecoder::readWord() { - - int b0 = readByte(); - int b1 = readByte(); - return (b1 << 8) | b0; -} - -// Read the specified number of bytes into the specified buffer -template -int GifDecoder::readIntoBuffer(void *buffer, int numberOfBytes) { - - int result = fileReadBlockCallback(buffer, numberOfBytes); - if (result == -1) { - Serial.println("Read error or EOF occurred"); - } - return result; -} - -// Fill a portion of imageData buffer with a color index -template -void GifDecoder::fillImageDataRect(uint8_t colorIndex, int x, int y, int width, int height) { - - int yOffset; - - for (int yy = y; yy < height + y; yy++) { - yOffset = yy * maxGifWidth; - for (int xx = x; xx < width + x; xx++) { - imageData[yOffset + xx] = colorIndex; - } - } -} - -// Fill entire imageData buffer with a color index -template -void GifDecoder::fillImageData(uint8_t colorIndex) { - - memset(imageData, colorIndex, sizeof(imageData)); -} - -// Copy image data in rect from a src to a dst -template -void GifDecoder::copyImageDataRect(uint8_t *dst, uint8_t *src, int x, int y, int width, int height) { - - int yOffset, offset; - - for (int yy = y; yy < height + y; yy++) { - yOffset = yy * maxGifWidth; - for (int xx = x; xx < width + x; xx++) { - offset = yOffset + xx; - dst[offset] = src[offset]; - } - } -} - -// Make sure the file is a Gif file -template -bool GifDecoder::parseGifHeader() { - - char buffer[10]; - - readIntoBuffer(buffer, GIFHDRSIZE); - if ((strncmp(buffer, GIFHDRTAGNORM, GIFHDRSIZE) != 0) && - (strncmp(buffer, GIFHDRTAGNORM1, GIFHDRSIZE) != 0)) { - return false; - } - else { - return true; - } -} - -// Parse the logical screen descriptor -template -void GifDecoder::parseLogicalScreenDescriptor() { - - lsdWidth = readWord(); - lsdHeight = readWord(); - lsdPackedField = readByte(); - lsdBackgroundIndex = readByte(); - lsdAspectRatio = readByte(); - -#if GIFDEBUG == 1 && DEBUG_SCREEN_DESCRIPTOR == 1 - Serial.print("lsdWidth: "); - Serial.println(lsdWidth); - Serial.print("lsdHeight: "); - Serial.println(lsdHeight); - Serial.print("lsdPackedField: "); - Serial.println(lsdPackedField, HEX); - Serial.print("lsdBackgroundIndex: "); - Serial.println(lsdBackgroundIndex); - Serial.print("lsdAspectRatio: "); - Serial.println(lsdAspectRatio); -#endif -} - -// Parse the global color table -template -void GifDecoder::parseGlobalColorTable() { - - // Does a global color table exist? - if (lsdPackedField & COLORTBLFLAG) { - - // A GCT was present determine how many colors it contains - colorCount = 1 << ((lsdPackedField & 7) + 1); - -#if GIFDEBUG == 1 && DEBUG_GLOBAL_COLOR_TABLE == 1 - Serial.print("Global color table with "); - Serial.print(colorCount); - Serial.println(" colors present"); -#endif - // Read color values into the palette array - int colorTableBytes = sizeof(rgb_24) * colorCount; - readIntoBuffer(palette, colorTableBytes); - } -} - -// Parse plain text extension and dispose of it -template -void GifDecoder::parsePlainTextExtension() { - -#if GIFDEBUG == 1 && DEBUG_PROCESSING_PLAIN_TEXT_EXT == 1 - Serial.println("\nProcessing Plain Text Extension"); -#endif - // Read plain text header length - uint8_t len = readByte(); - - // Consume plain text header data - readIntoBuffer(tempBuffer, len); - - // Consume the plain text data in blocks - len = readByte(); - while (len != 0) { - readIntoBuffer(tempBuffer, len); - len = readByte(); - } -} - -// Parse a graphic control extension -template -void GifDecoder::parseGraphicControlExtension() { - -#if GIFDEBUG == 1 && DEBUG_PROCESSING_GRAPHIC_CONTROL_EXT == 1 - Serial.println("\nProcessing Graphic Control Extension"); -#endif - int len = readByte(); // Check length - if (len != 4) { - Serial.println("Bad graphic control extension"); - } - - int packedBits = readByte(); - frameDelay = readWord(); - transparentColorIndex = readByte(); - - if ((packedBits & TRANSPARENTFLAG) == 0) { - // Indicate no transparent index - transparentColorIndex = NO_TRANSPARENT_INDEX; - } - disposalMethod = (packedBits >> 2) & 7; - if (disposalMethod > 3) { - disposalMethod = 0; - Serial.println("Invalid disposal value"); - } - - readByte(); // Toss block end - -#if GIFDEBUG == 1 && DEBUG_PROCESSING_GRAPHIC_CONTROL_EXT == 1 - Serial.print("PacketBits: "); - Serial.println(packedBits, HEX); - Serial.print("Frame delay: "); - Serial.println(frameDelay); - Serial.print("transparentColorIndex: "); - Serial.println(transparentColorIndex); - Serial.print("disposalMethod: "); - Serial.println(disposalMethod); -#endif -} - -// Parse application extension -template -void GifDecoder::parseApplicationExtension() { - - memset(tempBuffer, 0, sizeof(tempBuffer)); - -#if GIFDEBUG == 1 && DEBUG_PROCESSING_APP_EXT == 1 - Serial.println("\nProcessing Application Extension"); -#endif - - // Read block length - uint8_t len = readByte(); - - // Read app data - readIntoBuffer(tempBuffer, len); - -#if GIFDEBUG == 1 && DEBUG_PROCESSING_APP_EXT == 1 - // Conditionally display the application extension string - if (strlen(tempBuffer) != 0) { - Serial.print("Application Extension: "); - Serial.println(tempBuffer); - } -#endif - - // Consume any additional app data - len = readByte(); - while (len != 0) { - readIntoBuffer(tempBuffer, len); - len = readByte(); - } -} - -// Parse comment extension -template -void GifDecoder::parseCommentExtension() { - -#if GIFDEBUG == 1 && DEBUG_PROCESSING_COMMENT_EXT == 1 - Serial.println("\nProcessing Comment Extension"); -#endif - - // Read block length - uint8_t len = readByte(); - while (len != 0) { - // Clear buffer - memset(tempBuffer, 0, sizeof(tempBuffer)); - - // Read len bytes into buffer - readIntoBuffer(tempBuffer, len); - -#if GIFDEBUG == 1 && DEBUG_PROCESSING_COMMENT_EXT == 1 - // Display the comment extension string - if (strlen(tempBuffer) != 0) { - Serial.print("Comment Extension: "); - Serial.println(tempBuffer); - } -#endif - // Read the new block length - len = readByte(); - } -} - -// Parse file terminator -template -int GifDecoder::parseGIFFileTerminator() { - -#if GIFDEBUG == 1 && DEBUG_PROCESSING_FILE_TERM == 1 - Serial.println("\nProcessing file terminator"); -#endif - - uint8_t b = readByte(); - if (b != 0x3B) { - -#if GIFDEBUG == 1 && DEBUG_PROCESSING_FILE_TERM == 1 - Serial.print("Terminator byte: "); - Serial.println(b, HEX); -#endif - Serial.println("Bad GIF file format - Bad terminator"); - return ERROR_BADGIFFORMAT; - } - else { - return ERROR_NONE; - } -} - -// Parse table based image data -template -void GifDecoder::parseTableBasedImage() { - -#if GIFDEBUG == 1 && DEBUG_PROCESSING_TBI_DESC_START == 1 - Serial.println("\nProcessing Table Based Image Descriptor"); -#endif - -#if GIFDEBUG == 1 && DEBUG_PARSING_DATA == 1 - Serial.println("File Position: "); - Serial.println(filePositionCallback()); - Serial.println("File Size: "); - //Serial.println(file.size()); -#endif - - // Parse image descriptor - tbiImageX = readWord(); - tbiImageY = readWord(); - tbiWidth = readWord(); - tbiHeight = readWord(); - tbiPackedBits = readByte(); - -#if GIFDEBUG == 1 - Serial.print("tbiImageX: "); - Serial.println(tbiImageX); - Serial.print("tbiImageY: "); - Serial.println(tbiImageY); - Serial.print("tbiWidth: "); - Serial.println(tbiWidth); - Serial.print("tbiHeight: "); - Serial.println(tbiHeight); - Serial.print("PackedBits: "); - Serial.println(tbiPackedBits, HEX); -#endif - - // Is this image interlaced ? - tbiInterlaced = ((tbiPackedBits & INTERLACEFLAG) != 0); - -#if GIFDEBUG == 1 && DEBUG_PROCESSING_TBI_DESC_INTERLACED == 1 - Serial.print("Image interlaced: "); - Serial.println((tbiInterlaced != 0) ? "Yes" : "No"); -#endif - - // Does this image have a local color table ? - bool localColorTable = ((tbiPackedBits & COLORTBLFLAG) != 0); - - if (localColorTable) { - int colorBits = ((tbiPackedBits & 7) + 1); - colorCount = 1 << colorBits; - -#if GIFDEBUG == 1 && DEBUG_PROCESSING_TBI_DESC_LOCAL_COLOR_TABLE == 1 - Serial.print("Local color table with "); - Serial.print(colorCount); - Serial.println(" colors present"); -#endif - // Read colors into palette - int colorTableBytes = sizeof(rgb_24) * colorCount; - readIntoBuffer(palette, colorTableBytes); - } - - // One time initialization of imageData before first frame - if (keyFrame) { - if (transparentColorIndex == NO_TRANSPARENT_INDEX) { - fillImageData(lsdBackgroundIndex); - } - else { - fillImageData(transparentColorIndex); - } - keyFrame = false; - - rectX = 0; - rectY = 0; - rectWidth = maxGifWidth; - rectHeight = maxGifHeight; - } - // Don't clear matrix screen for these disposal methods - if ((prevDisposalMethod != DISPOSAL_NONE) && (prevDisposalMethod != DISPOSAL_LEAVE)) { - if(screenClearCallback) - (*screenClearCallback)(); - } - - // Process previous disposal method - if (prevDisposalMethod == DISPOSAL_BACKGROUND) { - // Fill portion of imageData with previous background color - fillImageDataRect(prevBackgroundIndex, rectX, rectY, rectWidth, rectHeight); - } - else if (prevDisposalMethod == DISPOSAL_RESTORE) { - copyImageDataRect(imageData, imageDataBU, rectX, rectY, rectWidth, rectHeight); - } - - // Save disposal method for this frame for next time - prevDisposalMethod = disposalMethod; - - if (disposalMethod != DISPOSAL_NONE) { - // Save dimensions of this frame - rectX = tbiImageX; - rectY = tbiImageY; - rectWidth = tbiWidth; - rectHeight = tbiHeight; - - // limit rectangle to the bounds of maxGifWidth*maxGifHeight - if(rectX + rectWidth > maxGifWidth) - rectWidth = maxGifWidth-rectX; - if(rectY + rectHeight > maxGifHeight) - rectHeight = maxGifHeight-rectY; - if(rectX >= maxGifWidth || rectY >= maxGifHeight) { - rectX = rectY = rectWidth = rectHeight = 0; - } - - if (disposalMethod == DISPOSAL_BACKGROUND) { - if (transparentColorIndex != NO_TRANSPARENT_INDEX) { - prevBackgroundIndex = transparentColorIndex; - } - else { - prevBackgroundIndex = lsdBackgroundIndex; - } - } - else if (disposalMethod == DISPOSAL_RESTORE) { - copyImageDataRect(imageDataBU, imageData, rectX, rectY, rectWidth, rectHeight); - } - } - - // Read the min LZW code size - lzwCodeSize = readByte(); - -#if GIFDEBUG == 1 && DEBUG_PROCESSING_TBI_DESC_LZWCODESIZE == 1 - Serial.print("LzwCodeSize: "); - Serial.println(lzwCodeSize); - Serial.println("File Position Before: "); - Serial.println(filePositionCallback()); -#endif - - unsigned long filePositionBefore = filePositionCallback(); - - // Gather the lzw image data - // NOTE: the dataBlockSize byte is left in the data as the lzw decoder needs it - int offset = 0; - int dataBlockSize = readByte(); - while (dataBlockSize != 0) { -#if GIFDEBUG == 1 && DEBUG_PROCESSING_TBI_DESC_DATABLOCKSIZE == 1 - Serial.print("dataBlockSize: "); - Serial.println(dataBlockSize); -#endif - backUpStream(1); - dataBlockSize++; - fileSeekCallback(filePositionCallback() + dataBlockSize); - - offset += dataBlockSize; - dataBlockSize = readByte(); - } - -#if GIFDEBUG == 1 && DEBUG_PROCESSING_TBI_DESC_LZWIMAGEDATA_SIZE == 1 - Serial.print("total lzwImageData Size: "); - Serial.println(offset); - Serial.println("File Position Test: "); - Serial.println(filePositionCallback()); -#endif - - // this is the position where GIF decoding needs to pick up after decompressing frame - unsigned long filePositionAfter = filePositionCallback(); - - fileSeekCallback(filePositionBefore); - - // Process the animation frame for display - - // Initialize the LZW decoder for this frame - lzw_decode_init(lzwCodeSize); - lzw_setTempBuffer((uint8_t*)tempBuffer); - - // Make sure there is at least some delay between frames - if (frameDelay < 1) { - frameDelay = 1; - } - - // Decompress LZW data and display the frame - decompressAndDisplayFrame(filePositionAfter); - - // Graphic control extension is for a single frame - transparentColorIndex = NO_TRANSPARENT_INDEX; - disposalMethod = DISPOSAL_NONE; -} - -// Parse gif data -template -int GifDecoder::parseData() { - if(nextFrameTime_ms > millis()) - return ERROR_WAITING; - -#if GIFDEBUG == 1 && DEBUG_PARSING_DATA == 1 - Serial.println("\nParsing Data Block"); -#endif - - bool parsedFrame = false; - while (!parsedFrame) { - -#if GIFDEBUG == 1 && DEBUG_WAIT_FOR_KEY_PRESS == 1 - Serial.println("\nPress Key For Next"); - while(Serial.read() <= 0); -#endif - - // Determine what kind of data to process - uint8_t b = readByte(); - - if (b == 0x2c) { - // Parse table based image -#if GIFDEBUG == 1 && DEBUG_PARSING_DATA == 1 - Serial.println("\nParsing Table Based"); -#endif - parseTableBasedImage(); - parsedFrame = true; - - } - else if (b == 0x21) { - // Parse extension - b = readByte(); - -#if GIFDEBUG == 1 && DEBUG_PARSING_DATA == 1 - Serial.println("\nParsing Extension"); -#endif - - // Determine which kind of extension to parse - switch (b) { - case 0x01: - // Plain test extension - parsePlainTextExtension(); - break; - case 0xf9: - // Graphic control extension - parseGraphicControlExtension(); - break; - case 0xfe: - // Comment extension - parseCommentExtension(); - break; - case 0xff: - // Application extension - parseApplicationExtension(); - break; - default: - Serial.print("Unknown control extension: "); - Serial.println(b, HEX); - return ERROR_UNKNOWNCONTROLEXT; - } - } - else { -#if GIFDEBUG == 1 && DEBUG_PARSING_DATA == 1 - Serial.println("\nParsing Done"); -#endif - - // Push unprocessed byte back into the stream for later processing - backUpStream(1); - - return ERROR_DONE_PARSING; - } - } - return ERROR_NONE; -} - -template -int GifDecoder::startDecoding(void) { - // Initialize variables - keyFrame = true; - prevDisposalMethod = DISPOSAL_NONE; - transparentColorIndex = NO_TRANSPARENT_INDEX; - nextFrameTime_ms = 0; - fileSeekCallback(0); - - // Validate the header - if (! parseGifHeader()) { - Serial.println("Not a GIF file"); - return ERROR_FILENOTGIF; - } - // If we get here we have a gif file to process - - // Parse the logical screen descriptor - parseLogicalScreenDescriptor(); - - // Parse the global color table - parseGlobalColorTable(); - - return ERROR_NONE; -} - -template -int GifDecoder::decodeFrame(void) { - // Parse gif data - int result = parseData(); - if (result < ERROR_NONE) { - Serial.println("Error: "); - Serial.println(result); - Serial.println(" occurred during parsing of data"); - return result; - } - - if (result == ERROR_DONE_PARSING) { - //startDecoding(); - // Initialize variables like with a new file - keyFrame = true; - prevDisposalMethod = DISPOSAL_NONE; - transparentColorIndex = NO_TRANSPARENT_INDEX; - nextFrameTime_ms = 0; - fileSeekCallback(0); - - // parse Gif Header like with a new file - parseGifHeader(); - - // Parse the logical screen descriptor - parseLogicalScreenDescriptor(); - - // Parse the global color table - parseGlobalColorTable(); - } - - return result; -} - -// Decompress LZW data and display animation frame -template -void GifDecoder::decompressAndDisplayFrame(unsigned long filePositionAfter) { - - // Each pixel of image is 8 bits and is an index into the palette - - // How the image is decoded depends upon whether it is interlaced or not - // Decode the interlaced LZW data into the image buffer - if (tbiInterlaced) { - // Decode every 8th line starting at line 0 - for (int line = tbiImageY + 0; line < tbiHeight + tbiImageY; line += 8) { - lzw_decode(imageData + (line * maxGifWidth) + tbiImageX, tbiWidth, min(imageData + (line * maxGifWidth) + maxGifWidth, imageData + sizeof(imageData))); - } - // Decode every 8th line starting at line 4 - for (int line = tbiImageY + 4; line < tbiHeight + tbiImageY; line += 8) { - lzw_decode(imageData + (line * maxGifWidth) + tbiImageX, tbiWidth, min(imageData + (line * maxGifWidth) + maxGifWidth, imageData + sizeof(imageData))); - } - // Decode every 4th line starting at line 2 - for (int line = tbiImageY + 2; line < tbiHeight + tbiImageY; line += 4) { - lzw_decode(imageData + (line * maxGifWidth) + tbiImageX, tbiWidth, min(imageData + (line * maxGifWidth) + maxGifWidth, imageData + sizeof(imageData))); - } - // Decode every 2nd line starting at line 1 - for (int line = tbiImageY + 1; line < tbiHeight + tbiImageY; line += 2) { - lzw_decode(imageData + (line * maxGifWidth) + tbiImageX, tbiWidth, min(imageData + (line * maxGifWidth) + maxGifWidth, imageData + sizeof(imageData))); - } - } - else { - // Decode the non interlaced LZW data into the image data buffer - for (int line = tbiImageY; line < tbiHeight + tbiImageY; line++) { - lzw_decode(imageData + (line * maxGifWidth) + tbiImageX, tbiWidth, imageData + sizeof(imageData)); - } - } - -#if GIFDEBUG == 1 && DEBUG_DECOMPRESS_AND_DISPLAY == 1 - Serial.println("File Position After: "); - Serial.println(filePositionCallback()); -#endif - -#if GIFDEBUG == 1 && DEBUG_WAIT_FOR_KEY_PRESS == 1 - Serial.println("\nPress Key For Next"); - while(Serial.read() <= 0); -#endif - - // LZW doesn't parse through all the data, manually set position - fileSeekCallback(filePositionAfter); - - // Optional callback can be used to get drawing routines ready - if(startDrawingCallback) - (*startDrawingCallback)(); - - // Image data is decompressed, now display portion of image affected by frame - int yOffset, pixel; - for (int y = tbiImageY; y < tbiHeight + tbiImageY; y++) { - yOffset = y * maxGifWidth; - for (int x = tbiImageX; x < tbiWidth + tbiImageX; x++) { - // Get the next pixel - pixel = imageData[yOffset + x]; - - // Check pixel transparency - if (pixel == transparentColorIndex) { - continue; - } - - // Pixel not transparent so get color from palette and draw the pixel - if(drawPixelCallback) - (*drawPixelCallback)(x, y, palette[pixel].red, palette[pixel].green, palette[pixel].blue); - } - } - // Make animation frame visible - // swapBuffers() call can take up to 1/framerate seconds to return (it waits until a buffer copy is complete) - // note the time before calling - - // wait until time to display next frame - while(nextFrameTime_ms > millis()); - - // calculate time to display next frame - nextFrameTime_ms = millis() + (10 * frameDelay); - if(updateScreenCallback) - (*updateScreenCallback)(); -} diff --git a/examples/AnimatedGIF/LICENSE.txt b/examples/AnimatedGIF/LICENSE.txt deleted file mode 100644 index c69f703..0000000 --- a/examples/AnimatedGIF/LICENSE.txt +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014 Craig A. Lindley - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. diff --git a/examples/AnimatedGIF/LzwDecoder_Impl.h b/examples/AnimatedGIF/LzwDecoder_Impl.h deleted file mode 100644 index 720ac24..0000000 --- a/examples/AnimatedGIF/LzwDecoder_Impl.h +++ /dev/null @@ -1,169 +0,0 @@ -/* - * This file contains code to decompress the LZW encoded animated GIF data - * - * Written by: Craig A. Lindley, Fabrice Bellard and Steven A. Bennett - * See my book, "Practical Image Processing in C", John Wiley & Sons, Inc. - * - * Copyright (c) 2014 Craig A. Lindley - * Minor modifications by Louis Beaudoin (pixelmatix) - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of - * this software and associated documentation files (the "Software"), to deal in - * the Software without restriction, including without limitation the rights to - * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of - * the Software, and to permit persons to whom the Software is furnished to do so, - * subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS - * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR - * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#define LZWDEBUG 0 - -#include "GifDecoder.h" - -template -void GifDecoder::lzw_setTempBuffer(uint8_t * tempBuffer) { - temp_buffer = tempBuffer; -} - -// Initialize LZW decoder -// csize initial code size in bits -// buf input data -template -void GifDecoder::lzw_decode_init (int csize) { - - // Initialize read buffer variables - bbuf = 0; - bbits = 0; - bs = 0; - bcnt = 0; - - // Initialize decoder variables - codesize = csize; - cursize = codesize + 1; - curmask = mask[cursize]; - top_slot = 1 << cursize; - clear_code = 1 << codesize; - end_code = clear_code + 1; - slot = newcodes = clear_code + 2; - oc = fc = -1; - sp = stack; -} - -// Get one code of given number of bits from stream -template -int GifDecoder::lzw_get_code() { - - while (bbits < cursize) { - if (bcnt == bs) { - // get number of bytes in next block - readIntoBuffer(temp_buffer, 1); - bs = temp_buffer[0]; - readIntoBuffer(temp_buffer, bs); - bcnt = 0; - } - bbuf |= temp_buffer[bcnt] << bbits; - bbits += 8; - bcnt++; - } - int c = bbuf; - bbuf >>= cursize; - bbits -= cursize; - return c & curmask; -} - -// Decode given number of bytes -// buf 8 bit output buffer -// len number of pixels to decode -// returns the number of bytes decoded -template -int GifDecoder::lzw_decode(uint8_t *buf, int len, uint8_t *bufend) { - int l, c, code; - -#if LZWDEBUG == 1 - unsigned char debugMessagePrinted = 0; -#endif - - if (end_code < 0) { - return 0; - } - l = len; - - for (;;) { - while (sp > stack) { - // load buf with data if we're still within bounds - if(buf < bufend) { - *buf++ = *(--sp); - } else { - // out of bounds, keep incrementing the pointers, but don't use the data -#if LZWDEBUG == 1 - // only print this message once per call to lzw_decode - if(buf == bufend) - Serial.println("****** LZW imageData buffer overrun *******"); -#endif - } - if ((--l) == 0) { - return len; - } - } - c = lzw_get_code(); - if (c == end_code) { - break; - - } - else if (c == clear_code) { - cursize = codesize + 1; - curmask = mask[cursize]; - slot = newcodes; - top_slot = 1 << cursize; - fc= oc= -1; - - } - else { - - code = c; - if ((code == slot) && (fc >= 0)) { - *sp++ = fc; - code = oc; - } - else if (code >= slot) { - break; - } - while (code >= newcodes) { - *sp++ = suffix[code]; - code = prefix[code]; - } - *sp++ = code; - if ((slot < top_slot) && (oc >= 0)) { - suffix[slot] = code; - prefix[slot++] = oc; - } - fc = code; - oc = c; - if (slot >= top_slot) { - if (cursize < lzwMaxBits) { - top_slot <<= 1; - curmask = mask[++cursize]; - } else { -#if LZWDEBUG == 1 - if(!debugMessagePrinted) { - debugMessagePrinted = 1; - Serial.println("****** cursize >= lzwMaxBits *******"); - } -#endif - } - - } - } - } - end_code = -1; - return len - l; -} diff --git a/examples/AnimatedGIF/data/Text_Animations.txt.txt b/examples/AnimatedGIF/data/Text_Animations.txt.txt deleted file mode 100644 index 8431cd4..0000000 --- a/examples/AnimatedGIF/data/Text_Animations.txt.txt +++ /dev/null @@ -1 +0,0 @@ -https://loading.io/animation/text/ \ No newline at end of file diff --git a/examples/AnimatedGIFPanel/AnimatedGIFPanel/AnimatedGIFPanel.ino b/examples/AnimatedGIFPanel/AnimatedGIFPanel.ino similarity index 100% rename from examples/AnimatedGIFPanel/AnimatedGIFPanel/AnimatedGIFPanel.ino rename to examples/AnimatedGIFPanel/AnimatedGIFPanel.ino diff --git a/examples/AnimatedGIFPanel/AnimatedGIFPanel/data/gifs/ezgif.com-pacmn.gif b/examples/AnimatedGIFPanel/AnimatedGIFPanel/data/gifs/ezgif.com-pacmn.gif deleted file mode 100644 index 0a219a4..0000000 Binary files a/examples/AnimatedGIFPanel/AnimatedGIFPanel/data/gifs/ezgif.com-pacmn.gif and /dev/null differ diff --git a/examples/AnimatedGIFPanel/AnimatedGIFPanel/data/gifs/loading.io-64x32px.gif b/examples/AnimatedGIFPanel/AnimatedGIFPanel/data/gifs/loading.io-64x32px.gif deleted file mode 100644 index 342f8ae..0000000 Binary files a/examples/AnimatedGIFPanel/AnimatedGIFPanel/data/gifs/loading.io-64x32px.gif and /dev/null differ diff --git a/examples/AnimatedGIFPanel/AnimatedGIFPanel/README.md b/examples/AnimatedGIFPanel/README.md similarity index 100% rename from examples/AnimatedGIFPanel/AnimatedGIFPanel/README.md rename to examples/AnimatedGIFPanel/README.md diff --git a/examples/AnimatedGIF/data/ezgif.com-pacmn.gif b/examples/AnimatedGIFPanel/data/gifs/ezgif.com-pacmn.gif similarity index 100% rename from examples/AnimatedGIF/data/ezgif.com-pacmn.gif rename to examples/AnimatedGIFPanel/data/gifs/ezgif.com-pacmn.gif diff --git a/examples/AnimatedGIF/data/loading.io-64x32px.gif b/examples/AnimatedGIFPanel/data/gifs/loading.io-64x32px.gif similarity index 100% rename from examples/AnimatedGIF/data/loading.io-64x32px.gif rename to examples/AnimatedGIFPanel/data/gifs/loading.io-64x32px.gif diff --git a/examples/AnimatedGIFPanel/AnimatedGIFPanel/data/gifs/matrix-spin.gif b/examples/AnimatedGIFPanel/data/gifs/matrix-spin.gif similarity index 100% rename from examples/AnimatedGIFPanel/AnimatedGIFPanel/data/gifs/matrix-spin.gif rename to examples/AnimatedGIFPanel/data/gifs/matrix-spin.gif diff --git a/examples/AnimatedGIFPanel/AnimatedGIFPanel/data/gifs/shock.gif b/examples/AnimatedGIFPanel/data/gifs/shock.gif similarity index 100% rename from examples/AnimatedGIFPanel/AnimatedGIFPanel/data/gifs/shock.gif rename to examples/AnimatedGIFPanel/data/gifs/shock.gif