#!/usr/bin/env python3 """ Template System Example for pyPhotoAlbum This example demonstrates: - Creating templates from existing pages - Using built-in templates - Applying templates to new pages - Template scaling modes - Saving and loading custom templates Based on template_manager.py and TEMPLATES_README.md """ import os import sys import tempfile from pathlib import Path # Add parent directory to path to import pyPhotoAlbum sys.path.insert(0, str(Path(__file__).parent.parent)) from pyPhotoAlbum.project import Project, Page from pyPhotoAlbum.page_layout import PageLayout from pyPhotoAlbum.models import ImageData, TextBoxData, PlaceholderData from pyPhotoAlbum.template_manager import TemplateManager, Template from pyPhotoAlbum.project_serializer import save_to_zip def create_sample_image(path: str, color: str = 'blue', size: tuple = (400, 300)): """Create a sample image for testing""" try: from PIL import Image, ImageDraw, ImageFont img = Image.new('RGB', size, color=color) draw = ImageDraw.Draw(img) # Draw a border border_width = 10 draw.rectangle( [(border_width, border_width), (size[0]-border_width, size[1]-border_width)], outline='white', width=5 ) # Add text text = f"{color.upper()}" try: font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 48) except: font = ImageFont.load_default() bbox = draw.textbbox((0, 0), text, font=font) text_width = bbox[2] - bbox[0] text_height = bbox[3] - bbox[1] x = (size[0] - text_width) // 2 y = (size[1] - text_height) // 2 draw.text((x, y), text, fill='white', font=font) img.save(path) print(f" Created: {path}") return True except Exception as e: print(f" Could not create image: {e}") return False def example_1_list_templates(): """ Example 1: List available templates From template_manager.py """ print("\n" + "="*60) print("Example 1: Listing Available Templates") print("="*60) manager = TemplateManager() print("\nAvailable templates:") templates = manager.list_templates() for i, template_name in enumerate(templates, 1): print(f" {i}. {template_name}") # Load and display info about each template print("\nTemplate Details:") for template_name in templates[:2]: # Show first 2 templates try: template = manager.load_template(template_name) print(f"\n {template.name}:") print(f" Description: {template.description}") print(f" Page Size: {template.page_size_mm[0]}x{template.page_size_mm[1]} mm") print(f" Elements: {len(template.elements)}") except Exception as e: print(f" Error loading: {e}") def example_2_create_page_from_template(): """ Example 2: Create a new page from a built-in template From template_manager.py - create_page_from_template method """ print("\n" + "="*60) print("Example 2: Creating Page from Template") print("="*60) manager = TemplateManager() output_dir = Path(__file__).parent / "output" output_dir.mkdir(exist_ok=True) # Create a project temp_dir = tempfile.mkdtemp(prefix="template_example_") project_folder = os.path.join(temp_dir, "template_project") project = Project(name="Template Example", folder_path=project_folder) project.page_size_mm = (210, 297) # A4 project.working_dpi = 300 print(f"\nCreated project: {project.name}") print(f"Page size: {project.page_size_mm[0]}x{project.page_size_mm[1]} mm") # Create a page from Grid_2x2 template print("\nCreating page from 'Grid_2x2' template...") page = manager.create_page_from_template( template_name="Grid_2x2", target_page_size=project.page_size_mm, page_number=1 ) print(f" Created page with {len(page.layout.elements)} placeholder elements") # Show details of placeholders for i, element in enumerate(page.layout.elements, 1): if isinstance(element, PlaceholderData): print(f" Placeholder {i}: position={element.position}, size={element.size}") project.add_page(page) # Now replace placeholders with actual images print("\nReplacing placeholders with images...") colors = ['red', 'green', 'blue', 'yellow'] for i, element in enumerate(page.layout.elements): if isinstance(element, PlaceholderData) and i < len(colors): # Create sample image image_path = output_dir / f"grid_image_{colors[i]}.jpg" create_sample_image(str(image_path), color=colors[i], size=(600, 600)) # Import to project imported_path = project.asset_manager.import_asset(str(image_path)) # Replace placeholder with image image = ImageData( image_path=imported_path, x=element.position[0], y=element.position[1], width=element.size[0], height=element.size[1], z_index=element.z_index ) # Remove placeholder and add image page.layout.remove_element(element) page.layout.add_element(image) print(f" Replaced placeholder {i+1} with {colors[i]} image") # Save project project_path = output_dir / "template_project.ppz" print(f"\nSaving project to: {project_path}") success, error = save_to_zip(project, str(project_path)) if success: print(" Project saved successfully!") else: print(f" Error: {error}") def example_3_create_custom_template(): """ Example 3: Create a custom template from a page From template_manager.py - create_template_from_page method """ print("\n" + "="*60) print("Example 3: Creating Custom Template") print("="*60) manager = TemplateManager() output_dir = Path(__file__).parent / "output" output_dir.mkdir(exist_ok=True) # Create a page with a custom layout print("\nDesigning custom page layout...") layout = PageLayout(width=210, height=297) # Large image at top top_image = ImageData( image_path="dummy.jpg", # Will be converted to placeholder x=10.0, y=10.0, width=190.0, height=140.0, z_index=0 ) layout.add_element(top_image) print(" Added large top image") # Two smaller images at bottom bottom_left = ImageData( image_path="dummy.jpg", x=10.0, y=160.0, width=90.0, height=90.0, z_index=0 ) layout.add_element(bottom_left) bottom_right = ImageData( image_path="dummy.jpg", x=110.0, y=160.0, width=90.0, height=90.0, z_index=0 ) layout.add_element(bottom_right) print(" Added two smaller bottom images") # Title text box title = TextBoxData( text_content="Title", font_settings={"family": "Arial", "size": 20, "color": (0, 0, 0)}, alignment="center", x=10.0, y=260.0, width=190.0, height=30.0, z_index=1 ) layout.add_element(title) print(" Added title text box") # Create page page = Page(layout=layout, page_number=1) # Create template from page print("\nCreating template from page...") template = manager.create_template_from_page( page=page, name="Custom_Large_Plus_Two", description="One large image at top, two smaller at bottom, with title" ) print(f" Template created: {template.name}") print(f" Description: {template.description}") print(f" Elements: {len(template.elements)}") # Save template print("\nSaving custom template...") try: manager.save_template(template) print(f" Template saved successfully!") print(f" Location: {manager._get_templates_directory()}") except Exception as e: print(f" Error saving template: {e}") # Verify it's in the list templates = manager.list_templates() if template.name in templates: print(f" Verified: Template appears in list") def example_4_template_scaling_modes(): """ Example 4: Demonstrate different template scaling modes From template_manager.py - scale_template_elements method """ print("\n" + "="*60) print("Example 4: Template Scaling Modes") print("="*60) manager = TemplateManager() # Create a simple template print("\nCreating test template (100x100mm square)...") template = Template(name="Test Square", page_size_mm=(100, 100)) # Add a centered square element element = PlaceholderData( x=25.0, y=25.0, width=50.0, height=50.0 ) template.add_element(element) print(f" Original element: position={element.position}, size={element.size}") # Test different target sizes target_sizes = [ (200, 200, "Same aspect ratio (2x)"), (200, 100, "Wider (2x wide, 1x tall)"), (100, 200, "Taller (1x wide, 2x tall)") ] scaling_modes = ["proportional", "stretch", "center"] for target_w, target_h, desc in target_sizes: print(f"\nTarget size: {target_w}x{target_h}mm ({desc})") for mode in scaling_modes: scaled = manager.scale_template_elements( template.elements.copy(), source_size=template.page_size_mm, target_size=(target_w, target_h), scaling=mode ) if scaled: scaled_element = scaled[0] print(f" {mode:12s}: position={scaled_element.position}, size={scaled_element.size}") def example_5_apply_template_modes(): """ Example 5: Apply template to existing page with different modes From template_manager.py - apply_template_to_page method """ print("\n" + "="*60) print("Example 5: Applying Template to Existing Page") print("="*60) manager = TemplateManager() output_dir = Path(__file__).parent / "output" output_dir.mkdir(exist_ok=True) # Create a page with some existing content print("\nCreating page with existing images...") temp_dir = tempfile.mkdtemp(prefix="template_apply_") project_folder = os.path.join(temp_dir, "apply_project") project = Project(name="Apply Template Test", folder_path=project_folder) project.page_size_mm = (210, 297) layout = PageLayout(width=210, height=297) # Add some images colors = ['red', 'green', 'blue'] for i, color in enumerate(colors): image_path = output_dir / f"apply_{color}.jpg" create_sample_image(str(image_path), color=color, size=(600, 400)) imported_path = project.asset_manager.import_asset(str(image_path)) image = ImageData( image_path=imported_path, x=10.0 + i*20, y=10.0 + i*30, width=100.0, height=100.0 ) layout.add_element(image) page = Page(layout=layout, page_number=1) project.add_page(page) print(f" Created page with {len(page.layout.elements)} images") # Apply Grid_2x2 template with "reflow" mode print("\nApplying Grid_2x2 template with 'reflow' mode...") print(" This will reposition existing images to fit template slots") try: template = manager.load_template("Grid_2x2") manager.apply_template_to_page( template=template, target_page=page, mode="reflow", # Keep existing images, reposition them scaling="proportional" ) print(f" Template applied! Page now has {len(page.layout.elements)} elements") # Show new positions for i, element in enumerate(page.layout.elements, 1): print(f" Element {i}: position={element.position}, size={element.size}") except Exception as e: print(f" Error applying template: {e}") # Save result project_path = output_dir / "template_applied.ppz" print(f"\nSaving result to: {project_path}") success, error = save_to_zip(project, str(project_path)) if success: print(" Saved successfully!") def main(): """Run all template examples""" print("\n" + "="*60) print("pyPhotoAlbum - Template System Examples") print("="*60) print("\nDemonstrating the template system using code from") print("template_manager.py and TEMPLATES_README.md\n") try: # Example 1: List templates example_1_list_templates() # Example 2: Create page from template example_2_create_page_from_template() # Example 3: Create custom template example_3_create_custom_template() # Example 4: Scaling modes example_4_template_scaling_modes() # Example 5: Apply template example_5_apply_template_modes() print("\n" + "="*60) print("All template examples completed!") print("="*60) print(f"\nOutput files are in: {Path(__file__).parent / 'output'}") except Exception as e: print(f"\nError running examples: {e}") import traceback traceback.print_exc() if __name__ == "__main__": main()