313 lines
9.9 KiB
Python
313 lines
9.9 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Table Text Wrapping Example
|
|
|
|
This example demonstrates the line wrapping functionality in table cells:
|
|
- Tables with long text that wraps across multiple lines
|
|
- Automatic word wrapping within cell boundaries
|
|
- Hyphenation support for long words
|
|
- Multiple paragraphs per cell
|
|
- Comparison of narrow vs. wide columns
|
|
|
|
Shows how the Line-based text layout system handles text overflow in tables.
|
|
"""
|
|
|
|
from pyWebLayout.io.readers.html_extraction import parse_html_string
|
|
from pyWebLayout.layout.document_layouter import DocumentLayouter
|
|
from pyWebLayout.style.page_style import PageStyle
|
|
from pyWebLayout.concrete.table import TableStyle
|
|
from pyWebLayout.concrete.page import Page
|
|
import sys
|
|
from pathlib import Path
|
|
from PIL import Image
|
|
|
|
# Add pyWebLayout to path
|
|
sys.path.insert(0, str(Path(__file__).parent.parent))
|
|
|
|
|
|
def create_narrow_columns_example():
|
|
"""Create a table with narrow columns to show aggressive wrapping."""
|
|
print(" - Narrow columns with text wrapping")
|
|
|
|
html = """
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Feature</th>
|
|
<th>Description</th>
|
|
<th>Benefits</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>Automatic Line Wrapping</td>
|
|
<td>Text automatically wraps to fit within the available cell width, creating multiple lines as needed.</td>
|
|
<td>Improves readability and prevents horizontal overflow in tables.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Hyphenation Support</td>
|
|
<td>Long words are intelligently hyphenated using pyphen library or brute-force splitting when necessary.</td>
|
|
<td>Handles extraordinarily long words that wouldn't fit on a single line.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Multi-paragraph Cells</td>
|
|
<td>Each cell can contain multiple paragraphs or headings, all properly wrapped.</td>
|
|
<td>Allows rich content within table cells.</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
"""
|
|
|
|
return html, "Text Wrapping in Narrow Columns"
|
|
|
|
|
|
def create_mixed_content_example():
|
|
"""Create a table with both short and long content."""
|
|
print(" - Mixed content lengths")
|
|
|
|
html = """
|
|
<table>
|
|
<caption>Product Comparison</caption>
|
|
<thead>
|
|
<tr>
|
|
<th>Product</th>
|
|
<th>Short Description</th>
|
|
<th>Detailed Features</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>Widget Pro</td>
|
|
<td>Premium</td>
|
|
<td>Advanced functionality with enterprise-grade reliability, comprehensive warranty coverage, and dedicated customer support available around the clock.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Widget Lite</td>
|
|
<td>Basic</td>
|
|
<td>Essential features for everyday use with straightforward operation and minimal learning curve.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>Widget Max</td>
|
|
<td>Ultimate</td>
|
|
<td>Everything from Widget Pro plus additional customization options, API integration capabilities, and advanced analytics dashboard.</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
"""
|
|
|
|
return html, "Mixed Short and Long Content"
|
|
|
|
|
|
def create_technical_documentation_example():
|
|
"""Create a table like technical documentation."""
|
|
print(" - Technical documentation style")
|
|
|
|
html = """
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>API Method</th>
|
|
<th>Parameters</th>
|
|
<th>Description</th>
|
|
<th>Return Value</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>render_table()</td>
|
|
<td>table, origin, width, draw, style</td>
|
|
<td>Renders a table with automatic text wrapping in cells. Uses the Line class for intelligent word placement and hyphenation.</td>
|
|
<td>Rendered table with calculated height and width properties.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>add_word()</td>
|
|
<td>word, pretext</td>
|
|
<td>Attempts to add a word to the current line. If it doesn't fit, tries hyphenation strategies including pyphen and brute-force splitting.</td>
|
|
<td>Tuple of (success, overflow_text) indicating whether word was added and any remaining text.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>calculate_spacing()</td>
|
|
<td>text_objects, width, min_spacing, max_spacing</td>
|
|
<td>Determines optimal spacing between words to achieve proper justification within the specified constraints.</td>
|
|
<td>Calculated spacing value and position offset for alignment.</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
"""
|
|
|
|
return html, "Technical Documentation Table"
|
|
|
|
|
|
def create_news_article_example():
|
|
"""Create a table with article-style content."""
|
|
print(" - News article layout")
|
|
|
|
html = """
|
|
<table>
|
|
<thead>
|
|
<tr>
|
|
<th>Date</th>
|
|
<th>Headline</th>
|
|
<th>Summary</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
<tr>
|
|
<td>2024-01-15</td>
|
|
<td>New Text Wrapping Feature</td>
|
|
<td>PyWebLayout now supports automatic line wrapping in table cells, bringing sophisticated text layout capabilities to table rendering. The implementation leverages the existing Line class infrastructure.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>2024-01-10</td>
|
|
<td>Hyphenation Improvements</td>
|
|
<td>Enhanced hyphenation algorithms now include both dictionary-based pyphen hyphenation and intelligent brute-force splitting for edge cases.</td>
|
|
</tr>
|
|
<tr>
|
|
<td>2024-01-05</td>
|
|
<td>Performance Optimization</td>
|
|
<td>Table rendering performance improved through better caching and reduced font object creation overhead.</td>
|
|
</tr>
|
|
</tbody>
|
|
</table>
|
|
"""
|
|
|
|
return html, "News Article Layout"
|
|
|
|
|
|
def render_table_example(html, title, style_variant=0):
|
|
"""Render a single table example."""
|
|
from pyWebLayout.style import Font
|
|
from pyWebLayout.abstract.block import Table
|
|
|
|
# Parse HTML
|
|
base_font = Font(font_size=12)
|
|
blocks = parse_html_string(html, base_font=base_font)
|
|
|
|
# Find the table block
|
|
table = None
|
|
for block in blocks:
|
|
if isinstance(block, Table):
|
|
table = block
|
|
break
|
|
|
|
if not table:
|
|
print(f" Warning: No table found in {title}")
|
|
return None
|
|
|
|
# Create page style
|
|
page_style = PageStyle(
|
|
padding=(20, 20, 20, 20),
|
|
background_color=(255, 255, 255)
|
|
)
|
|
|
|
# Create page
|
|
page_size = (900, 600)
|
|
page = Page(size=page_size, style=page_style)
|
|
|
|
# Create table style variants
|
|
table_styles = [
|
|
# Default style
|
|
TableStyle(
|
|
border_width=1,
|
|
border_color=(0, 0, 0),
|
|
cell_padding=(8, 8, 8, 8),
|
|
header_bg_color=(240, 240, 240),
|
|
cell_bg_color=(255, 255, 255)
|
|
),
|
|
# Blue header style
|
|
TableStyle(
|
|
border_width=2,
|
|
border_color=(70, 130, 180),
|
|
cell_padding=(10, 10, 10, 10),
|
|
header_bg_color=(176, 196, 222),
|
|
cell_bg_color=(245, 250, 255)
|
|
),
|
|
# Minimal style
|
|
TableStyle(
|
|
border_width=1,
|
|
border_color=(200, 200, 200),
|
|
cell_padding=(6, 6, 6, 6),
|
|
header_bg_color=(250, 250, 250),
|
|
cell_bg_color=(255, 255, 255)
|
|
),
|
|
]
|
|
|
|
table_style = table_styles[style_variant % len(table_styles)]
|
|
|
|
# Create layouter and render table
|
|
layouter = DocumentLayouter(page)
|
|
layouter.layout_table(table, style=table_style)
|
|
|
|
# Get the rendered canvas
|
|
_ = page.draw # Ensure canvas exists
|
|
img = page._canvas
|
|
|
|
return img
|
|
|
|
|
|
def combine_examples(examples):
|
|
"""Combine multiple example images into one."""
|
|
images = []
|
|
titles = []
|
|
|
|
for html, title in examples:
|
|
img = render_table_example(html, title)
|
|
if img:
|
|
images.append(img)
|
|
titles.append(title)
|
|
|
|
if not images:
|
|
return None
|
|
|
|
# Calculate combined image size
|
|
max_width = max(img.width for img in images)
|
|
total_height = sum(img.height for img in images) + 40 * len(images) # Extra space between images
|
|
|
|
# Create combined image
|
|
combined = Image.new('RGB', (max_width, total_height), color=(255, 255, 255))
|
|
|
|
# Paste images
|
|
y_offset = 20
|
|
for img in images:
|
|
combined.paste(img, (0, y_offset))
|
|
y_offset += img.height + 40
|
|
|
|
return combined
|
|
|
|
|
|
def main():
|
|
"""Run the table text wrapping example."""
|
|
print("\nTable Text Wrapping Example")
|
|
print("=" * 50)
|
|
|
|
# Create examples
|
|
print("\n Creating table examples...")
|
|
examples = [
|
|
create_narrow_columns_example(),
|
|
create_mixed_content_example(),
|
|
create_technical_documentation_example(),
|
|
create_news_article_example(),
|
|
]
|
|
|
|
print("\n Rendering table examples...")
|
|
combined_image = combine_examples(examples)
|
|
|
|
if combined_image:
|
|
# Save the output
|
|
output_dir = Path(__file__).parent.parent / 'docs' / 'images'
|
|
output_dir.mkdir(parents=True, exist_ok=True)
|
|
output_path = output_dir / 'example_11_table_text_wrapping.png'
|
|
|
|
combined_image.save(str(output_path))
|
|
|
|
print("\n✓ Example completed!")
|
|
print(f" Output saved to: {output_path}")
|
|
print(f" Image size: {combined_image.width}x{combined_image.height} pixels")
|
|
print(f" Created {len(examples)} table examples with text wrapping")
|
|
else:
|
|
print("\n✗ Failed to generate examples")
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|