rotate fullscreen bmp CCW instead of CW

This commit is contained in:
Sam Davis 2025-12-14 19:50:05 +11:00
parent 0a33516d85
commit c308e6c60f
3 changed files with 25 additions and 34 deletions

View File

@ -3,7 +3,7 @@
#include <cstdlib>
#include <cstring>
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);

View File

@ -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);
};

View File

@ -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;
}