Files
crosspoint-reader-mod/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h

123 lines
4.3 KiB
C
Raw Normal View History

#pragma once
#include <expat.h>
#include <climits>
#include <functional>
#include <memory>
feat: slim footnotes support (#1031) ## Summary **What is the goal of this PR?** Implement support for footnotes in epub files. It is based on #553, but simplified — removed the parts which complicated the code and burden the CPU/RAM. This version supports basic footnotes and lets the user jump from location to location inside the epub. **What changes are included?** - `FootnoteEntry` struct — A small POD struct (number[24], href[64]) shared between parser, page storage, and UI. - Parser: `<a href>` detection (`ChapterHtmlSlimParser`) — During a single parsing pass, internal epub links are detected and collected as footnotes. The link text is underlined to hint navigability. Bracket/whitespace normalization is applied to the display label (e.g. [1] → 1). - Footnote-to-page assignment (`ChapterHtmlSlimParser`, `Page`) — Footnotes are attached to the exact page where their anchor word appears, tracked via a cumulative word counter during layout, surviving paragraph splits and the 750-word mid-paragraph safety flush. - Page serialization (`Page`, `Section`) — Footnotes are serialized/deserialized per page (max 16 per page). Section cache version bumped to 14 to force a clean rebuild. - Href → spine resolution (`Epub`) — `resolveHrefToSpineIndex()` maps an href (e.g. `chapter2.xhtml#note1`) to its spine index by filename matching. - Footnotes menu + activity (`EpubReaderMenuActivity`, `EpubReaderFootnotesActivity`) — A new "Footnotes" entry in the reader menu lists all footnote links found on the current page. The user scrolls and selects to navigate. - Navigate & restore (`EpubReaderActivity`) — `navigateToHref()` saves the current spine index and page number, then jumps to the target. The Back button restores the saved position when the user is done reading the footnote. **Additional Context** **What was removed vs #553:** virtual spine items (`addVirtualSpineItem`, `isVirtualSpineItem`), two-pass parsing, `<aside>` content extraction to temp HTML files, `<p class="note">` paragraph note extraction, `replaceHtmlEntities` (master already has `lookupHtmlEntity`), `footnotePages` / `buildFilteredChapterList`, `noterefCallback` / `Noteref` struct, and the stack size increase from 8 KB to 24 KB (not needed without two-pass parsing and virtual file I/O on the render task). **Performance:** Single-pass parsing. No new heap allocations in the hot path — footnote text is collected into fixed stack buffers (char[24], char[64]). Active runtime memory is ~2.8 KB worst-case (one page × 16 footnotes × 88 bytes, mirrored in `currentPageFootnotes`). Flash usage is unchanged at 97.4%; RAM stays at 31%. **Known limitations:** When clicking a footnote, it jumps to the start of the HTML file instead of the specific anchor. This could be problematic for books that don't have separate files for each footnote. (no element-id-to-page mapping yet - will be another PR soon). --- ### AI Usage Did you use AI tools to help write this code? _**< PARTIALLY>**_ Claude Opus 4.6 was used to do most of the migration, I checked manually its work, and fixed some stuff, but I haven't review all the changes yet, so feedback is welcomed. --------- Co-authored-by: Arthur Tazhitdinov <lisnake@gmail.com>
2026-02-26 16:47:34 +02:00
#include <vector>
feat: slim footnotes support (#1031) ## Summary **What is the goal of this PR?** Implement support for footnotes in epub files. It is based on #553, but simplified — removed the parts which complicated the code and burden the CPU/RAM. This version supports basic footnotes and lets the user jump from location to location inside the epub. **What changes are included?** - `FootnoteEntry` struct — A small POD struct (number[24], href[64]) shared between parser, page storage, and UI. - Parser: `<a href>` detection (`ChapterHtmlSlimParser`) — During a single parsing pass, internal epub links are detected and collected as footnotes. The link text is underlined to hint navigability. Bracket/whitespace normalization is applied to the display label (e.g. [1] → 1). - Footnote-to-page assignment (`ChapterHtmlSlimParser`, `Page`) — Footnotes are attached to the exact page where their anchor word appears, tracked via a cumulative word counter during layout, surviving paragraph splits and the 750-word mid-paragraph safety flush. - Page serialization (`Page`, `Section`) — Footnotes are serialized/deserialized per page (max 16 per page). Section cache version bumped to 14 to force a clean rebuild. - Href → spine resolution (`Epub`) — `resolveHrefToSpineIndex()` maps an href (e.g. `chapter2.xhtml#note1`) to its spine index by filename matching. - Footnotes menu + activity (`EpubReaderMenuActivity`, `EpubReaderFootnotesActivity`) — A new "Footnotes" entry in the reader menu lists all footnote links found on the current page. The user scrolls and selects to navigate. - Navigate & restore (`EpubReaderActivity`) — `navigateToHref()` saves the current spine index and page number, then jumps to the target. The Back button restores the saved position when the user is done reading the footnote. **Additional Context** **What was removed vs #553:** virtual spine items (`addVirtualSpineItem`, `isVirtualSpineItem`), two-pass parsing, `<aside>` content extraction to temp HTML files, `<p class="note">` paragraph note extraction, `replaceHtmlEntities` (master already has `lookupHtmlEntity`), `footnotePages` / `buildFilteredChapterList`, `noterefCallback` / `Noteref` struct, and the stack size increase from 8 KB to 24 KB (not needed without two-pass parsing and virtual file I/O on the render task). **Performance:** Single-pass parsing. No new heap allocations in the hot path — footnote text is collected into fixed stack buffers (char[24], char[64]). Active runtime memory is ~2.8 KB worst-case (one page × 16 footnotes × 88 bytes, mirrored in `currentPageFootnotes`). Flash usage is unchanged at 97.4%; RAM stays at 31%. **Known limitations:** When clicking a footnote, it jumps to the start of the HTML file instead of the specific anchor. This could be problematic for books that don't have separate files for each footnote. (no element-id-to-page mapping yet - will be another PR soon). --- ### AI Usage Did you use AI tools to help write this code? _**< PARTIALLY>**_ Claude Opus 4.6 was used to do most of the migration, I checked manually its work, and fixed some stuff, but I haven't review all the changes yet, so feedback is welcomed. --------- Co-authored-by: Arthur Tazhitdinov <lisnake@gmail.com>
2026-02-26 16:47:34 +02:00
#include "../FootnoteEntry.h"
#include "../ParsedText.h"
feat: add png jpeg support (#556) ## Summary - Add embedded image support to EPUB rendering with JPEG and PNG decoders - Implement pixel caching system to cache decoded/dithered images to SD card for faster re-rendering - Add 4-level grayscale support for display ## Changes ### New Image Rendering System - Add `ImageBlock` class to represent an image with its cached path and display dimensions - Add `PageImage` class as a new `PageElement` type for images on pages - Add `ImageToFramebufferDecoder` interface for format-specific image decoders - Add `JpegToFramebufferConverter` - JPEG decoder with Bayer dithering and scaling - Add `PngToFramebufferConverter` - PNG decoder with Bayer dithering and scaling - Add `ImageDecoderFactory` to select appropriate decoder based on file extension - Add `getRenderMode()` to GfxRenderer for grayscale render mode queries ### Dithering and Grayscale - Implement 4x4 Bayer ordered dithering for 4-level grayscale output - Stateless algorithm works correctly with MCU block decoding - Handles scaling without artifacts - Add grayscale render mode support (BW, GRAYSCALE_LSB, GRAYSCALE_MSB) - Image decoders and cache renderer respect current render mode - Enables proper 4-level e-ink grayscale when anti-aliasing is enabled ### Pixel Caching - Cache decoded/dithered images to `.pxc` files on SD card - Cache format: 2-bit packed pixels (4 pixels per byte) with width/height header - On subsequent renders, load directly from cache instead of re-decoding - Cache renderer supports grayscale render modes for multi-pass rendering - Significantly improves page navigation speed for image-heavy EPUBs ### HTML Parser Integration - Update `ChapterHtmlSlimParser` to process `<img>` tags and extract images from EPUB - Resolve relative image paths within EPUB ZIP structure - Extract images to cache directory before decoding - Create `PageImage` elements with proper scaling to fit viewport - Fall back to alt text display if image processing fails ### Build Configuration - Add `PNG_MAX_BUFFERED_PIXELS=6402` to support up to 800px wide images ### Test Script - Generate test EPUBs with annotated JPEG and PNG images - Test cases cover: grayscale (4 levels), centering, scaling, cache performance ## Test plan - [x] Open EPUB with JPEG images - verify images display with proper grayscale - [x] Open EPUB with PNG images - verify images display correctly and no crash - [x] Navigate away from image page and back - verify faster load from cache - [x] Verify grayscale tones render correctly (not just black/white dithering) - [x] Verify large images are scaled down to fit screen - [x] Verify images are centered horizontally - [x] Verify page serialization/deserialization works with images - [x] Verify images rendered in landscape mode ## Test Results [png](https://photos.app.goo.gl/5zFUb8xA8db3dPd19) [jpeg](https://photos.app.goo.gl/SwtwaL2DSQwKybhw7) ![20260128_231123790](https://github.com/user-attachments/assets/78855971-4bb8-441a-b207-0a292b9739f5) ![20260128_231012253](https://github.com/user-attachments/assets/f08fb63f-1b73-41d9-a25e-78232ec0c495) ![20260128_231004209](https://github.com/user-attachments/assets/06c94acc-8a06-4955-978e-6e583399478d) ![20260128_230954997](https://github.com/user-attachments/assets/49bc44d5-0f2c-416b-9199-4d680fb0f4c3) ![20260128_230945717](https://github.com/user-attachments/assets/93446da5-2e07-410c-89c9-6a21d14e5acb) ![20260128_230938313](https://github.com/user-attachments/assets/4c74c72a-3d40-4a25-b0f3-acc703f42c00) ![20260128_230925546](https://github.com/user-attachments/assets/8d8f62ee-c8fc-4f19-a12c-da29083bb766) ![20260128_230918374](https://github.com/user-attachments/assets/f007d5db-41cc-4fa6-bb22-9e767ee7b00d) --- ### AI Usage Did you use AI tools to help write this code? _**< YES >**_ --------- Co-authored-by: Matthías Páll Gissurarson <mpg@mpg.is> Co-authored-by: Dave Allie <dave@daveallie.com>
2026-02-16 08:56:59 +00:00
#include "../blocks/ImageBlock.h"
#include "../blocks/TextBlock.h"
feat: Add CSS parsing and CSS support in EPUBs (#411) ## Summary * **What is the goal of this PR?** - Adds basic CSS parsing to EPUBs and determine the CSS rules when rendering to the screen so that text is styled correctly. Currently supports bold, underline, italics, margin, padding, and text alignment ## Additional Context - My main reason for wanting this is that the book I'm currently reading, Carl's Doomsday Scenario (2nd in the Dungeon Crawler Carl series), relies _a lot_ on styled text for telling parts of the story. When text is bolded, it's supposed to be a message that's rendered "on-screen" in the story. When characters are "chatting" with each other, the text is bolded and their names are underlined. Plus, normal emphasis is provided with italicizing words here and there. So, this greatly improves my experience reading this book on the Xteink, and I figured it was useful enough for others too. - For transparency: I'm a software engineer, but I'm mostly frontend and TypeScript/JavaScript. It's been _years_ since I did any C/C++, so I would not be surprised if I'm doing something dumb along the way in this code. Please don't hesitate to ask for changes if something looks off. I heavily relied on Claude Code for help, and I had a lot of inspiration from how [microreader](https://github.com/CidVonHighwind/microreader) achieves their CSS parsing and styling. I did give this as good of a code review as I could and went through everything, and _it works on my machine_ 😄 ### Before ![IMG_6271](https://github.com/user-attachments/assets/dba7554d-efb6-4d13-88bc-8b83cd1fc615) ![IMG_6272](https://github.com/user-attachments/assets/61ba2de0-87c9-4f39-956f-013da4fe20a4) ### After ![IMG_6268](https://github.com/user-attachments/assets/ebe11796-cca9-4a46-b9c7-0709c7932818) ![IMG_6269](https://github.com/user-attachments/assets/e89c33dc-ff47-4bb7-855e-863fe44b3202) --- ### AI Usage Did you use AI tools to help write this code? **YES**, Claude Code
2026-02-05 05:28:10 -05:00
#include "../css/CssParser.h"
#include "../css/CssStyle.h"
class Page;
class GfxRenderer;
feat: add png jpeg support (#556) ## Summary - Add embedded image support to EPUB rendering with JPEG and PNG decoders - Implement pixel caching system to cache decoded/dithered images to SD card for faster re-rendering - Add 4-level grayscale support for display ## Changes ### New Image Rendering System - Add `ImageBlock` class to represent an image with its cached path and display dimensions - Add `PageImage` class as a new `PageElement` type for images on pages - Add `ImageToFramebufferDecoder` interface for format-specific image decoders - Add `JpegToFramebufferConverter` - JPEG decoder with Bayer dithering and scaling - Add `PngToFramebufferConverter` - PNG decoder with Bayer dithering and scaling - Add `ImageDecoderFactory` to select appropriate decoder based on file extension - Add `getRenderMode()` to GfxRenderer for grayscale render mode queries ### Dithering and Grayscale - Implement 4x4 Bayer ordered dithering for 4-level grayscale output - Stateless algorithm works correctly with MCU block decoding - Handles scaling without artifacts - Add grayscale render mode support (BW, GRAYSCALE_LSB, GRAYSCALE_MSB) - Image decoders and cache renderer respect current render mode - Enables proper 4-level e-ink grayscale when anti-aliasing is enabled ### Pixel Caching - Cache decoded/dithered images to `.pxc` files on SD card - Cache format: 2-bit packed pixels (4 pixels per byte) with width/height header - On subsequent renders, load directly from cache instead of re-decoding - Cache renderer supports grayscale render modes for multi-pass rendering - Significantly improves page navigation speed for image-heavy EPUBs ### HTML Parser Integration - Update `ChapterHtmlSlimParser` to process `<img>` tags and extract images from EPUB - Resolve relative image paths within EPUB ZIP structure - Extract images to cache directory before decoding - Create `PageImage` elements with proper scaling to fit viewport - Fall back to alt text display if image processing fails ### Build Configuration - Add `PNG_MAX_BUFFERED_PIXELS=6402` to support up to 800px wide images ### Test Script - Generate test EPUBs with annotated JPEG and PNG images - Test cases cover: grayscale (4 levels), centering, scaling, cache performance ## Test plan - [x] Open EPUB with JPEG images - verify images display with proper grayscale - [x] Open EPUB with PNG images - verify images display correctly and no crash - [x] Navigate away from image page and back - verify faster load from cache - [x] Verify grayscale tones render correctly (not just black/white dithering) - [x] Verify large images are scaled down to fit screen - [x] Verify images are centered horizontally - [x] Verify page serialization/deserialization works with images - [x] Verify images rendered in landscape mode ## Test Results [png](https://photos.app.goo.gl/5zFUb8xA8db3dPd19) [jpeg](https://photos.app.goo.gl/SwtwaL2DSQwKybhw7) ![20260128_231123790](https://github.com/user-attachments/assets/78855971-4bb8-441a-b207-0a292b9739f5) ![20260128_231012253](https://github.com/user-attachments/assets/f08fb63f-1b73-41d9-a25e-78232ec0c495) ![20260128_231004209](https://github.com/user-attachments/assets/06c94acc-8a06-4955-978e-6e583399478d) ![20260128_230954997](https://github.com/user-attachments/assets/49bc44d5-0f2c-416b-9199-4d680fb0f4c3) ![20260128_230945717](https://github.com/user-attachments/assets/93446da5-2e07-410c-89c9-6a21d14e5acb) ![20260128_230938313](https://github.com/user-attachments/assets/4c74c72a-3d40-4a25-b0f3-acc703f42c00) ![20260128_230925546](https://github.com/user-attachments/assets/8d8f62ee-c8fc-4f19-a12c-da29083bb766) ![20260128_230918374](https://github.com/user-attachments/assets/f007d5db-41cc-4fa6-bb22-9e767ee7b00d) --- ### AI Usage Did you use AI tools to help write this code? _**< YES >**_ --------- Co-authored-by: Matthías Páll Gissurarson <mpg@mpg.is> Co-authored-by: Dave Allie <dave@daveallie.com>
2026-02-16 08:56:59 +00:00
class Epub;
#define MAX_WORD_SIZE 200
class ChapterHtmlSlimParser {
feat: add png jpeg support (#556) ## Summary - Add embedded image support to EPUB rendering with JPEG and PNG decoders - Implement pixel caching system to cache decoded/dithered images to SD card for faster re-rendering - Add 4-level grayscale support for display ## Changes ### New Image Rendering System - Add `ImageBlock` class to represent an image with its cached path and display dimensions - Add `PageImage` class as a new `PageElement` type for images on pages - Add `ImageToFramebufferDecoder` interface for format-specific image decoders - Add `JpegToFramebufferConverter` - JPEG decoder with Bayer dithering and scaling - Add `PngToFramebufferConverter` - PNG decoder with Bayer dithering and scaling - Add `ImageDecoderFactory` to select appropriate decoder based on file extension - Add `getRenderMode()` to GfxRenderer for grayscale render mode queries ### Dithering and Grayscale - Implement 4x4 Bayer ordered dithering for 4-level grayscale output - Stateless algorithm works correctly with MCU block decoding - Handles scaling without artifacts - Add grayscale render mode support (BW, GRAYSCALE_LSB, GRAYSCALE_MSB) - Image decoders and cache renderer respect current render mode - Enables proper 4-level e-ink grayscale when anti-aliasing is enabled ### Pixel Caching - Cache decoded/dithered images to `.pxc` files on SD card - Cache format: 2-bit packed pixels (4 pixels per byte) with width/height header - On subsequent renders, load directly from cache instead of re-decoding - Cache renderer supports grayscale render modes for multi-pass rendering - Significantly improves page navigation speed for image-heavy EPUBs ### HTML Parser Integration - Update `ChapterHtmlSlimParser` to process `<img>` tags and extract images from EPUB - Resolve relative image paths within EPUB ZIP structure - Extract images to cache directory before decoding - Create `PageImage` elements with proper scaling to fit viewport - Fall back to alt text display if image processing fails ### Build Configuration - Add `PNG_MAX_BUFFERED_PIXELS=6402` to support up to 800px wide images ### Test Script - Generate test EPUBs with annotated JPEG and PNG images - Test cases cover: grayscale (4 levels), centering, scaling, cache performance ## Test plan - [x] Open EPUB with JPEG images - verify images display with proper grayscale - [x] Open EPUB with PNG images - verify images display correctly and no crash - [x] Navigate away from image page and back - verify faster load from cache - [x] Verify grayscale tones render correctly (not just black/white dithering) - [x] Verify large images are scaled down to fit screen - [x] Verify images are centered horizontally - [x] Verify page serialization/deserialization works with images - [x] Verify images rendered in landscape mode ## Test Results [png](https://photos.app.goo.gl/5zFUb8xA8db3dPd19) [jpeg](https://photos.app.goo.gl/SwtwaL2DSQwKybhw7) ![20260128_231123790](https://github.com/user-attachments/assets/78855971-4bb8-441a-b207-0a292b9739f5) ![20260128_231012253](https://github.com/user-attachments/assets/f08fb63f-1b73-41d9-a25e-78232ec0c495) ![20260128_231004209](https://github.com/user-attachments/assets/06c94acc-8a06-4955-978e-6e583399478d) ![20260128_230954997](https://github.com/user-attachments/assets/49bc44d5-0f2c-416b-9199-4d680fb0f4c3) ![20260128_230945717](https://github.com/user-attachments/assets/93446da5-2e07-410c-89c9-6a21d14e5acb) ![20260128_230938313](https://github.com/user-attachments/assets/4c74c72a-3d40-4a25-b0f3-acc703f42c00) ![20260128_230925546](https://github.com/user-attachments/assets/8d8f62ee-c8fc-4f19-a12c-da29083bb766) ![20260128_230918374](https://github.com/user-attachments/assets/f007d5db-41cc-4fa6-bb22-9e767ee7b00d) --- ### AI Usage Did you use AI tools to help write this code? _**< YES >**_ --------- Co-authored-by: Matthías Páll Gissurarson <mpg@mpg.is> Co-authored-by: Dave Allie <dave@daveallie.com>
2026-02-16 08:56:59 +00:00
std::shared_ptr<Epub> epub;
const std::string& filepath;
GfxRenderer& renderer;
std::function<void(std::unique_ptr<Page>)> completePageFn;
std::function<void()> popupFn; // Popup callback
int depth = 0;
int skipUntilDepth = INT_MAX;
int boldUntilDepth = INT_MAX;
int italicUntilDepth = INT_MAX;
feat: Add CSS parsing and CSS support in EPUBs (#411) ## Summary * **What is the goal of this PR?** - Adds basic CSS parsing to EPUBs and determine the CSS rules when rendering to the screen so that text is styled correctly. Currently supports bold, underline, italics, margin, padding, and text alignment ## Additional Context - My main reason for wanting this is that the book I'm currently reading, Carl's Doomsday Scenario (2nd in the Dungeon Crawler Carl series), relies _a lot_ on styled text for telling parts of the story. When text is bolded, it's supposed to be a message that's rendered "on-screen" in the story. When characters are "chatting" with each other, the text is bolded and their names are underlined. Plus, normal emphasis is provided with italicizing words here and there. So, this greatly improves my experience reading this book on the Xteink, and I figured it was useful enough for others too. - For transparency: I'm a software engineer, but I'm mostly frontend and TypeScript/JavaScript. It's been _years_ since I did any C/C++, so I would not be surprised if I'm doing something dumb along the way in this code. Please don't hesitate to ask for changes if something looks off. I heavily relied on Claude Code for help, and I had a lot of inspiration from how [microreader](https://github.com/CidVonHighwind/microreader) achieves their CSS parsing and styling. I did give this as good of a code review as I could and went through everything, and _it works on my machine_ 😄 ### Before ![IMG_6271](https://github.com/user-attachments/assets/dba7554d-efb6-4d13-88bc-8b83cd1fc615) ![IMG_6272](https://github.com/user-attachments/assets/61ba2de0-87c9-4f39-956f-013da4fe20a4) ### After ![IMG_6268](https://github.com/user-attachments/assets/ebe11796-cca9-4a46-b9c7-0709c7932818) ![IMG_6269](https://github.com/user-attachments/assets/e89c33dc-ff47-4bb7-855e-863fe44b3202) --- ### AI Usage Did you use AI tools to help write this code? **YES**, Claude Code
2026-02-05 05:28:10 -05:00
int underlineUntilDepth = INT_MAX;
// buffer for building up words from characters, will auto break if longer than this
// leave one char at end for null pointer
char partWordBuffer[MAX_WORD_SIZE + 1] = {};
int partWordBufferIndex = 0;
bool nextWordContinues = false; // true when next flushed word attaches to previous (inline element boundary)
std::unique_ptr<ParsedText> currentTextBlock = nullptr;
std::unique_ptr<Page> currentPage = nullptr;
2025-12-13 00:42:17 +11:00
int16_t currentPageNextY = 0;
int fontId;
float lineCompression;
bool extraParagraphSpacing;
uint8_t paragraphAlignment;
uint16_t viewportWidth;
uint16_t viewportHeight;
bool hyphenationEnabled;
feat: Add CSS parsing and CSS support in EPUBs (#411) ## Summary * **What is the goal of this PR?** - Adds basic CSS parsing to EPUBs and determine the CSS rules when rendering to the screen so that text is styled correctly. Currently supports bold, underline, italics, margin, padding, and text alignment ## Additional Context - My main reason for wanting this is that the book I'm currently reading, Carl's Doomsday Scenario (2nd in the Dungeon Crawler Carl series), relies _a lot_ on styled text for telling parts of the story. When text is bolded, it's supposed to be a message that's rendered "on-screen" in the story. When characters are "chatting" with each other, the text is bolded and their names are underlined. Plus, normal emphasis is provided with italicizing words here and there. So, this greatly improves my experience reading this book on the Xteink, and I figured it was useful enough for others too. - For transparency: I'm a software engineer, but I'm mostly frontend and TypeScript/JavaScript. It's been _years_ since I did any C/C++, so I would not be surprised if I'm doing something dumb along the way in this code. Please don't hesitate to ask for changes if something looks off. I heavily relied on Claude Code for help, and I had a lot of inspiration from how [microreader](https://github.com/CidVonHighwind/microreader) achieves their CSS parsing and styling. I did give this as good of a code review as I could and went through everything, and _it works on my machine_ 😄 ### Before ![IMG_6271](https://github.com/user-attachments/assets/dba7554d-efb6-4d13-88bc-8b83cd1fc615) ![IMG_6272](https://github.com/user-attachments/assets/61ba2de0-87c9-4f39-956f-013da4fe20a4) ### After ![IMG_6268](https://github.com/user-attachments/assets/ebe11796-cca9-4a46-b9c7-0709c7932818) ![IMG_6269](https://github.com/user-attachments/assets/e89c33dc-ff47-4bb7-855e-863fe44b3202) --- ### AI Usage Did you use AI tools to help write this code? **YES**, Claude Code
2026-02-05 05:28:10 -05:00
const CssParser* cssParser;
bool embeddedStyle;
uint8_t imageRendering;
feat: add png jpeg support (#556) ## Summary - Add embedded image support to EPUB rendering with JPEG and PNG decoders - Implement pixel caching system to cache decoded/dithered images to SD card for faster re-rendering - Add 4-level grayscale support for display ## Changes ### New Image Rendering System - Add `ImageBlock` class to represent an image with its cached path and display dimensions - Add `PageImage` class as a new `PageElement` type for images on pages - Add `ImageToFramebufferDecoder` interface for format-specific image decoders - Add `JpegToFramebufferConverter` - JPEG decoder with Bayer dithering and scaling - Add `PngToFramebufferConverter` - PNG decoder with Bayer dithering and scaling - Add `ImageDecoderFactory` to select appropriate decoder based on file extension - Add `getRenderMode()` to GfxRenderer for grayscale render mode queries ### Dithering and Grayscale - Implement 4x4 Bayer ordered dithering for 4-level grayscale output - Stateless algorithm works correctly with MCU block decoding - Handles scaling without artifacts - Add grayscale render mode support (BW, GRAYSCALE_LSB, GRAYSCALE_MSB) - Image decoders and cache renderer respect current render mode - Enables proper 4-level e-ink grayscale when anti-aliasing is enabled ### Pixel Caching - Cache decoded/dithered images to `.pxc` files on SD card - Cache format: 2-bit packed pixels (4 pixels per byte) with width/height header - On subsequent renders, load directly from cache instead of re-decoding - Cache renderer supports grayscale render modes for multi-pass rendering - Significantly improves page navigation speed for image-heavy EPUBs ### HTML Parser Integration - Update `ChapterHtmlSlimParser` to process `<img>` tags and extract images from EPUB - Resolve relative image paths within EPUB ZIP structure - Extract images to cache directory before decoding - Create `PageImage` elements with proper scaling to fit viewport - Fall back to alt text display if image processing fails ### Build Configuration - Add `PNG_MAX_BUFFERED_PIXELS=6402` to support up to 800px wide images ### Test Script - Generate test EPUBs with annotated JPEG and PNG images - Test cases cover: grayscale (4 levels), centering, scaling, cache performance ## Test plan - [x] Open EPUB with JPEG images - verify images display with proper grayscale - [x] Open EPUB with PNG images - verify images display correctly and no crash - [x] Navigate away from image page and back - verify faster load from cache - [x] Verify grayscale tones render correctly (not just black/white dithering) - [x] Verify large images are scaled down to fit screen - [x] Verify images are centered horizontally - [x] Verify page serialization/deserialization works with images - [x] Verify images rendered in landscape mode ## Test Results [png](https://photos.app.goo.gl/5zFUb8xA8db3dPd19) [jpeg](https://photos.app.goo.gl/SwtwaL2DSQwKybhw7) ![20260128_231123790](https://github.com/user-attachments/assets/78855971-4bb8-441a-b207-0a292b9739f5) ![20260128_231012253](https://github.com/user-attachments/assets/f08fb63f-1b73-41d9-a25e-78232ec0c495) ![20260128_231004209](https://github.com/user-attachments/assets/06c94acc-8a06-4955-978e-6e583399478d) ![20260128_230954997](https://github.com/user-attachments/assets/49bc44d5-0f2c-416b-9199-4d680fb0f4c3) ![20260128_230945717](https://github.com/user-attachments/assets/93446da5-2e07-410c-89c9-6a21d14e5acb) ![20260128_230938313](https://github.com/user-attachments/assets/4c74c72a-3d40-4a25-b0f3-acc703f42c00) ![20260128_230925546](https://github.com/user-attachments/assets/8d8f62ee-c8fc-4f19-a12c-da29083bb766) ![20260128_230918374](https://github.com/user-attachments/assets/f007d5db-41cc-4fa6-bb22-9e767ee7b00d) --- ### AI Usage Did you use AI tools to help write this code? _**< YES >**_ --------- Co-authored-by: Matthías Páll Gissurarson <mpg@mpg.is> Co-authored-by: Dave Allie <dave@daveallie.com>
2026-02-16 08:56:59 +00:00
std::string contentBase;
std::string imageBasePath;
int imageCounter = 0;
feat: Add CSS parsing and CSS support in EPUBs (#411) ## Summary * **What is the goal of this PR?** - Adds basic CSS parsing to EPUBs and determine the CSS rules when rendering to the screen so that text is styled correctly. Currently supports bold, underline, italics, margin, padding, and text alignment ## Additional Context - My main reason for wanting this is that the book I'm currently reading, Carl's Doomsday Scenario (2nd in the Dungeon Crawler Carl series), relies _a lot_ on styled text for telling parts of the story. When text is bolded, it's supposed to be a message that's rendered "on-screen" in the story. When characters are "chatting" with each other, the text is bolded and their names are underlined. Plus, normal emphasis is provided with italicizing words here and there. So, this greatly improves my experience reading this book on the Xteink, and I figured it was useful enough for others too. - For transparency: I'm a software engineer, but I'm mostly frontend and TypeScript/JavaScript. It's been _years_ since I did any C/C++, so I would not be surprised if I'm doing something dumb along the way in this code. Please don't hesitate to ask for changes if something looks off. I heavily relied on Claude Code for help, and I had a lot of inspiration from how [microreader](https://github.com/CidVonHighwind/microreader) achieves their CSS parsing and styling. I did give this as good of a code review as I could and went through everything, and _it works on my machine_ 😄 ### Before ![IMG_6271](https://github.com/user-attachments/assets/dba7554d-efb6-4d13-88bc-8b83cd1fc615) ![IMG_6272](https://github.com/user-attachments/assets/61ba2de0-87c9-4f39-956f-013da4fe20a4) ### After ![IMG_6268](https://github.com/user-attachments/assets/ebe11796-cca9-4a46-b9c7-0709c7932818) ![IMG_6269](https://github.com/user-attachments/assets/e89c33dc-ff47-4bb7-855e-863fe44b3202) --- ### AI Usage Did you use AI tools to help write this code? **YES**, Claude Code
2026-02-05 05:28:10 -05:00
// Style tracking (replaces depth-based approach)
struct StyleStackEntry {
int depth = 0;
bool hasBold = false, bold = false;
bool hasItalic = false, italic = false;
bool hasUnderline = false, underline = false;
};
std::vector<StyleStackEntry> inlineStyleStack;
CssStyle currentCssStyle;
bool effectiveBold = false;
bool effectiveItalic = false;
bool effectiveUnderline = false;
int tableDepth = 0;
int tableRowIndex = 0;
int tableColIndex = 0;
feat: Add CSS parsing and CSS support in EPUBs (#411) ## Summary * **What is the goal of this PR?** - Adds basic CSS parsing to EPUBs and determine the CSS rules when rendering to the screen so that text is styled correctly. Currently supports bold, underline, italics, margin, padding, and text alignment ## Additional Context - My main reason for wanting this is that the book I'm currently reading, Carl's Doomsday Scenario (2nd in the Dungeon Crawler Carl series), relies _a lot_ on styled text for telling parts of the story. When text is bolded, it's supposed to be a message that's rendered "on-screen" in the story. When characters are "chatting" with each other, the text is bolded and their names are underlined. Plus, normal emphasis is provided with italicizing words here and there. So, this greatly improves my experience reading this book on the Xteink, and I figured it was useful enough for others too. - For transparency: I'm a software engineer, but I'm mostly frontend and TypeScript/JavaScript. It's been _years_ since I did any C/C++, so I would not be surprised if I'm doing something dumb along the way in this code. Please don't hesitate to ask for changes if something looks off. I heavily relied on Claude Code for help, and I had a lot of inspiration from how [microreader](https://github.com/CidVonHighwind/microreader) achieves their CSS parsing and styling. I did give this as good of a code review as I could and went through everything, and _it works on my machine_ 😄 ### Before ![IMG_6271](https://github.com/user-attachments/assets/dba7554d-efb6-4d13-88bc-8b83cd1fc615) ![IMG_6272](https://github.com/user-attachments/assets/61ba2de0-87c9-4f39-956f-013da4fe20a4) ### After ![IMG_6268](https://github.com/user-attachments/assets/ebe11796-cca9-4a46-b9c7-0709c7932818) ![IMG_6269](https://github.com/user-attachments/assets/e89c33dc-ff47-4bb7-855e-863fe44b3202) --- ### AI Usage Did you use AI tools to help write this code? **YES**, Claude Code
2026-02-05 05:28:10 -05:00
feat: slim footnotes support (#1031) ## Summary **What is the goal of this PR?** Implement support for footnotes in epub files. It is based on #553, but simplified — removed the parts which complicated the code and burden the CPU/RAM. This version supports basic footnotes and lets the user jump from location to location inside the epub. **What changes are included?** - `FootnoteEntry` struct — A small POD struct (number[24], href[64]) shared between parser, page storage, and UI. - Parser: `<a href>` detection (`ChapterHtmlSlimParser`) — During a single parsing pass, internal epub links are detected and collected as footnotes. The link text is underlined to hint navigability. Bracket/whitespace normalization is applied to the display label (e.g. [1] → 1). - Footnote-to-page assignment (`ChapterHtmlSlimParser`, `Page`) — Footnotes are attached to the exact page where their anchor word appears, tracked via a cumulative word counter during layout, surviving paragraph splits and the 750-word mid-paragraph safety flush. - Page serialization (`Page`, `Section`) — Footnotes are serialized/deserialized per page (max 16 per page). Section cache version bumped to 14 to force a clean rebuild. - Href → spine resolution (`Epub`) — `resolveHrefToSpineIndex()` maps an href (e.g. `chapter2.xhtml#note1`) to its spine index by filename matching. - Footnotes menu + activity (`EpubReaderMenuActivity`, `EpubReaderFootnotesActivity`) — A new "Footnotes" entry in the reader menu lists all footnote links found on the current page. The user scrolls and selects to navigate. - Navigate & restore (`EpubReaderActivity`) — `navigateToHref()` saves the current spine index and page number, then jumps to the target. The Back button restores the saved position when the user is done reading the footnote. **Additional Context** **What was removed vs #553:** virtual spine items (`addVirtualSpineItem`, `isVirtualSpineItem`), two-pass parsing, `<aside>` content extraction to temp HTML files, `<p class="note">` paragraph note extraction, `replaceHtmlEntities` (master already has `lookupHtmlEntity`), `footnotePages` / `buildFilteredChapterList`, `noterefCallback` / `Noteref` struct, and the stack size increase from 8 KB to 24 KB (not needed without two-pass parsing and virtual file I/O on the render task). **Performance:** Single-pass parsing. No new heap allocations in the hot path — footnote text is collected into fixed stack buffers (char[24], char[64]). Active runtime memory is ~2.8 KB worst-case (one page × 16 footnotes × 88 bytes, mirrored in `currentPageFootnotes`). Flash usage is unchanged at 97.4%; RAM stays at 31%. **Known limitations:** When clicking a footnote, it jumps to the start of the HTML file instead of the specific anchor. This could be problematic for books that don't have separate files for each footnote. (no element-id-to-page mapping yet - will be another PR soon). --- ### AI Usage Did you use AI tools to help write this code? _**< PARTIALLY>**_ Claude Opus 4.6 was used to do most of the migration, I checked manually its work, and fixed some stuff, but I haven't review all the changes yet, so feedback is welcomed. --------- Co-authored-by: Arthur Tazhitdinov <lisnake@gmail.com>
2026-02-26 16:47:34 +02:00
// Footnote link tracking
bool insideFootnoteLink = false;
int footnoteLinkDepth = -1;
char currentFootnoteLinkText[24] = {};
int currentFootnoteLinkTextLen = 0;
char currentFootnoteLinkHref[64] = {};
std::vector<std::pair<int, FootnoteEntry>> pendingFootnotes; // <wordIndex, entry>
int wordsExtractedInBlock = 0;
feat: Add CSS parsing and CSS support in EPUBs (#411) ## Summary * **What is the goal of this PR?** - Adds basic CSS parsing to EPUBs and determine the CSS rules when rendering to the screen so that text is styled correctly. Currently supports bold, underline, italics, margin, padding, and text alignment ## Additional Context - My main reason for wanting this is that the book I'm currently reading, Carl's Doomsday Scenario (2nd in the Dungeon Crawler Carl series), relies _a lot_ on styled text for telling parts of the story. When text is bolded, it's supposed to be a message that's rendered "on-screen" in the story. When characters are "chatting" with each other, the text is bolded and their names are underlined. Plus, normal emphasis is provided with italicizing words here and there. So, this greatly improves my experience reading this book on the Xteink, and I figured it was useful enough for others too. - For transparency: I'm a software engineer, but I'm mostly frontend and TypeScript/JavaScript. It's been _years_ since I did any C/C++, so I would not be surprised if I'm doing something dumb along the way in this code. Please don't hesitate to ask for changes if something looks off. I heavily relied on Claude Code for help, and I had a lot of inspiration from how [microreader](https://github.com/CidVonHighwind/microreader) achieves their CSS parsing and styling. I did give this as good of a code review as I could and went through everything, and _it works on my machine_ 😄 ### Before ![IMG_6271](https://github.com/user-attachments/assets/dba7554d-efb6-4d13-88bc-8b83cd1fc615) ![IMG_6272](https://github.com/user-attachments/assets/61ba2de0-87c9-4f39-956f-013da4fe20a4) ### After ![IMG_6268](https://github.com/user-attachments/assets/ebe11796-cca9-4a46-b9c7-0709c7932818) ![IMG_6269](https://github.com/user-attachments/assets/e89c33dc-ff47-4bb7-855e-863fe44b3202) --- ### AI Usage Did you use AI tools to help write this code? **YES**, Claude Code
2026-02-05 05:28:10 -05:00
void updateEffectiveInlineStyle();
void startNewTextBlock(const BlockStyle& blockStyle);
void flushPartWordBuffer();
void makePages();
// XML callbacks
static void XMLCALL startElement(void* userData, const XML_Char* name, const XML_Char** atts);
static void XMLCALL characterData(void* userData, const XML_Char* s, int len);
static void XMLCALL defaultHandlerExpand(void* userData, const XML_Char* s, int len);
static void XMLCALL endElement(void* userData, const XML_Char* name);
public:
feat: add png jpeg support (#556) ## Summary - Add embedded image support to EPUB rendering with JPEG and PNG decoders - Implement pixel caching system to cache decoded/dithered images to SD card for faster re-rendering - Add 4-level grayscale support for display ## Changes ### New Image Rendering System - Add `ImageBlock` class to represent an image with its cached path and display dimensions - Add `PageImage` class as a new `PageElement` type for images on pages - Add `ImageToFramebufferDecoder` interface for format-specific image decoders - Add `JpegToFramebufferConverter` - JPEG decoder with Bayer dithering and scaling - Add `PngToFramebufferConverter` - PNG decoder with Bayer dithering and scaling - Add `ImageDecoderFactory` to select appropriate decoder based on file extension - Add `getRenderMode()` to GfxRenderer for grayscale render mode queries ### Dithering and Grayscale - Implement 4x4 Bayer ordered dithering for 4-level grayscale output - Stateless algorithm works correctly with MCU block decoding - Handles scaling without artifacts - Add grayscale render mode support (BW, GRAYSCALE_LSB, GRAYSCALE_MSB) - Image decoders and cache renderer respect current render mode - Enables proper 4-level e-ink grayscale when anti-aliasing is enabled ### Pixel Caching - Cache decoded/dithered images to `.pxc` files on SD card - Cache format: 2-bit packed pixels (4 pixels per byte) with width/height header - On subsequent renders, load directly from cache instead of re-decoding - Cache renderer supports grayscale render modes for multi-pass rendering - Significantly improves page navigation speed for image-heavy EPUBs ### HTML Parser Integration - Update `ChapterHtmlSlimParser` to process `<img>` tags and extract images from EPUB - Resolve relative image paths within EPUB ZIP structure - Extract images to cache directory before decoding - Create `PageImage` elements with proper scaling to fit viewport - Fall back to alt text display if image processing fails ### Build Configuration - Add `PNG_MAX_BUFFERED_PIXELS=6402` to support up to 800px wide images ### Test Script - Generate test EPUBs with annotated JPEG and PNG images - Test cases cover: grayscale (4 levels), centering, scaling, cache performance ## Test plan - [x] Open EPUB with JPEG images - verify images display with proper grayscale - [x] Open EPUB with PNG images - verify images display correctly and no crash - [x] Navigate away from image page and back - verify faster load from cache - [x] Verify grayscale tones render correctly (not just black/white dithering) - [x] Verify large images are scaled down to fit screen - [x] Verify images are centered horizontally - [x] Verify page serialization/deserialization works with images - [x] Verify images rendered in landscape mode ## Test Results [png](https://photos.app.goo.gl/5zFUb8xA8db3dPd19) [jpeg](https://photos.app.goo.gl/SwtwaL2DSQwKybhw7) ![20260128_231123790](https://github.com/user-attachments/assets/78855971-4bb8-441a-b207-0a292b9739f5) ![20260128_231012253](https://github.com/user-attachments/assets/f08fb63f-1b73-41d9-a25e-78232ec0c495) ![20260128_231004209](https://github.com/user-attachments/assets/06c94acc-8a06-4955-978e-6e583399478d) ![20260128_230954997](https://github.com/user-attachments/assets/49bc44d5-0f2c-416b-9199-4d680fb0f4c3) ![20260128_230945717](https://github.com/user-attachments/assets/93446da5-2e07-410c-89c9-6a21d14e5acb) ![20260128_230938313](https://github.com/user-attachments/assets/4c74c72a-3d40-4a25-b0f3-acc703f42c00) ![20260128_230925546](https://github.com/user-attachments/assets/8d8f62ee-c8fc-4f19-a12c-da29083bb766) ![20260128_230918374](https://github.com/user-attachments/assets/f007d5db-41cc-4fa6-bb22-9e767ee7b00d) --- ### AI Usage Did you use AI tools to help write this code? _**< YES >**_ --------- Co-authored-by: Matthías Páll Gissurarson <mpg@mpg.is> Co-authored-by: Dave Allie <dave@daveallie.com>
2026-02-16 08:56:59 +00:00
explicit ChapterHtmlSlimParser(std::shared_ptr<Epub> epub, const std::string& filepath, GfxRenderer& renderer,
const int fontId, const float lineCompression, const bool extraParagraphSpacing,
const uint8_t paragraphAlignment, const uint16_t viewportWidth,
const uint16_t viewportHeight, const bool hyphenationEnabled,
Add retry logic and progress bar for chapter indexing (#128) ## Summary * **What is the goal of this PR?** Improve reliability and user experience during chapter indexing by adding retry logic for SD card operations and a visual progress bar. * **What changes are included?** - **Retry logic**: Add 3 retry attempts with 50ms delay for ZIP to SD card streaming to handle timing issues after display refresh - **Progress bar**: Display a visual progress bar (0-100%) during chapter indexing based on file read progress, updating every 10% to balance responsiveness with e-ink display limitations ## Additional Context * **Problem observed**: When navigating quickly through books with many chapters (before chapter titles finish rendering), the "Indexing..." screen would appear frozen. Checking the serial log revealed the operation had silently failed, but the UI showed no indication of this. Users would likely assume the device had crashed. Pressing the next button again would resume operation, but this behavior was confusing and unexpected. * **Solution**: - Retry logic handles transient SD card timing failures automatically, so users don't need to manually retry - Progress bar provides visual feedback so users know indexing is actively working (not frozen) * **Why timing issues occur**: After display refresh operations, there can be timing conflicts when immediately starting SD card write operations. This is more likely to happen when rapidly navigating through chapters. * **Progress bar design**: Updates every 10% to avoid excessive e-ink refreshes while still providing meaningful feedback during long indexing operations (especially for large chapters with CJK characters). * **Performance**: Minimal overhead - progress calculation is simple byte counting, and display updates use `FAST_REFRESH` mode.
2025-12-28 13:59:44 +09:00
const std::function<void(std::unique_ptr<Page>)>& completePageFn,
feat: add png jpeg support (#556) ## Summary - Add embedded image support to EPUB rendering with JPEG and PNG decoders - Implement pixel caching system to cache decoded/dithered images to SD card for faster re-rendering - Add 4-level grayscale support for display ## Changes ### New Image Rendering System - Add `ImageBlock` class to represent an image with its cached path and display dimensions - Add `PageImage` class as a new `PageElement` type for images on pages - Add `ImageToFramebufferDecoder` interface for format-specific image decoders - Add `JpegToFramebufferConverter` - JPEG decoder with Bayer dithering and scaling - Add `PngToFramebufferConverter` - PNG decoder with Bayer dithering and scaling - Add `ImageDecoderFactory` to select appropriate decoder based on file extension - Add `getRenderMode()` to GfxRenderer for grayscale render mode queries ### Dithering and Grayscale - Implement 4x4 Bayer ordered dithering for 4-level grayscale output - Stateless algorithm works correctly with MCU block decoding - Handles scaling without artifacts - Add grayscale render mode support (BW, GRAYSCALE_LSB, GRAYSCALE_MSB) - Image decoders and cache renderer respect current render mode - Enables proper 4-level e-ink grayscale when anti-aliasing is enabled ### Pixel Caching - Cache decoded/dithered images to `.pxc` files on SD card - Cache format: 2-bit packed pixels (4 pixels per byte) with width/height header - On subsequent renders, load directly from cache instead of re-decoding - Cache renderer supports grayscale render modes for multi-pass rendering - Significantly improves page navigation speed for image-heavy EPUBs ### HTML Parser Integration - Update `ChapterHtmlSlimParser` to process `<img>` tags and extract images from EPUB - Resolve relative image paths within EPUB ZIP structure - Extract images to cache directory before decoding - Create `PageImage` elements with proper scaling to fit viewport - Fall back to alt text display if image processing fails ### Build Configuration - Add `PNG_MAX_BUFFERED_PIXELS=6402` to support up to 800px wide images ### Test Script - Generate test EPUBs with annotated JPEG and PNG images - Test cases cover: grayscale (4 levels), centering, scaling, cache performance ## Test plan - [x] Open EPUB with JPEG images - verify images display with proper grayscale - [x] Open EPUB with PNG images - verify images display correctly and no crash - [x] Navigate away from image page and back - verify faster load from cache - [x] Verify grayscale tones render correctly (not just black/white dithering) - [x] Verify large images are scaled down to fit screen - [x] Verify images are centered horizontally - [x] Verify page serialization/deserialization works with images - [x] Verify images rendered in landscape mode ## Test Results [png](https://photos.app.goo.gl/5zFUb8xA8db3dPd19) [jpeg](https://photos.app.goo.gl/SwtwaL2DSQwKybhw7) ![20260128_231123790](https://github.com/user-attachments/assets/78855971-4bb8-441a-b207-0a292b9739f5) ![20260128_231012253](https://github.com/user-attachments/assets/f08fb63f-1b73-41d9-a25e-78232ec0c495) ![20260128_231004209](https://github.com/user-attachments/assets/06c94acc-8a06-4955-978e-6e583399478d) ![20260128_230954997](https://github.com/user-attachments/assets/49bc44d5-0f2c-416b-9199-4d680fb0f4c3) ![20260128_230945717](https://github.com/user-attachments/assets/93446da5-2e07-410c-89c9-6a21d14e5acb) ![20260128_230938313](https://github.com/user-attachments/assets/4c74c72a-3d40-4a25-b0f3-acc703f42c00) ![20260128_230925546](https://github.com/user-attachments/assets/8d8f62ee-c8fc-4f19-a12c-da29083bb766) ![20260128_230918374](https://github.com/user-attachments/assets/f007d5db-41cc-4fa6-bb22-9e767ee7b00d) --- ### AI Usage Did you use AI tools to help write this code? _**< YES >**_ --------- Co-authored-by: Matthías Páll Gissurarson <mpg@mpg.is> Co-authored-by: Dave Allie <dave@daveallie.com>
2026-02-16 08:56:59 +00:00
const bool embeddedStyle, const std::string& contentBase,
const std::string& imageBasePath, const uint8_t imageRendering = 0,
const std::function<void()>& popupFn = nullptr, const CssParser* cssParser = nullptr)
feat: Add CSS parsing and CSS support in EPUBs (#411) ## Summary * **What is the goal of this PR?** - Adds basic CSS parsing to EPUBs and determine the CSS rules when rendering to the screen so that text is styled correctly. Currently supports bold, underline, italics, margin, padding, and text alignment ## Additional Context - My main reason for wanting this is that the book I'm currently reading, Carl's Doomsday Scenario (2nd in the Dungeon Crawler Carl series), relies _a lot_ on styled text for telling parts of the story. When text is bolded, it's supposed to be a message that's rendered "on-screen" in the story. When characters are "chatting" with each other, the text is bolded and their names are underlined. Plus, normal emphasis is provided with italicizing words here and there. So, this greatly improves my experience reading this book on the Xteink, and I figured it was useful enough for others too. - For transparency: I'm a software engineer, but I'm mostly frontend and TypeScript/JavaScript. It's been _years_ since I did any C/C++, so I would not be surprised if I'm doing something dumb along the way in this code. Please don't hesitate to ask for changes if something looks off. I heavily relied on Claude Code for help, and I had a lot of inspiration from how [microreader](https://github.com/CidVonHighwind/microreader) achieves their CSS parsing and styling. I did give this as good of a code review as I could and went through everything, and _it works on my machine_ 😄 ### Before ![IMG_6271](https://github.com/user-attachments/assets/dba7554d-efb6-4d13-88bc-8b83cd1fc615) ![IMG_6272](https://github.com/user-attachments/assets/61ba2de0-87c9-4f39-956f-013da4fe20a4) ### After ![IMG_6268](https://github.com/user-attachments/assets/ebe11796-cca9-4a46-b9c7-0709c7932818) ![IMG_6269](https://github.com/user-attachments/assets/e89c33dc-ff47-4bb7-855e-863fe44b3202) --- ### AI Usage Did you use AI tools to help write this code? **YES**, Claude Code
2026-02-05 05:28:10 -05:00
feat: add png jpeg support (#556) ## Summary - Add embedded image support to EPUB rendering with JPEG and PNG decoders - Implement pixel caching system to cache decoded/dithered images to SD card for faster re-rendering - Add 4-level grayscale support for display ## Changes ### New Image Rendering System - Add `ImageBlock` class to represent an image with its cached path and display dimensions - Add `PageImage` class as a new `PageElement` type for images on pages - Add `ImageToFramebufferDecoder` interface for format-specific image decoders - Add `JpegToFramebufferConverter` - JPEG decoder with Bayer dithering and scaling - Add `PngToFramebufferConverter` - PNG decoder with Bayer dithering and scaling - Add `ImageDecoderFactory` to select appropriate decoder based on file extension - Add `getRenderMode()` to GfxRenderer for grayscale render mode queries ### Dithering and Grayscale - Implement 4x4 Bayer ordered dithering for 4-level grayscale output - Stateless algorithm works correctly with MCU block decoding - Handles scaling without artifacts - Add grayscale render mode support (BW, GRAYSCALE_LSB, GRAYSCALE_MSB) - Image decoders and cache renderer respect current render mode - Enables proper 4-level e-ink grayscale when anti-aliasing is enabled ### Pixel Caching - Cache decoded/dithered images to `.pxc` files on SD card - Cache format: 2-bit packed pixels (4 pixels per byte) with width/height header - On subsequent renders, load directly from cache instead of re-decoding - Cache renderer supports grayscale render modes for multi-pass rendering - Significantly improves page navigation speed for image-heavy EPUBs ### HTML Parser Integration - Update `ChapterHtmlSlimParser` to process `<img>` tags and extract images from EPUB - Resolve relative image paths within EPUB ZIP structure - Extract images to cache directory before decoding - Create `PageImage` elements with proper scaling to fit viewport - Fall back to alt text display if image processing fails ### Build Configuration - Add `PNG_MAX_BUFFERED_PIXELS=6402` to support up to 800px wide images ### Test Script - Generate test EPUBs with annotated JPEG and PNG images - Test cases cover: grayscale (4 levels), centering, scaling, cache performance ## Test plan - [x] Open EPUB with JPEG images - verify images display with proper grayscale - [x] Open EPUB with PNG images - verify images display correctly and no crash - [x] Navigate away from image page and back - verify faster load from cache - [x] Verify grayscale tones render correctly (not just black/white dithering) - [x] Verify large images are scaled down to fit screen - [x] Verify images are centered horizontally - [x] Verify page serialization/deserialization works with images - [x] Verify images rendered in landscape mode ## Test Results [png](https://photos.app.goo.gl/5zFUb8xA8db3dPd19) [jpeg](https://photos.app.goo.gl/SwtwaL2DSQwKybhw7) ![20260128_231123790](https://github.com/user-attachments/assets/78855971-4bb8-441a-b207-0a292b9739f5) ![20260128_231012253](https://github.com/user-attachments/assets/f08fb63f-1b73-41d9-a25e-78232ec0c495) ![20260128_231004209](https://github.com/user-attachments/assets/06c94acc-8a06-4955-978e-6e583399478d) ![20260128_230954997](https://github.com/user-attachments/assets/49bc44d5-0f2c-416b-9199-4d680fb0f4c3) ![20260128_230945717](https://github.com/user-attachments/assets/93446da5-2e07-410c-89c9-6a21d14e5acb) ![20260128_230938313](https://github.com/user-attachments/assets/4c74c72a-3d40-4a25-b0f3-acc703f42c00) ![20260128_230925546](https://github.com/user-attachments/assets/8d8f62ee-c8fc-4f19-a12c-da29083bb766) ![20260128_230918374](https://github.com/user-attachments/assets/f007d5db-41cc-4fa6-bb22-9e767ee7b00d) --- ### AI Usage Did you use AI tools to help write this code? _**< YES >**_ --------- Co-authored-by: Matthías Páll Gissurarson <mpg@mpg.is> Co-authored-by: Dave Allie <dave@daveallie.com>
2026-02-16 08:56:59 +00:00
: epub(epub),
filepath(filepath),
renderer(renderer),
fontId(fontId),
lineCompression(lineCompression),
extraParagraphSpacing(extraParagraphSpacing),
paragraphAlignment(paragraphAlignment),
Rotation Support (#77) • What is the goal of this PR? Implement a horizontal EPUB reading mode so books can be read in landscape orientation (both 90° and 270°), while keeping the rest of the UI in portrait. • What changes are included? ◦ Rendering / Display ▪ Added an orientation model to GfxRenderer (Portrait, LandscapeNormal, LandscapeFlipped) and made: ▪ drawPixel, drawImage, displayWindow map logical coordinates differently depending on orientation. ▪ getScreenWidth() / getScreenHeight() return orientation‑aware logical dimensions (480×800 in portrait, 800×480 in landscape). ◦ Settings / Configuration ▪ Extended CrossPointSettings with: ▪ landscapeReading (toggle for portrait vs. landscape EPUB reading). ▪ landscapeFlipped (toggle to flip landscape 180° so both horizontal holding directions are supported). ▪ Updated settings serialization/deserialization to persist these fields while remaining backward‑compatible with existing settings files. ▪ Updated SettingsActivity to expose two new toggles: ▪ “Landscape Reading” ▪ “Flip Landscape (swap top/bottom)” ◦ EPUB Reader ▪ In EpubReaderActivity: ▪ On onEnter, set GfxRenderer orientation based on the new settings (Portrait, LandscapeNormal, or LandscapeFlipped). ▪ On onExit, reset orientation back to Portrait so Home, WiFi, Settings, etc. continue to render as before. ▪ Adjusted renderStatusBar to position the status bar and battery indicator relative to GfxRenderer::getScreenHeight() instead of hard‑coded Y coordinates, so it stays correctly at the bottom in both portrait and landscape. ◦ EPUB Caching / Layout ▪ Extended Section cache metadata (section.bin) to include the logical screenWidth and screenHeight used when pages were generated; bumped SECTION_FILE_VERSION. ▪ Updated loadCacheMetadata to compare: ▪ font/margins/line compression/extraParagraphSpacing and screen dimensions; mismatches now invalidate and clear the cache. ▪ Updated persistPageDataToSD and all call sites in EpubReaderActivity to pass the current GfxRenderer::getScreenWidth() / getScreenHeight() so portrait and landscape caches are kept separate and correctly sized. Additional Context • Cache behavior / migration ◦ Existing section.bin files (old SECTION_FILE_VERSION) will be detected as incompatible and their caches cleared and rebuilt once per chapter when first opened after this change. ◦ Within a given orientation, caches will be reused as before. Switching orientation (portrait ↔ landscape) will cause a one‑time re‑index of each chapter in the new orientation. • Scope and risks ◦ Orientation changes are scoped to the EPUB reader; the Home screen, Settings, WiFi selection, sleep screens, and web server UI continue to assume portrait orientation. ◦ The renderer’s orientation is a static/global setting; if future code uses GfxRenderer outside the reader while a reader instance is active, it should be aware that orientation is no longer implicitly fixed. ◦ All drawing primitives now go through orientation‑aware coordinate transforms; any code that previously relied on edge‑case behavior or out‑of‑bounds writes might surface as logged “Outside range” warnings instead. • Testing suggestions / areas to focus on ◦ Verify in hardware: ▪ Portrait mode still renders correctly (boot, home, settings, WiFi, reader). ▪ Landscape reading in both directions: ▪ Landscape Reading = ON, Flip Landscape = OFF. ▪ Landscape Reading = ON, Flip Landscape = ON. ▪ Status bar (page X/Y, % progress, battery icon) is fully visible and aligned at the bottom in all three combinations. ◦ Open the same book: ▪ In portrait first, then switch to landscape and reopen it. ▪ Confirm that: ▪ Old portrait caches are rebuilt once for landscape (you should see the “Indexing…” page). ▪ Progress save/restore still works (resume opens to the correct page in the current orientation). ◦ Ensure grayscale rendering (the secondary pass in EpubReaderActivity::renderContents) still looks correct in both orientations. --------- Co-authored-by: Dave Allie <dave@daveallie.com>
2025-12-28 05:33:20 -05:00
viewportWidth(viewportWidth),
viewportHeight(viewportHeight),
hyphenationEnabled(hyphenationEnabled),
Add retry logic and progress bar for chapter indexing (#128) ## Summary * **What is the goal of this PR?** Improve reliability and user experience during chapter indexing by adding retry logic for SD card operations and a visual progress bar. * **What changes are included?** - **Retry logic**: Add 3 retry attempts with 50ms delay for ZIP to SD card streaming to handle timing issues after display refresh - **Progress bar**: Display a visual progress bar (0-100%) during chapter indexing based on file read progress, updating every 10% to balance responsiveness with e-ink display limitations ## Additional Context * **Problem observed**: When navigating quickly through books with many chapters (before chapter titles finish rendering), the "Indexing..." screen would appear frozen. Checking the serial log revealed the operation had silently failed, but the UI showed no indication of this. Users would likely assume the device had crashed. Pressing the next button again would resume operation, but this behavior was confusing and unexpected. * **Solution**: - Retry logic handles transient SD card timing failures automatically, so users don't need to manually retry - Progress bar provides visual feedback so users know indexing is actively working (not frozen) * **Why timing issues occur**: After display refresh operations, there can be timing conflicts when immediately starting SD card write operations. This is more likely to happen when rapidly navigating through chapters. * **Progress bar design**: Updates every 10% to avoid excessive e-ink refreshes while still providing meaningful feedback during long indexing operations (especially for large chapters with CJK characters). * **Performance**: Minimal overhead - progress calculation is simple byte counting, and display updates use `FAST_REFRESH` mode.
2025-12-28 13:59:44 +09:00
completePageFn(completePageFn),
feat: Add CSS parsing and CSS support in EPUBs (#411) ## Summary * **What is the goal of this PR?** - Adds basic CSS parsing to EPUBs and determine the CSS rules when rendering to the screen so that text is styled correctly. Currently supports bold, underline, italics, margin, padding, and text alignment ## Additional Context - My main reason for wanting this is that the book I'm currently reading, Carl's Doomsday Scenario (2nd in the Dungeon Crawler Carl series), relies _a lot_ on styled text for telling parts of the story. When text is bolded, it's supposed to be a message that's rendered "on-screen" in the story. When characters are "chatting" with each other, the text is bolded and their names are underlined. Plus, normal emphasis is provided with italicizing words here and there. So, this greatly improves my experience reading this book on the Xteink, and I figured it was useful enough for others too. - For transparency: I'm a software engineer, but I'm mostly frontend and TypeScript/JavaScript. It's been _years_ since I did any C/C++, so I would not be surprised if I'm doing something dumb along the way in this code. Please don't hesitate to ask for changes if something looks off. I heavily relied on Claude Code for help, and I had a lot of inspiration from how [microreader](https://github.com/CidVonHighwind/microreader) achieves their CSS parsing and styling. I did give this as good of a code review as I could and went through everything, and _it works on my machine_ 😄 ### Before ![IMG_6271](https://github.com/user-attachments/assets/dba7554d-efb6-4d13-88bc-8b83cd1fc615) ![IMG_6272](https://github.com/user-attachments/assets/61ba2de0-87c9-4f39-956f-013da4fe20a4) ### After ![IMG_6268](https://github.com/user-attachments/assets/ebe11796-cca9-4a46-b9c7-0709c7932818) ![IMG_6269](https://github.com/user-attachments/assets/e89c33dc-ff47-4bb7-855e-863fe44b3202) --- ### AI Usage Did you use AI tools to help write this code? **YES**, Claude Code
2026-02-05 05:28:10 -05:00
popupFn(popupFn),
cssParser(cssParser),
feat: add png jpeg support (#556) ## Summary - Add embedded image support to EPUB rendering with JPEG and PNG decoders - Implement pixel caching system to cache decoded/dithered images to SD card for faster re-rendering - Add 4-level grayscale support for display ## Changes ### New Image Rendering System - Add `ImageBlock` class to represent an image with its cached path and display dimensions - Add `PageImage` class as a new `PageElement` type for images on pages - Add `ImageToFramebufferDecoder` interface for format-specific image decoders - Add `JpegToFramebufferConverter` - JPEG decoder with Bayer dithering and scaling - Add `PngToFramebufferConverter` - PNG decoder with Bayer dithering and scaling - Add `ImageDecoderFactory` to select appropriate decoder based on file extension - Add `getRenderMode()` to GfxRenderer for grayscale render mode queries ### Dithering and Grayscale - Implement 4x4 Bayer ordered dithering for 4-level grayscale output - Stateless algorithm works correctly with MCU block decoding - Handles scaling without artifacts - Add grayscale render mode support (BW, GRAYSCALE_LSB, GRAYSCALE_MSB) - Image decoders and cache renderer respect current render mode - Enables proper 4-level e-ink grayscale when anti-aliasing is enabled ### Pixel Caching - Cache decoded/dithered images to `.pxc` files on SD card - Cache format: 2-bit packed pixels (4 pixels per byte) with width/height header - On subsequent renders, load directly from cache instead of re-decoding - Cache renderer supports grayscale render modes for multi-pass rendering - Significantly improves page navigation speed for image-heavy EPUBs ### HTML Parser Integration - Update `ChapterHtmlSlimParser` to process `<img>` tags and extract images from EPUB - Resolve relative image paths within EPUB ZIP structure - Extract images to cache directory before decoding - Create `PageImage` elements with proper scaling to fit viewport - Fall back to alt text display if image processing fails ### Build Configuration - Add `PNG_MAX_BUFFERED_PIXELS=6402` to support up to 800px wide images ### Test Script - Generate test EPUBs with annotated JPEG and PNG images - Test cases cover: grayscale (4 levels), centering, scaling, cache performance ## Test plan - [x] Open EPUB with JPEG images - verify images display with proper grayscale - [x] Open EPUB with PNG images - verify images display correctly and no crash - [x] Navigate away from image page and back - verify faster load from cache - [x] Verify grayscale tones render correctly (not just black/white dithering) - [x] Verify large images are scaled down to fit screen - [x] Verify images are centered horizontally - [x] Verify page serialization/deserialization works with images - [x] Verify images rendered in landscape mode ## Test Results [png](https://photos.app.goo.gl/5zFUb8xA8db3dPd19) [jpeg](https://photos.app.goo.gl/SwtwaL2DSQwKybhw7) ![20260128_231123790](https://github.com/user-attachments/assets/78855971-4bb8-441a-b207-0a292b9739f5) ![20260128_231012253](https://github.com/user-attachments/assets/f08fb63f-1b73-41d9-a25e-78232ec0c495) ![20260128_231004209](https://github.com/user-attachments/assets/06c94acc-8a06-4955-978e-6e583399478d) ![20260128_230954997](https://github.com/user-attachments/assets/49bc44d5-0f2c-416b-9199-4d680fb0f4c3) ![20260128_230945717](https://github.com/user-attachments/assets/93446da5-2e07-410c-89c9-6a21d14e5acb) ![20260128_230938313](https://github.com/user-attachments/assets/4c74c72a-3d40-4a25-b0f3-acc703f42c00) ![20260128_230925546](https://github.com/user-attachments/assets/8d8f62ee-c8fc-4f19-a12c-da29083bb766) ![20260128_230918374](https://github.com/user-attachments/assets/f007d5db-41cc-4fa6-bb22-9e767ee7b00d) --- ### AI Usage Did you use AI tools to help write this code? _**< YES >**_ --------- Co-authored-by: Matthías Páll Gissurarson <mpg@mpg.is> Co-authored-by: Dave Allie <dave@daveallie.com>
2026-02-16 08:56:59 +00:00
embeddedStyle(embeddedStyle),
imageRendering(imageRendering),
feat: add png jpeg support (#556) ## Summary - Add embedded image support to EPUB rendering with JPEG and PNG decoders - Implement pixel caching system to cache decoded/dithered images to SD card for faster re-rendering - Add 4-level grayscale support for display ## Changes ### New Image Rendering System - Add `ImageBlock` class to represent an image with its cached path and display dimensions - Add `PageImage` class as a new `PageElement` type for images on pages - Add `ImageToFramebufferDecoder` interface for format-specific image decoders - Add `JpegToFramebufferConverter` - JPEG decoder with Bayer dithering and scaling - Add `PngToFramebufferConverter` - PNG decoder with Bayer dithering and scaling - Add `ImageDecoderFactory` to select appropriate decoder based on file extension - Add `getRenderMode()` to GfxRenderer for grayscale render mode queries ### Dithering and Grayscale - Implement 4x4 Bayer ordered dithering for 4-level grayscale output - Stateless algorithm works correctly with MCU block decoding - Handles scaling without artifacts - Add grayscale render mode support (BW, GRAYSCALE_LSB, GRAYSCALE_MSB) - Image decoders and cache renderer respect current render mode - Enables proper 4-level e-ink grayscale when anti-aliasing is enabled ### Pixel Caching - Cache decoded/dithered images to `.pxc` files on SD card - Cache format: 2-bit packed pixels (4 pixels per byte) with width/height header - On subsequent renders, load directly from cache instead of re-decoding - Cache renderer supports grayscale render modes for multi-pass rendering - Significantly improves page navigation speed for image-heavy EPUBs ### HTML Parser Integration - Update `ChapterHtmlSlimParser` to process `<img>` tags and extract images from EPUB - Resolve relative image paths within EPUB ZIP structure - Extract images to cache directory before decoding - Create `PageImage` elements with proper scaling to fit viewport - Fall back to alt text display if image processing fails ### Build Configuration - Add `PNG_MAX_BUFFERED_PIXELS=6402` to support up to 800px wide images ### Test Script - Generate test EPUBs with annotated JPEG and PNG images - Test cases cover: grayscale (4 levels), centering, scaling, cache performance ## Test plan - [x] Open EPUB with JPEG images - verify images display with proper grayscale - [x] Open EPUB with PNG images - verify images display correctly and no crash - [x] Navigate away from image page and back - verify faster load from cache - [x] Verify grayscale tones render correctly (not just black/white dithering) - [x] Verify large images are scaled down to fit screen - [x] Verify images are centered horizontally - [x] Verify page serialization/deserialization works with images - [x] Verify images rendered in landscape mode ## Test Results [png](https://photos.app.goo.gl/5zFUb8xA8db3dPd19) [jpeg](https://photos.app.goo.gl/SwtwaL2DSQwKybhw7) ![20260128_231123790](https://github.com/user-attachments/assets/78855971-4bb8-441a-b207-0a292b9739f5) ![20260128_231012253](https://github.com/user-attachments/assets/f08fb63f-1b73-41d9-a25e-78232ec0c495) ![20260128_231004209](https://github.com/user-attachments/assets/06c94acc-8a06-4955-978e-6e583399478d) ![20260128_230954997](https://github.com/user-attachments/assets/49bc44d5-0f2c-416b-9199-4d680fb0f4c3) ![20260128_230945717](https://github.com/user-attachments/assets/93446da5-2e07-410c-89c9-6a21d14e5acb) ![20260128_230938313](https://github.com/user-attachments/assets/4c74c72a-3d40-4a25-b0f3-acc703f42c00) ![20260128_230925546](https://github.com/user-attachments/assets/8d8f62ee-c8fc-4f19-a12c-da29083bb766) ![20260128_230918374](https://github.com/user-attachments/assets/f007d5db-41cc-4fa6-bb22-9e767ee7b00d) --- ### AI Usage Did you use AI tools to help write this code? _**< YES >**_ --------- Co-authored-by: Matthías Páll Gissurarson <mpg@mpg.is> Co-authored-by: Dave Allie <dave@daveallie.com>
2026-02-16 08:56:59 +00:00
contentBase(contentBase),
imageBasePath(imageBasePath) {}
feat: Add CSS parsing and CSS support in EPUBs (#411) ## Summary * **What is the goal of this PR?** - Adds basic CSS parsing to EPUBs and determine the CSS rules when rendering to the screen so that text is styled correctly. Currently supports bold, underline, italics, margin, padding, and text alignment ## Additional Context - My main reason for wanting this is that the book I'm currently reading, Carl's Doomsday Scenario (2nd in the Dungeon Crawler Carl series), relies _a lot_ on styled text for telling parts of the story. When text is bolded, it's supposed to be a message that's rendered "on-screen" in the story. When characters are "chatting" with each other, the text is bolded and their names are underlined. Plus, normal emphasis is provided with italicizing words here and there. So, this greatly improves my experience reading this book on the Xteink, and I figured it was useful enough for others too. - For transparency: I'm a software engineer, but I'm mostly frontend and TypeScript/JavaScript. It's been _years_ since I did any C/C++, so I would not be surprised if I'm doing something dumb along the way in this code. Please don't hesitate to ask for changes if something looks off. I heavily relied on Claude Code for help, and I had a lot of inspiration from how [microreader](https://github.com/CidVonHighwind/microreader) achieves their CSS parsing and styling. I did give this as good of a code review as I could and went through everything, and _it works on my machine_ 😄 ### Before ![IMG_6271](https://github.com/user-attachments/assets/dba7554d-efb6-4d13-88bc-8b83cd1fc615) ![IMG_6272](https://github.com/user-attachments/assets/61ba2de0-87c9-4f39-956f-013da4fe20a4) ### After ![IMG_6268](https://github.com/user-attachments/assets/ebe11796-cca9-4a46-b9c7-0709c7932818) ![IMG_6269](https://github.com/user-attachments/assets/e89c33dc-ff47-4bb7-855e-863fe44b3202) --- ### AI Usage Did you use AI tools to help write this code? **YES**, Claude Code
2026-02-05 05:28:10 -05:00
~ChapterHtmlSlimParser() = default;
bool parseAndBuildPages();
void addLineToPage(std::shared_ptr<TextBlock> line);
};