Files
crosspoint-reader-mod/chat-summaries/2026-02-13_letterbox-extend-edges.md
cottongin dfbc931c14 mod: Phase 1 - bring forward mod-exclusive files with ActivityManager migration
Brings ~55 mod-exclusive files to the upstream-based mod/master-resync branch:

Activities (migrated to new ActivityManager pattern):
- Clock/Time: SetTimeActivity, SetTimezoneOffsetActivity, NtpSyncActivity
- Dictionary: DictionaryDefinitionActivity, DictionarySuggestionsActivity,
  DictionaryWordSelectActivity, LookedUpWordsActivity
- Bookmark: EpubReaderBookmarkSelectionActivity
- Book management: BookManageMenuActivity, EndOfBookMenuActivity
- OPDS: OpdsServerListActivity, OpdsSettingsActivity
- Utility: DirectoryPickerActivity, NumericStepperActivity

Utilities (unchanged):
- BookManager, BookSettings, BookmarkStore, BootNtpSync
- Dictionary, LookupHistory, TimeSync, OpdsServerStore

Libraries: PlaceholderCover, TableData, ChapterXPathIndexer
Scripts: inject_mod_version, generate_book_icon, preview_placeholder_cover
Docs: KOReader sync XPath mapping

Migration changes:
- ActivityWithSubactivity -> Activity base class
- Callback constructors -> finish()/setResult() pattern
- enterNewActivity() -> startActivityForResult()
- Activity::RenderLock&& -> RenderLock&&

These files won't compile yet - they reference mod settings and I18n
strings that will be added in subsequent phases.

Made-with: Cursor
2026-03-07 15:10:00 -05:00

2.9 KiB

Letterbox Fill: Replace Dithering with Edge Replication ("Extend Edges")

Date: 2026-02-13

Task Description

After implementing Bayer ordered dithering for the "Blended" letterbox fill mode (replacing earlier noise dithering), the user reported that the problematic cover (The World in a Grain by Vince Beiser) looked even worse. Investigation revealed that any dithering technique is fundamentally incompatible with the e-ink multi-pass rendering pipeline for large uniform fill areas:

  • The BW HALF_REFRESH pass creates a visible dark/white pattern in the letterbox
  • The subsequent greyscale correction can't cleanly handle mixed-level patterns in large uniform areas
  • This causes crosstalk artifacts that can affect adjacent cover rendering
  • Uniform fills (all same level, like Solid mode) work fine because all pixels go through identical correction

The user's key insight: the display already renders the cover's grayscale correctly (including Atkinson-dithered mixed levels). Instead of re-dithering an averaged color, replicate the cover's actual boundary pixels into the letterbox -- letting the display render them the same way it renders the cover itself.

Changes Made

src/CrossPointSettings.h

  • Renamed LETTERBOX_BLENDED (value 2) → LETTERBOX_EXTENDED
  • Updated comment to reflect "None / Solid / Extend Edges"

src/SettingsList.h

  • Changed UI label from "Blended""Extend Edges"

src/activities/boot_sleep/SleepActivity.cpp

  • Removed: BAYER_4X4 matrix, quantizeBayerDither() function (all Bayer dithering code)
  • Added: getPackedPixel(), setPackedPixel() helpers for packed 2-bit array access
  • Rewrote LetterboxFillData struct:
    • Added edgeA/edgeB (dynamically allocated packed 2-bit arrays) for per-pixel edge data
    • Added edgePixelCount, scale for coordinate mapping
    • Added freeEdgeData() cleanup method
  • Renamed computeEdgeAverages()computeEdgeData():
    • New captureEdgePixels parameter controls whether to allocate and fill edge arrays
    • For horizontal letterboxing: captures first/last visible BMP rows
    • For vertical letterboxing: captures leftmost/rightmost pixel per visible row
    • Still computes averages for SOLID mode in the same pass
  • Rewrote drawLetterboxFill():
    • SOLID mode: unchanged (uniform fill with snapped level)
    • EXTENDED mode: maps screen coordinates → BMP coordinates via scale factor, looks up stored 2-bit pixel values from the cover's boundary row/column
  • Updated renderBitmapSleepScreen(): new log messages, freeEdgeData() call at end

Backward Compatibility

  • Enum value 2 is unchanged (was LETTERBOX_BLENDED, now LETTERBOX_EXTENDED)
  • Serialized settings files continue to work without migration

Follow-up Items

  • Test "Extend Edges" mode with both covers (Power Broker and World in a Grain)
  • Test vertical letterboxing (left/right) if applicable covers are available
  • Verify SOLID mode still works as expected