#!/usr/bin/env python3 """ Table Rendering Example This example demonstrates rendering HTML tables: - Simple tables with headers - Tables with multiple rows and columns - Tables with colspan and borders - Tables with formatted content - Tables parsed from HTML using DocumentLayouter Shows the HTML-first rendering pipeline. """ import sys from pathlib import Path from PIL import Image, ImageDraw # Add pyWebLayout to path sys.path.insert(0, str(Path(__file__).parent.parent)) from pyWebLayout.concrete.page import Page from pyWebLayout.concrete.table import TableStyle from pyWebLayout.style.page_style import PageStyle from pyWebLayout.layout.document_layouter import DocumentLayouter from pyWebLayout.io.readers.html_extraction import parse_html_string from pyWebLayout.style import Font from pyWebLayout.abstract.block import Table def create_simple_table_example(): """Create a simple table from HTML.""" print(" - Simple data table") html = """
Name Age City
Alice 28 Paris
Bob 34 London
Charlie 25 Tokyo
""" return html, "Simple Table" def create_styled_table_example(): """Create a table with custom styling.""" print(" - Styled table") html = """
Monthly Sales Report
Month Revenue Expenses Profit
January $50,000 $30,000 $20,000
February $55,000 $32,000 $23,000
March $60,000 $35,000 $25,000
""" return html, "Styled Table" def create_complex_table_example(): """Create a table with colspan.""" print(" - Complex table with colspan") html = """
Product Specifications
Product Features Price
Laptop 16GB RAM, 512GB SSD $1,299
Monitor 27 inch, 4K Resolution $599
Keyboard Mechanical, RGB $129
""" return html, "Complex Table" def create_data_table_example(): """Create a table with numerical data.""" print(" - Data table") html = """
Test Results
Test Score Status
Unit Tests 98% Pass
Integration 95% Pass
Performance 87% Pass
""" return html, "Data Table" def render_table_example(html: str, title: str, style_variant: int = 0, page_size=(500, 400)): """Render a table from HTML to an image using DocumentLayouter.""" # Create page with varying backgrounds bg_colors = [ (255, 255, 255), # White (250, 255, 250), # Light green tint (255, 250, 245), # Light orange tint (245, 250, 255), # Light blue tint ] page_style = PageStyle( border_width=2, border_color=(200, 200, 200), padding=(20, 20, 20, 20), background_color=bg_colors[style_variant % len(bg_colors)] ) page = Page(size=page_size, style=page_style) # Parse HTML to get table 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 # Table styles with different themes table_styles = [ # Style 0: Classic blue header TableStyle( border_width=1, border_color=(80, 80, 80), cell_padding=(8, 10, 8, 10), header_bg_color=(70, 130, 180), # Steel blue cell_bg_color=(255, 255, 255), alternate_row_color=(240, 248, 255) # Alice blue ), # Style 1: Green theme TableStyle( border_width=2, border_color=(34, 139, 34), # Forest green cell_padding=(10, 12, 10, 12), header_bg_color=(144, 238, 144), # Light green cell_bg_color=(255, 255, 255), alternate_row_color=(240, 255, 240) # Honeydew ), # Style 2: Minimal style TableStyle( border_width=0, border_color=(200, 200, 200), cell_padding=(6, 8, 6, 8), header_bg_color=(245, 245, 245), cell_bg_color=(255, 255, 255), alternate_row_color=None # No alternating ), # Style 3: Bold borders TableStyle( border_width=3, border_color=(0, 0, 0), cell_padding=(10, 10, 10, 10), header_bg_color=(255, 215, 0), # Gold cell_bg_color=(255, 255, 255), alternate_row_color=(255, 250, 205) # Lemon chiffon ), ] table_style = table_styles[style_variant % len(table_styles)] if table: # Create DocumentLayouter layouter = DocumentLayouter(page) # Use DocumentLayouter to layout the table layouter.layout_table(table, style=table_style) # Get the rendered canvas _ = page.draw # Ensure canvas exists image = page._canvas else: # No table found - create empty page _ = page.draw # Ensure canvas exists draw = ImageDraw.Draw(page._canvas) draw.text((page.border_size + 10, page.border_size + 50), "No table found in HTML", fill=(200, 0, 0)) image = page._canvas return image def combine_examples(examples): """Combine multiple table examples into a grid.""" print("\n Rendering table examples...") images = [] for i, (html, title) in enumerate(examples): img = render_table_example(html, title, style_variant=i) images.append(img) # Create grid (2x2) padding = 15 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 + 50 # Extra for main title combined = Image.new('RGB', (total_width, total_height), (240, 240, 240)) draw = ImageDraw.Draw(combined) # Add main title from PIL import ImageFont try: main_font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 20) except: main_font = ImageFont.load_default() title_text = "Table Rendering Examples" bbox = draw.textbbox((0, 0), title_text, font=main_font) text_width = bbox[2] - bbox[0] title_x = (total_width - text_width) // 2 draw.text((title_x, 15), title_text, fill=(50, 50, 50), font=main_font) # Place images y_offset = 50 + 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 table rendering.""" print("Table Rendering Example") print("=" * 50) # Create table examples print("\n Creating table examples...") examples = [ create_simple_table_example(), create_styled_table_example(), create_complex_table_example(), create_data_table_example() ] # Render and combine combined_image = combine_examples(examples) # Save output output_dir = Path("docs/images") output_dir.mkdir(parents=True, exist_ok=True) output_path = output_dir / "example_04_table_rendering.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" Created {len(examples)} table examples") return combined_image if __name__ == "__main__": main()