From d60378719cd9f4cb67b12cbb1e68f36de1bd502b Mon Sep 17 00:00:00 2001 From: Sam Davis Date: Sun, 14 Dec 2025 19:50:05 +1100 Subject: [PATCH] rotate fullscreen bmp CCW instead of CW --- .gitignore | 2 +- lib/BmpToMono/BmpToMono.cpp | 27 +++++++++++---------------- lib/BmpToMono/BmpToMono.h | 16 ++++++---------- lib/GfxRenderer/GfxRenderer.cpp | 16 ++++++++-------- 4 files changed, 26 insertions(+), 35 deletions(-) diff --git a/.gitignore b/.gitignore index 3690b08..c989c30 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ .pio .idea .DS_Store -.vscode \ No newline at end of file +.vscode diff --git a/lib/BmpToMono/BmpToMono.cpp b/lib/BmpToMono/BmpToMono.cpp index 10e9303..b2eb982 100644 --- a/lib/BmpToMono/BmpToMono.cpp +++ b/lib/BmpToMono/BmpToMono.cpp @@ -3,7 +3,7 @@ #include #include -uint16_t BmpToMono::readLE16(fs::File& f) { +uint16_t BmpToMono::readLE16(File& f) { const int c0 = f.read(); const int c1 = f.read(); const uint8_t b0 = (uint8_t)(c0 < 0 ? 0 : c0); @@ -11,7 +11,7 @@ uint16_t BmpToMono::readLE16(fs::File& f) { return (uint16_t)b0 | ((uint16_t)b1 << 8); } -uint32_t BmpToMono::readLE32(fs::File& f) { +uint32_t BmpToMono::readLE32(File& f) { const int c0 = f.read(); const int c1 = f.read(); const int c2 = f.read(); @@ -67,15 +67,11 @@ const char* BmpToMono::errorToString(BmpToMonoError err) { return "Unknown"; } -BmpToMonoError BmpToMono::convert24(fs::File& file, MonoBitmap& out, uint8_t threshold, bool invert) { - return convert24Impl(file, out, threshold, invert, false); +BmpToMonoError BmpToMono::convert24BitRotate90CCW(File& file, MonoBitmap& out, uint8_t threshold) { + return convert24BitImpl(file, out, threshold, true); } -BmpToMonoError BmpToMono::convert24Rotate90CW(fs::File& file, MonoBitmap& out, uint8_t threshold, bool invert) { - return convert24Impl(file, out, threshold, invert, true); -} - -BmpToMonoError BmpToMono::convert24Impl(fs::File& f, MonoBitmap& out, uint8_t threshold, bool invert, bool rotate90CW) { +BmpToMonoError BmpToMono::convert24BitImpl(File& f, MonoBitmap& out, uint8_t threshold, bool rotate90CCW) { freeMonoBitmap(out); if (!f) return BmpToMonoError::FileInvalid; @@ -117,8 +113,8 @@ BmpToMonoError BmpToMono::convert24Impl(fs::File& f, MonoBitmap& out, uint8_t th if (srcH <= 0) return BmpToMonoError::BadDimensions; // Output dimensions - out.width = rotate90CW ? (int)srcH : (int)srcW; - out.height = rotate90CW ? (int)srcW : (int)srcH; + out.width = rotate90CCW ? (int)srcH : (int)srcW; + out.height = rotate90CCW ? (int)srcW : (int)srcH; const size_t outBytesPerRow = (size_t)(out.width + 7) / 8; out.len = outBytesPerRow * (size_t)out.height; @@ -158,16 +154,15 @@ BmpToMonoError BmpToMono::convert24Impl(fs::File& f, MonoBitmap& out, uint8_t th const uint8_t lum = (uint8_t)((77u * r + 150u * g + 29u * b) >> 8); bool isBlack = (lum < threshold); - if (invert) isBlack = !isBlack; int outX, outY; - if (!rotate90CW) { + if (!rotate90CCW) { outX = srcX; outY = srcY; } else { - // 90° clockwise: (x,y) -> (h-1-y, x) - outX = (int)srcH - 1 - srcY; - outY = srcX; + // 90° counter-clockwise: (x,y) -> (y, w-1-x) + outX = srcY; + outY = (int)srcW - 1 - srcX; } setMonoPixel(out.data, out.width, outX, outY, isBlack); diff --git a/lib/BmpToMono/BmpToMono.h b/lib/BmpToMono/BmpToMono.h index b50937d..ef2d3b6 100644 --- a/lib/BmpToMono/BmpToMono.h +++ b/lib/BmpToMono/BmpToMono.h @@ -32,20 +32,16 @@ enum class BmpToMonoError : uint8_t { class BmpToMono { public: - // No rotation: output size == BMP size - static BmpToMonoError convert24(fs::File& file, MonoBitmap& out, uint8_t threshold = 160, bool invert = false); - - // Rotate 90° clockwise: (w,h) -> (h,w) - // Useful for converting portrait BMP (480x800) into landscape framebuffer (800x480). - static BmpToMonoError convert24Rotate90CW(fs::File& file, MonoBitmap& out, uint8_t threshold = 160, - bool invert = false); + // Rotate 90° counter-clockwise: (w,h) -> (h,w) + // Used for converting portrait BMP (480x800) into landscape framebuffer (800x480) + static BmpToMonoError convert24BitRotate90CCW(File& file, MonoBitmap& out, uint8_t threshold = 160); static void freeMonoBitmap(MonoBitmap& bmp); static const char* errorToString(BmpToMonoError err); private: - static uint16_t readLE16(fs::File& f); - static uint32_t readLE32(fs::File& f); + static uint16_t readLE16(File& f); + static uint32_t readLE32(File& f); // Writes a single pixel into a row-aligned 1bpp buffer (MSB-first), 0=black, 1=white static inline void setMonoPixel(uint8_t* buf, int w, int x, int y, bool isBlack) { @@ -58,5 +54,5 @@ class BmpToMono { buf[idx] |= mask; } - static BmpToMonoError convert24Impl(fs::File& file, MonoBitmap& out, uint8_t threshold, bool invert, bool rotate90CW); + static BmpToMonoError convert24BitImpl(File& file, MonoBitmap& out, uint8_t threshold, bool rotate90CW); }; \ No newline at end of file diff --git a/lib/GfxRenderer/GfxRenderer.cpp b/lib/GfxRenderer/GfxRenderer.cpp index cdd519f..3509188 100644 --- a/lib/GfxRenderer/GfxRenderer.cpp +++ b/lib/GfxRenderer/GfxRenderer.cpp @@ -129,8 +129,8 @@ bool GfxRenderer::drawFullScreenBmp(File& file) { file.seek(0); // Ensure we're at the start of the file - MonoBitmap mono; - auto err = BmpToMono::convert24Rotate90CW(file, mono, 160, false); + MonoBitmap bmp; + auto err = BmpToMono::convert24BitRotate90CCW(file, bmp); if (err != BmpToMonoError::Ok) { Serial.printf("[%lu] [GFX] BMP convert failed: %s\n", millis(), BmpToMono::errorToString(err)); @@ -138,17 +138,17 @@ bool GfxRenderer::drawFullScreenBmp(File& file) { } // Hard requirement: must match panel exactly - if (mono.width != EInkDisplay::DISPLAY_WIDTH || mono.height != EInkDisplay::DISPLAY_HEIGHT) { + if (bmp.width != EInkDisplay::DISPLAY_WIDTH || bmp.height != EInkDisplay::DISPLAY_HEIGHT) { Serial.printf("[%lu] [GFX] drawFullScreenBmp: rotated BMP size %dx%d does not match panel %dx%d\n", millis(), - mono.width, mono.height, EInkDisplay::DISPLAY_WIDTH, EInkDisplay::DISPLAY_HEIGHT); - BmpToMono::freeMonoBitmap(mono); + bmp.width, bmp.height, EInkDisplay::DISPLAY_WIDTH, EInkDisplay::DISPLAY_HEIGHT); + BmpToMono::freeMonoBitmap(bmp); return false; } - // Raw full-screen blit - einkDisplay.drawImage(mono.data, 0, 0, mono.width, mono.height); + // Full-screen blit + einkDisplay.drawImage(bmp.data, 0, 0, bmp.width, bmp.height); - BmpToMono::freeMonoBitmap(mono); + BmpToMono::freeMonoBitmap(bmp); return true; }