Recognize and use printed pages info
This commit is contained in:
@@ -159,6 +159,43 @@ When `startNewTextBlock` reuses an empty text block (the early-return path), `wo
|
||||
|
||||
`scripts/generate_spine_toc_edges_epub.py` generates `test/epubs/test_spine_toc_edges.epub`, a purpose-built epub that exercises spine/TOC relationship patterns. See the script header for the full list of edge cases covered.
|
||||
|
||||
## Printed-page labels (status bar hint)
|
||||
|
||||
The status bar can show the printed-book page number for the current rendered page in addition to the device-relative `currentPage/pageCount` counter, e.g. `(42) 137/305 18%`. The printed-page label is sourced from the EPUB itself; the device counter remains authoritative for spine pagination.
|
||||
|
||||
### Three input formats
|
||||
|
||||
The reader accepts printed-page data from three places, in priority order:
|
||||
|
||||
1. **Inline `doc-pagebreak` markers** in the XHTML (EPUB 3 accessibility convention): any element with `role="doc-pagebreak"` or `epub:type="pagebreak"`. The visible label is read from `aria-label`, falling back to `title`, falling back to the NCX/nav/page-map label if cross-referenced.
|
||||
2. **EPUB 3 `<nav epub:type="page-list">`** in the nav document (`TocNavParser`).
|
||||
3. **NCX `<pageList>`** (EPUB 2 extension) and **`page-map.xml`** (EPUB 2.01, a separate top-level manifest item with media-type `application/oebps-page-map+xml`), both parsed by `TocNcxParser` / `PageMapParser`.
|
||||
|
||||
Only one of (2), (3a), or (3b) writes the cache file `<book-cache>/pagelist.bin`. The nav parser runs first; the NCX page-list is written only if the nav parser found nothing. The page-map parser runs last and is skipped if `pagelist.bin` already exists. Inline `doc-pagebreak` markers always take effect in addition to the cache file (they are matched at chapter parse time, independent of the cache).
|
||||
|
||||
### pagelist.bin format
|
||||
|
||||
Written once per book at index time; consumed once per section build. Format:
|
||||
|
||||
```
|
||||
[uint16_t entryCount]
|
||||
[String href][String anchor][String label] // repeated entryCount times
|
||||
```
|
||||
|
||||
`href` is the normalised spine href (e.g. `OEBPS/c9_split_000.xhtml`). `anchor` is the fragment id (empty for "start of file"). `label` is the visible printed-page label (e.g. `"42"`, `"iv"`).
|
||||
|
||||
### Section parse path
|
||||
|
||||
When `Section::createSectionFile` runs for a chapter, it streams `pagelist.bin`, filters to entries whose `href` matches the current spine item, and passes the resulting `(anchor → label)` pairs to `ChapterHtmlSlimParser::setExternalPageBreakAnchors`. During parsing, an element whose `id=` matches a known external anchor is treated as if it carried an inline `doc-pagebreak` marker — the existing `recordPageBreakLabel()` path is reused. The NCX/nav/page-map "start of file" entries (empty anchor) emit their label on the very first element of the chapter.
|
||||
|
||||
### Section cache storage
|
||||
|
||||
The section cache file (`section.bin`) gained a `pageBreakMap` block: `uint16_t count`, then for each entry `uint16_t pageIndex` + `String label`. The header carries a `pageBreakMapOffset` between `anchorMapOffset` and `paragraphLutOffset`. On reload, `Section::buildPageBreakLabelsFromFile` populates `pageBreakLabels` for status-bar queries.
|
||||
|
||||
### Status bar lookup
|
||||
|
||||
`Section::getPrintedPageLabelForPage(devicePage)` returns the parenthesised label (e.g. `"(42)"`) for the rendered device page if one or more printed-page anchors land on it. When several labels co-occur on a single device page (short page contains both `page_7` and `page_8`), the result collapses to `"(7/8)"`. Returns `nullopt` when no printed-page anchor falls on this exact device page — in that case the status bar shows only the device counter.
|
||||
|
||||
## Performance characteristics
|
||||
|
||||
- **Per page turn**: All in-memory. `getTocIndexForPage` (binary search on 1-3 entries), `getTocItem` for title (one file seek to BookMetadataCache -- noted as a future optimization opportunity).
|
||||
|
||||
@@ -109,6 +109,14 @@ if (parsedSize != fileSize) {
|
||||
|
||||
## `section.bin`
|
||||
|
||||
### Current version
|
||||
|
||||
`SECTION_FILE_VERSION = 28`. The on-disk layout has evolved past the v21 pattern shown below; the ImHex pattern is preserved for archeology but no longer reflects all fields. Changes since v21 (read `lib/Epub/Epub/Section.cpp` `header::*` constants for the authoritative layout):
|
||||
|
||||
- `parseComplete` (`bool`) inserted before `pageCount` so a truncated parse can be detected on reload.
|
||||
- `paragraphLutOffset` extended: each per-page entry is now `u32 xhtmlByteOffset + u16 paragraphIndex + u16 listItemIndex` (added the running `<li>` count for KOReader list-item XPath sync).
|
||||
- `pageBreakMapOffset` (`u32`) added in the header between `anchorMapOffset` and `paragraphLutOffset`. The block at that offset stores printed-page labels: `u16 count`, then per entry `u16 pageIndex + String label`. Populated from inline `doc-pagebreak` markers and from the per-book `pagelist.bin` (NCX `<pageList>` / EPUB 3 `<nav epub:type="page-list">` / EPUB 2.01 `page-map.xml`). See `docs/epub-toc-navigation.md` for the source-format selection rules.
|
||||
|
||||
### Version 21
|
||||
|
||||
ImHex Pattern:
|
||||
@@ -251,3 +259,24 @@ if (parsedSize != fileSize) {
|
||||
std::warning(std::format("Unparsed data detected: {} bytes remaining at offset 0x{:X}", fileSize - parsedSize, parsedSize));
|
||||
}
|
||||
```
|
||||
|
||||
## `pagelist.bin`
|
||||
|
||||
Per-book cache file produced at index time from one of the EPUB printed-page sources (NCX `<pageList>`, EPUB 3 nav `<nav epub:type="page-list">`, or EPUB 2.01 `page-map.xml`). Consumed once per section build by `Section::createSectionFile`. Absent for books that have no printed-page data.
|
||||
|
||||
```
|
||||
u16 entryCount
|
||||
struct PageListEntry {
|
||||
String href; // normalised spine href, e.g. "OEBPS/c9_split_000.xhtml"
|
||||
String anchor; // fragment id; empty means "start of file"
|
||||
String label; // printed-page label, e.g. "42" or "iv"
|
||||
}
|
||||
PageListEntry entries[entryCount];
|
||||
```
|
||||
|
||||
Selection rules (see `docs/epub-toc-navigation.md`):
|
||||
|
||||
- The EPUB 3 nav page-list parser runs first.
|
||||
- The NCX `<pageList>` writer runs only if the nav writer produced nothing.
|
||||
- The EPUB 2.01 `page-map.xml` writer runs only if `pagelist.bin` doesn't already exist on disk.
|
||||
- Inline `doc-pagebreak` markers in XHTML are matched at chapter parse time and don't need the cache file; they coexist with whichever source above won.
|
||||
|
||||
Reference in New Issue
Block a user