dreader-application/examples/README_EREADER.md

10 KiB

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 and block spacing
  • 📊 Progress Tracking - Get reading progress and position information
  • 💾 Context Manager Support - Automatic cleanup with with statement

Quick Start

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

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

# 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

# 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.

# 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

# 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

# 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

# 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:

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

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}%")

Demo Script

Run the comprehensive demo to see all features in action:

python examples/ereader_demo.py path/to/book.epub

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/):

{
  "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:

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