49 lines
4.3 KiB
Markdown
49 lines
4.3 KiB
Markdown
|
|
# feat: Sleep screen letterbox fill and image upscaling
|
|||
|
|
|
|||
|
|
**Branch:** `mod/sleep-screen-tweaks`
|
|||
|
|
|
|||
|
|
## Summary
|
|||
|
|
|
|||
|
|
* **What is the goal of this PR?**
|
|||
|
|
Improve the sleep screen experience for cover images that don't match the display's aspect ratio, and fix Fit mode for images smaller than the screen.
|
|||
|
|
|
|||
|
|
* **What changes are included?**
|
|||
|
|
- Configurable letterbox fill for sleep screen cover images. Four fill modes:
|
|||
|
|
- **Solid** — computes the dominant (average) shade from the image edge and fills the entire letterbox area with that single dithered color.
|
|||
|
|
- **Blended** — fills using per-pixel sampled edge colors with noise dithering (no distance-based interpolation), producing a smooth edge-matching fill that varies along the image border.
|
|||
|
|
- **Gradient** — interpolates per-pixel edge colors toward a configurable target color (white or black) over distance, creating a fade effect.
|
|||
|
|
- **None** — plain white letterbox (original behavior).
|
|||
|
|
- Image upscaling in Fit mode: images smaller than the display are now scaled up to fit while preserving aspect ratio. Previously, small images were simply centered without scaling.
|
|||
|
|
- Edge data caching: the edge-sampling pass (which reads the full bitmap) is performed once per cover and cached as a compact binary file (~1KB) alongside the cover BMP in `.crosspoint/`. Subsequent sleeps load from cache, skipping the bitmap scan entirely. Cache is validated against screen dimensions and auto-regenerated when stale.
|
|||
|
|
- Two new user-facing settings:
|
|||
|
|
- **Letterbox Fill** — None / Solid / Blended / Gradient
|
|||
|
|
- **Gradient Direction** — To White / To Black
|
|||
|
|
|
|||
|
|
## Files Changed
|
|||
|
|
|
|||
|
|
| File | Change |
|
|||
|
|
|------|--------|
|
|||
|
|
| `lib/GfxRenderer/GfxRenderer.cpp` | Unified block-fill scaling in `drawBitmap`/`drawBitmap1Bit` supporting both upscaling and downscaling; added `drawPixelGray` helper |
|
|||
|
|
| `lib/GfxRenderer/GfxRenderer.h` | `drawPixelGray` declaration |
|
|||
|
|
| `lib/GfxRenderer/BitmapHelpers.cpp` | Added `quantizeNoiseDither` — hash-based noise dithering for gradient/solid fills |
|
|||
|
|
| `lib/GfxRenderer/BitmapHelpers.h` | `quantizeNoiseDither` declaration |
|
|||
|
|
| `src/activities/boot_sleep/SleepActivity.cpp` | Edge sampling (`sampleBitmapEdges`), letterbox fill rendering (`drawLetterboxFill`), edge data cache (`loadEdgeCache`/`saveEdgeCache`), integration in `renderBitmapSleepScreen`/`renderCoverSleepScreen`; unconditional aspect-ratio scaling for Fit mode |
|
|||
|
|
| `src/activities/boot_sleep/SleepActivity.h` | Updated `renderBitmapSleepScreen` signature with optional `edgeCachePath` parameter |
|
|||
|
|
| `src/CrossPointSettings.h` | New enums `SLEEP_SCREEN_LETTERBOX_FILL` (4 values) and `SLEEP_SCREEN_GRADIENT_DIR`; new fields `sleepScreenLetterboxFill`, `sleepScreenGradientDir` |
|
|||
|
|
| `src/CrossPointSettings.cpp` | Serialization of new settings fields (incremented `SETTINGS_COUNT`) |
|
|||
|
|
| `src/SettingsList.h` | New "Letterbox Fill" and "Gradient Direction" setting entries in Display category |
|
|||
|
|
|
|||
|
|
## Additional Context
|
|||
|
|
|
|||
|
|
* **Performance:** The edge sampling pass reads the full bitmap row-by-row (~48KB for a full-screen 2-bit image). This is done once per cover image and cached. Subsequent sleeps for the same cover skip this pass entirely, loading ~1KB from the cache file instead.
|
|||
|
|
* **Memory:** Edge sampling uses temporary `uint32_t` accumulator arrays (~10KB peak) which are freed immediately after processing. Final edge data arrays (~1.6KB max) persist only for the duration of rendering. The cache file is ~970 bytes for a 480-wide image.
|
|||
|
|
* **Upscaling approach:** Nearest-neighbor via block-fill — each source pixel maps to a rectangle of destination pixels. No interpolation, which is appropriate for the 4-level grayscale e-ink display.
|
|||
|
|
* **Cache invalidation:** Validated by cache version byte and screen dimensions (width × height). Orientation changes trigger regeneration. Each cover mode (Fit vs Crop) produces a different BMP and thus a different cache path. Cache files live in the book-specific `.crosspoint/epub_<hash>/` directory and are naturally scoped per-book.
|
|||
|
|
* **Potential risks:** The `drawBitmap`/`drawBitmap1Bit` scaling refactor affects all bitmap rendering, not just sleep screens. The logic is functionally equivalent for downscaling (≤1.0) and 1:1 cases; upscaling (>1.0) is new behavior only triggered when both `maxWidth` and `maxHeight` are provided.
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### AI Usage
|
|||
|
|
|
|||
|
|
Did you use AI tools to help write this code? _**YES**_
|