(experimental) adjust image scaling when segment options change during playback

* move scaling calculation and decoder.setDrawPixelCallback() into a separate function
*re-calculate scaling before decoding a new frame
* reset gifWidth and gifHeight to zero in endplayback
This commit is contained in:
Frank
2025-11-16 19:18:21 +01:00
parent 2a120e81f8
commit 16540f58b3

View File

@@ -49,7 +49,7 @@ bool openGif(const char *filename) { // side-effect: updates "file"
}
static Segment* activeSeg;
static uint16_t gifWidth, gifHeight; // these two must stay uint16_t, because they are passed by reference
static uint16_t gifWidth = 0, gifHeight = 0; // these two must stay uint16_t, because they are passed by reference
static unsigned segCols = 1;
static unsigned segRows = 1;
static unsigned segLen = 1; // for 1D and 1DExpand support
@@ -107,6 +107,29 @@ void drawPixelCallback2D(int16_t x, int16_t y, uint8_t red, uint8_t green, uint8
}
}
// calculate image scaling; updates scaling factors and sets the best pixel drawing callback
static void calculateScaling() {
if (gifDecodeFailed) return;
if ((gifWidth > 0 && gifHeight > 0)) {
if (activeSeg->is2D()) {
perPixelX = (segCols + gifWidth -1) / gifWidth;
perPixelY = (segRows + gifHeight-1) / gifHeight;
if (segCols != gifWidth || segRows != gifHeight) {
decoder.setDrawPixelCallback(drawPixelCallback2D); // use 2D callback with scaling
} else {
decoder.setDrawPixelCallback(drawPixelCallbackNoScale2D); // use 2D callback without scaling
}
} else {
int totalImgPix = (int)gifWidth * gifHeight;
if (totalImgPix - segLen == 1) totalImgPix--; // handle off-by-one: skip last pixel instead of first (gifs constructed from 1D input pad last pixel if length is odd)
perPixelX = (segLen + totalImgPix-1) / totalImgPix;
if (totalImgPix != segLen) {
decoder.setDrawPixelCallback(drawPixelCallback1D); // use 1D callback with scaling
}
}
}
}
#define IMAGE_ERROR_NONE 0
#define IMAGE_ERROR_NO_NAME 1
#define IMAGE_ERROR_SEG_LIMIT 2
@@ -192,24 +215,7 @@ byte renderImageToSegment(Segment &seg) {
USER_PRINTF("Invalid GIF dimensions: %dx%d\n", gifWidth, gifHeight);
return IMAGE_ERROR_GIF_DECODE;
}
if (activeSeg->is2D()) {
perPixelX = (segCols + gifWidth -1) / gifWidth;
perPixelY = (segRows + gifHeight-1) / gifHeight;
if (segCols != gifWidth || segRows != gifHeight) {
decoder.setDrawPixelCallback(drawPixelCallback2D); // use 2D callback with scaling
//DEBUG_PRINTLN(F("scaling image"));
} else {
decoder.setDrawPixelCallback(drawPixelCallbackNoScale2D); // use 2D callback without scaling
}
} else {
int totalImgPix = (int)gifWidth * gifHeight;
if (totalImgPix - segLen == 1) totalImgPix--; // handle off-by-one: skip last pixel instead of first (gifs constructed from 1D input pad last pixel if length is odd)
perPixelX = (segLen + totalImgPix-1) / totalImgPix;
if (totalImgPix != segLen) {
decoder.setDrawPixelCallback(drawPixelCallback1D); // use 1D callback with scaling
//DEBUG_PRINTLN(F("scaling image"));
}
}
calculateScaling();
}
if (gifDecodeFailed) return IMAGE_ERROR_PREV;
@@ -227,6 +233,9 @@ byte renderImageToSegment(Segment &seg) {
unsigned td0 = millis();
while (strip.isUpdating() && (millis() - td0 < 20)) delay(1); // wait up to 20ms for LED output to finish
// WLEDMM experimental: segment options might change (mirror, transpose, grouping, spacing) at any time
calculateScaling(); // --> re-calculate scaling for each frame
int result = decoder.decodeFrame(false);
if (result < 0) {
USER_PRINTF("GIF Decoding error %d in decodeFrame().\n", result);
@@ -247,6 +256,7 @@ void endImagePlayback(Segment *seg) {
if (!activeSeg || activeSeg != seg) return;
if (file) file.close();
decoder.dealloc();
gifWidth = 0; gifHeight = 0; // WLEDMM clear cached image dimensions
gifDecodeFailed = false;
activeSeg = nullptr;
strcpy(lastFilename, "/"); // reset filename