#!/usr/bin/env python3 """ Table with Images Example This example demonstrates rendering tables with images: - Creating tables programmatically - Adding images to table cells - Book catalog / product showcase tables - Mixed content (images and text) in cells Uses the cover images from tests/data directory. """ 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.concrete.page import Page from pyWebLayout.style.page_style import PageStyle from pyWebLayout.concrete.table import TableRenderer, TableStyle from pyWebLayout.abstract.block import Table, Image as AbstractImage from pyWebLayout.abstract.inline import Word from pyWebLayout.style import Font def create_book_catalog_table(cover_images: dict): """Create a book catalog table with cover images and details.""" print(" - Creating book catalog table...") # Get base path for images data_path = Path(__file__).parent.parent / "tests" / "data" # Create table table = Table(caption="Book Catalog", style=Font(font_size=14)) # Header row header = table.create_row("header") header.create_cell(is_header=True).create_paragraph().add_word(Word("Cover", Font(font_size=12))) header.create_cell(is_header=True).create_paragraph().add_word(Word("Title", Font(font_size=12))) header.create_cell(is_header=True).create_paragraph().add_word(Word("Author", Font(font_size=12))) header.create_cell(is_header=True).create_paragraph().add_word(Word("Price", Font(font_size=12))) # Book entries books = [ ("cover 1.png", "The Great Adventure", "John Smith", "$19.99"), ("cover 2.png", "Mystery of the Ages", "Jane Doe", "$24.99"), ("cover 3.png", "Science Today", "Dr. Brown", "$29.99"), ("cover 4.png", "Art & Design", "M. Artist", "$34.99"), ] for cover_file, title, author, price in books: row = table.create_row("body") # Cover cell with actual Image block cover_cell = row.create_cell() if cover_file in cover_images: cover_path = str(data_path / cover_file) AbstractImage.create_and_add_to(cover_cell, source=cover_path, alt_text=title) # Title cell title_cell = row.create_cell() title_para = title_cell.create_paragraph() for word in title.split(): title_para.add_word(Word(word, Font(font_size=11))) # Author cell author_cell = row.create_cell() author_para = author_cell.create_paragraph() for word in author.split(): author_para.add_word(Word(word, Font(font_size=11))) # Price cell price_cell = row.create_cell() price_para = price_cell.create_paragraph() price_para.add_word(Word(price, Font(font_size=11, weight="bold"))) return table def create_product_showcase_table(cover_images: dict): """Create a product showcase table.""" print(" - Creating product showcase table...") # Get base path for images data_path = Path(__file__).parent.parent / "tests" / "data" table = Table(caption="Product Showcase", style=Font(font_size=14)) # Header row header = table.create_row("header") header.create_cell(is_header=True).create_paragraph().add_word(Word("Product", Font(font_size=12))) header.create_cell(is_header=True).create_paragraph().add_word(Word("Description", Font(font_size=12))) # Products with covers products = [ ("cover 1.png", "Premium Edition - Hardcover with gold embossing"), ("cover 2.png", "Collector's Item - Limited print run"), ] for cover_file, description in products: row = table.create_row("body") # Product cell with actual Image block product_cell = row.create_cell() if cover_file in cover_images: cover_path = str(data_path / cover_file) AbstractImage.create_and_add_to(product_cell, source=cover_path, alt_text="Product cover") # Description cell desc_cell = row.create_cell() desc_para = desc_cell.create_paragraph() for word in description.split(): desc_para.add_word(Word(word, Font(font_size=10))) return table def render_table_with_images(table: Table, title: str, style_variant: int = 0, page_size=(600, 500)): """Render a table with images using the library API.""" # Create page page_style = PageStyle( border_width=2, border_color=(180, 180, 180), padding=(20, 20, 20, 20), background_color=(255, 255, 255) ) page = Page(size=page_size, style=page_style) canvas = page.render() draw = ImageDraw.Draw(canvas) # Add title try: title_font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 16) except: title_font = ImageFont.load_default() draw.text((page.border_size + 10, page.border_size + 10), title, fill=(50, 50, 150), font=title_font) # Table styles table_styles = [ TableStyle( border_width=1, border_color=(100, 100, 100), cell_padding=(8, 10, 8, 10), header_bg_color=(70, 130, 180), cell_bg_color=(255, 255, 255), alternate_row_color=(245, 248, 250) ), TableStyle( border_width=2, border_color=(60, 120, 60), cell_padding=(10, 12, 10, 12), header_bg_color=(144, 238, 144), cell_bg_color=(255, 255, 255), alternate_row_color=(240, 255, 240) ), ] table_style = table_styles[style_variant % len(table_styles)] # Position table table_origin = (page.border_size + 10, page.border_size + 45) table_width = page.content_size[0] - 20 # Render table with canvas support for images renderer = TableRenderer( table, table_origin, table_width, draw, table_style, canvas # Pass canvas to enable image rendering ) renderer.render() return canvas def main(): """Demonstrate tables with images.""" print("Table with Images Example") print("=" * 50) # Load cover images print("\n Loading cover images...") cover_images = {} data_path = Path(__file__).parent.parent / "tests" / "data" for i in range(1, 5): cover_path = data_path / f"cover {i}.png" if cover_path.exists(): cover_images[f"cover {i}.png"] = Image.open(cover_path) print(f" āœ“ Loaded cover {i}.png") if not cover_images: print(" āœ— No cover images found!") return # Create tables print("\n Creating tables...") book_table = create_book_catalog_table(cover_images) product_table = create_product_showcase_table(cover_images) # Render tables print("\n Rendering tables with images...") print(" - Rendering book catalog...") book_image = render_table_with_images( book_table, "Book Catalog with Covers", style_variant=0, page_size=(700, 600) ) print(" - Rendering product showcase...") product_image = render_table_with_images( product_table, "Product Showcase", style_variant=1, page_size=(600, 350) ) # Combine images side by side print("\n Combining images...") padding = 20 total_width = book_image.size[0] + product_image.size[0] + padding * 3 total_height = max(book_image.size[1], product_image.size[1]) + padding * 2 combined = Image.new('RGB', (total_width, total_height), (240, 240, 240)) combined.paste(book_image, (padding, padding)) combined.paste(product_image, (book_image.size[0] + padding * 2, padding)) # Save output output_dir = Path("docs/images") output_dir.mkdir(parents=True, exist_ok=True) output_path = output_dir / "example_05_table_with_images.png" combined.save(output_path) print(f"\nāœ“ Example completed!") print(f" Output saved to: {output_path}") print(f" Image size: {combined.size[0]}x{combined.size[1]} pixels") print(f" Used {len(cover_images)} cover images") return combined if __name__ == "__main__": main()