sleep screen filled with cover image's perimeter dominant color prior to being drawn

This commit is contained in:
cottongin
2026-01-24 03:29:34 -05:00
parent 1e20d30875
commit 2f21f55512
4 changed files with 209 additions and 14 deletions

View File

@@ -262,3 +262,90 @@ BmpReaderError Bitmap::rewindToData() const {
return BmpReaderError::Ok;
}
bool Bitmap::detectPerimeterIsBlack() const {
// Detect if the 1-pixel perimeter of the image is mostly black or white.
// Returns true if mostly black (luminance < 128), false if mostly white.
if (width <= 0 || height <= 0) return false;
auto* rowBuffer = static_cast<uint8_t*>(malloc(rowBytes));
if (!rowBuffer) return false;
int blackCount = 0;
int whiteCount = 0;
// Helper lambda to get luminance from a pixel at position x in rowBuffer
auto getLuminance = [&](int x) -> uint8_t {
switch (bpp) {
case 32: {
const uint8_t* p = rowBuffer + x * 4;
return (77u * p[2] + 150u * p[1] + 29u * p[0]) >> 8;
}
case 24: {
const uint8_t* p = rowBuffer + x * 3;
return (77u * p[2] + 150u * p[1] + 29u * p[0]) >> 8;
}
case 8:
return paletteLum[rowBuffer[x]];
case 2:
return paletteLum[(rowBuffer[x >> 2] >> (6 - ((x & 3) * 2))) & 0x03];
case 1: {
const uint8_t palIndex = (rowBuffer[x >> 3] & (0x80 >> (x & 7))) ? 1 : 0;
return paletteLum[palIndex];
}
default:
return 128; // Neutral if unsupported
}
};
// Helper to classify and count a pixel
auto countPixel = [&](int x) {
const uint8_t lum = getLuminance(x);
if (lum < 128) {
blackCount++;
} else {
whiteCount++;
}
};
// Helper to seek to a specific image row (accounting for top-down vs bottom-up)
auto seekToRow = [&](int imageRow) -> bool {
// In bottom-up BMP (topDown=false), row 0 in file is the bottom row of image
// In top-down BMP (topDown=true), row 0 in file is the top row of image
int fileRow = topDown ? imageRow : (height - 1 - imageRow);
return file.seek(bfOffBits + static_cast<uint32_t>(fileRow) * rowBytes);
};
// Sample top row (image row 0) - all pixels
if (seekToRow(0) && file.read(rowBuffer, rowBytes) == rowBytes) {
for (int x = 0; x < width; x++) {
countPixel(x);
}
}
// Sample bottom row (image row height-1) - all pixels
if (height > 1) {
if (seekToRow(height - 1) && file.read(rowBuffer, rowBytes) == rowBytes) {
for (int x = 0; x < width; x++) {
countPixel(x);
}
}
}
// Sample left and right edges from intermediate rows
for (int y = 1; y < height - 1; y++) {
if (seekToRow(y) && file.read(rowBuffer, rowBytes) == rowBytes) {
countPixel(0); // Left edge
countPixel(width - 1); // Right edge
}
}
free(rowBuffer);
// Rewind file position for subsequent drawing
rewindToData();
// Return true if perimeter is mostly black
return blackCount > whiteCount;
}

View File

@@ -37,6 +37,7 @@ class Bitmap {
BmpReaderError parseHeaders();
BmpReaderError readNextRow(uint8_t* data, uint8_t* rowBuffer) const;
BmpReaderError rewindToData() const;
bool detectPerimeterIsBlack() const;
int getWidth() const { return width; }
int getHeight() const { return height; }
bool isTopDown() const { return topDown; }