update docs
Python CI / test (3.12) (push) Successful in 8m40s
Python CI / test (3.13) (push) Successful in 22m41s

This commit is contained in:
2025-11-09 22:06:06 +01:00
parent 0f9e38eb7c
commit 8f6205dcfe
6 changed files with 1606 additions and 1503 deletions
-164
View File
@@ -1,164 +0,0 @@
# Library Reading Demo
This directory contains scripts to demonstrate the complete LIBRARY ↔ READING workflow for the dreader e-reader application.
## Demo GIF
**File**: [`doc/images/library_reading_demo.gif`](../doc/images/library_reading_demo.gif) (591 KB, 800x1200 pixels)
### What the Demo Shows
The animated GIF demonstrates the complete user workflow:
1. **Library View** (2s)
- Shows a grid of available books
- Title: "📚 My Library - Select a book"
2. **Book Selection** (1.5s)
- Visual tap indicator on the first book
- Shows where user taps to select
3. **Reading Pages** (5 frames, ~5s total)
- Opens "Alice's Adventures in Wonderland"
- Shows 5 consecutive pages
- Page turns are animated
- Progress shown in header
4. **Settings Overlay** (2s)
- Shows settings panel with font controls
- Highlights "Back to Library" button
- Visual tap indicator showing where to click
5. **Return to Library** (2s)
- Book closes, position saved automatically
- Library view shown again
- Annotation: "Back to Library (position saved)"
6. **Reopen Book** (1.5s)
- User taps same book again
- Visual indicator shows reselection
7. **Auto-Resume** (3s)
- Book opens at saved position (24.6% progress)
- Shows the exact page where user left off
- Annotation: "✅ Auto-resumed at 24.6%"
**Total Duration**: ~17 seconds (looping)
## Scripts
### `generate_library_demo_gif.py`
Generate the demo GIF showing the complete workflow.
**Usage**:
```bash
python generate_library_demo_gif.py path/to/library [output.gif]
```
**Examples**:
```bash
# Generate to default location (doc/images/library_reading_demo.gif)
python generate_library_demo_gif.py tests/data/library-epub/
# Generate to custom location
python generate_library_demo_gif.py tests/data/library-epub/ doc/images/custom_demo.gif
```
**Features**:
- Automatic book scanning and cover extraction
- Visual tap indicators showing user interactions
- Annotations explaining each step
- Configurable frame durations
- Auto-resume demonstration
### `library_reading_integration.py`
Comprehensive integration test for the library ↔ reading workflow.
**Usage**:
```bash
python library_reading_integration.py path/to/library
```
**What it Tests**:
1. Library scanning and rendering
2. Book selection via tap
3. Book loading and reading
4. Page navigation (swipe gestures)
5. Settings overlay
6. Settings adjustments (font size)
7. Back to library button
8. Auto-resume functionality
9. Multiple book selection
**Output**: Generates PNG images for each step (8 images total)
## Implementation Status
### ✅ Complete Features
- **Library Management** ([library.py](../dreader/library.py))
- Book scanning and metadata extraction
- Cover image caching
- Interactive book selection
- Clickable book rows
- **Reading Mode** ([application.py](../dreader/application.py))
- EPUB rendering
- Page navigation (swipe, tap)
- Progress tracking
- Position saving/loading
- **State Persistence** ([state.py](../dreader/state.py))
- Auto-save on page turn
- Resume at last position
- Settings persistence
- Per-book bookmarks
- **Overlays**
- TOC (Table of Contents) - ✅ Working
- Settings - ✅ Working
- Bookmarks - ✅ Working
### 🚧 Known Issues
- **HTML Link Interactivity**: The "Back to Library" button in settings overlay doesn't respond to taps
- Root cause documented in [HTML_LINKS_INVESTIGATION.md](../HTML_LINKS_INVESTIGATION.md)
- Workaround: Will be implemented using programmatic UI generation
- Does not affect the demo GIF (which shows the intended workflow)
## Requirements
- Python 3.8+
- PIL/Pillow (for image generation)
- dreader application
- pyWebLayout library
- Test EPUB files in the library directory
## File Sizes
- Demo GIF: ~622 KB (optimized for quality)
- Integration test PNGs: ~50-170 KB each
- Total demo assets: <2 MB
## Demo Generation Time
- Library scanning: <1 second
- EPUB loading: <1 second
- Page rendering: ~0.5 seconds per page
- Total: ~10-15 seconds to generate complete GIF
## Use Cases
1. **Documentation**: Visual demonstration of application features
2. **Testing**: Verify complete workflow end-to-end
3. **Presentations**: Show stakeholders the user experience
4. **Debugging**: Identify issues in the workflow
5. **Training**: Help users understand the application flow
## See Also
- [REQUIREMENTS.md](../REQUIREMENTS.md) - Full application requirements
- [HTML_GENERATION.md](../HTML_GENERATION.md) - HTML rendering documentation
- [HTML_LINKS_INVESTIGATION.md](../HTML_LINKS_INVESTIGATION.md) - Link interactivity debugging
-421
View File
@@ -1,421 +0,0 @@
# EbookReader - Simple EPUB Reader Application
The `EbookReader` class provides a complete, user-friendly interface for building ebook reader applications with pyWebLayout. It wraps all the complex ereader infrastructure into a simple API.
## Features
- 📖 **EPUB Loading** - Load EPUB files with automatic content extraction
- ⬅️➡️ **Page Navigation** - Forward and backward page navigation
- 🔖 **Position Management** - Save/load reading positions (stable across font changes)
- 📑 **Chapter Navigation** - Jump to chapters by title or index
- 🔤 **Font Size Control** - Increase/decrease font size with live re-rendering
- 📏 **Spacing Control** - Adjust line, block, and word spacing
- 💾 **Persistent Settings** - Save and restore rendering preferences across sessions
- 📊 **Progress Tracking** - Get reading progress and position information
- 🎨 **Text Highlighting** - Highlight words and passages with colors
- 📋 **Overlays** - TOC, Settings, and Bookmarks overlays
- 🖱️ **Gesture Support** - Handle tap, swipe, pinch gestures
- 💾 **Context Manager Support** - Automatic cleanup with `with` statement
## Quick Start
```python
from pyWebLayout.layout.ereader_application import EbookReader
# Create reader
reader = EbookReader(page_size=(800, 1000))
# Load an EPUB
reader.load_epub("mybook.epub")
# Get current page as PIL Image
page_image = reader.get_current_page()
page_image.save("current_page.png")
# Navigate
reader.next_page()
reader.previous_page()
# Close reader
reader.close()
```
## API Reference
### Initialization
```python
reader = EbookReader(
page_size=(800, 1000), # Page dimensions (width, height) in pixels
margin=40, # Page margin in pixels
background_color=(255, 255, 255), # RGB background color
line_spacing=5, # Line spacing in pixels
inter_block_spacing=15, # Space between blocks in pixels
bookmarks_dir="ereader_bookmarks", # Directory for bookmarks
buffer_size=5 # Number of pages to cache
)
```
### Loading EPUB
```python
# Load EPUB file
success = reader.load_epub("path/to/book.epub")
# Check if book is loaded
if reader.is_loaded():
print("Book loaded successfully")
# Get book information
book_info = reader.get_book_info()
# Returns: {
# 'title': 'Book Title',
# 'author': 'Author Name',
# 'document_id': 'book',
# 'total_blocks': 5000,
# 'total_chapters': 20,
# 'page_size': (800, 1000),
# 'font_scale': 1.0
# }
```
### Page Navigation
```python
# Get current page as PIL Image
page = reader.get_current_page()
# Navigate to next page
page = reader.next_page() # Returns None at end of book
# Navigate to previous page
page = reader.previous_page() # Returns None at beginning
# Save current page to file
reader.render_to_file("page.png")
```
### Position Management
Positions are saved based on abstract document structure (chapter/block/word indices), making them stable across font size and styling changes.
```python
# Save current position
reader.save_position("my_bookmark")
# Load saved position
page = reader.load_position("my_bookmark")
# List all saved positions
positions = reader.list_saved_positions()
# Returns: ['my_bookmark', 'chapter_2', ...]
# Delete a position
reader.delete_position("my_bookmark")
# Get detailed position info
info = reader.get_position_info()
# Returns: {
# 'position': {'chapter_index': 0, 'block_index': 42, 'word_index': 15, ...},
# 'chapter': {'title': 'Chapter 1', 'level': 'H1', ...},
# 'progress': 0.15, # 15% through the book
# 'font_scale': 1.0,
# 'book_title': 'Book Title',
# 'book_author': 'Author Name'
# }
# Get reading progress (0.0 to 1.0)
progress = reader.get_reading_progress()
print(f"You're {progress*100:.1f}% through the book")
```
### Chapter Navigation
```python
# Get all chapters
chapters = reader.get_chapters()
# Returns: [('Chapter 1', 0), ('Chapter 2', 1), ...]
# Get chapters with positions
chapter_positions = reader.get_chapter_positions()
# Returns: [('Chapter 1', RenderingPosition(...)), ...]
# Jump to chapter by index
page = reader.jump_to_chapter(1) # Jump to second chapter
# Jump to chapter by title
page = reader.jump_to_chapter("Chapter 1")
# Get current chapter info
chapter_info = reader.get_current_chapter_info()
# Returns: {'title': 'Chapter 1', 'level': HeadingLevel.H1, 'block_index': 0}
```
### Font Size Control
```python
# Get current font size scale
scale = reader.get_font_size() # Default: 1.0
# Set specific font size scale
page = reader.set_font_size(1.5) # 150% of normal size
# Increase font size by 10%
page = reader.increase_font_size()
# Decrease font size by 10%
page = reader.decrease_font_size()
```
### Spacing Control
```python
# Set line spacing (spacing between lines within a paragraph)
page = reader.set_line_spacing(10) # 10 pixels
# Set inter-block spacing (spacing between paragraphs, headings, etc.)
page = reader.set_inter_block_spacing(20) # 20 pixels
```
### Context Manager
The reader supports Python's context manager protocol for automatic cleanup:
```python
with EbookReader(page_size=(800, 1000)) as reader:
reader.load_epub("book.epub")
page = reader.get_current_page()
# ... do stuff
# Automatically saves position and cleans up resources
```
## Complete Example
```python
from pyWebLayout.layout.ereader_application import EbookReader
# Create reader with custom settings
with EbookReader(
page_size=(800, 1000),
margin=50,
line_spacing=8,
inter_block_spacing=20
) as reader:
# Load EPUB
if not reader.load_epub("my_novel.epub"):
print("Failed to load EPUB")
exit(1)
# Get book info
info = reader.get_book_info()
print(f"Reading: {info['title']} by {info['author']}")
print(f"Total chapters: {info['total_chapters']}")
# Navigate through first few pages
for i in range(5):
page = reader.get_current_page()
page.save(f"page_{i+1:03d}.png")
reader.next_page()
# Save current position
reader.save_position("page_5")
# Jump to a chapter
chapters = reader.get_chapters()
if len(chapters) > 2:
print(f"Jumping to: {chapters[2][0]}")
reader.jump_to_chapter(2)
reader.render_to_file("chapter_3_start.png")
# Return to saved position
reader.load_position("page_5")
# Adjust font size
reader.increase_font_size()
reader.render_to_file("page_5_larger_font.png")
# Get progress
progress = reader.get_reading_progress()
print(f"Reading progress: {progress*100:.1f}%")
```
## Persistent Settings
Settings like font size and spacing are automatically saved and restored across sessions:
```python
from dreader import EbookReader
from dreader.state import StateManager
from pathlib import Path
# Initialize state manager
state_file = Path.home() / ".config" / "dreader" / "state.json"
state_manager = StateManager(state_file=state_file)
# Load saved state
state = state_manager.load_state()
print(f"Saved font scale: {state.settings.font_scale}")
# Create reader with saved settings
reader = EbookReader(
line_spacing=state.settings.line_spacing,
inter_block_spacing=state.settings.inter_block_spacing
)
# Load book and apply all saved settings
reader.load_epub("mybook.epub")
reader.apply_settings(state.settings.to_dict())
# User changes settings...
reader.increase_font_size()
reader.set_line_spacing(10)
# Save new settings for next session
current_settings = reader.get_current_settings()
state_manager.update_settings(current_settings)
state_manager.save_state()
# Next time the app starts, these settings will be restored!
```
See [persistent_settings_example.py](persistent_settings_example.py) for a complete demonstration.
## Demo Scripts
Run these demos to see features in action:
```bash
# Comprehensive feature demo
python examples/ereader_demo.py path/to/book.epub
# Persistent settings demo
python examples/persistent_settings_example.py
# TOC overlay demo (generates animated GIF)
python examples/demo_toc_overlay.py
# Settings overlay demo (generates animated GIF)
python examples/demo_settings_overlay.py
# Word highlighting examples
python examples/word_selection_highlighting.py
```
This will demonstrate:
- Basic page navigation
- Position save/load
- Chapter navigation
- Font size adjustments
- Spacing adjustments
- Book information retrieval
The demo generates multiple PNG files showing different pages and settings.
## Position Storage Format
Positions are stored as JSON files in the `bookmarks_dir` (default: `ereader_bookmarks/`):
```json
{
"chapter_index": 0,
"block_index": 42,
"word_index": 15,
"table_row": 0,
"table_col": 0,
"list_item_index": 0,
"remaining_pretext": null,
"page_y_offset": 0
}
```
This format is tied to the abstract document structure, making positions stable across:
- Font size changes
- Line spacing changes
- Inter-block spacing changes
- Page size changes
## Integration Example: Simple GUI
Here's a minimal example of integrating with Tkinter:
```python
import tkinter as tk
from tkinter import filedialog
from PIL import ImageTk
from pyWebLayout.layout.ereader_application import EbookReader
class SimpleEreaderGUI:
def __init__(self, root):
self.root = root
self.reader = EbookReader(page_size=(600, 800))
# Create UI
self.image_label = tk.Label(root)
self.image_label.pack()
btn_frame = tk.Frame(root)
btn_frame.pack()
tk.Button(btn_frame, text="Open EPUB", command=self.open_epub).pack(side=tk.LEFT)
tk.Button(btn_frame, text="Previous", command=self.prev_page).pack(side=tk.LEFT)
tk.Button(btn_frame, text="Next", command=self.next_page).pack(side=tk.LEFT)
tk.Button(btn_frame, text="Font+", command=self.increase_font).pack(side=tk.LEFT)
tk.Button(btn_frame, text="Font-", command=self.decrease_font).pack(side=tk.LEFT)
def open_epub(self):
filepath = filedialog.askopenfilename(filetypes=[("EPUB files", "*.epub")])
if filepath:
self.reader.load_epub(filepath)
self.display_page()
def display_page(self):
page = self.reader.get_current_page()
if page:
photo = ImageTk.PhotoImage(page)
self.image_label.config(image=photo)
self.image_label.image = photo
def next_page(self):
if self.reader.next_page():
self.display_page()
def prev_page(self):
if self.reader.previous_page():
self.display_page()
def increase_font(self):
self.reader.increase_font_size()
self.display_page()
def decrease_font(self):
self.reader.decrease_font_size()
self.display_page()
root = tk.Tk()
root.title("Simple Ereader")
app = SimpleEreaderGUI(root)
root.mainloop()
```
## Performance Notes
- The reader uses intelligent page caching for fast navigation
- First page load may take ~1 second, subsequent pages are typically < 0.1 seconds
- Background rendering attempts to pre-cache upcoming pages (you may see pickle warnings, which can be ignored)
- Font size changes invalidate the cache and require re-rendering from the current position
- Position save/load is nearly instantaneous
## Limitations
- Currently supports EPUB files only (no PDF, MOBI, etc.)
- Images in EPUBs may not render in some cases
- Tables are skipped in rendering
- Complex HTML layouts may not render perfectly
- No text selection or search functionality (these would need to be added separately)
## See Also
- `examples/ereader_demo.py` - Comprehensive feature demonstration
- `pyWebLayout/layout/ereader_manager.py` - Underlying manager class
- `pyWebLayout/layout/ereader_layout.py` - Core layout engine
- `examples/README_EPUB_RENDERERS.md` - Lower-level EPUB rendering