From 8e2454d7dbbe49061c0bd2564edab649fc343596 Mon Sep 17 00:00:00 2001 From: Jonas Diemer Date: Sat, 3 Jan 2026 14:29:34 +0100 Subject: [PATCH] Made crop mode an option. --- lib/GfxRenderer/GfxRenderer.cpp | 6 +++-- lib/JpegToBmpConverter/JpegToBmpConverter.cpp | 3 +-- src/CrossPointSettings.cpp | 4 +++- src/CrossPointSettings.h | 2 ++ src/activities/boot_sleep/SleepActivity.cpp | 24 ++++++++++++------- src/activities/settings/SettingsActivity.cpp | 3 ++- 6 files changed, 27 insertions(+), 15 deletions(-) diff --git a/lib/GfxRenderer/GfxRenderer.cpp b/lib/GfxRenderer/GfxRenderer.cpp index 168e494e..1750b3f3 100644 --- a/lib/GfxRenderer/GfxRenderer.cpp +++ b/lib/GfxRenderer/GfxRenderer.cpp @@ -187,10 +187,11 @@ void GfxRenderer::drawBitmap(const Bitmap& bitmap, const int x, const int y, con for (int bmpY = 0; bmpY < (bitmap.getHeight() - cropPixY); bmpY++) { // The BMP's (0, 0) is the bottom-left corner (if the height is positive, top-left if negative). // Screen's (0, 0) is the top-left corner. - int screenY = y - cropPixY + (bitmap.isTopDown() ? bmpY : bitmap.getHeight() - 1 - bmpY); + int screenY = -cropPixY + (bitmap.isTopDown() ? bmpY : bitmap.getHeight() - 1 - bmpY); if (isScaled) { screenY = std::floor(screenY * scale); } + screenY += y; // the offset should not be scaled if (screenY >= getScreenHeight()) { break; } @@ -208,10 +209,11 @@ void GfxRenderer::drawBitmap(const Bitmap& bitmap, const int x, const int y, con } for (int bmpX = cropPixX; bmpX < bitmap.getWidth() - cropPixX; bmpX++) { - int screenX = x + bmpX - cropPixX; + int screenX = bmpX - cropPixX; if (isScaled) { screenX = std::floor(screenX * scale); } + screenX += x; // the offset should not be scaled if (screenX >= getScreenWidth()) { break; } diff --git a/lib/JpegToBmpConverter/JpegToBmpConverter.cpp b/lib/JpegToBmpConverter/JpegToBmpConverter.cpp index 4bf26994..8c8db889 100644 --- a/lib/JpegToBmpConverter/JpegToBmpConverter.cpp +++ b/lib/JpegToBmpConverter/JpegToBmpConverter.cpp @@ -468,8 +468,7 @@ bool JpegToBmpConverter::jpegFileToBmpStream(FsFile& jpegFile, Print& bmpOut) { // Calculate scale to fit within target dimensions while maintaining aspect ratio const float scaleToFitWidth = static_cast(TARGET_MAX_WIDTH) / imageInfo.m_width; const float scaleToFitHeight = static_cast(TARGET_MAX_HEIGHT) / imageInfo.m_height; - // const float scale = (scaleToFitWidth < scaleToFitHeight) ? scaleToFitWidth : scaleToFitHeight; - // For now, scale to the smaller dimension, so we can crop later. + // We scale to the smaller dimension, so we can potentially crop later. // TODO: ideally, we already crop here. const float scale = (scaleToFitWidth > scaleToFitHeight) ? scaleToFitWidth : scaleToFitHeight; diff --git a/src/CrossPointSettings.cpp b/src/CrossPointSettings.cpp index d304c4e4..83df3935 100644 --- a/src/CrossPointSettings.cpp +++ b/src/CrossPointSettings.cpp @@ -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 = 13; +constexpr uint8_t SETTINGS_COUNT = 14; constexpr char SETTINGS_FILE[] = "/.crosspoint/settings.bin"; } // namespace @@ -40,6 +40,7 @@ bool CrossPointSettings::saveToFile() const { serialization::writePod(outputFile, paragraphAlignment); serialization::writePod(outputFile, sleepTimeout); serialization::writePod(outputFile, refreshFrequency); + serialization::writePod(outputFile, sleepScreenCoverMode); outputFile.close(); Serial.printf("[%lu] [CPS] Settings saved to file\n", millis()); @@ -92,6 +93,7 @@ bool CrossPointSettings::loadFromFile() { if (++settingsRead >= fileSettingsCount) break; serialization::readPod(inputFile, refreshFrequency); if (++settingsRead >= fileSettingsCount) break; + serialization::readPod(inputFile, sleepScreenCoverMode); } while (false); inputFile.close(); diff --git a/src/CrossPointSettings.h b/src/CrossPointSettings.h index f24cde5f..05cd7cc3 100644 --- a/src/CrossPointSettings.h +++ b/src/CrossPointSettings.h @@ -54,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 diff --git a/src/activities/boot_sleep/SleepActivity.cpp b/src/activities/boot_sleep/SleepActivity.cpp index 0b5b2679..c072e4e0 100644 --- a/src/activities/boot_sleep/SleepActivity.cpp +++ b/src/activities/boot_sleep/SleepActivity.cpp @@ -154,19 +154,24 @@ void SleepActivity::renderBitmapSleepScreen(const Bitmap& bitmap) const { 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 - cropX = 1.0f - (screenRatio / ratio); - Serial.printf("[%lu] [SLP] Cropping bitmap x: %f\n", millis(), cropX); - ratio = (1 - cropX) * static_cast(bitmap.getWidth()) / static_cast(bitmap.getHeight()); + 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(bitmap.getWidth()) / static_cast(bitmap.getHeight()); + } x = 0; - y = (pageHeight - pageWidth / ratio) / 2; + y = std::round((static_cast(pageHeight) - static_cast(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 - // try to crop - cropY = 1.0f - (ratio / screenRatio); - Serial.printf("[%lu] [SLP] Cropping bitmap y: %f\n", millis(), cropY); - ratio = static_cast(bitmap.getWidth()) / ((1 - cropY) * static_cast(bitmap.getHeight())); - 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(bitmap.getWidth()) / ((1.0f - cropY) * static_cast(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 @@ -174,6 +179,7 @@ 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, cropX, cropY); renderer.displayBuffer(EInkDisplay::HALF_REFRESH); diff --git a/src/activities/settings/SettingsActivity.cpp b/src/activities/settings/SettingsActivity.cpp index a242389d..c9a72230 100644 --- a/src/activities/settings/SettingsActivity.cpp +++ b/src/activities/settings/SettingsActivity.cpp @@ -9,10 +9,11 @@ // Define the static settings list namespace { -constexpr int settingsCount = 14; +constexpr int settingsCount = 16; const SettingInfo settingsList[settingsCount] = { // Should match with SLEEP_SCREEN_MODE {"Sleep Screen", SettingType::ENUM, &CrossPointSettings::sleepScreen, {"Dark", "Light", "Custom", "Cover"}}, + {"Sleep Screen Cover Mode", SettingType::ENUM, &CrossPointSettings::sleepScreenCoverMode, {"Fit", "Crop"}}, {"Status Bar", SettingType::ENUM, &CrossPointSettings::statusBar, {"None", "No Progress", "Full"}}, {"Extra Paragraph Spacing", SettingType::TOGGLE, &CrossPointSettings::extraParagraphSpacing, {}}, {"Short Power Button Click", SettingType::TOGGLE, &CrossPointSettings::shortPwrBtn, {}},