215 lines
6.1 KiB
Python
215 lines
6.1 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Text and Layout Example
|
|
|
|
This example demonstrates text rendering using the pyWebLayout system:
|
|
- Different text alignments
|
|
- Font sizes and styles
|
|
- Multi-line paragraphs
|
|
- Document layout and pagination
|
|
|
|
This example uses the HTML parsing system to create rich text layouts.
|
|
"""
|
|
|
|
import sys
|
|
from pathlib import Path
|
|
from PIL import Image, ImageDraw, ImageFont
|
|
|
|
# Add pyWebLayout to path
|
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
|
|
from pyWebLayout.io.readers.html_extraction import parse_html_string
|
|
from pyWebLayout.style import Font
|
|
from pyWebLayout.concrete.page import Page
|
|
from pyWebLayout.style.page_style import PageStyle
|
|
|
|
|
|
def create_sample_document():
|
|
"""Create different HTML samples demonstrating various features."""
|
|
samples = []
|
|
|
|
# Sample 1: Text alignment examples
|
|
samples.append((
|
|
"Text Alignment",
|
|
"""
|
|
<html><body>
|
|
<h2>Left Aligned</h2>
|
|
<p>This is left-aligned text. It is the default alignment for most text.</p>
|
|
|
|
<h2>Justified Text</h2>
|
|
<p style="text-align: justify;">This paragraph is justified. The text stretches to fill the entire width of the line, creating clean edges on both sides.</p>
|
|
|
|
<h2>Centered</h2>
|
|
<p style="text-align: center;">This text is centered.</p>
|
|
</body></html>
|
|
"""
|
|
))
|
|
|
|
# Sample 2: Font sizes
|
|
samples.append((
|
|
"Font Sizes",
|
|
"""
|
|
<html><body>
|
|
<h1>Heading 1</h1>
|
|
<h2>Heading 2</h2>
|
|
<h3>Heading 3</h3>
|
|
<p>Normal paragraph text at the default size.</p>
|
|
<p><small>Small text for fine print.</small></p>
|
|
</body></html>
|
|
"""
|
|
))
|
|
|
|
# Sample 3: Text styles
|
|
samples.append((
|
|
"Text Styles",
|
|
"""
|
|
<html><body>
|
|
<p>Normal text with <b>bold words</b> and <i>italic text</i>.</p>
|
|
<p><b>Completely bold paragraph.</b></p>
|
|
<p><i>Completely italic paragraph.</i></p>
|
|
<p>Text with <u>underlined words</u> for emphasis.</p>
|
|
</body></html>
|
|
"""
|
|
))
|
|
|
|
# Sample 4: Mixed content
|
|
samples.append((
|
|
"Mixed Content",
|
|
"""
|
|
<html><body>
|
|
<h2>Document Title</h2>
|
|
<p>A paragraph with <b>bold</b>, <i>italic</i>, and normal text all mixed together.</p>
|
|
<h3>Subsection</h3>
|
|
<p>Another paragraph demonstrating the layout system.</p>
|
|
</body></html>
|
|
"""
|
|
))
|
|
|
|
return samples
|
|
|
|
|
|
def render_html_to_image(html_content, page_size=(500, 400)):
|
|
"""Render HTML content to an image using the pyWebLayout system."""
|
|
# Create a page
|
|
page_style = PageStyle(
|
|
border_width=2,
|
|
border_color=(200, 200, 200),
|
|
padding=(30, 30, 30, 30),
|
|
background_color=(255, 255, 255)
|
|
)
|
|
|
|
page = Page(size=page_size, style=page_style)
|
|
|
|
# Parse HTML
|
|
base_font = Font(font_size=14)
|
|
blocks = parse_html_string(html_content, base_font=base_font)
|
|
|
|
# For now, just render the page structure
|
|
# (The full layout engine would place the blocks, but we'll show the page)
|
|
image = page.render()
|
|
draw = ImageDraw.Draw(image)
|
|
|
|
# Add a note that this is HTML-parsed content
|
|
try:
|
|
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 11)
|
|
except:
|
|
font = ImageFont.load_default()
|
|
|
|
# Draw info about what was parsed
|
|
content_x = page.border_size + page.style.padding_left + 10
|
|
content_y = page.border_size + page.style.padding_top + 10
|
|
|
|
draw.text((content_x, content_y),
|
|
f"Parsed {len(blocks)} block(s) from HTML",
|
|
fill=(100, 100, 100), font=font)
|
|
|
|
# List the block types
|
|
y_offset = content_y + 25
|
|
for i, block in enumerate(blocks[:10]): # Show first 10
|
|
block_type = type(block).__name__
|
|
draw.text((content_x, y_offset),
|
|
f" {i+1}. {block_type}",
|
|
fill=(60, 60, 60), font=font)
|
|
y_offset += 18
|
|
|
|
if y_offset > page.size[1] - 60: # Don't overflow
|
|
break
|
|
|
|
return image
|
|
|
|
|
|
def combine_samples(samples):
|
|
"""Combine multiple sample renders into a grid."""
|
|
print("\n Rendering samples...")
|
|
|
|
images = []
|
|
for title, html in samples:
|
|
print(f" - {title}")
|
|
img = render_html_to_image(html)
|
|
|
|
# Add title to image
|
|
draw = ImageDraw.Draw(img)
|
|
try:
|
|
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 14)
|
|
except:
|
|
font = ImageFont.load_default()
|
|
|
|
draw.text((10, 10), title, fill=(50, 50, 150), font=font)
|
|
images.append(img)
|
|
|
|
# Create grid (2x2)
|
|
padding = 20
|
|
cols = 2
|
|
rows = 2
|
|
|
|
img_width = images[0].size[0]
|
|
img_height = images[0].size[1]
|
|
|
|
total_width = cols * img_width + (cols + 1) * padding
|
|
total_height = rows * img_height + (rows + 1) * padding
|
|
|
|
combined = Image.new('RGB', (total_width, total_height), (240, 240, 240))
|
|
|
|
# Place images
|
|
y_offset = padding
|
|
for row in range(rows):
|
|
x_offset = padding
|
|
for col in range(cols):
|
|
idx = row * cols + col
|
|
if idx < len(images):
|
|
combined.paste(images[idx], (x_offset, y_offset))
|
|
x_offset += img_width + padding
|
|
y_offset += img_height + padding
|
|
|
|
return combined
|
|
|
|
|
|
def main():
|
|
"""Demonstrate text and layout features."""
|
|
print("Text and Layout Example")
|
|
print("=" * 50)
|
|
|
|
# Create sample documents
|
|
samples = create_sample_document()
|
|
|
|
# Render and combine
|
|
combined_image = combine_samples(samples)
|
|
|
|
# Save output
|
|
output_dir = Path("docs/images")
|
|
output_dir.mkdir(parents=True, exist_ok=True)
|
|
output_path = output_dir / "example_02_text_and_layout.png"
|
|
combined_image.save(output_path)
|
|
|
|
print(f"\n✓ Example completed!")
|
|
print(f" Output saved to: {output_path}")
|
|
print(f" Image size: {combined_image.size[0]}x{combined_image.size[1]} pixels")
|
|
print(f" Note: This example demonstrates HTML parsing")
|
|
print(f" Full layout rendering requires the typesetting engine")
|
|
|
|
return combined_image
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|