Duncan Tourolle c76f8696c7
All checks were successful
Python CI / test (3.12) (push) Successful in 7m4s
Python CI / test (3.13) (push) Successful in 6m59s
don't draw border
2025-11-10 15:15:22 +01:00
2025-11-09 15:19:43 +01:00
2025-11-10 15:15:22 +01:00
2025-11-09 22:06:06 +01:00
2025-11-10 14:31:19 +01:00
2025-11-09 15:42:51 +01:00
2025-11-09 22:06:06 +01:00
2025-11-07 18:47:10 +01:00
2025-11-08 20:12:20 +01:00
2025-11-09 22:06:06 +01:00
2025-11-09 22:06:06 +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 requires a Hardware Abstraction Layer (HAL) for display and input:

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 for detailed integration guidelines.

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%