Skip to content

Commit 3dae4aa

Browse files
committed
Fix image rendering artifacts, implement centering/scaling, and resolve JPEGDEC linkage issues
1 parent 097a98c commit 3dae4aa

2 files changed

Lines changed: 41 additions & 22 deletions

File tree

src/core/ImageDecoder.cpp

Lines changed: 39 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ bool ImageDecoder::decodeToBW(const char* path, uint8_t* outBuffer, uint16_t tar
1111
ctx.outBuffer = outBuffer;
1212
ctx.targetWidth = targetWidth;
1313
ctx.targetHeight = targetHeight;
14+
ctx.offsetX = 0;
15+
ctx.offsetY = 0;
1416
ctx.success = false;
1517
g_ctx = &ctx;
1618

@@ -22,7 +24,7 @@ bool ImageDecoder::decodeToBW(const char* path, uint8_t* outBuffer, uint16_t tar
2224
File f = SD.open(path);
2325
if (!f) return false;
2426

25-
// Use the simpler open() with callbacks to avoid linkage issues with File-based open
27+
// Use manual callback-based open to avoid linkage issues with File-based open
2628
int rc = jpeg.open((void *)&f, (int)f.size(), [](void *p) { /* close */ },
2729
[](JPEGFILE *pfn, uint8_t *pBuf, int32_t iLen) -> int32_t {
2830
if (!pfn->fHandle) return -1;
@@ -35,16 +37,28 @@ bool ImageDecoder::decodeToBW(const char* path, uint8_t* outBuffer, uint16_t tar
3537

3638
if (rc) {
3739
jpeg.setUserPointer(&ctx);
38-
// We want to fit the image to the screen
40+
3941
int scale = 0;
40-
if (jpeg.getWidth() > targetWidth || jpeg.getHeight() > targetHeight) {
41-
// Simplified scaling (JPEGDEC supports 1/2, 1/4, 1/8)
42-
if (jpeg.getWidth() > targetWidth * 4) scale = JPEG_SCALE_EIGHTH;
43-
else if (jpeg.getWidth() > targetWidth * 2) scale = JPEG_SCALE_QUARTER;
44-
else scale = JPEG_SCALE_HALF;
42+
int iw = jpeg.getWidth();
43+
int ih = jpeg.getHeight();
44+
45+
// Determine scaling factor (JPEGDEC supports 1/2, 1/4, 1/8)
46+
if (iw > targetWidth * 4 || ih > targetHeight * 4) {
47+
scale = JPEG_SCALE_EIGHTH;
48+
iw >>= 3; ih >>= 3;
49+
} else if (iw > targetWidth * 2 || ih > targetHeight * 2) {
50+
scale = JPEG_SCALE_QUARTER;
51+
iw >>= 2; ih >>= 2;
52+
} else if (iw > targetWidth || ih > targetHeight) {
53+
scale = JPEG_SCALE_HALF;
54+
iw >>= 1; ih >>= 1;
4555
}
56+
57+
// Calculate centering offsets
58+
ctx.offsetX = (targetWidth - iw) / 2;
59+
ctx.offsetY = (targetHeight - ih) / 2;
4660

47-
if (jpeg.decode(0, 0, scale)) {
61+
if (jpeg.decode(ctx.offsetX, ctx.offsetY, scale)) {
4862
ctx.success = true;
4963
}
5064
jpeg.close();
@@ -87,6 +101,10 @@ bool ImageDecoder::decodeToBW(const char* path, uint8_t* outBuffer, uint16_t tar
87101
});
88102

89103
if (rc == PNG_SUCCESS) {
104+
// PNGdec doesn't have built-in scaling, so it will be drawn top-left or cropped
105+
ctx.offsetX = (targetWidth - png.getWidth()) / 2;
106+
ctx.offsetY = (targetHeight - png.getHeight()) / 2;
107+
90108
rc = png.decode(&ctx, 0);
91109
if (rc == PNG_SUCCESS) {
92110
ctx.success = true;
@@ -106,7 +124,7 @@ int ImageDecoder::JPEGDraw(JPEGDRAW *pDraw) {
106124
DecodeContext *ctx = (DecodeContext *)pDraw->pUser;
107125

108126
const int destStride = (ctx->targetWidth + 7) / 8;
109-
Serial.printf("JPEGDraw: x=%d, y=%d, w=%d, h=%d, destStride=%d\n", pDraw->x, pDraw->y, pDraw->iWidth, pDraw->iHeight, destStride);
127+
// Serial.printf("JPEGDraw: x=%d, y=%d, w=%d, h=%d, destStride=%d\n", pDraw->x, pDraw->y, pDraw->iWidth, pDraw->iHeight, destStride);
110128

111129
for (int y = 0; y < pDraw->iHeight; y++) {
112130
int targetY = pDraw->y + y;
@@ -130,11 +148,11 @@ int ImageDecoder::JPEGDraw(JPEGDRAW *pDraw) {
130148
int bitIdx = 7 - (targetX % 8);
131149

132150
if (lum < 128) {
133-
// Black pixel (1 in E-Ink/SSD1677)
134-
ctx->outBuffer[byteIdx] |= (1 << bitIdx);
135-
} else {
136-
// White pixel (0 in E-Ink/SSD1677)
151+
// Black pixel (0 in E-Ink/SSD1677 based on EInkDisplay.cpp)
137152
ctx->outBuffer[byteIdx] &= ~(1 << bitIdx);
153+
} else {
154+
// White pixel (1 in E-Ink/SSD1677 based on EInkDisplay.cpp)
155+
ctx->outBuffer[byteIdx] |= (1 << bitIdx);
138156
}
139157
}
140158
}
@@ -150,14 +168,13 @@ void ImageDecoder::PNGDraw(PNGDRAW *pDraw) {
150168
currentPNG->getLineAsRGB565(pDraw, usPixels, PNG_RGB565_LITTLE_ENDIAN, 0xffffffff);
151169

152170
const int destStride = (ctx->targetWidth + 7) / 8;
153-
// Serial.printf("PNGDraw: y=%d, w=%d, destStride=%d\n", pDraw->y, pDraw->iWidth, destStride);
154171

155-
int targetY = pDraw->y;
156-
if (targetY >= ctx->targetHeight) return;
172+
int targetY = pDraw->y + ctx->offsetY;
173+
if (targetY < 0 || targetY >= ctx->targetHeight) return;
157174

158175
for (int x = 0; x < pDraw->iWidth; x++) {
159-
int targetX = x;
160-
if (targetX >= ctx->targetWidth) break;
176+
int targetX = x + ctx->offsetX;
177+
if (targetX < 0 || targetX >= ctx->targetWidth) continue;
161178

162179
uint16_t pixel = usPixels[x];
163180
uint8_t r = (pixel >> 11) & 0x1F;
@@ -170,11 +187,11 @@ void ImageDecoder::PNGDraw(PNGDRAW *pDraw) {
170187
int bitIdx = 7 - (targetX % 8);
171188

172189
if (lum < 128) {
173-
// Black pixel (1 in E-Ink/SSD1677)
174-
ctx->outBuffer[byteIdx] |= (1 << bitIdx);
175-
} else {
176-
// White pixel (0 in E-Ink/SSD1677)
190+
// Black pixel (0 in E-Ink/SSD1677)
177191
ctx->outBuffer[byteIdx] &= ~(1 << bitIdx);
192+
} else {
193+
// White pixel (1 in E-Ink/SSD1677)
194+
ctx->outBuffer[byteIdx] |= (1 << bitIdx);
178195
}
179196
}
180197
}

src/core/ImageDecoder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ class ImageDecoder {
1717
uint8_t* outBuffer;
1818
uint16_t targetWidth;
1919
uint16_t targetHeight;
20+
int16_t offsetX;
21+
int16_t offsetY;
2022
bool success;
2123
};
2224
/**

0 commit comments

Comments
 (0)