Formatting.

This commit is contained in:
Jonas Diemer 2025-12-18 13:43:47 +01:00
parent 13fc5f7bbb
commit 5c22342dcc

View File

@ -9,83 +9,82 @@
#include "config.h" #include "config.h"
#include "images/CrossLarge.h" #include "images/CrossLarge.h"
void convertBmpToBWdisplayData(uint8_t* bmpData, void convertBmpToBWdisplayData(uint8_t* bmpData, int width, int height, uint8_t* displayImage) {
int width, int height, uint8_t* displayImage){ // Convert BMP data to 1bpp format for e-ink display
// Convert BMP data to 1bpp format for e-ink display // Implementation details depend on the specific BMP format and display requirements
// Implementation details depend on the specific BMP format and display requirements
// Static lookup table for bit masks (better performance) // Static lookup table for bit masks (better performance)
static const uint8_t bitMasks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; static const uint8_t bitMasks[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
// For 1bpp images where width is divisible by 8, we can use a highly optimized approach // For 1bpp images where width is divisible by 8, we can use a highly optimized approach
const int bytesPerSrcRow = width / 8; const int bytesPerSrcRow = width / 8;
const int bytesPerRow = (height + 7) / 8; // use heigth due to 90deg rotation const int bytesPerRow = (height + 7) / 8; // use heigth due to 90deg rotation
int bmpRowSize = width / 8; // 1 bit per pixel, assuming width is divisible by 8 int bmpRowSize = width / 8; // 1 bit per pixel, assuming width is divisible by 8
// Process each source row // Process each source row
for (int y = 0; y < height; y++) { for (int y = 0; y < height; y++) {
// Calculate source row (BMPs are normally stored bottom-to-top) // Calculate source row (BMPs are normally stored bottom-to-top)
int srcRow = height-1-y; int srcRow = height - 1 - y;
// In 90-degree rotation, source Y becomes destination X // In 90-degree rotation, source Y becomes destination X
int destX = y; int destX = y;
int destByteX = destX / 8; int destByteX = destX / 8;
int destBitInByte = destX & 0x07; // Fast mod 8 int destBitInByte = destX & 0x07; // Fast mod 8
uint8_t destBitMask = bitMasks[destBitInByte]; uint8_t destBitMask = bitMasks[destBitInByte];
// Get pointer to this row's data // Get pointer to this row's data
uint8_t* srcRowData = bmpData + (srcRow * bmpRowSize); uint8_t* srcRowData = bmpData + (srcRow * bmpRowSize);
// Process all bytes in this row // Process all bytes in this row
for (int xByte = 0; xByte < bytesPerSrcRow; xByte++) { for (int xByte = 0; xByte < bytesPerSrcRow; xByte++) {
uint8_t srcByte = srcRowData[xByte]; uint8_t srcByte = srcRowData[xByte];
// Skip processing if byte is all white // Skip processing if byte is all white
if (srcByte == 0xFF) continue; if (srcByte == 0xFF) continue;
// For bytes that are either all black or have a simple pattern, optimize // For bytes that are either all black or have a simple pattern, optimize
if (srcByte == 0x00) { if (srcByte == 0x00) {
// All 8 pixels are black - use fast path // All 8 pixels are black - use fast path
for (int bit = 0; bit < 8; bit++) { for (int bit = 0; bit < 8; bit++) {
int srcX = (xByte * 8) + bit;
int destY = width - 1 - srcX;
int destByteIdx = (destY * bytesPerRow) + destByteX;
displayImage[destByteIdx] &= ~destBitMask;
}
} else {
// Process individual bits for mixed bytes
for (int bit = 0; bit < 8; bit++) {
// Only process if this bit is black (0)
if ((srcByte & bitMasks[bit]) == 0) {
int srcX = (xByte * 8) + bit; int srcX = (xByte * 8) + bit;
int destY = width - 1 - srcX; int destY = width - 1 - srcX;
int destByteIdx = (destY * bytesPerRow) + destByteX; int destByteIdx = (destY * bytesPerRow) + destByteX;
displayImage[destByteIdx] &= ~destBitMask; displayImage[destByteIdx] &= ~destBitMask;
} }
} else {
// Process individual bits for mixed bytes
for (int bit = 0; bit < 8; bit++) {
// Only process if this bit is black (0)
if ((srcByte & bitMasks[bit]) == 0) {
int srcX = (xByte * 8) + bit;
int destY = width - 1 - srcX;
int destByteIdx = (destY * bytesPerRow) + destByteX;
displayImage[destByteIdx] &= ~destBitMask;
}
}
} }
} }
} }
}
} }
// BMP file header structure // BMP file header structure
#pragma pack(push, 1) #pragma pack(push, 1)
struct BMPHeader { struct BMPHeader {
uint16_t signature; // 'BM' uint16_t signature; // 'BM'
uint32_t fileSize; // Size of the BMP file in bytes uint32_t fileSize; // Size of the BMP file in bytes
uint32_t reserved; // Reserved uint32_t reserved; // Reserved
uint32_t dataOffset; // Offset to bitmap data uint32_t dataOffset; // Offset to bitmap data
uint32_t headerSize; // Size of the header uint32_t headerSize; // Size of the header
int32_t width; // Width of the image int32_t width; // Width of the image
int32_t height; // Height of the image int32_t height; // Height of the image
uint16_t planes; // Number of color planes uint16_t planes; // Number of color planes
uint16_t bitsPerPixel; // Bits per pixel uint16_t bitsPerPixel; // Bits per pixel
uint32_t compression; // Compression method uint32_t compression; // Compression method
uint32_t imageSize; // Size of the image data uint32_t imageSize; // Size of the image data
int32_t xPixelsPerMeter; // Horizontal resolution int32_t xPixelsPerMeter; // Horizontal resolution
int32_t yPixelsPerMeter; // Vertical resolution int32_t yPixelsPerMeter; // Vertical resolution
uint32_t totalColors; // Number of colors in palette uint32_t totalColors; // Number of colors in palette
uint32_t importantColors;// Number of important colors uint32_t importantColors; // Number of important colors
}; };
#pragma pack(pop) #pragma pack(pop)
@ -112,19 +111,19 @@ uint8_t* loadBMP(const char* filename, int& width, int& height) {
bmpFile.read((uint8_t*)&header, sizeof(BMPHeader)); bmpFile.read((uint8_t*)&header, sizeof(BMPHeader));
// Check if this is a valid BMP file // Check if this is a valid BMP file
if (header.signature != 0x4D42) { // "BM" in little-endian if (header.signature != 0x4D42) { // "BM" in little-endian
Serial.printf("[%lu] [SleepScreen] Invalid BMP signature\n", millis()); Serial.printf("[%lu] [SleepScreen] Invalid BMP signature\n", millis());
bmpFile.close(); bmpFile.close();
return nullptr; return nullptr;
} }
// Check for supported bit depths // Check for supported bit depths
if (header.bitsPerPixel != 1){ //} && header.bitsPerPixel != 24) { if (header.bitsPerPixel != 1) { //} && header.bitsPerPixel != 24) {
Serial.printf("[%lu] [SleepScreen] Unsupported bit depth: %d\n", millis(), header.bitsPerPixel); Serial.printf("[%lu] [SleepScreen] Unsupported bit depth: %d\n", millis(), header.bitsPerPixel);
bmpFile.close(); bmpFile.close();
return nullptr; return nullptr;
} }
if (header.height < 0){ //} && header.bitsPerPixel != 24) { if (header.height < 0) { //} && header.bitsPerPixel != 24) {
Serial.printf("[%lu] [SleepScreen] Unsupported negative height\n", millis()); Serial.printf("[%lu] [SleepScreen] Unsupported negative height\n", millis());
bmpFile.close(); bmpFile.close();
return nullptr; return nullptr;
@ -134,7 +133,8 @@ uint8_t* loadBMP(const char* filename, int& width, int& height) {
width = header.width; width = header.width;
height = header.height; height = header.height;
Serial.printf("[%lu] [SleepScreen] BMP dimensions: %dx%d, %d bits/pixel\n", millis(), width, height, header.bitsPerPixel); Serial.printf("[%lu] [SleepScreen] BMP dimensions: %dx%d, %d bits/pixel\n", millis(), width, height,
header.bitsPerPixel);
// Calculate destination dimensions based on rotation type // Calculate destination dimensions based on rotation type
int destWidth, destHeight; int destWidth, destHeight;
@ -158,7 +158,6 @@ uint8_t* loadBMP(const char* filename, int& width, int& height) {
// Initialize to all white (0xFF = all bits set to 1) // Initialize to all white (0xFF = all bits set to 1)
memset(displayImage, 0xFF, bufferSize); memset(displayImage, 0xFF, bufferSize);
// With 4-byte divisibility assertion, no padding calculations are needed // With 4-byte divisibility assertion, no padding calculations are needed
// Add assertion that dimensions are divisible by 4 // Add assertion that dimensions are divisible by 4
@ -180,8 +179,7 @@ uint8_t* loadBMP(const char* filename, int& width, int& height) {
// Allocate a buffer for the entire bitmap // Allocate a buffer for the entire bitmap
uint8_t* bmpData = (uint8_t*)malloc(totalBitmapSize); uint8_t* bmpData = (uint8_t*)malloc(totalBitmapSize);
if (!bmpData) { if (!bmpData) {
Serial.printf("[%lu] [SleepScreen] Failed to allocate bitmap buffer (%d bytes)\n", Serial.printf("[%lu] [SleepScreen] Failed to allocate bitmap buffer (%d bytes)\n", millis(), totalBitmapSize);
millis(), totalBitmapSize);
free(displayImage); free(displayImage);
bmpFile.close(); bmpFile.close();
return nullptr; return nullptr;
@ -191,15 +189,15 @@ uint8_t* loadBMP(const char* filename, int& width, int& height) {
bmpFile.seek(header.dataOffset); bmpFile.seek(header.dataOffset);
bmpFile.read(bmpData, totalBitmapSize); bmpFile.read(bmpData, totalBitmapSize);
convertBmpToBWdisplayData(bmpData, width, height,displayImage); convertBmpToBWdisplayData(bmpData, width, height, displayImage);
// Clean up // Clean up
free(bmpData); free(bmpData);
} }
bmpFile.close(); bmpFile.close();
const unsigned long elapsedTime = millis() - startTime; const unsigned long elapsedTime = millis() - startTime;
Serial.printf("[%lu] [SleepScreen] Successfully loaded BMP: %dx%d in %lu ms\n", Serial.printf("[%lu] [SleepScreen] Successfully loaded BMP: %dx%d in %lu ms\n", millis(), destWidth, destHeight,
millis(), destWidth, destHeight, elapsedTime); elapsedTime);
return displayImage; return displayImage;
} }
@ -221,8 +219,8 @@ void SleepActivity::onEnter() {
for (const char* path : bmpPaths) { for (const char* path : bmpPaths) {
imageData = loadBMP(path, imageWidth, imageHeight); imageData = loadBMP(path, imageWidth, imageHeight);
if (imageData) { if (imageData) {
Serial.printf("[%lu] [SleepScreen] Successfully loaded: %s\n", millis(), path); Serial.printf("[%lu] [SleepScreen] Successfully loaded: %s\n", millis(), path);
break; break;
} }
} }
@ -240,8 +238,8 @@ void SleepActivity::onEnter() {
// Note: We've applied 90-degree clockwise rotation to compensate for // Note: We've applied 90-degree clockwise rotation to compensate for
// the renderer's behavior and ensure the image appears correctly // the renderer's behavior and ensure the image appears correctly
// on the e-ink display. // on the e-ink display.
Serial.printf("[%lu] [SleepScreen] Drawing at position: %d,%d (dimensions: %dx%d)\n", millis(), Serial.printf("[%lu] [SleepScreen] Drawing at position: %d,%d (dimensions: %dx%d)\n", millis(), xPos, yPos,
xPos, yPos, imageWidth, imageHeight); imageWidth, imageHeight);
renderer.drawImage(imageData, xPos, yPos, imageWidth, imageHeight); renderer.drawImage(imageData, xPos, yPos, imageWidth, imageHeight);
// Free the image data // Free the image data