mirror of
https://github.com/daveallie/crosspoint-reader.git
synced 2025-12-18 15:17:42 +03:00
rotate fullscreen bmp CCW instead of CW
This commit is contained in:
parent
602d3da3a2
commit
d60378719c
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,4 +1,4 @@
|
|||||||
.pio
|
.pio
|
||||||
.idea
|
.idea
|
||||||
.DS_Store
|
.DS_Store
|
||||||
.vscode
|
.vscode
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
uint16_t BmpToMono::readLE16(fs::File& f) {
|
uint16_t BmpToMono::readLE16(File& f) {
|
||||||
const int c0 = f.read();
|
const int c0 = f.read();
|
||||||
const int c1 = f.read();
|
const int c1 = f.read();
|
||||||
const uint8_t b0 = (uint8_t)(c0 < 0 ? 0 : c0);
|
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);
|
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 c0 = f.read();
|
||||||
const int c1 = f.read();
|
const int c1 = f.read();
|
||||||
const int c2 = f.read();
|
const int c2 = f.read();
|
||||||
@ -67,15 +67,11 @@ const char* BmpToMono::errorToString(BmpToMonoError err) {
|
|||||||
return "Unknown";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
BmpToMonoError BmpToMono::convert24(fs::File& file, MonoBitmap& out, uint8_t threshold, bool invert) {
|
BmpToMonoError BmpToMono::convert24BitRotate90CCW(File& file, MonoBitmap& out, uint8_t threshold) {
|
||||||
return convert24Impl(file, out, threshold, invert, false);
|
return convert24BitImpl(file, out, threshold, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
BmpToMonoError BmpToMono::convert24Rotate90CW(fs::File& file, MonoBitmap& out, uint8_t threshold, bool invert) {
|
BmpToMonoError BmpToMono::convert24BitImpl(File& f, MonoBitmap& out, uint8_t threshold, bool rotate90CCW) {
|
||||||
return convert24Impl(file, out, threshold, invert, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
BmpToMonoError BmpToMono::convert24Impl(fs::File& f, MonoBitmap& out, uint8_t threshold, bool invert, bool rotate90CW) {
|
|
||||||
freeMonoBitmap(out);
|
freeMonoBitmap(out);
|
||||||
|
|
||||||
if (!f) return BmpToMonoError::FileInvalid;
|
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;
|
if (srcH <= 0) return BmpToMonoError::BadDimensions;
|
||||||
|
|
||||||
// Output dimensions
|
// Output dimensions
|
||||||
out.width = rotate90CW ? (int)srcH : (int)srcW;
|
out.width = rotate90CCW ? (int)srcH : (int)srcW;
|
||||||
out.height = rotate90CW ? (int)srcW : (int)srcH;
|
out.height = rotate90CCW ? (int)srcW : (int)srcH;
|
||||||
|
|
||||||
const size_t outBytesPerRow = (size_t)(out.width + 7) / 8;
|
const size_t outBytesPerRow = (size_t)(out.width + 7) / 8;
|
||||||
out.len = outBytesPerRow * (size_t)out.height;
|
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);
|
const uint8_t lum = (uint8_t)((77u * r + 150u * g + 29u * b) >> 8);
|
||||||
bool isBlack = (lum < threshold);
|
bool isBlack = (lum < threshold);
|
||||||
if (invert) isBlack = !isBlack;
|
|
||||||
|
|
||||||
int outX, outY;
|
int outX, outY;
|
||||||
if (!rotate90CW) {
|
if (!rotate90CCW) {
|
||||||
outX = srcX;
|
outX = srcX;
|
||||||
outY = srcY;
|
outY = srcY;
|
||||||
} else {
|
} else {
|
||||||
// 90° clockwise: (x,y) -> (h-1-y, x)
|
// 90° counter-clockwise: (x,y) -> (y, w-1-x)
|
||||||
outX = (int)srcH - 1 - srcY;
|
outX = srcY;
|
||||||
outY = srcX;
|
outY = (int)srcW - 1 - srcX;
|
||||||
}
|
}
|
||||||
|
|
||||||
setMonoPixel(out.data, out.width, outX, outY, isBlack);
|
setMonoPixel(out.data, out.width, outX, outY, isBlack);
|
||||||
|
|||||||
@ -32,20 +32,16 @@ enum class BmpToMonoError : uint8_t {
|
|||||||
|
|
||||||
class BmpToMono {
|
class BmpToMono {
|
||||||
public:
|
public:
|
||||||
// No rotation: output size == BMP size
|
// Rotate 90° counter-clockwise: (w,h) -> (h,w)
|
||||||
static BmpToMonoError convert24(fs::File& file, MonoBitmap& out, uint8_t threshold = 160, bool invert = false);
|
// Used for converting portrait BMP (480x800) into landscape framebuffer (800x480)
|
||||||
|
static BmpToMonoError convert24BitRotate90CCW(File& file, MonoBitmap& out, uint8_t threshold = 160);
|
||||||
// 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);
|
|
||||||
|
|
||||||
static void freeMonoBitmap(MonoBitmap& bmp);
|
static void freeMonoBitmap(MonoBitmap& bmp);
|
||||||
static const char* errorToString(BmpToMonoError err);
|
static const char* errorToString(BmpToMonoError err);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static uint16_t readLE16(fs::File& f);
|
static uint16_t readLE16(File& f);
|
||||||
static uint32_t readLE32(fs::File& f);
|
static uint32_t readLE32(File& f);
|
||||||
|
|
||||||
// Writes a single pixel into a row-aligned 1bpp buffer (MSB-first), 0=black, 1=white
|
// 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) {
|
static inline void setMonoPixel(uint8_t* buf, int w, int x, int y, bool isBlack) {
|
||||||
@ -58,5 +54,5 @@ class BmpToMono {
|
|||||||
buf[idx] |= mask;
|
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);
|
||||||
};
|
};
|
||||||
@ -129,8 +129,8 @@ bool GfxRenderer::drawFullScreenBmp(File& file) {
|
|||||||
|
|
||||||
file.seek(0); // Ensure we're at the start of the file
|
file.seek(0); // Ensure we're at the start of the file
|
||||||
|
|
||||||
MonoBitmap mono;
|
MonoBitmap bmp;
|
||||||
auto err = BmpToMono::convert24Rotate90CW(file, mono, 160, false);
|
auto err = BmpToMono::convert24BitRotate90CCW(file, bmp);
|
||||||
|
|
||||||
if (err != BmpToMonoError::Ok) {
|
if (err != BmpToMonoError::Ok) {
|
||||||
Serial.printf("[%lu] [GFX] BMP convert failed: %s\n", millis(), BmpToMono::errorToString(err));
|
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
|
// 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(),
|
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);
|
bmp.width, bmp.height, EInkDisplay::DISPLAY_WIDTH, EInkDisplay::DISPLAY_HEIGHT);
|
||||||
BmpToMono::freeMonoBitmap(mono);
|
BmpToMono::freeMonoBitmap(bmp);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Raw full-screen blit
|
// Full-screen blit
|
||||||
einkDisplay.drawImage(mono.data, 0, 0, mono.width, mono.height);
|
einkDisplay.drawImage(bmp.data, 0, 0, bmp.width, bmp.height);
|
||||||
|
|
||||||
BmpToMono::freeMonoBitmap(mono);
|
BmpToMono::freeMonoBitmap(bmp);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user