Merge branch 'main' into aws-queue-0_16

This commit is contained in:
Will Tatam 2025-01-26 16:07:15 +00:00
commit 7c05914e5a
10 changed files with 240 additions and 45 deletions

View File

@ -24,29 +24,30 @@
// risk to running the build directly on the host. // risk to running the build directly on the host.
// "runArgs": ["--privileged", "-v", "/dev/bus/usb:/dev/bus/usb", "--group-add", "dialout"], // "runArgs": ["--privileged", "-v", "/dev/bus/usb:/dev/bus/usb", "--group-add", "dialout"],
// Set *default* container specific settings.json values on container create. "customizations": {
"settings": { "vscode": {
"terminal.integrated.shell.linux": "/bin/bash", "settings": {
"python.pythonPath": "/usr/local/bin/python", "terminal.integrated.shell.linux": "/bin/bash",
"python.linting.enabled": true, "python.pythonPath": "/usr/local/bin/python",
"python.linting.pylintEnabled": true, "python.linting.enabled": true,
"python.formatting.autopep8Path": "/usr/local/py-utils/bin/autopep8", "python.linting.pylintEnabled": true,
"python.formatting.blackPath": "/usr/local/py-utils/bin/black", "python.formatting.autopep8Path": "/usr/local/py-utils/bin/autopep8",
"python.formatting.yapfPath": "/usr/local/py-utils/bin/yapf", "python.formatting.blackPath": "/usr/local/py-utils/bin/black",
"python.linting.banditPath": "/usr/local/py-utils/bin/bandit", "python.formatting.yapfPath": "/usr/local/py-utils/bin/yapf",
"python.linting.flake8Path": "/usr/local/py-utils/bin/flake8", "python.linting.banditPath": "/usr/local/py-utils/bin/bandit",
"python.linting.mypyPath": "/usr/local/py-utils/bin/mypy", "python.linting.flake8Path": "/usr/local/py-utils/bin/flake8",
"python.linting.pycodestylePath": "/usr/local/py-utils/bin/pycodestyle", "python.linting.mypyPath": "/usr/local/py-utils/bin/mypy",
"python.linting.pydocstylePath": "/usr/local/py-utils/bin/pydocstyle", "python.linting.pycodestylePath": "/usr/local/py-utils/bin/pycodestyle",
"python.linting.pylintPath": "/usr/local/py-utils/bin/pylint" "python.linting.pydocstylePath": "/usr/local/py-utils/bin/pydocstyle",
"python.linting.pylintPath": "/usr/local/py-utils/bin/pylint"
},
"extensions": [
"ms-python.python",
"platformio.platformio-ide"
]
}
}, },
// Add the IDs of extensions you want installed when the container is created.
"extensions": [
"ms-python.python",
"platformio.platformio-ide"
],
// Use 'forwardPorts' to make a list of ports inside the container available locally. // Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [], // "forwardPorts": [],

View File

@ -37,4 +37,5 @@ jobs:
prerelease: true prerelease: true
body: ${{ steps.changelog.outputs.changelog }} body: ${{ steps.changelog.outputs.changelog }}
files: | files: |
./*.bin *.bin
*.bin.gz

View File

@ -238,6 +238,13 @@ lib_deps_compat =
https://github.com/blazoncek/QuickESPNow.git#optional-debug https://github.com/blazoncek/QuickESPNow.git#optional-debug
https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.4.0 https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.4.0
[esp32_all_variants]
lib_deps =
willmmiles/AsyncTCP @ 1.3.1
bitbank2/AnimatedGIF@^1.4.7
https://github.com/Aircoookie/GifDecoder#bc3af18
build_flags =
-D WLED_ENABLE_GIF
[esp32] [esp32]
#platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2.3/platform-espressif32-2.0.2.3.zip #platform = https://github.com/tasmota/platform-espressif32/releases/download/v2.0.2.3/platform-espressif32-2.0.2.3.zip
@ -251,6 +258,8 @@ build_flags = -g
#use LITTLEFS library by lorol in ESP32 core 1.x.x instead of built-in in 2.x.x #use LITTLEFS library by lorol in ESP32 core 1.x.x instead of built-in in 2.x.x
-D LOROL_LITTLEFS -D LOROL_LITTLEFS
; -DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3 ; -DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3
${esp32_all_variants.build_flags}
tiny_partitions = tools/WLED_ESP32_2MB_noOTA.csv tiny_partitions = tools/WLED_ESP32_2MB_noOTA.csv
default_partitions = tools/WLED_ESP32_4MB_1MB_FS.csv default_partitions = tools/WLED_ESP32_4MB_1MB_FS.csv
extended_partitions = tools/WLED_ESP32_4MB_700k_FS.csv extended_partitions = tools/WLED_ESP32_4MB_700k_FS.csv
@ -259,7 +268,7 @@ large_partitions = tools/WLED_ESP32_8MB.csv
extreme_partitions = tools/WLED_ESP32_16MB_9MB_FS.csv extreme_partitions = tools/WLED_ESP32_16MB_9MB_FS.csv
lib_deps = lib_deps =
https://github.com/lorol/LITTLEFS.git https://github.com/lorol/LITTLEFS.git
willmmiles/AsyncTCP @ 1.3.1 ${esp32_all_variants.lib_deps}
${env.lib_deps} ${env.lib_deps}
# additional build flags for audioreactive # additional build flags for audioreactive
AR_build_flags = -D USERMOD_AUDIOREACTIVE AR_build_flags = -D USERMOD_AUDIOREACTIVE
@ -282,9 +291,10 @@ build_flags = -g
-DARDUINO_ARCH_ESP32 -DESP32 -DARDUINO_ARCH_ESP32 -DESP32
-D CONFIG_ASYNC_TCP_USE_WDT=0 -D CONFIG_ASYNC_TCP_USE_WDT=0
-DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3 -DARDUINO_USB_CDC_ON_BOOT=0 ;; this flag is mandatory for "classic ESP32" when building with arduino-esp32 >=2.0.3
${esp32_all_variants.build_flags}
-D WLED_ENABLE_DMX_INPUT -D WLED_ENABLE_DMX_INPUT
lib_deps = lib_deps =
willmmiles/AsyncTCP @ 1.3.1 ${esp32_all_variants.lib_deps}
https://github.com/someweisguy/esp_dmx.git#47db25d https://github.com/someweisguy/esp_dmx.git#47db25d
${env.lib_deps} ${env.lib_deps}
board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs
@ -303,8 +313,9 @@ build_flags = -g
-DARDUINO_USB_MODE=0 ;; this flag is mandatory for ESP32-S2 ! -DARDUINO_USB_MODE=0 ;; this flag is mandatory for ESP32-S2 !
;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry: ;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry:
;; ARDUINO_USB_CDC_ON_BOOT ;; ARDUINO_USB_CDC_ON_BOOT
${esp32_all_variants.build_flags}
lib_deps = lib_deps =
willmmiles/AsyncTCP @ 1.3.1 ${esp32_all_variants.lib_deps}
${env.lib_deps} ${env.lib_deps}
board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs
@ -321,8 +332,9 @@ build_flags = -g
-DARDUINO_USB_MODE=1 ;; this flag is mandatory for ESP32-C3 -DARDUINO_USB_MODE=1 ;; this flag is mandatory for ESP32-C3
;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry: ;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry:
;; ARDUINO_USB_CDC_ON_BOOT ;; ARDUINO_USB_CDC_ON_BOOT
${esp32_all_variants.build_flags}
lib_deps = lib_deps =
willmmiles/AsyncTCP @ 1.3.1 ${esp32_all_variants.lib_deps}
${env.lib_deps} ${env.lib_deps}
board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs board_build.partitions = ${esp32.default_partitions} ;; default partioning for 4MB Flash - can be overridden in build envs
board_build.flash_mode = qio board_build.flash_mode = qio
@ -341,8 +353,9 @@ build_flags = -g
-DCO -DCO
;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry: ;; please make sure that the following flags are properly set (to 0 or 1) by your board.json, or included in your custom platformio_override.ini entry:
;; ARDUINO_USB_MODE, ARDUINO_USB_CDC_ON_BOOT ;; ARDUINO_USB_MODE, ARDUINO_USB_CDC_ON_BOOT
${esp32_all_variants.build_flags}
lib_deps = lib_deps =
willmmiles/AsyncTCP @ 1.3.1 ${esp32_all_variants.lib_deps}
${env.lib_deps} ${env.lib_deps}
board_build.partitions = ${esp32.large_partitions} ;; default partioning for 8MB flash - can be overridden in build envs board_build.partitions = ${esp32.large_partitions} ;; default partioning for 8MB flash - can be overridden in build envs

View File

@ -1,5 +1,5 @@
# #
# This file is autogenerated by pip-compile with Python 3.12 # This file is autogenerated by pip-compile with Python 3.11
# by the following command: # by the following command:
# #
# pip-compile # pip-compile

View File

@ -4450,6 +4450,24 @@ uint16_t mode_washing_machine(void) {
static const char _data_FX_MODE_WASHING_MACHINE[] PROGMEM = "Washing Machine@!,!;;!"; 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) {
#ifndef WLED_ENABLE_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);
// }
}
static const char _data_FX_MODE_IMAGE[] PROGMEM = "Image@!,;;;12;sx=128";
/* /*
Blends random colors across palette Blends random colors across palette
Modified, originally by Mark Kriegsman https://gist.github.com/kriegsman/1f7ccbbfa492a73c015e Modified, originally by Mark Kriegsman https://gist.github.com/kriegsman/1f7ccbbfa492a73c015e
@ -7734,7 +7752,9 @@ void WS2812FX::setupEffectData() {
addEffect(FX_MODE_TWO_DOTS, &mode_two_dots, _data_FX_MODE_TWO_DOTS); 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_FAIRYTWINKLE, &mode_fairytwinkle, _data_FX_MODE_FAIRYTWINKLE);
addEffect(FX_MODE_RUNNING_DUAL, &mode_running_dual, _data_FX_MODE_RUNNING_DUAL); 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_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_WIPE, &mode_tricolor_wipe, _data_FX_MODE_TRICOLOR_WIPE);
addEffect(FX_MODE_TRICOLOR_FADE, &mode_tricolor_fade, _data_FX_MODE_TRICOLOR_FADE); addEffect(FX_MODE_TRICOLOR_FADE, &mode_tricolor_fade, _data_FX_MODE_TRICOLOR_FADE);

View File

@ -184,7 +184,7 @@ extern byte realtimeMode; // used in getMappedPixelIndex()
#define FX_MODE_TWO_DOTS 50 #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_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_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_CHASE 54
#define FX_MODE_TRICOLOR_WIPE 55 #define FX_MODE_TRICOLOR_WIPE 55
#define FX_MODE_TRICOLOR_FADE 56 #define FX_MODE_TRICOLOR_FADE 56

View File

@ -199,6 +199,9 @@ void Segment::resetIfRequired() {
if (data && _dataLen > 0) memset(data, 0, _dataLen); // prevent heap fragmentation (just erase buffer instead of deallocateData()) if (data && _dataLen > 0) memset(data, 0, _dataLen); // prevent heap fragmentation (just erase buffer instead of deallocateData())
next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0; next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0;
reset = false; reset = false;
#ifdef WLED_ENABLE_GIF
endImagePlayback(this);
#endif
} }
CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) { CRGBPalette16 &Segment::loadPalette(CRGBPalette16 &targetPalette, uint8_t pal) {

View File

@ -128,7 +128,7 @@
<div style="padding: 8px 0;" id="btns"> <div style="padding: 8px 0;" id="btns">
<button class="btn btn-xs" title="File editor" type="button" id="edit" onclick="window.location.href=getURL('/edit')"><i class="icons btn-icon">&#xe2c6;</i></button> <button class="btn btn-xs" title="File editor" type="button" id="edit" onclick="window.location.href=getURL('/edit')"><i class="icons btn-icon">&#xe2c6;</i></button>
<button class="btn btn-xs" title="Pixel Magic Tool" type="button" id="pxmb" onclick="window.location.href=getURL('/pxmagic.htm')"><i class="icons btn-icon">&#xe410;</i></button> <button class="btn btn-xs" title="Pixel Magic Tool" type="button" id="pxmb" onclick="window.location.href=getURL('/pxmagic.htm')"><i class="icons btn-icon">&#xe410;</i></button>
<button class="btn btn-xs" title="Add custom palette" type="button" onclick="window.location.href=getURL('/cpal.htm')"><i class="icons btn-icon">&#xe18a;</i></button> <button class="btn btn-xs" title="Add custom palette" type="button" id="adPal" onclick="window.location.href=getURL('/cpal.htm')"><i class="icons btn-icon">&#xe18a;</i></button>
<button class="btn btn-xs" title="Remove last custom palette" type="button" id="rmPal" onclick="palettesData=null;localStorage.removeItem('wledPalx');requestJson({rmcpal:true});setTimeout(loadPalettes,250,loadPalettesData);"><i class="icons btn-icon">&#xe037;</i></button> <button class="btn btn-xs" title="Remove last custom palette" type="button" id="rmPal" onclick="palettesData=null;localStorage.removeItem('wledPalx');requestJson({rmcpal:true});setTimeout(loadPalettes,250,loadPalettesData);"><i class="icons btn-icon">&#xe037;</i></button>
</div> </div>
<p class="labels hd" id="pall"><i class="icons sel-icon" onclick="tglHex()">&#xe2b3;</i> Color palette</p> <p class="labels hd" id="pall"><i class="icons sel-icon" onclick="tglHex()">&#xe2b3;</i> Color palette</p>
@ -273,20 +273,20 @@
<option value="1">Fairy Dust</option> <option value="1">Fairy Dust</option>
<option value="2">Swipe right</option> <option value="2">Swipe right</option>
<option value="3">Swipe left</option> <option value="3">Swipe left</option>
<option value="4">Push right</option> <option value="16">Push right</option>
<option value="5">Push left</option> <option value="17">Push left</option>
<option value="6">Pinch-out</option> <option value="4">Pinch-out</option>
<option value="7">Inside-out</option> <option value="5">Inside-out</option>
<option value="8" data-type="2D">Swipe up</option> <option value="6" data-type="2D">Swipe up</option>
<option value="9" data-type="2D">Swipe down</option> <option value="7" data-type="2D">Swipe down</option>
<option value="10" data-type="2D">Open V</option> <option value="8" data-type="2D">Open H</option>
<option value="11" data-type="2D">Open H</option> <option value="9" data-type="2D">Open V</option>
<option value="12" data-type="2D">Push up</option> <option value="18" data-type="2D">Push up</option>
<option value="13" data-type="2D">Push down</option> <option value="19" data-type="2D">Push down</option>
<option value="14" data-type="2D">Push TL</option> <option value="20" data-type="2D">Push TL</option>
<option value="15" data-type="2D">Push TR</option> <option value="21" data-type="2D">Push TR</option>
<option value="16" data-type="2D">Push BR</option> <option value="22" data-type="2D">Push BR</option>
<option value="17" data-type="2D">Push BL</option> <option value="23" data-type="2D">Push BL</option>
</select> </select>
</p> </p>
<p id="ledmap" class="hide"></p> <p id="ledmap" class="hide"></p>

View File

@ -219,6 +219,19 @@ void onHueConnect(void* arg, AsyncClient* client);
void sendHuePoll(); void sendHuePoll();
void onHueData(void* arg, AsyncClient* client, void *data, size_t len); 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
#ifdef WLED_ENABLE_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);
void endImagePlayback(Segment* seg);
#endif
//improv.cpp //improv.cpp
enum ImprovRPCType { enum ImprovRPCType {
Command_Wifi = 0x01, Command_Wifi = 0x01,

144
wled00/image_loader.cpp Normal file
View File

@ -0,0 +1,144 @@
#include "wled.h"
#ifdef WLED_ENABLE_GIF
#include "GifDecoder.h"
/*
* Functions to render images from filesystem to segments, used by the "Image" effect
*/
File file;
char lastFilename[34] = "/";
GifDecoder<320,320,12,true> decoder;
bool gifDecodeFailed = false;
unsigned 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;
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;
// 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;
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; }
decoder.setScreenClearCallback(screenClearCallback);
decoder.setUpdateScreenCallback(updateScreenCallback);
decoder.setDrawPixelCallback(drawPixelCallback);
decoder.setFileSeekCallback(fileSeekCallback);
decoder.setFilePositionCallback(filePositionCallback);
decoder.setFileReadCallback(fileReadCallback);
decoder.setFileReadBlockCallback(fileReadBlockCallback);
decoder.setFileSizeCallback(fileSizeCallback);
decoder.alloc();
DEBUG_PRINTLN(F("Starting decoding"));
if(decoder.startDecoding() < 0) { gifDecodeFailed = true; return IMAGE_ERROR_GIF_DECODE; }
DEBUG_PRINTLN(F("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;
// 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);
int result = decoder.decodeFrame(false);
if (result < 0) { gifDecodeFailed = true; return IMAGE_ERROR_FRAME_DECODE; }
currentFrameDelay = decoder.getFrameDelay_ms();
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;
}
void endImagePlayback(Segment *seg) {
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';
DEBUG_PRINTLN(F("Image playback ended"));
}
#endif