fix: use double FAST_REFRESH to prevent washout on large grey images#957
Conversation
📝 WalkthroughWalkthroughAdds Page APIs to access an image's ImageBlock and compute the union bounding box of all images on a page; updates EpubReaderActivity rendering to use an image-with-AA path that blanks the image box and performs two FAST_REFRESH passes with a HALF_REFRESH fallback. Changes
Sequence DiagramsequenceDiagram
participant RA as EpubReaderActivity
participant Page as Page
participant Render as RenderingSystem
alt Image page with AA and bounding box available
RA->>Page: getImageBoundingBox()
Page-->>RA: bounding box (x,y,w,h)
RA->>Render: clearArea(x,y,w,h)
RA->>Render: FAST_REFRESH
RA->>Page: render page (with images)
RA->>Render: render status bar
RA->>Render: FAST_REFRESH
else Image page with AA but no bounding box
RA->>Render: HALF_REFRESH (fallback)
else Non-image or non-AA page
RA->>Render: standard HALF_REFRESH or full render as per cadence
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
lib/Epub/Epub/Page.hsrc/activities/reader/EpubReaderActivity.cpp
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-02-16T20:43:19.339Z
Learnt from: Levrk
Repo: crosspoint-reader/crosspoint-reader PR: 909
File: src/activities/reader/EpubReaderActivity.cpp:461-461
Timestamp: 2026-02-16T20:43:19.339Z
Learning: In src/activities/reader/EpubReaderActivity.cpp, when using ConfirmationActivity with enterNewActivity(), it's not necessary to call exitActivity() beforehand. The ConfirmationActivity operates as a modal dialog and cleanup is handled via the pendingSubactivityExit flag in the callback lambda. This differs from other activities like EpubReaderChapterSelectionActivity or KOReaderSyncActivity which do require exitActivity() before enterNewActivity().
Applied to files:
src/activities/reader/EpubReaderActivity.cpp
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Title Check
- GitHub Check: build
- GitHub Check: cppcheck
🔇 Additional comments (2)
lib/Epub/Epub/Page.h (2)
52-52: LGTM - accessor provides necessary access for the new rendering flow.The const reference return is appropriate here. Note: This assumes
imageBlockis never null, which appears to be a class invariant given the constructor takes anImageBlockshared_ptr.
68-95: Clean bounding box implementation with one minor edge-case note.The algorithm correctly computes the union of all image rectangles. The use of
INT16_MAX/INT16_MINfor initialization and early-return on no images is appropriate.Minor note: Lines 79-80 compute
right = x + widthandbottom = y + height. If an image is positioned near coordinate limits, this could overflowint16_t. For typical e-ink display dimensions this is unlikely, but if dimensions can exceed ~32K, consider usingint32_tfor intermediate calculations.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/activities/reader/EpubReaderActivity.cpp`:
- Around line 640-663: pagesUntilFullRefresh is always decremented inside the
imagePageWithAA branch which lets it go negative because the normal reset check
is only outside that branch; fix by adding the same reset logic inside the
imagePageWithAA handling: after pagesUntilFullRefresh--, check if
(pagesUntilFullRefresh <= 1) pagesUntilFullRefresh = refreshFrequency (or the
appropriate full-refresh interval variable used elsewhere) so image pages with
AA do not drive the counter negative; alternatively, if you prefer not to count
those pages at all, simply omit the pagesUntilFullRefresh-- inside the
imagePageWithAA branch (update the code around page->getImageBoundingBox /
renderer.displayBuffer logic accordingly).
…hout HALF_REFRESH sets e-ink particles too firmly for the grayscale LUT to adjust, causing washed-out images (especially large, light-gray ones). Replace HALF_REFRESH with pablohc's double FAST_REFRESH technique: blank only the image bounding box area, then re-render with images. This clears ghosting while keeping particles loosely set for grayscale.
75d5266 to
0db326e
Compare
|
issue originally mentioned at 6c3a615#commitcomment-177296177 |
The double FAST approach is ~360ms faster per page because two FAST_REFRESHes (844ms) are faster than one HALF_REFRESH (1583ms). The extra BW render + fillRect for the image blanking adds back ~380ms of CPU work, but it's still a net win and the images are rendered correctly now. |
…957) ## Summary Fixes #1011 Use double FAST_REFRESH for image pages to prevent grayscale washout, HALF_REFRESH sets e-ink particles too firmly for the grayscale LUT to adjust, causing washed-out images (especially large, light-gray ones). Replace HALF_REFRESH with @pablohc's double FAST_REFRESH technique: blank only the image bounding box area, then re-render with images. This clears ghosting while keeping particles loosely set for grayscale. ## Additional Context --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**< PARTIALLY >**_
|
Thanks @martinbrook for this fix, and @ngxson for the idea! ;) |
…rosspoint-reader#957) ## Summary Fixes crosspoint-reader#1011 Use double FAST_REFRESH for image pages to prevent grayscale washout, HALF_REFRESH sets e-ink particles too firmly for the grayscale LUT to adjust, causing washed-out images (especially large, light-gray ones). Replace HALF_REFRESH with @pablohc's double FAST_REFRESH technique: blank only the image bounding box area, then re-render with images. This clears ghosting while keeping particles loosely set for grayscale. ## Additional Context --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? _**< PARTIALLY >**_
|
Will this work for sleep screens as described in #627 ? Or is this another issue / choice? Thank you. |


Summary
Fixes #1011
Use double FAST_REFRESH for image pages to prevent grayscale washout, HALF_REFRESH sets e-ink particles too firmly for the grayscale LUT to adjust, causing washed-out images (especially large, light-gray ones). Replace HALF_REFRESH with @pablohc's double FAST_REFRESH technique: blank only the image bounding box area, then re-render with images. This clears ghosting while keeping particles loosely set for grayscale.
Additional Context
AI Usage
While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it
helps set the right context for reviewers.
Did you use AI tools to help write this code? < PARTIALLY >