Feature/cover crop mode (#225)

Added a setting to select `fit` or `crop` for cover image on sleep
screen.

Might add a `expand` feature in the future that does not crop but rather
fills the blank space with a mirror of the image.

---------

Co-authored-by: Dave Allie <dave@daveallie.com>
This commit is contained in:
Jonas Diemer
2026-01-05 11:07:27 +01:00
committed by GitHub
parent 9f95b31de5
commit afe9672156
9 changed files with 70 additions and 37 deletions

View File

@@ -12,7 +12,7 @@ CrossPointSettings CrossPointSettings::instance;
namespace {
constexpr uint8_t SETTINGS_FILE_VERSION = 1;
// Increment this when adding new persisted settings fields
constexpr uint8_t SETTINGS_COUNT = 14;
constexpr uint8_t SETTINGS_COUNT = 15;
constexpr char SETTINGS_FILE[] = "/.crosspoint/settings.bin";
} // namespace
@@ -41,7 +41,7 @@ bool CrossPointSettings::saveToFile() const {
serialization::writePod(outputFile, sleepTimeout);
serialization::writePod(outputFile, refreshFrequency);
serialization::writePod(outputFile, screenMargin);
serialization::writePod(outputFile, sleepScreenCoverMode);
outputFile.close();
Serial.printf("[%lu] [CPS] Settings saved to file\n", millis());
@@ -96,7 +96,8 @@ bool CrossPointSettings::loadFromFile() {
if (++settingsRead >= fileSettingsCount) break;
serialization::readPod(inputFile, screenMargin);
if (++settingsRead >= fileSettingsCount) break;
serialization::readPod(inputFile, sleepScreenCoverMode);
if (++settingsRead >= fileSettingsCount) break;
} while (false);
inputFile.close();
@@ -212,4 +213,4 @@ int CrossPointSettings::getReaderFontId() const {
return OPENDYSLEXIC_14_FONT_ID;
}
}
}
}

View File

@@ -17,6 +17,7 @@ class CrossPointSettings {
// Should match with SettingsActivity text
enum SLEEP_SCREEN_MODE { DARK = 0, LIGHT = 1, CUSTOM = 2, COVER = 3, BLANK = 4 };
enum SLEEP_SCREEN_COVER_MODE { FIT = 0, CROP = 1 };
// Status bar display type enum
enum STATUS_BAR_MODE { NONE = 0, NO_PROGRESS = 1, FULL = 2 };
@@ -53,6 +54,8 @@ class CrossPointSettings {
// Sleep screen settings
uint8_t sleepScreen = DARK;
// Sleep screen cover mode settings
uint8_t sleepScreenCoverMode = FIT;
// Status bar settings
uint8_t statusBar = FULL;
// Text rendering settings

View File

@@ -146,20 +146,36 @@ void SleepActivity::renderBitmapSleepScreen(const Bitmap& bitmap) const {
int x, y;
const auto pageWidth = renderer.getScreenWidth();
const auto pageHeight = renderer.getScreenHeight();
float cropX = 0, cropY = 0;
Serial.printf("[%lu] [SLP] bitmap %d x %d, screen %d x %d\n", millis(), bitmap.getWidth(), bitmap.getHeight(),
pageWidth, pageHeight);
if (bitmap.getWidth() > pageWidth || bitmap.getHeight() > pageHeight) {
// image will scale, make sure placement is right
const float ratio = static_cast<float>(bitmap.getWidth()) / static_cast<float>(bitmap.getHeight());
float ratio = static_cast<float>(bitmap.getWidth()) / static_cast<float>(bitmap.getHeight());
const float screenRatio = static_cast<float>(pageWidth) / static_cast<float>(pageHeight);
Serial.printf("[%lu] [SLP] bitmap ratio: %f, screen ratio: %f\n", millis(), ratio, screenRatio);
if (ratio > screenRatio) {
// image wider than viewport ratio, scaled down image needs to be centered vertically
if (SETTINGS.sleepScreenCoverMode == CrossPointSettings::SLEEP_SCREEN_COVER_MODE::CROP) {
cropX = 1.0f - (screenRatio / ratio);
Serial.printf("[%lu] [SLP] Cropping bitmap x: %f\n", millis(), cropX);
ratio = (1.0f - cropX) * static_cast<float>(bitmap.getWidth()) / static_cast<float>(bitmap.getHeight());
}
x = 0;
y = (pageHeight - pageWidth / ratio) / 2;
y = std::round((static_cast<float>(pageHeight) - static_cast<float>(pageWidth) / ratio) / 2);
Serial.printf("[%lu] [SLP] Centering with ratio %f to y=%d\n", millis(), ratio, y);
} else {
// image taller than viewport ratio, scaled down image needs to be centered horizontally
x = (pageWidth - pageHeight * ratio) / 2;
if (SETTINGS.sleepScreenCoverMode == CrossPointSettings::SLEEP_SCREEN_COVER_MODE::CROP) {
cropY = 1.0f - (ratio / screenRatio);
Serial.printf("[%lu] [SLP] Cropping bitmap y: %f\n", millis(), cropY);
ratio = static_cast<float>(bitmap.getWidth()) / ((1.0f - cropY) * static_cast<float>(bitmap.getHeight()));
}
x = std::round((pageWidth - pageHeight * ratio) / 2);
y = 0;
Serial.printf("[%lu] [SLP] Centering with ratio %f to x=%d\n", millis(), ratio, x);
}
} else {
// center the image
@@ -167,21 +183,22 @@ void SleepActivity::renderBitmapSleepScreen(const Bitmap& bitmap) const {
y = (pageHeight - bitmap.getHeight()) / 2;
}
Serial.printf("[%lu] [SLP] drawing to %d x %d\n", millis(), x, y);
renderer.clearScreen();
renderer.drawBitmap(bitmap, x, y, pageWidth, pageHeight);
renderer.drawBitmap(bitmap, x, y, pageWidth, pageHeight, cropX, cropY);
renderer.displayBuffer(EInkDisplay::HALF_REFRESH);
if (bitmap.hasGreyscale()) {
bitmap.rewindToData();
renderer.clearScreen(0x00);
renderer.setRenderMode(GfxRenderer::GRAYSCALE_LSB);
renderer.drawBitmap(bitmap, x, y, pageWidth, pageHeight);
renderer.drawBitmap(bitmap, x, y, pageWidth, pageHeight, cropX, cropY);
renderer.copyGrayscaleLsbBuffers();
bitmap.rewindToData();
renderer.clearScreen(0x00);
renderer.setRenderMode(GfxRenderer::GRAYSCALE_MSB);
renderer.drawBitmap(bitmap, x, y, pageWidth, pageHeight);
renderer.drawBitmap(bitmap, x, y, pageWidth, pageHeight, cropX, cropY);
renderer.copyGrayscaleMsbBuffers();
renderer.displayGrayBuffer();

View File

@@ -10,10 +10,11 @@
// Define the static settings list
namespace {
constexpr int settingsCount = 15;
constexpr int settingsCount = 16;
const SettingInfo settingsList[settingsCount] = {
// Should match with SLEEP_SCREEN_MODE
SettingInfo::Enum("Sleep Screen", &CrossPointSettings::sleepScreen, {"Dark", "Light", "Custom", "Cover", "None"}),
SettingInfo::Enum("Sleep Screen Cover Mode", &CrossPointSettings::sleepScreenCoverMode, {"Fit", "Crop"}),
SettingInfo::Enum("Status Bar", &CrossPointSettings::statusBar, {"None", "No Progress", "Full"}),
SettingInfo::Toggle("Extra Paragraph Spacing", &CrossPointSettings::extraParagraphSpacing),
SettingInfo::Toggle("Short Power Button Click", &CrossPointSettings::shortPwrBtn),