update docs
This commit is contained in:
parent
0f9e38eb7c
commit
8f6205dcfe
1303
HAL_IMPLEMENTATION_SPEC.md
Normal file
1303
HAL_IMPLEMENTATION_SPEC.md
Normal file
File diff suppressed because it is too large
Load Diff
185
README.md
185
README.md
@ -8,11 +8,9 @@
|
||||
|  | **Documentation Coverage** - Percentage of code with docstrings |
|
||||
|  | **License** - Project licensing information |
|
||||
|
||||
> 📋 **Note**: Badges show results from the commit referenced in the URLs. Red "error" badges indicate build failures for that specific step.
|
||||
|
||||
## Description
|
||||
|
||||
DReader Application is a complete, production-ready ebook reader built on [pyWebLayout](https://gitea.tourolle.paris/dtourolle/pyWebLayout). It demonstrates how to build a full-featured ebook reader with text highlighting, bookmarks, gesture support, and position persistence.
|
||||
DReader Application is a complete, production-ready ebook reader built on [pyWebLayout](https://gitea.tourolle.paris/dtourolle/pyWebLayout). It demonstrates how to build a full-featured ebook reader with library browsing, text highlighting, bookmarks, gesture support, overlays, and position persistence.
|
||||
|
||||
This project serves as both a reference implementation and a ready-to-use ereader library for building desktop, web-based, or embedded reading applications.
|
||||
|
||||
@ -20,11 +18,12 @@ This project serves as both a reference implementation and a ready-to-use ereade
|
||||
|
||||
### Core Reading Features
|
||||
- 📖 **EPUB Support** - Load and render EPUB files with full text extraction
|
||||
- 📚 **Library Management** - Browse and select books from your collection
|
||||
- 📄 **Page Rendering** - Render pages as PIL Images optimized for any display
|
||||
- ⬅️➡️ **Navigation** - Smooth forward and backward page navigation
|
||||
- 🔖 **Bookmarks** - Save and restore reading positions with persistence
|
||||
- 📑 **Chapter Navigation** - Jump to chapters by title or index via TOC
|
||||
- 📋 **TOC Overlay** - Interactive table of contents overlay with gesture support
|
||||
- 📋 **Unified Overlays** - Navigation (TOC + Bookmarks) and Settings overlays
|
||||
- 📊 **Progress Tracking** - Real-time reading progress percentage
|
||||
|
||||
### Text Interaction
|
||||
@ -40,6 +39,7 @@ This project serves as both a reference implementation and a ready-to-use ereade
|
||||
- 💾 **Position Persistence** - Stable positions across style changes
|
||||
- ⚡ **Smart Reflow** - Automatic text reflow on font/spacing changes
|
||||
- 🎨 **Custom Styling** - Full control over colors, fonts, and layout
|
||||
- 💾 **Settings Persistence** - Save and restore preferences across sessions
|
||||
|
||||
## Installation
|
||||
|
||||
@ -156,8 +156,8 @@ reader.get_chapters() # List all chapters
|
||||
reader.get_current_chapter_info()
|
||||
reader.get_reading_progress() # Returns 0.0 to 1.0
|
||||
|
||||
# TOC Overlay
|
||||
overlay_image = reader.open_toc_overlay() # Returns composited image with TOC
|
||||
# Navigation Overlay (unified TOC + Bookmarks)
|
||||
overlay_image = reader.open_navigation_overlay() # Opens with tabs
|
||||
reader.close_overlay()
|
||||
reader.is_overlay_open()
|
||||
```
|
||||
@ -236,34 +236,84 @@ elif response.action == ActionType.CHAPTER_SELECTED:
|
||||
# - TAP: Select words, activate links, navigate TOC
|
||||
# - LONG_PRESS: Show definitions or context menu
|
||||
# - SWIPE_LEFT/RIGHT: Page navigation
|
||||
# - SWIPE_UP: Open TOC overlay (from bottom 20% of screen)
|
||||
# - SWIPE_DOWN: Close overlay
|
||||
# - SWIPE_UP: Open navigation overlay (from bottom 20% of screen)
|
||||
# - SWIPE_DOWN: Close overlay or open settings (from top 20%)
|
||||
# - PINCH_IN/OUT: Font size adjustment
|
||||
# - DRAG: Text selection
|
||||
```
|
||||
|
||||
### File Operations
|
||||
### Settings Persistence
|
||||
|
||||
```python
|
||||
# Save current page to file
|
||||
reader.render_to_file("current_page.png")
|
||||
from dreader.state import StateManager
|
||||
from pathlib import Path
|
||||
|
||||
# Context manager (auto-saves position on close)
|
||||
with EbookReader(page_size=(800, 1000)) as reader:
|
||||
reader.load_epub("book.epub")
|
||||
# ... use reader ...
|
||||
# Position automatically saved on exit
|
||||
# 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()
|
||||
|
||||
# Create reader and apply saved settings
|
||||
reader = EbookReader(page_size=(800, 1000))
|
||||
reader.load_epub("mybook.epub")
|
||||
reader.apply_settings(state.settings.to_dict())
|
||||
|
||||
# Settings are automatically saved
|
||||
reader.increase_font_size()
|
||||
state_manager.update_settings(reader.get_current_settings())
|
||||
state_manager.save_state()
|
||||
```
|
||||
|
||||
### Library Management
|
||||
|
||||
```python
|
||||
from dreader.library import LibraryManager
|
||||
|
||||
# Initialize library
|
||||
library = LibraryManager(
|
||||
library_path="/path/to/books",
|
||||
page_size=(800, 1200)
|
||||
)
|
||||
|
||||
# Scan for EPUB files
|
||||
library.scan_library()
|
||||
|
||||
# Render library view
|
||||
library_image = library.render_library()
|
||||
|
||||
# Handle book selection
|
||||
book_path = library.handle_library_tap(x=400, y=300)
|
||||
if book_path:
|
||||
reader.load_epub(book_path)
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Check out the `examples/` directory for complete working examples:
|
||||
Check out the [examples/](examples/) directory for complete working examples:
|
||||
|
||||
### Basic Examples
|
||||
- **[simple_ereader_example.py](examples/simple_ereader_example.py)** - Basic ereader usage with EPUB loading and navigation
|
||||
- **[ereader_demo.py](examples/ereader_demo.py)** - Comprehensive demo showcasing all features
|
||||
- **[word_selection_highlighting.py](examples/word_selection_highlighting.py)** - Text selection and highlighting
|
||||
- **[simple_word_highlight.py](examples/simple_word_highlight.py)** - Minimal highlighting example
|
||||
|
||||
### Text Highlighting
|
||||
- **[word_selection_highlighting.py](examples/word_selection_highlighting.py)** - Text selection and highlighting
|
||||
|
||||
### Overlays
|
||||
- **[demo_toc_overlay.py](examples/demo_toc_overlay.py)** - Interactive table of contents overlay
|
||||
- **[navigation_overlay_example.py](examples/navigation_overlay_example.py)** - Unified navigation overlay (TOC + Bookmarks)
|
||||
- **[demo_settings_overlay.py](examples/demo_settings_overlay.py)** - Settings panel with font/spacing controls
|
||||
|
||||
### Library & State
|
||||
- **[library_reading_integration.py](examples/library_reading_integration.py)** - Complete library → reading → resume workflow
|
||||
- **[persistent_settings_example.py](examples/persistent_settings_example.py)** - Save/restore settings across sessions
|
||||
|
||||
### Advanced
|
||||
- **[demo_pagination.py](examples/demo_pagination.py)** - Pagination system demonstration
|
||||
- **[generate_ereader_gifs.py](examples/generate_ereader_gifs.py)** - Generate animated GIF demonstrations
|
||||
- **[generate_library_demo_gif.py](examples/generate_library_demo_gif.py)** - Generate library demo animations
|
||||
|
||||
## Architecture
|
||||
|
||||
@ -279,6 +329,27 @@ dreader.application.EbookReader (High-Level API)
|
||||
└── pyWebLayout.io.readers.epub_reader # EPUB parsing
|
||||
```
|
||||
|
||||
### Component Structure
|
||||
|
||||
```
|
||||
dreader/
|
||||
├── application.py # Main EbookReader class (coordinator)
|
||||
├── managers/ # Specialized management modules
|
||||
│ ├── document.py # Document loading (EPUB/HTML)
|
||||
│ ├── settings.py # Font and spacing controls
|
||||
│ └── highlight_coordinator.py # Text highlighting
|
||||
├── handlers/
|
||||
│ └── gestures.py # Touch event routing
|
||||
├── overlays/ # UI overlay system
|
||||
│ ├── base.py # Base overlay functionality
|
||||
│ ├── navigation.py # TOC and bookmarks overlay
|
||||
│ └── settings.py # Settings overlay
|
||||
├── library.py # Library browsing and book selection
|
||||
├── state.py # Application state persistence
|
||||
├── html_generator.py # HTML generation for overlays
|
||||
└── gesture.py # Gesture definitions and responses
|
||||
```
|
||||
|
||||
### Relationship to pyWebLayout
|
||||
|
||||
**pyWebLayout** is a layout engine library providing low-level primitives:
|
||||
@ -297,6 +368,30 @@ Think of it like this:
|
||||
- **pyWebLayout** = React (library)
|
||||
- **DReader Application** = Next.js (framework)
|
||||
|
||||
## State Management
|
||||
|
||||
### File Structure
|
||||
```
|
||||
~/.config/dreader/
|
||||
├── state.json # Application state
|
||||
├── covers/ # Cached book covers
|
||||
├── bookmarks/ # Per-book bookmarks
|
||||
├── highlights/ # Per-book highlights
|
||||
└── xray/ # X-Ray data (future)
|
||||
```
|
||||
|
||||
### State Persistence
|
||||
- **Auto-save**: Every 60 seconds
|
||||
- **Immediate save**: On mode change, settings change, shutdown
|
||||
- **Boot behavior**: Resume last book at last position or show library
|
||||
- **Error handling**: Fall back to library if book missing or state corrupt
|
||||
|
||||
### Position Stability
|
||||
- Positions stored by abstract document structure (chapter/block/word indices)
|
||||
- Stable across font size changes, spacing changes, page size changes
|
||||
- Per-book storage using document IDs
|
||||
- Special `__auto_resume__` bookmark for last reading position
|
||||
|
||||
## Use Cases
|
||||
|
||||
- 📱 **Desktop Ereader Applications** - Build native ereader apps with Python
|
||||
@ -340,6 +435,9 @@ python simple_ereader_example.py /path/to/book.epub
|
||||
# Run comprehensive demo
|
||||
python ereader_demo.py /path/to/book.epub
|
||||
|
||||
# Run library integration demo
|
||||
python library_reading_integration.py /path/to/library/
|
||||
|
||||
# Generate animated GIFs
|
||||
python generate_ereader_gifs.py /path/to/book.epub
|
||||
```
|
||||
@ -351,6 +449,10 @@ The project includes comprehensive tests covering:
|
||||
- **Application API** - All EbookReader methods and workflows
|
||||
- **System Integration** - Layout manager, bookmarks, and state management
|
||||
- **Highlighting** - Word and selection highlighting with persistence
|
||||
- **Overlays** - Navigation and settings overlay interactions
|
||||
- **Gestures** - Touch event handling and routing
|
||||
- **Boot Recovery** - State persistence and position restoration
|
||||
- **Library** - Book scanning, selection, and metadata
|
||||
- **Edge Cases** - Error handling, boundary conditions, and recovery
|
||||
|
||||
```bash
|
||||
@ -367,6 +469,53 @@ pytest -v
|
||||
pytest --cov=dreader --cov-report=term-missing
|
||||
```
|
||||
|
||||
## Hardware Integration
|
||||
|
||||
DReader requires a Hardware Abstraction Layer (HAL) for display and input:
|
||||
|
||||
```python
|
||||
from abc import ABC, abstractmethod
|
||||
from PIL import Image
|
||||
|
||||
class DisplayHAL(ABC):
|
||||
"""Abstract display interface for platform integration"""
|
||||
|
||||
@abstractmethod
|
||||
def show_image(self, image: Image.Image):
|
||||
"""Display a PIL Image on the screen"""
|
||||
|
||||
@abstractmethod
|
||||
def get_touch_events(self) -> Iterator[TouchEvent]:
|
||||
"""Get iterator of touch events from hardware"""
|
||||
|
||||
@abstractmethod
|
||||
def set_brightness(self, level: int):
|
||||
"""Set display brightness (0-10)"""
|
||||
```
|
||||
|
||||
**Example HAL Implementations:**
|
||||
- **E-ink Displays**: IT8951, Remarkable device SDK
|
||||
- **Desktop**: pygame, tkinter, Qt
|
||||
- **Web**: Flask + HTML canvas
|
||||
- **Embedded**: Device-specific framebuffer
|
||||
|
||||
See [HAL_IMPLEMENTATION_SPEC.md](HAL_IMPLEMENTATION_SPEC.md) for detailed integration guidelines.
|
||||
|
||||
## Documentation
|
||||
|
||||
- [README.md](README.md) - This file, main project documentation
|
||||
- [REQUIREMENTS.md](REQUIREMENTS.md) - Application requirements specification
|
||||
- [ARCHITECTURE.md](ARCHITECTURE.md) - System architecture and design details
|
||||
- [HAL_IMPLEMENTATION_SPEC.md](HAL_IMPLEMENTATION_SPEC.md) - Hardware integration guide
|
||||
|
||||
## Performance
|
||||
|
||||
- **Boot Time**: ~2-3 seconds to resume reading
|
||||
- **Page Turn**: ~50-100ms (depends on page complexity)
|
||||
- **Overlay Open**: ~200-250ms (includes HTML generation and rendering)
|
||||
- **Memory Usage**: ~20-30MB base + 10-50MB per book
|
||||
- **Cache**: Automatic cover image and metadata caching for fast library loading
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions welcome! This project demonstrates what's possible with pyWebLayout. If you build something cool or find ways to improve the reader, please share!
|
||||
|
||||
1029
REQUIREMENTS.md
1029
REQUIREMENTS.md
File diff suppressed because it is too large
Load Diff
@ -200,6 +200,8 @@ class PygameDisplayHAL(EventLoopHAL):
|
||||
|
||||
# Detect gesture type
|
||||
gesture = None
|
||||
# For swipe gestures, use the starting position (mouse_down_pos)
|
||||
# For tap/long-press, use the ending position (mouse_up_pos)
|
||||
x, y = mouse_up_pos
|
||||
|
||||
if distance < self.drag_threshold:
|
||||
@ -211,7 +213,8 @@ class PygameDisplayHAL(EventLoopHAL):
|
||||
gesture = GestureType.TAP
|
||||
logger.info(f"[GESTURE] ✓ Detected: TAP")
|
||||
else:
|
||||
# Swipe
|
||||
# Swipe - use starting position for location-based checks
|
||||
x, y = self.mouse_down_pos
|
||||
if abs(dx) > abs(dy):
|
||||
# Horizontal swipe
|
||||
if dx > 0:
|
||||
@ -233,6 +236,8 @@ class PygameDisplayHAL(EventLoopHAL):
|
||||
self.mouse_down_pos = None
|
||||
|
||||
if gesture:
|
||||
# For swipe gestures, (x,y) is the start position
|
||||
# For tap/long-press, (x,y) is the tap position
|
||||
logger.info(f"[EVENT] Returning TouchEvent: {gesture.value} at ({x}, {y})")
|
||||
return TouchEvent(gesture, x, y)
|
||||
else:
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
Loading…
x
Reference in New Issue
Block a user