From e8c09104e1962e183d07c2937cfbe5e7b4878058 Mon Sep 17 00:00:00 2001 From: Christian Schwinne Date: Sun, 10 Mar 2024 14:34:15 +0100 Subject: [PATCH 1/9] GIF testing --- wled00/fcn_declare.h | 12 ++++ wled00/image_loader.cpp | 135 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 wled00/image_loader.cpp diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 1e88c59418..d08c6f636c 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -109,6 +109,18 @@ void onHueConnect(void* arg, AsyncClient* client); void sendHuePoll(); void onHueData(void* arg, AsyncClient* client, void *data, size_t len); +#include "FX.h" // must be below colors.cpp declarations (potentially due to duplicate declarations of e.g. color_blend) + +//image_loader.cpp +#ifndef WLED_DISABLE_GIF +bool fileSeekCallback(unsigned long position); +unsigned long filePositionCallback(void); +int fileReadCallback(void); +int fileReadBlockCallback(void * buffer, int numberOfBytes); +int fileSizeCallback(void); +byte renderImageToSegment(Segment &seg); +#endif + //improv.cpp enum ImprovRPCType { Command_Wifi = 0x01, diff --git a/wled00/image_loader.cpp b/wled00/image_loader.cpp new file mode 100644 index 0000000000..4a8052400d --- /dev/null +++ b/wled00/image_loader.cpp @@ -0,0 +1,135 @@ +#ifndef WLED_DISABLE_GIF + +#include "GifDecoder.h" +#include "wled.h" + +File file; +char lastFilename[34] = "/"; +GifDecoder<32,32,12> decoder; +bool gifDecodeFailed = false; +long lastFrameDisplayTime = 0, currentFrameDelay = 0; + +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); +} + +int fileSizeCallback(void) { + return file.size(); +} + +bool openGif(const char *filename) { + file = WLED_FS.open(filename, "r"); + + if (!file) return false; + return true; +} + +Segment* activeSeg; +uint16_t gifWidth, gifHeight; +//uint16_t fillPixX, fillPixY; + +void screenClearCallback(void) { + activeSeg->fill(0); +} + +void updateScreenCallback(void) {} + +void drawPixelCallback(int16_t x, int16_t y, uint8_t red, uint8_t green, uint8_t blue) { + // simple nearest-neighbor scaling + int16_t outY = y * activeSeg->height() / gifHeight; + int16_t outX = x * activeSeg->width() / gifWidth; + // set multiple pixels if upscaling + for (int16_t i = 0; i < (activeSeg->width()+(gifWidth-1)) / gifWidth; i++) { + for (int16_t j = 0; j < (activeSeg->height()+(gifHeight-1)) / gifHeight; j++) { + activeSeg->setPixelColorXY(outX + i, outY + j, gamma8(red), gamma8(green), gamma8(blue)); + } + } +} + +#define IMAGE_ERROR_NONE 0 +#define IMAGE_ERROR_NO_NAME 1 +#define IMAGE_ERROR_SEG_LIMIT 2 +#define IMAGE_ERROR_UNSUPPORTED_FORMAT 3 +#define IMAGE_ERROR_FILE_MISSING 4 +#define IMAGE_ERROR_DECODER_ALLOC 5 +#define IMAGE_ERROR_GIF_DECODE 6 +#define IMAGE_ERROR_FRAME_DECODE 7 +#define IMAGE_ERROR_WAITING 254 +#define IMAGE_ERROR_PREV 255 + +// renders an image (.gif only; .bmp and .fseq to be added soon) from FS to a segment +byte renderImageToSegment(Segment &seg) { + if (!seg.name) return IMAGE_ERROR_NO_NAME; + if (activeSeg && activeSeg != &seg) return IMAGE_ERROR_SEG_LIMIT; // only one segment at a time + activeSeg = &seg; + + if (strncmp(lastFilename +1, seg.name, 32) != 0) { // segment name changed, load new image + strncpy(lastFilename +1, seg.name, 32); + gifDecodeFailed = false; + if (strcmp(lastFilename + strlen(lastFilename) - 4, ".gif") != 0) { + gifDecodeFailed = true; + return IMAGE_ERROR_UNSUPPORTED_FORMAT; + } + if (file) file.close(); + openGif(lastFilename); + if (!file) { gifDecodeFailed = true; return IMAGE_ERROR_FILE_MISSING; } + //if (!decoder) decoder = new GifDecoder<32,32,12>(); + //if (!decoder) { gifDecodeFailed = true; return IMAGE_ERROR_DECODER_ALLOC; } + decoder.setScreenClearCallback(screenClearCallback); + decoder.setUpdateScreenCallback(updateScreenCallback); + decoder.setDrawPixelCallback(drawPixelCallback); + decoder.setFileSeekCallback(fileSeekCallback); + decoder.setFilePositionCallback(filePositionCallback); + decoder.setFileReadCallback(fileReadCallback); + decoder.setFileReadBlockCallback(fileReadBlockCallback); + decoder.setFileSizeCallback(fileSizeCallback); + Serial.println("Starting decoding"); + if(decoder.startDecoding() < 0) { gifDecodeFailed = true; return IMAGE_ERROR_GIF_DECODE; } + Serial.println("Decoding started"); + } + + if (gifDecodeFailed) return IMAGE_ERROR_PREV; + if (!file) { gifDecodeFailed = true; return IMAGE_ERROR_FILE_MISSING; } + //if (!decoder) { gifDecodeFailed = true; return IMAGE_ERROR_DECODER_ALLOC; } + + // speed 0 = half speed, 128 = normal, 255 = full FX FPS + // TODO: 0 = 4x slow, 64 = 2x slow, 128 = normal, 192 = 2x fast, 255 = 4x fast + uint32_t wait = currentFrameDelay * 2 - seg.speed * currentFrameDelay / 128; + + if((millis() - lastFrameDisplayTime) < wait) return IMAGE_ERROR_WAITING; + + decoder.getSize(&gifWidth, &gifHeight); + //fillPixX = (seg.width()+(gifWidth-1)) / gifWidth; + //fillPixY = (seg.height()+(gifHeight-1)) / gifHeight; + int result = decoder.decodeFrame(false); + if (result < 0) { gifDecodeFailed = true; return IMAGE_ERROR_FRAME_DECODE; } + //long lastFrameDelay = currentFrameDelay; + currentFrameDelay = decoder.getFrameDelay_ms(); + //long tooSlowBy = (millis() - lastFrameDisplayTime) - wait; // if last frame was longer than intended, compensate + //currentFrameDelay -= tooSlowBy; // TODO this is broken + lastFrameDisplayTime = millis(); + + return IMAGE_ERROR_NONE; +} + +void endImagePlayback() { + if (file) file.close(); + //delete decoder; + gifDecodeFailed = false; + activeSeg = nullptr; + lastFilename[0] = '\0'; +} + +#endif \ No newline at end of file From b8a29bcbf8cf5e3080920baffb3bc447f6017860 Mon Sep 17 00:00:00 2001 From: Christian Schwinne Date: Sun, 10 Mar 2024 21:36:13 +0100 Subject: [PATCH 2/9] GIFs work again in principle --- platformio.ini | 1 + wled00/FX.cpp | 17 ++++++++++++++++- wled00/FX_fcn.cpp | 1 + wled00/fcn_declare.h | 1 + wled00/image_loader.cpp | 13 +++++++++---- 5 files changed, 28 insertions(+), 5 deletions(-) diff --git a/platformio.ini b/platformio.ini index 471f7bf5b7..5d723c16da 100644 --- a/platformio.ini +++ b/platformio.ini @@ -374,6 +374,7 @@ lib_deps = https://github.com/softhack007/LITTLEFS-threadsafe.git#master makuna/NeoPixelBus @ 2.7.5 ;; makuna/NeoPixelBus @ 2.7.9 ;; experimental + https://github.com/Aircoookie/GifDecoder#e76f58f ${env.lib_deps} ;; Compatibility with upstream --> you should prefer using ${common_mm.build_flags_S} and ${common_mm.lib_deps_S} diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 04a77701f2..e56fa45a62 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -4650,6 +4650,21 @@ uint16_t mode_washing_machine(void) { static const char _data_FX_MODE_WASHING_MACHINE[] PROGMEM = "Washing Machine@!,!;;!"; +/* + Image effect + Draws a .gif image from filesystem on the matrix/strip +*/ +uint16_t mode_image(void) { + //Serial.println(renderImageToSegment(SEGMENT)); + int status = renderImageToSegment(SEGMENT); + if (status != 0 && status != 254 && status != 255) { + Serial.print("GIF renderer return: "); + Serial.println(status); + } + return FRAMETIME; +} +static const char _data_FX_MODE_IMAGE[] PROGMEM = "Image@!,;;;12;sx=128"; + /* Blends random colors across palette Modified, originally by Mark Kriegsman https://gist.github.com/kriegsman/1f7ccbbfa492a73c015e @@ -9071,7 +9086,7 @@ void WS2812FX::setupEffectData() { addEffect(FX_MODE_TWO_DOTS, &mode_two_dots, _data_FX_MODE_TWO_DOTS); addEffect(FX_MODE_FAIRYTWINKLE, &mode_fairytwinkle, _data_FX_MODE_FAIRYTWINKLE); addEffect(FX_MODE_RUNNING_DUAL, &mode_running_dual, _data_FX_MODE_RUNNING_DUAL); - + addEffect(FX_MODE_IMAGE, &mode_image, _data_FX_MODE_IMAGE); addEffect(FX_MODE_TRICOLOR_CHASE, &mode_tricolor_chase, _data_FX_MODE_TRICOLOR_CHASE); addEffect(FX_MODE_TRICOLOR_WIPE, &mode_tricolor_wipe, _data_FX_MODE_TRICOLOR_WIPE); addEffect(FX_MODE_TRICOLOR_FADE, &mode_tricolor_fade, _data_FX_MODE_TRICOLOR_FADE); diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index b09136f533..ef4b51e947 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -287,6 +287,7 @@ void Segment::resetIfRequired() { needsBlank = false; } } + endImagePlayback(this); } void Segment::setUpLeds() { diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index d08c6f636c..76da5d6fb8 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -119,6 +119,7 @@ int fileReadCallback(void); int fileReadBlockCallback(void * buffer, int numberOfBytes); int fileSizeCallback(void); byte renderImageToSegment(Segment &seg); +void endImagePlayback(Segment* seg); #endif //improv.cpp diff --git a/wled00/image_loader.cpp b/wled00/image_loader.cpp index 4a8052400d..44fb7f7c8b 100644 --- a/wled00/image_loader.cpp +++ b/wled00/image_loader.cpp @@ -5,7 +5,7 @@ File file; char lastFilename[34] = "/"; -GifDecoder<32,32,12> decoder; +GifDecoder<32,32,12,true> decoder; bool gifDecodeFailed = false; long lastFrameDisplayTime = 0, currentFrameDelay = 0; @@ -85,7 +85,7 @@ byte renderImageToSegment(Segment &seg) { if (file) file.close(); openGif(lastFilename); if (!file) { gifDecodeFailed = true; return IMAGE_ERROR_FILE_MISSING; } - //if (!decoder) decoder = new GifDecoder<32,32,12>(); + //if (!decoder) decoder = new GifDecoder<32,32,12,true>(); //if (!decoder) { gifDecodeFailed = true; return IMAGE_ERROR_DECODER_ALLOC; } decoder.setScreenClearCallback(screenClearCallback); decoder.setUpdateScreenCallback(updateScreenCallback); @@ -95,6 +95,7 @@ byte renderImageToSegment(Segment &seg) { decoder.setFileReadCallback(fileReadCallback); decoder.setFileReadBlockCallback(fileReadBlockCallback); decoder.setFileSizeCallback(fileSizeCallback); + decoder.alloc(); // TODO only if not already allocated Serial.println("Starting decoding"); if(decoder.startDecoding() < 0) { gifDecodeFailed = true; return IMAGE_ERROR_GIF_DECODE; } Serial.println("Decoding started"); @@ -124,12 +125,16 @@ byte renderImageToSegment(Segment &seg) { return IMAGE_ERROR_NONE; } -void endImagePlayback() { +void endImagePlayback(Segment *seg) { + Serial.println("Image playback end called"); + if (!activeSeg || activeSeg != seg) return; if (file) file.close(); //delete decoder; + decoder.dealloc(); gifDecodeFailed = false; activeSeg = nullptr; - lastFilename[0] = '\0'; + lastFilename[1] = '\0'; + Serial.println("Image playback ended"); } #endif \ No newline at end of file From 255be30b38f98c3937d588253d3659dedbf4cfc8 Mon Sep 17 00:00:00 2001 From: Christian Schwinne Date: Sun, 17 Mar 2024 22:24:55 +0100 Subject: [PATCH 3/9] Working GIF support --- wled00/FX.cpp | 11 +++++------ wled00/image_loader.cpp | 28 +++++++++++++++------------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index e56fa45a62..e556d7729d 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -4655,12 +4655,11 @@ static const char _data_FX_MODE_WASHING_MACHINE[] PROGMEM = "Washing Machine@!,! Draws a .gif image from filesystem on the matrix/strip */ uint16_t mode_image(void) { - //Serial.println(renderImageToSegment(SEGMENT)); - int status = renderImageToSegment(SEGMENT); - if (status != 0 && status != 254 && status != 255) { - Serial.print("GIF renderer return: "); - Serial.println(status); - } + renderImageToSegment(SEGMENT); + // if (status != 0 && status != 254 && status != 255) { + // Serial.print("GIF renderer return: "); + // Serial.println(status); + // } return FRAMETIME; } static const char _data_FX_MODE_IMAGE[] PROGMEM = "Image@!,;;;12;sx=128"; diff --git a/wled00/image_loader.cpp b/wled00/image_loader.cpp index 44fb7f7c8b..9ad4662e60 100644 --- a/wled00/image_loader.cpp +++ b/wled00/image_loader.cpp @@ -3,11 +3,15 @@ #include "GifDecoder.h" #include "wled.h" +/* + * Functions to render images from filesystem to segments, used by the "Image" effect + */ + File file; char lastFilename[34] = "/"; -GifDecoder<32,32,12,true> decoder; +GifDecoder<320,320,12,true> decoder; bool gifDecodeFailed = false; -long lastFrameDisplayTime = 0, currentFrameDelay = 0; +unsigned long lastFrameDisplayTime = 0, currentFrameDelay = 0; bool fileSeekCallback(unsigned long position) { return file.seek(position); @@ -38,7 +42,6 @@ bool openGif(const char *filename) { Segment* activeSeg; uint16_t gifWidth, gifHeight; -//uint16_t fillPixX, fillPixY; void screenClearCallback(void) { activeSeg->fill(0); @@ -72,6 +75,8 @@ void drawPixelCallback(int16_t x, int16_t y, uint8_t red, uint8_t green, uint8_t // renders an image (.gif only; .bmp and .fseq to be added soon) from FS to a segment byte renderImageToSegment(Segment &seg) { if (!seg.name) return IMAGE_ERROR_NO_NAME; + // disable during effect transition, causes flickering, multiple allocations and depending on image, part of old FX remaining + if (seg.mode != seg.currentMode()) return IMAGE_ERROR_WAITING; if (activeSeg && activeSeg != &seg) return IMAGE_ERROR_SEG_LIMIT; // only one segment at a time activeSeg = &seg; @@ -85,8 +90,6 @@ byte renderImageToSegment(Segment &seg) { if (file) file.close(); openGif(lastFilename); if (!file) { gifDecodeFailed = true; return IMAGE_ERROR_FILE_MISSING; } - //if (!decoder) decoder = new GifDecoder<32,32,12,true>(); - //if (!decoder) { gifDecodeFailed = true; return IMAGE_ERROR_DECODER_ALLOC; } decoder.setScreenClearCallback(screenClearCallback); decoder.setUpdateScreenCallback(updateScreenCallback); decoder.setDrawPixelCallback(drawPixelCallback); @@ -95,7 +98,7 @@ byte renderImageToSegment(Segment &seg) { decoder.setFileReadCallback(fileReadCallback); decoder.setFileReadBlockCallback(fileReadBlockCallback); decoder.setFileSizeCallback(fileSizeCallback); - decoder.alloc(); // TODO only if not already allocated + decoder.alloc(); Serial.println("Starting decoding"); if(decoder.startDecoding() < 0) { gifDecodeFailed = true; return IMAGE_ERROR_GIF_DECODE; } Serial.println("Decoding started"); @@ -109,17 +112,17 @@ byte renderImageToSegment(Segment &seg) { // TODO: 0 = 4x slow, 64 = 2x slow, 128 = normal, 192 = 2x fast, 255 = 4x fast uint32_t wait = currentFrameDelay * 2 - seg.speed * currentFrameDelay / 128; - if((millis() - lastFrameDisplayTime) < wait) return IMAGE_ERROR_WAITING; + // TODO consider handling this on FX level with a different frametime, but that would cause slow gifs to speed up during transitions + if (millis() - lastFrameDisplayTime < wait) return IMAGE_ERROR_WAITING; decoder.getSize(&gifWidth, &gifHeight); - //fillPixX = (seg.width()+(gifWidth-1)) / gifWidth; - //fillPixY = (seg.height()+(gifHeight-1)) / gifHeight; + int result = decoder.decodeFrame(false); if (result < 0) { gifDecodeFailed = true; return IMAGE_ERROR_FRAME_DECODE; } - //long lastFrameDelay = currentFrameDelay; + currentFrameDelay = decoder.getFrameDelay_ms(); - //long tooSlowBy = (millis() - lastFrameDisplayTime) - wait; // if last frame was longer than intended, compensate - //currentFrameDelay -= tooSlowBy; // TODO this is broken + unsigned long tooSlowBy = (millis() - lastFrameDisplayTime) - wait; // if last frame was longer than intended, compensate + currentFrameDelay = tooSlowBy > currentFrameDelay ? 0 : currentFrameDelay - tooSlowBy; lastFrameDisplayTime = millis(); return IMAGE_ERROR_NONE; @@ -129,7 +132,6 @@ void endImagePlayback(Segment *seg) { Serial.println("Image playback end called"); if (!activeSeg || activeSeg != seg) return; if (file) file.close(); - //delete decoder; decoder.dealloc(); gifDecodeFailed = false; activeSeg = nullptr; From 9caa7cb4e9b72f50db2812ca89fae73262786964 Mon Sep 17 00:00:00 2001 From: Christian Schwinne Date: Sun, 17 Mar 2024 22:57:15 +0100 Subject: [PATCH 4/9] Fix missing GIF enable macros --- platformio.ini | 2 +- wled00/FX.cpp | 6 +++++- wled00/FX_fcn.cpp | 2 ++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/platformio.ini b/platformio.ini index 5d723c16da..df6b93a0da 100644 --- a/platformio.ini +++ b/platformio.ini @@ -374,7 +374,7 @@ lib_deps = https://github.com/softhack007/LITTLEFS-threadsafe.git#master makuna/NeoPixelBus @ 2.7.5 ;; makuna/NeoPixelBus @ 2.7.9 ;; experimental - https://github.com/Aircoookie/GifDecoder#e76f58f + https://github.com/Aircoookie/GifDecoder#bc3af18 ${env.lib_deps} ;; Compatibility with upstream --> you should prefer using ${common_mm.build_flags_S} and ${common_mm.lib_deps_S} diff --git a/wled00/FX.cpp b/wled00/FX.cpp index e556d7729d..56499d8eb3 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -4655,12 +4655,16 @@ static const char _data_FX_MODE_WASHING_MACHINE[] PROGMEM = "Washing Machine@!,! Draws a .gif image from filesystem on the matrix/strip */ uint16_t mode_image(void) { + #ifdef WLED_DISABLE_GIF + return mode_static(); + #else renderImageToSegment(SEGMENT); + return FRAMETIME; + #endif // if (status != 0 && status != 254 && status != 255) { // Serial.print("GIF renderer return: "); // Serial.println(status); // } - return FRAMETIME; } static const char _data_FX_MODE_IMAGE[] PROGMEM = "Image@!,;;;12;sx=128"; diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index ef4b51e947..545d69cf7f 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -287,7 +287,9 @@ void Segment::resetIfRequired() { needsBlank = false; } } + #ifndef WLED_DISABLE_GIF endImagePlayback(this); + #endif } void Segment::setUpLeds() { From 132244cb429244f7e6a4c4bd302ad76e25c47986 Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Sat, 22 Feb 2025 12:53:37 +0000 Subject: [PATCH 5/9] Fix build errors --- platformio.ini | 3 ++- wled00/FX.h | 2 +- wled00/image_loader.cpp | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/platformio.ini b/platformio.ini index df6b93a0da..d3355b52d6 100644 --- a/platformio.ini +++ b/platformio.ini @@ -261,6 +261,8 @@ lib_deps = IRremoteESP8266 @ 2.8.2 ;;makuna/NeoPixelBus @ 2.7.5 ;; WLEDMM will be added in board specific sections https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.2.1 ;; newer with bugfixes and stability improvements + https://github.com/Aircoookie/GifDecoder#bc3af18 + https://github.com/bitbank2/AnimatedGIF #For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line #TFT_eSPI #For compatible OLED display uncomment following @@ -374,7 +376,6 @@ lib_deps = https://github.com/softhack007/LITTLEFS-threadsafe.git#master makuna/NeoPixelBus @ 2.7.5 ;; makuna/NeoPixelBus @ 2.7.9 ;; experimental - https://github.com/Aircoookie/GifDecoder#bc3af18 ${env.lib_deps} ;; Compatibility with upstream --> you should prefer using ${common_mm.build_flags_S} and ${common_mm.lib_deps_S} diff --git a/wled00/FX.h b/wled00/FX.h index ddbd014610..46e897df18 100644 --- a/wled00/FX.h +++ b/wled00/FX.h @@ -186,7 +186,7 @@ bool strip_uses_global_leds(void) __attribute__((pure)); // WLEDMM implemented #define FX_MODE_TWO_DOTS 50 #define FX_MODE_FAIRYTWINKLE 51 //was Two Areas prior to 0.13.0-b6 (use "Two Dots" with full intensity) #define FX_MODE_RUNNING_DUAL 52 -// #define FX_MODE_HALLOWEEN 53 // removed in 0.14! +#define FX_MODE_IMAGE 53 #define FX_MODE_TRICOLOR_CHASE 54 #define FX_MODE_TRICOLOR_WIPE 55 #define FX_MODE_TRICOLOR_FADE 56 diff --git a/wled00/image_loader.cpp b/wled00/image_loader.cpp index 9ad4662e60..cbf6c25b54 100644 --- a/wled00/image_loader.cpp +++ b/wled00/image_loader.cpp @@ -76,7 +76,7 @@ void drawPixelCallback(int16_t x, int16_t y, uint8_t red, uint8_t green, uint8_t byte renderImageToSegment(Segment &seg) { if (!seg.name) return IMAGE_ERROR_NO_NAME; // disable during effect transition, causes flickering, multiple allocations and depending on image, part of old FX remaining - if (seg.mode != seg.currentMode()) return IMAGE_ERROR_WAITING; + // TODO: if (seg.mode != seg.currentMode()) return IMAGE_ERROR_WAITING; if (activeSeg && activeSeg != &seg) return IMAGE_ERROR_SEG_LIMIT; // only one segment at a time activeSeg = &seg; From 6d67dc9828a99ff984575a5b81f7125ab92b404f Mon Sep 17 00:00:00 2001 From: Christian Schwinne Date: Sat, 13 Apr 2024 20:06:33 +0200 Subject: [PATCH 6/9] Proper debug statements --- wled00/image_loader.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/wled00/image_loader.cpp b/wled00/image_loader.cpp index cbf6c25b54..17dea8cc3f 100644 --- a/wled00/image_loader.cpp +++ b/wled00/image_loader.cpp @@ -1,7 +1,9 @@ +#include "wled.h" + #ifndef WLED_DISABLE_GIF #include "GifDecoder.h" -#include "wled.h" + /* * Functions to render images from filesystem to segments, used by the "Image" effect @@ -99,9 +101,9 @@ byte renderImageToSegment(Segment &seg) { decoder.setFileReadBlockCallback(fileReadBlockCallback); decoder.setFileSizeCallback(fileSizeCallback); decoder.alloc(); - Serial.println("Starting decoding"); + DEBUG_PRINTLN(F("Starting decoding")); if(decoder.startDecoding() < 0) { gifDecodeFailed = true; return IMAGE_ERROR_GIF_DECODE; } - Serial.println("Decoding started"); + DEBUG_PRINTLN(F("Decoding started")); } if (gifDecodeFailed) return IMAGE_ERROR_PREV; @@ -129,14 +131,14 @@ byte renderImageToSegment(Segment &seg) { } void endImagePlayback(Segment *seg) { - Serial.println("Image playback end called"); + DEBUG_PRINTLN(F("Image playback end called")); if (!activeSeg || activeSeg != seg) return; if (file) file.close(); decoder.dealloc(); gifDecodeFailed = false; activeSeg = nullptr; lastFilename[1] = '\0'; - Serial.println("Image playback ended"); + DEBUG_PRINTLN(F("Image playback ended")); } #endif \ No newline at end of file From d9ab8785039938ea6d49096606b22d2da45695ec Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Tue, 14 Jan 2025 18:40:41 +0000 Subject: [PATCH 7/9] Swap to WLED_ENABLE_GIF --- wled00/FX.cpp | 4 +++- wled00/FX_fcn.cpp | 2 +- wled00/fcn_declare.h | 2 +- wled00/image_loader.cpp | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/wled00/FX.cpp b/wled00/FX.cpp index 56499d8eb3..dbd0d6ad3c 100644 --- a/wled00/FX.cpp +++ b/wled00/FX.cpp @@ -4655,7 +4655,7 @@ static const char _data_FX_MODE_WASHING_MACHINE[] PROGMEM = "Washing Machine@!,! Draws a .gif image from filesystem on the matrix/strip */ uint16_t mode_image(void) { - #ifdef WLED_DISABLE_GIF + #ifndef WLED_ENABLE_GIF return mode_static(); #else renderImageToSegment(SEGMENT); @@ -9089,7 +9089,9 @@ void WS2812FX::setupEffectData() { addEffect(FX_MODE_TWO_DOTS, &mode_two_dots, _data_FX_MODE_TWO_DOTS); addEffect(FX_MODE_FAIRYTWINKLE, &mode_fairytwinkle, _data_FX_MODE_FAIRYTWINKLE); addEffect(FX_MODE_RUNNING_DUAL, &mode_running_dual, _data_FX_MODE_RUNNING_DUAL); + #ifdef WLED_ENABLE_GIF addEffect(FX_MODE_IMAGE, &mode_image, _data_FX_MODE_IMAGE); + #endif addEffect(FX_MODE_TRICOLOR_CHASE, &mode_tricolor_chase, _data_FX_MODE_TRICOLOR_CHASE); addEffect(FX_MODE_TRICOLOR_WIPE, &mode_tricolor_wipe, _data_FX_MODE_TRICOLOR_WIPE); addEffect(FX_MODE_TRICOLOR_FADE, &mode_tricolor_fade, _data_FX_MODE_TRICOLOR_FADE); diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 545d69cf7f..07695e30a3 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -287,7 +287,7 @@ void Segment::resetIfRequired() { needsBlank = false; } } - #ifndef WLED_DISABLE_GIF + #ifdef WLED_ENABLE_GIF endImagePlayback(this); #endif } diff --git a/wled00/fcn_declare.h b/wled00/fcn_declare.h index 76da5d6fb8..d4b74b3a9d 100644 --- a/wled00/fcn_declare.h +++ b/wled00/fcn_declare.h @@ -112,7 +112,7 @@ void onHueData(void* arg, AsyncClient* client, void *data, size_t len); #include "FX.h" // must be below colors.cpp declarations (potentially due to duplicate declarations of e.g. color_blend) //image_loader.cpp -#ifndef WLED_DISABLE_GIF +#ifdef WLED_ENABLE_GIF bool fileSeekCallback(unsigned long position); unsigned long filePositionCallback(void); int fileReadCallback(void); diff --git a/wled00/image_loader.cpp b/wled00/image_loader.cpp index 17dea8cc3f..2bb465f93c 100644 --- a/wled00/image_loader.cpp +++ b/wled00/image_loader.cpp @@ -1,6 +1,6 @@ #include "wled.h" -#ifndef WLED_DISABLE_GIF +#ifdef WLED_ENABLE_GIF #include "GifDecoder.h" From 1c414dc1f3612b10b32c17cb2224568376b66e4d Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Sat, 22 Feb 2025 13:25:27 +0000 Subject: [PATCH 8/9] WLED_ENABLE_GIF --- platformio.ini | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index d3355b52d6..5271790e3d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -261,8 +261,8 @@ lib_deps = IRremoteESP8266 @ 2.8.2 ;;makuna/NeoPixelBus @ 2.7.5 ;; WLEDMM will be added in board specific sections https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.2.1 ;; newer with bugfixes and stability improvements + bitbank2/AnimatedGIF@^1.4.7 https://github.com/Aircoookie/GifDecoder#bc3af18 - https://github.com/bitbank2/AnimatedGIF #For use of the TTGO T-Display ESP32 Module with integrated TFT display uncomment the following line #TFT_eSPI #For compatible OLED display uncomment following @@ -1110,6 +1110,7 @@ build_flags_S = ; -D USERMOD_ARTIFX ;; WLEDMM usermod - temporarily moved into "_M", due to problems in "_S" when compiling with -O2 -D WLEDMM_FASTPATH ;; WLEDMM experimental option. Reduces audio lag (latency), and allows for faster LED framerates. May break compatibility with previous versions. ; -D WLED_DEBUG_HEAP ;; WLEDMM enable heap debugging + -D WLED_ENABLE_GIF lib_deps_S = ;; https://github.com/kosme/arduinoFFT#develop @ 1.9.2+sha.419d7b0 ;; used for USERMOD_AUDIOREACTIVE - using "known working" hash From c5a28c2977b5ee3db97a84f68c9227a90a60f87a Mon Sep 17 00:00:00 2001 From: Will Tatam Date: Sun, 15 Jun 2025 12:13:00 +0100 Subject: [PATCH 9/9] only call endImagePlayback if reset true in resetIfRequired --- wled00/FX_fcn.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/wled00/FX_fcn.cpp b/wled00/FX_fcn.cpp index 07695e30a3..4941529f18 100644 --- a/wled00/FX_fcn.cpp +++ b/wled00/FX_fcn.cpp @@ -278,6 +278,9 @@ void Segment::resetIfRequired() { reset = false; // setOption(SEG_OPTION_RESET, false); startFrame(); // WLEDMM update cached propoerties if (isActive() && !freeze) { fill(BLACK); needsBlank = false; } // WLEDMM start clean + #ifdef WLED_ENABLE_GIF + endImagePlayback(this); + #endif DEBUG_PRINTLN("Segment reset"); } else if (needsBlank) { startFrame(); // WLEDMM update cached propoerties @@ -287,9 +290,6 @@ void Segment::resetIfRequired() { needsBlank = false; } } - #ifdef WLED_ENABLE_GIF - endImagePlayback(this); - #endif } void Segment::setUpLeds() {