Duncan Tourolle 70c0b4a1f2
All checks were successful
Python CI / test (3.12) (push) Successful in 7m1s
Python CI / test (3.13) (push) Successful in 7m10s
HW integratation
2025-11-11 11:57:39 +01:00
2025-11-09 15:19:43 +01:00
2025-11-10 18:22:44 +01:00
2025-11-11 11:57:39 +01:00
2025-11-11 11:57:39 +01:00
2025-11-11 11:57:39 +01:00
2025-11-11 11:57:39 +01:00
2025-11-09 15:42:51 +01:00
2025-11-11 11:57:39 +01:00
2025-11-11 11:57:39 +01:00
2025-11-09 22:06:06 +01:00
2025-11-11 11:57:39 +01:00
2025-11-11 11:57:39 +01:00
2025-11-11 11:57:39 +01:00
2025-11-11 11:57:39 +01:00
2025-11-07 18:47:10 +01:00
2025-11-08 20:12:20 +01:00
2025-11-11 11:57:39 +01:00
2025-11-09 22:06:06 +01:00
2025-11-11 11:57:39 +01:00

DReader Application

Project Status

Badge Description
Test Coverage Test Coverage - Percentage of code covered by unit tests
Documentation Coverage Documentation Coverage - Percentage of code with docstrings
License License - Project licensing information

Description

DReader Application is a complete, production-ready ebook reader built on 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.

Key Features

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
  • 📋 Unified Overlays - Navigation (TOC + Bookmarks) and Settings overlays
  • 📊 Progress Tracking - Real-time reading progress percentage

Text Interaction

  • 🎨 Text Highlighting - Highlight words and text selections with custom colors
  • 💡 Highlight Notes - Attach notes and annotations to highlights
  • 🔍 Text Selection - Select words or ranges via pixel coordinates
  • 👆 Gesture Support - Handle tap, swipe, pinch, long-press events
  • 🎯 Pixel Queries - Query text content at any screen position

Customization & Display

  • 🔤 Font Control - Dynamically adjust font size with live preview
  • 📏 Spacing Control - Customize line and paragraph spacing
  • 💾 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

# Clone the repository
git clone https://gitea.tourolle.paris/dtourolle/dreader-application.git
cd dreader-application

# Install in development mode
pip install -e .

# Or install with dev dependencies
pip install -e ".[dev]"

The pyWebLayout dependency will be automatically installed from the git repository.

DReader in Action

Here are animated demonstrations of the key features:

Page Navigation
Page Navigation
Forward and backward navigation through pages
Font Size Adjustment
Font Size
Dynamic font size scaling with position preservation
Chapter Navigation
Chapter Navigation
Jump directly to chapters by title or index
Bookmarks & Positions
Bookmarks
Save and restore reading positions anywhere in the book
Text Highlighting
Highlighting
Highlight words and selections with custom colors and notes
TOC Overlay
TOC Overlay
Interactive table of contents with gesture-based navigation

Quick Start

from dreader.application import EbookReader

# Create an ebook reader
with EbookReader(page_size=(800, 1000)) as reader:
    # Load an EPUB file
    reader.load_epub("mybook.epub")

    # Get current page as PIL Image
    page = reader.get_current_page()
    page.save("page_001.png")

    # Navigate through pages
    reader.next_page()
    reader.previous_page()

    # Save reading position
    reader.save_position("chapter_3")

    # Jump to a chapter
    reader.jump_to_chapter("Chapter 5")

    # Adjust font size
    reader.increase_font_size()

    # Highlight text at coordinates
    highlight_id = reader.highlight_word(x=200, y=300, note="Important!")

    # Get progress
    progress = reader.get_reading_progress()
    print(f"Progress: {progress*100:.1f}%")

API Overview

Loading Content

reader.load_epub("book.epub")
reader.is_loaded()  # Check if book loaded
reader.get_book_info()  # Get metadata (title, author, etc.)

Navigation

reader.next_page()
reader.previous_page()
reader.jump_to_chapter("Chapter 1")  # By title
reader.jump_to_chapter(0)  # By index
reader.get_chapters()  # List all chapters
reader.get_current_chapter_info()
reader.get_reading_progress()  # Returns 0.0 to 1.0

# Navigation Overlay (unified TOC + Bookmarks)
overlay_image = reader.open_navigation_overlay()  # Opens with tabs
reader.close_overlay()
reader.is_overlay_open()

Styling & Display

reader.increase_font_size()
reader.decrease_font_size()
reader.set_font_size(1.5)  # 150% scale
reader.get_font_size()

reader.set_line_spacing(8)
reader.set_inter_block_spacing(20)

Bookmarks & Position Management

reader.save_position("my_bookmark")
reader.load_position("my_bookmark")
reader.list_saved_positions()
reader.delete_position("my_bookmark")

Text Highlighting

from pyWebLayout.core.highlight import HighlightColor

# Highlight a word at pixel coordinates
highlight_id = reader.highlight_word(
    x=100,
    y=200,
    color=HighlightColor.YELLOW,
    note="Important concept!"
)

# Highlight a text selection
highlight_id = reader.highlight_selection(
    start=(100, 200),
    end=(300, 250),
    color=(255, 255, 0, 128)  # RGBA
)

# Query word at position
result = reader.query_pixel(x=200, y=300)
if result:
    print(f"Word: {result.word.text}")

# Manage highlights
highlights = reader.list_highlights()
reader.remove_highlight(highlight_id)
reader.clear_highlights()
reader.get_highlights_for_current_page()

Gesture Handling

from dreader.gesture import TouchEvent, GestureType, ActionType

# Handle touch input
event = TouchEvent(GestureType.TAP, x=400, y=300)
response = reader.handle_touch(event)

# Response contains action type and data
if response.action == ActionType.PAGE_TURN:
    print(f"Page turned: {response.data['direction']}")
elif response.action == ActionType.WORD_SELECTED:
    print(f"Word selected: {response.data['word']}")
elif response.action == ActionType.CHAPTER_SELECTED:
    print(f"Chapter selected: {response.data['chapter_title']}")

# Supported gestures:
# - TAP: Select words, activate links, navigate TOC
# - LONG_PRESS: Show definitions or context menu
# - SWIPE_LEFT/RIGHT: Page navigation
# - 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

Settings Persistence

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()

# 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

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:

Basic Examples

Text Highlighting

Overlays

Library & State

Advanced

Architecture

DReader Application is a high-level application layer that combines pyWebLayout's low-level components:

dreader.application.EbookReader (High-Level API)
    ↓
├── pyWebLayout.layout.EreaderLayoutManager  # Layout engine & pagination
├── pyWebLayout.layout.EreaderLayout         # Bidirectional layout
├── pyWebLayout.core.HighlightManager        # Highlighting system
├── pyWebLayout.io.gesture                   # Touch/gesture handling
└── 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:

  • Text rendering and layout algorithms
  • Document structure and pagination
  • Query systems for interactive content
  • Core rendering infrastructure

DReader Application is an application framework that:

  • Combines pyWebLayout components into a complete reader
  • Provides user-friendly APIs for common ereader tasks
  • Manages application state (bookmarks, highlights, positions)
  • Handles business logic for gestures and interactions

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
  • 🌐 Web-based Readers - Serve rendered pages via Flask/FastAPI
  • 📟 E-ink Device Firmware - Optimized rendering for e-ink displays
  • 📊 Reading Analytics - Track reading patterns, highlights, and engagement
  • 🎓 Educational Tools - Create annotated reading experiences with highlights and notes
  • 🔬 Research Applications - Build specialized reading tools for academic work

Development

# Install in development mode with dev dependencies
pip install -e ".[dev]"

# Run tests
pytest

# Run tests with coverage
pytest --cov=dreader --cov-report=html

# Format code
black dreader/ tests/

# Type checking
mypy dreader/

# Linting
flake8 dreader/ tests/

Running Examples

# Ensure you have an EPUB file for testing
cd examples

# Run simple example
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

Testing

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
# Run all tests
pytest

# Run specific test file
pytest tests/test_ereader_application.py

# Run with verbose output
pytest -v

# Run with coverage report
pytest --cov=dreader --cov-report=term-missing

Hardware Integration

DReader includes complete hardware support for e-ink displays via the dreader-hal library.

Supported Hardware

  • Display: IT8951 e-ink controller (1872×1404)
  • Touch: FT5316 capacitive touch panel
  • Buttons: GPIO buttons (configurable)
  • Sensors: BMA400 accelerometer, PCF8523 RTC, INA219 power monitor

Quick Setup on Raspberry Pi

# 1. Clone and install
git clone https://gitea.tourolle.paris/dtourolle/dreader-application.git
cd dreader-application
python3 -m venv venv
source venv/bin/activate
pip install -e .
./install_hardware_drivers.sh

# 2. Interactive hardware setup
sudo python3 setup_rpi.py

# 3. Run on hardware
python examples/run_on_hardware_config.py

Hardware Configuration

The repository includes a pre-configured hardware_config.json for the reference hardware:

  • Buttons: GPIO 22 (prev), GPIO 27 (next), GPIO 21 (power)
  • Display: 1872×1404 IT8951 e-ink
  • I2C Bus: GPIO 2/3 (touch, sensors, RTC, power)

See HARDWARE_SETUP.md for complete wiring diagrams and setup instructions.

HAL Architecture

from dreader.hal_hardware import HardwareDisplayHAL
from dreader.main import DReaderApplication, AppConfig

# Hardware HAL with GPIO buttons
hal = HardwareDisplayHAL(width=1872, height=1404, vcom=-2.0)
config = AppConfig(display_hal=hal, library_path="~/Books")
app = DReaderApplication(config)

Available HAL Implementations:

  • HardwareDisplayHAL - Real e-ink hardware (IT8951 + dreader-hal)
  • PygameDisplayHAL - Desktop testing with pygame window

See HARDWARE_PINOUT.md for pin assignments and GPIO_BUTTONS.md for button configuration.

Documentation

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!

How to Contribute

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Make your changes with tests
  4. Run tests and ensure coverage stays high
  5. Format code with black
  6. Submit a pull request

License

MIT License - see LICENSE file for details

Author

Duncan Tourolle - duncan@tourolle.paris

Acknowledgments

Built with pyWebLayout - A powerful Python library for HTML-like layout and rendering.

Description
No description provided
Readme MIT 22 MiB
Languages
Python 99.5%
Shell 0.5%