pyWebLayout/examples/generate_readme_font_demo.py
2025-11-12 12:03:27 +00:00

253 lines
7.8 KiB
Python

"""
Generate a demo image for README.md showing font family switching feature.
Creates a side-by-side comparison of the same content rendered in
Sans, Serif, and Monospace fonts.
"""
from pyWebLayout.abstract import Paragraph, Heading, Word
from pyWebLayout.abstract.block import HeadingLevel
from pyWebLayout.style import Font
from pyWebLayout.style.fonts import BundledFont, FontWeight
from pyWebLayout.style.page_style import PageStyle
from pyWebLayout.layout.ereader_manager import create_ereader_manager
from PIL import Image, ImageDraw, ImageFont
def create_demo_content():
"""Create concise demo content that fits nicely on a small page"""
blocks = []
# Title
title_font = Font.from_family(BundledFont.SANS, font_size=28, weight=FontWeight.BOLD)
title = Heading(level=HeadingLevel.H1, style=title_font)
for word in "The Adventure Begins".split():
title.add_word(Word(word, title_font))
blocks.append(title)
# Paragraph
body_font = Font.from_family(BundledFont.SANS, font_size=14)
para = Paragraph(body_font)
text = (
"In the quiet village of Millbrook, young Emma discovered an ancient map "
"hidden in her grandmother's attic. The parchment revealed a mysterious "
"forest path marked with symbols she had never seen before. With courage "
"in her heart and the map in her pocket, she set out at dawn to uncover "
"the secrets that lay beyond the old oak trees."
)
for word in text.split():
para.add_word(Word(word, body_font))
blocks.append(para)
return blocks
def render_with_font_family(blocks, page_size, font_family, family_name):
"""Render a page with a specific font family"""
manager = create_ereader_manager(
blocks,
page_size,
document_id=f"demo_{family_name.lower()}"
)
# Set font family (None means original/default)
manager.set_font_family(font_family)
# Get the first page
page = manager.get_current_page()
return page.render()
def create_comparison_image():
"""Create a side-by-side comparison of all three font families"""
# Page size for each panel
page_width = 400
page_height = 300
# Create demo content
print("Creating demo content...")
blocks = create_demo_content()
# Render with each font family
print("Rendering with Sans font...")
sans_image = render_with_font_family(
blocks, (page_width, page_height), BundledFont.SANS, "Sans"
)
print("Rendering with Serif font...")
serif_image = render_with_font_family(
blocks, (page_width, page_height), BundledFont.SERIF, "Serif"
)
print("Rendering with Monospace font...")
mono_image = render_with_font_family(
blocks, (page_width, page_height), BundledFont.MONOSPACE, "Monospace"
)
# Create a composite image with all three side by side
spacing = 20
label_height = 30
total_width = page_width * 3 + spacing * 4
total_height = page_height + label_height + spacing * 2
composite = Image.new('RGB', (total_width, total_height), color='#f5f5f5')
# Paste the three images
x_positions = [
spacing,
spacing * 2 + page_width,
spacing * 3 + page_width * 2
]
for img, x_pos in zip([sans_image, serif_image, mono_image], x_positions):
composite.paste(img, (x_pos, label_height + spacing))
# Add labels
draw = ImageDraw.Draw(composite)
# Try to use a nice font, fallback to default if not available
try:
label_font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 20)
except:
label_font = ImageFont.load_default()
labels = ["Sans-Serif", "Serif", "Monospace"]
for label, x_pos in zip(labels, x_positions):
# Calculate text position to center it
bbox = draw.textbbox((0, 0), label, font=label_font)
text_width = bbox[2] - bbox[0]
text_x = x_pos + (page_width - text_width) // 2
draw.text((text_x, 5), label, fill='#333333', font=label_font)
# Save the image
output_path = "docs/images/font_family_switching.png"
composite.save(output_path, quality=95)
print(f"\n✓ Saved demo image to: {output_path}")
print(f" Image size: {total_width}x{total_height}")
return output_path
def create_single_vertical_comparison():
"""Create a vertical comparison that's better for README"""
# Page size for each panel
page_width = 700
page_height = 280
# Create demo content
print("\nCreating vertical comparison for README...")
blocks = create_demo_content()
# Render with each font family
print(" Rendering Sans...")
sans_image = render_with_font_family(
blocks, (page_width, page_height), BundledFont.SANS, "Sans"
)
print(" Rendering Serif...")
serif_image = render_with_font_family(
blocks, (page_width, page_height), BundledFont.SERIF, "Serif"
)
print(" Rendering Monospace...")
mono_image = render_with_font_family(
blocks, (page_width, page_height), BundledFont.MONOSPACE, "Monospace"
)
# Create a composite image stacked vertically
spacing = 15
label_width = 120
total_width = page_width + label_width + spacing * 2
total_height = page_height * 3 + spacing * 4
composite = Image.new('RGB', (total_width, total_height), color='#ffffff')
# Add a subtle border
draw = ImageDraw.Draw(composite)
draw.rectangle([(0, 0), (total_width-1, total_height-1)], outline='#e0e0e0', width=1)
# Paste the three images vertically
y_positions = [
spacing,
spacing * 2 + page_height,
spacing * 3 + page_height * 2
]
images_data = [
(sans_image, "Sans-Serif", "#4A90E2"),
(serif_image, "Serif", "#E94B3C"),
(mono_image, "Monospace", "#50C878")
]
# Try to use a nice font
try:
label_font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 16)
small_font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 11)
except:
label_font = ImageFont.load_default()
small_font = ImageFont.load_default()
for (img, label, color), y_pos in zip(images_data, y_positions):
# Paste the page image
composite.paste(img, (label_width + spacing, y_pos))
# Draw label background
draw.rectangle(
[(spacing, y_pos + 10), (label_width, y_pos + 40)],
fill=color
)
# Draw label text
draw.text(
(spacing + 10, y_pos + 17),
label,
fill='#ffffff',
font=label_font
)
# Draw font description
descriptions = {
"Sans-Serif": "Clean & Modern",
"Serif": "Classic & Formal",
"Monospace": "Code & Technical"
}
draw.text(
(spacing + 5, y_pos + 50),
descriptions[label],
fill='#666666',
font=small_font
)
# Save the image
output_path = "docs/images/font_family_switching_vertical.png"
composite.save(output_path, quality=95)
print(f" ✓ Saved: {output_path}")
print(f" Size: {total_width}x{total_height}")
return output_path
if __name__ == "__main__":
print("=" * 70)
print("Generating README Demo Images")
print("=" * 70)
# Create both versions
horizontal_path = create_comparison_image()
vertical_path = create_single_vertical_comparison()
print("\n" + "=" * 70)
print("Demo images generated successfully!")
print("=" * 70)
print(f"\nHorizontal comparison: {horizontal_path}")
print(f"Vertical comparison: {vertical_path}")
print("\nRecommended for README: vertical version")
print("\nMarkdown snippet:")
print("```markdown")
print("![Font Family Switching](docs/images/font_family_switching_vertical.png)")
print("```")
print()