first commit
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
# pyPhotoAlbum Examples
|
||||
|
||||
This directory contains working examples demonstrating various features of pyPhotoAlbum.
|
||||
|
||||
## Available Examples
|
||||
|
||||
### basic_usage.py
|
||||
Demonstrates the fundamentals of creating a photo album project:
|
||||
- Creating a project
|
||||
- Adding pages with images
|
||||
- Working with text boxes
|
||||
- Saving and loading projects
|
||||
- Asset management
|
||||
|
||||
Run:
|
||||
```bash
|
||||
python basic_usage.py
|
||||
```
|
||||
|
||||
### template_example.py
|
||||
Shows how to work with the template system:
|
||||
- Creating custom templates
|
||||
- Applying templates to pages
|
||||
- Using built-in templates
|
||||
- Template scaling modes
|
||||
|
||||
Run:
|
||||
```bash
|
||||
python template_example.py
|
||||
```
|
||||
|
||||
### generate_screenshots.py
|
||||
Script to generate documentation screenshots programmatically:
|
||||
- Creates example projects
|
||||
- Captures screenshots for documentation
|
||||
- Demonstrates various layouts
|
||||
|
||||
Run:
|
||||
```bash
|
||||
python generate_screenshots.py
|
||||
```
|
||||
|
||||
This creates screenshots in `examples/screenshots/` directory.
|
||||
|
||||
## Requirements
|
||||
|
||||
Make sure you have pyPhotoAlbum installed:
|
||||
|
||||
```bash
|
||||
# From the project root
|
||||
pip install -e .
|
||||
```
|
||||
|
||||
## Sample Images
|
||||
|
||||
The examples use placeholder images. To use your own:
|
||||
|
||||
1. Create an `images/` directory in the examples folder
|
||||
2. Add your sample images
|
||||
3. Update the image paths in the example scripts
|
||||
|
||||
## Output
|
||||
|
||||
Examples will create:
|
||||
- `examples/output/` - Generated project files (.ppz)
|
||||
- `examples/screenshots/` - Documentation screenshots
|
||||
- `examples/pdfs/` - Exported PDFs
|
||||
|
||||
These directories are created automatically when you run the examples.
|
||||
|
||||
## Notes
|
||||
|
||||
- The examples use realistic page sizes (A4, square formats)
|
||||
- DPI settings match typical print requirements (300 DPI)
|
||||
- All examples include error handling and cleanup
|
||||
- Examples demonstrate both programmatic and template-based workflows
|
||||
|
||||
## Regenerating Documentation Screenshots
|
||||
|
||||
To update screenshots for the documentation:
|
||||
|
||||
1. Run `python generate_screenshots.py`
|
||||
2. Review generated images in `screenshots/`
|
||||
3. Copy needed screenshots to documentation
|
||||
|
||||
The script generates:
|
||||
- UI screenshots
|
||||
- Layout examples
|
||||
- Template demonstrations
|
||||
- Feature showcases
|
||||
@@ -0,0 +1,426 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Basic Usage Example for pyPhotoAlbum
|
||||
|
||||
This example demonstrates:
|
||||
- Creating a new project
|
||||
- Adding pages with images and text
|
||||
- Working with the asset manager
|
||||
- Saving and loading projects
|
||||
- Basic element manipulation
|
||||
|
||||
Based on unit test examples from the pyPhotoAlbum test suite.
|
||||
"""
|
||||
|
||||
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.project_serializer import save_to_zip, load_from_zip, get_project_info
|
||||
from pyPhotoAlbum.pdf_exporter import PDFExporter
|
||||
|
||||
|
||||
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 some text
|
||||
text = f"{color.upper()}\n{size[0]}x{size[1]}"
|
||||
try:
|
||||
# Try to use a nice font
|
||||
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 36)
|
||||
except:
|
||||
# Fallback to default
|
||||
font = ImageFont.load_default()
|
||||
|
||||
# Calculate text position (center)
|
||||
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 sample image: {path}")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"Could not create sample image: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def example_1_create_basic_project():
|
||||
"""
|
||||
Example 1: Create a basic project with one page and an image
|
||||
|
||||
This demonstrates the fundamental workflow based on test_project.py
|
||||
"""
|
||||
print("\n" + "="*60)
|
||||
print("Example 1: Creating a Basic Project")
|
||||
print("="*60)
|
||||
|
||||
# Create output directory
|
||||
output_dir = Path(__file__).parent / "output"
|
||||
output_dir.mkdir(exist_ok=True)
|
||||
|
||||
# Create a temporary directory for the project
|
||||
temp_dir = tempfile.mkdtemp(prefix="photo_album_")
|
||||
project_folder = os.path.join(temp_dir, "my_album")
|
||||
|
||||
print(f"\nProject folder: {project_folder}")
|
||||
|
||||
# Create a new project (from test_project.py)
|
||||
project = Project(name="My First Album", folder_path=project_folder)
|
||||
project.page_size_mm = (210, 297) # A4 size
|
||||
project.working_dpi = 300
|
||||
project.export_dpi = 300
|
||||
|
||||
print(f"Created project: {project.name}")
|
||||
print(f"Page size: {project.page_size_mm[0]}mm x {project.page_size_mm[1]}mm")
|
||||
print(f"DPI: {project.working_dpi}")
|
||||
|
||||
# Create a sample image
|
||||
image_path = output_dir / "sample_photo.jpg"
|
||||
create_sample_image(str(image_path), color='blue', size=(800, 600))
|
||||
|
||||
# Import the image into the project (from test_project_serialization.py)
|
||||
imported_path = project.asset_manager.import_asset(str(image_path))
|
||||
print(f"\nImported asset: {imported_path}")
|
||||
|
||||
# Create a page layout (from test_project.py)
|
||||
layout = PageLayout(width=210, height=297)
|
||||
|
||||
# Add an image element (from test_models.py)
|
||||
image = ImageData(
|
||||
image_path=imported_path,
|
||||
x=10.0,
|
||||
y=10.0,
|
||||
width=190.0,
|
||||
height=140.0,
|
||||
rotation=0,
|
||||
z_index=0
|
||||
)
|
||||
layout.add_element(image)
|
||||
print(f"Added image at position ({image.position[0]}, {image.position[1]})")
|
||||
print(f"Image size: {image.size[0]}mm x {image.size[1]}mm")
|
||||
|
||||
# Add a text box (from test_models.py)
|
||||
textbox = TextBoxData(
|
||||
text_content="My First Photo Album",
|
||||
font_settings={"family": "Arial", "size": 24, "color": (0, 0, 0)},
|
||||
alignment="center",
|
||||
x=10.0,
|
||||
y=160.0,
|
||||
width=190.0,
|
||||
height=30.0
|
||||
)
|
||||
layout.add_element(textbox)
|
||||
print(f"Added text box: '{textbox.text_content}'")
|
||||
|
||||
# Create a page and add it to the project
|
||||
page = Page(layout=layout, page_number=1)
|
||||
project.add_page(page)
|
||||
print(f"\nAdded page {page.page_number} to project")
|
||||
print(f"Total pages: {len(project.pages)}")
|
||||
print(f"Total elements on page: {len(page.layout.elements)}")
|
||||
|
||||
# Save the project (from test_project_serialization.py)
|
||||
output_path = output_dir / "basic_project.ppz"
|
||||
print(f"\nSaving project to: {output_path}")
|
||||
success, error = save_to_zip(project, str(output_path))
|
||||
|
||||
if success:
|
||||
print("Project saved successfully!")
|
||||
|
||||
# Get project info without loading (from test_project_serialization.py)
|
||||
info = get_project_info(str(output_path))
|
||||
if info:
|
||||
print(f"\nProject Info:")
|
||||
print(f" Name: {info['name']}")
|
||||
print(f" Pages: {info['page_count']}")
|
||||
print(f" Version: {info['version']}")
|
||||
print(f" Working DPI: {info['working_dpi']}")
|
||||
else:
|
||||
print(f"Error saving project: {error}")
|
||||
|
||||
return str(output_path)
|
||||
|
||||
|
||||
def example_2_load_and_modify_project(project_path: str):
|
||||
"""
|
||||
Example 2: Load an existing project and add more pages
|
||||
|
||||
Based on test_project_serialization.py
|
||||
"""
|
||||
print("\n" + "="*60)
|
||||
print("Example 2: Loading and Modifying a Project")
|
||||
print("="*60)
|
||||
|
||||
# Load the project (from test_project_serialization.py)
|
||||
print(f"\nLoading project from: {project_path}")
|
||||
loaded_project, error = load_from_zip(project_path)
|
||||
|
||||
if not loaded_project:
|
||||
print(f"Error loading project: {error}")
|
||||
return
|
||||
|
||||
print(f"Loaded project: {loaded_project.name}")
|
||||
print(f"Pages: {len(loaded_project.pages)}")
|
||||
|
||||
# Create output directory
|
||||
output_dir = Path(__file__).parent / "output"
|
||||
|
||||
# Create more sample images
|
||||
for i in range(2, 4):
|
||||
image_path = output_dir / f"sample_photo_{i}.jpg"
|
||||
colors = ['red', 'green']
|
||||
create_sample_image(str(image_path), color=colors[i-2], size=(600, 800))
|
||||
|
||||
# Import the image
|
||||
imported_path = loaded_project.asset_manager.import_asset(str(image_path))
|
||||
|
||||
# Create a new page with the image (from test_project.py)
|
||||
layout = PageLayout(width=210, height=297)
|
||||
image = ImageData(
|
||||
image_path=imported_path,
|
||||
x=20.0 + i*5,
|
||||
y=20.0 + i*5,
|
||||
width=170.0,
|
||||
height=230.0
|
||||
)
|
||||
layout.add_element(image)
|
||||
|
||||
# Add caption
|
||||
caption = TextBoxData(
|
||||
text_content=f"Page {i}",
|
||||
font_settings={"family": "Arial", "size": 18, "color": (0, 0, 0)},
|
||||
alignment="center",
|
||||
x=20.0 + i*5,
|
||||
y=260.0,
|
||||
width=170.0,
|
||||
height=25.0
|
||||
)
|
||||
layout.add_element(caption)
|
||||
|
||||
page = Page(layout=layout, page_number=i)
|
||||
loaded_project.add_page(page)
|
||||
print(f"Added page {i} with {len(page.layout.elements)} elements")
|
||||
|
||||
# Save the modified project
|
||||
modified_path = output_dir / "modified_project.ppz"
|
||||
print(f"\nSaving modified project to: {modified_path}")
|
||||
success, error = save_to_zip(loaded_project, str(modified_path))
|
||||
|
||||
if success:
|
||||
print("Modified project saved successfully!")
|
||||
print(f"Total pages: {len(loaded_project.pages)}")
|
||||
else:
|
||||
print(f"Error saving: {error}")
|
||||
|
||||
return str(modified_path)
|
||||
|
||||
|
||||
def example_3_serialization_roundtrip():
|
||||
"""
|
||||
Example 3: Demonstrate serialization/deserialization
|
||||
|
||||
Based on test_models.py serialization tests
|
||||
"""
|
||||
print("\n" + "="*60)
|
||||
print("Example 3: Serialization Round-Trip")
|
||||
print("="*60)
|
||||
|
||||
# Create an image element (from test_models.py)
|
||||
print("\n1. Creating ImageData element...")
|
||||
original_image = ImageData(
|
||||
image_path="test.jpg",
|
||||
x=50.0,
|
||||
y=60.0,
|
||||
width=300.0,
|
||||
height=200.0,
|
||||
rotation=15.0,
|
||||
z_index=2,
|
||||
crop_info=(0.1, 0.1, 0.9, 0.9)
|
||||
)
|
||||
|
||||
print(f" Position: {original_image.position}")
|
||||
print(f" Size: {original_image.size}")
|
||||
print(f" Rotation: {original_image.rotation}°")
|
||||
print(f" Z-index: {original_image.z_index}")
|
||||
|
||||
# Serialize (from test_models.py)
|
||||
print("\n2. Serializing to dictionary...")
|
||||
data = original_image.serialize()
|
||||
print(f" Serialized data keys: {list(data.keys())}")
|
||||
print(f" Type: {data['type']}")
|
||||
|
||||
# Deserialize (from test_models.py)
|
||||
print("\n3. Deserializing from dictionary...")
|
||||
restored_image = ImageData()
|
||||
restored_image.deserialize(data)
|
||||
|
||||
print(f" Position: {restored_image.position}")
|
||||
print(f" Size: {restored_image.size}")
|
||||
print(f" Rotation: {restored_image.rotation}°")
|
||||
|
||||
# Verify round-trip
|
||||
print("\n4. Verifying round-trip...")
|
||||
assert restored_image.position == original_image.position
|
||||
assert restored_image.size == original_image.size
|
||||
assert restored_image.rotation == original_image.rotation
|
||||
assert restored_image.z_index == original_image.z_index
|
||||
assert restored_image.crop_info == original_image.crop_info
|
||||
print(" Round-trip successful!")
|
||||
|
||||
# Do the same for TextBoxData (from test_models.py)
|
||||
print("\n5. Testing TextBoxData serialization...")
|
||||
font_settings = {"family": "Georgia", "size": 20, "color": (255, 255, 0)}
|
||||
original_text = TextBoxData(
|
||||
text_content="Round Trip Test",
|
||||
font_settings=font_settings,
|
||||
alignment="center",
|
||||
x=85.0,
|
||||
y=95.0,
|
||||
width=320.0,
|
||||
height=120.0,
|
||||
rotation=25.0,
|
||||
z_index=9
|
||||
)
|
||||
|
||||
data = original_text.serialize()
|
||||
restored_text = TextBoxData()
|
||||
restored_text.deserialize(data)
|
||||
|
||||
assert restored_text.text_content == original_text.text_content
|
||||
assert restored_text.alignment == original_text.alignment
|
||||
assert restored_text.position == original_text.position
|
||||
print(" TextBoxData round-trip successful!")
|
||||
|
||||
|
||||
def example_4_export_to_pdf():
|
||||
"""
|
||||
Example 4: Export a project to PDF
|
||||
|
||||
Based on pdf_exporter.py usage
|
||||
"""
|
||||
print("\n" + "="*60)
|
||||
print("Example 4: Export to PDF")
|
||||
print("="*60)
|
||||
|
||||
# Create a simple project
|
||||
output_dir = Path(__file__).parent / "output"
|
||||
output_dir.mkdir(exist_ok=True)
|
||||
|
||||
temp_dir = tempfile.mkdtemp(prefix="photo_album_pdf_")
|
||||
project_folder = os.path.join(temp_dir, "pdf_export")
|
||||
|
||||
project = Project(name="PDF Export Example", folder_path=project_folder)
|
||||
project.page_size_mm = (140, 140) # Square format
|
||||
project.working_dpi = 300
|
||||
project.export_dpi = 300
|
||||
|
||||
print(f"\nCreating project with {project.page_size_mm[0]}x{project.page_size_mm[1]}mm pages")
|
||||
|
||||
# Create multiple pages with different colored images
|
||||
colors = ['red', 'green', 'blue', 'yellow']
|
||||
for i, color in enumerate(colors, 1):
|
||||
# Create sample image
|
||||
image_path = output_dir / f"pdf_sample_{color}.jpg"
|
||||
create_sample_image(str(image_path), color=color, size=(600, 600))
|
||||
|
||||
# Import and add to page
|
||||
imported_path = project.asset_manager.import_asset(str(image_path))
|
||||
|
||||
layout = PageLayout(width=140, height=140)
|
||||
image = ImageData(
|
||||
image_path=imported_path,
|
||||
x=10.0,
|
||||
y=10.0,
|
||||
width=120.0,
|
||||
height=120.0
|
||||
)
|
||||
layout.add_element(image)
|
||||
|
||||
page = Page(layout=layout, page_number=i)
|
||||
project.add_page(page)
|
||||
|
||||
print(f"Created {len(project.pages)} pages")
|
||||
|
||||
# Export to PDF
|
||||
pdf_path = output_dir / "example_album.pdf"
|
||||
print(f"\nExporting to PDF: {pdf_path}")
|
||||
|
||||
exporter = PDFExporter(project, export_dpi=300)
|
||||
|
||||
def progress_callback(current, total):
|
||||
print(f" Exporting page {current}/{total}...")
|
||||
|
||||
success, errors = exporter.export(
|
||||
output_path=str(pdf_path),
|
||||
progress_callback=progress_callback
|
||||
)
|
||||
|
||||
if success:
|
||||
print(f"\nPDF exported successfully!")
|
||||
print(f"File size: {os.path.getsize(pdf_path) / 1024:.1f} KB")
|
||||
else:
|
||||
print(f"\nErrors during export:")
|
||||
for error in errors:
|
||||
print(f" - {error}")
|
||||
|
||||
|
||||
def main():
|
||||
"""Run all examples"""
|
||||
print("\n" + "="*60)
|
||||
print("pyPhotoAlbum - Basic Usage Examples")
|
||||
print("="*60)
|
||||
print("\nThese examples demonstrate core functionality using")
|
||||
print("code patterns from the pyPhotoAlbum unit tests.\n")
|
||||
|
||||
try:
|
||||
# Example 1: Create a basic project
|
||||
project_path = example_1_create_basic_project()
|
||||
|
||||
# Example 2: Load and modify
|
||||
if project_path and os.path.exists(project_path):
|
||||
example_2_load_and_modify_project(project_path)
|
||||
|
||||
# Example 3: Serialization
|
||||
example_3_serialization_roundtrip()
|
||||
|
||||
# Example 4: PDF export
|
||||
example_4_export_to_pdf()
|
||||
|
||||
print("\n" + "="*60)
|
||||
print("All examples completed successfully!")
|
||||
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()
|
||||
@@ -0,0 +1,427 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Generate Documentation Screenshots
|
||||
|
||||
This script creates visual examples for documentation purposes:
|
||||
- Sample layouts
|
||||
- Template demonstrations
|
||||
- Feature showcases
|
||||
- UI mockups
|
||||
|
||||
Note: This creates programmatic representations rather than actual screenshots.
|
||||
For real screenshots, run the application and use a screen capture tool.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Add parent directory to path
|
||||
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.project_serializer import save_to_zip
|
||||
import tempfile
|
||||
|
||||
|
||||
def create_visual_mockup(path: str, title: str, description: str, elements: list):
|
||||
"""
|
||||
Create a visual mockup image showing a layout
|
||||
|
||||
Args:
|
||||
path: Output path for the image
|
||||
title: Title for the mockup
|
||||
description: Description text
|
||||
elements: List of (type, x, y, w, h, label) tuples
|
||||
"""
|
||||
try:
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
||||
# Create canvas (A4 aspect ratio)
|
||||
width, height = 800, 1132
|
||||
img = Image.new('RGB', (width, height), color='white')
|
||||
draw = ImageDraw.Draw(img)
|
||||
|
||||
# Try to load a nice font
|
||||
try:
|
||||
title_font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 32)
|
||||
desc_font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 18)
|
||||
label_font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 14)
|
||||
except:
|
||||
title_font = ImageFont.load_default()
|
||||
desc_font = ImageFont.load_default()
|
||||
label_font = ImageFont.load_default()
|
||||
|
||||
# Draw title
|
||||
draw.text((20, 20), title, fill='black', font=title_font)
|
||||
|
||||
# Draw description
|
||||
draw.text((20, 65), description, fill='gray', font=desc_font)
|
||||
|
||||
# Draw page boundary
|
||||
page_margin = 50
|
||||
page_top = 120
|
||||
page_bottom = height - 50
|
||||
page_width = width - 2 * page_margin
|
||||
page_height = page_bottom - page_top
|
||||
|
||||
# Light gray page background
|
||||
draw.rectangle(
|
||||
[(page_margin, page_top), (width - page_margin, page_bottom)],
|
||||
fill='#f5f5f5',
|
||||
outline='#cccccc',
|
||||
width=2
|
||||
)
|
||||
|
||||
# Draw elements
|
||||
colors = {
|
||||
'image': '#e3f2fd', # Light blue
|
||||
'text': '#fff9c4', # Light yellow
|
||||
'placeholder': '#e8f5e9' # Light green
|
||||
}
|
||||
|
||||
for elem_type, x, y, w, h, label in elements:
|
||||
# Convert from mm to pixels (rough approximation)
|
||||
px = page_margin + (x / 210) * page_width
|
||||
py = page_top + (y / 297) * page_height
|
||||
pw = (w / 210) * page_width
|
||||
ph = (h / 297) * page_height
|
||||
|
||||
# Draw element
|
||||
color = colors.get(elem_type, '#eeeeee')
|
||||
draw.rectangle(
|
||||
[(px, py), (px + pw, py + ph)],
|
||||
fill=color,
|
||||
outline='#666666',
|
||||
width=2
|
||||
)
|
||||
|
||||
# Draw label
|
||||
if label:
|
||||
label_bbox = draw.textbbox((0, 0), label, font=label_font)
|
||||
label_w = label_bbox[2] - label_bbox[0]
|
||||
label_h = label_bbox[3] - label_bbox[1]
|
||||
label_x = px + (pw - label_w) / 2
|
||||
label_y = py + (ph - label_h) / 2
|
||||
draw.text((label_x, label_y), label, fill='#333333', font=label_font)
|
||||
|
||||
# Save
|
||||
img.save(path)
|
||||
print(f" Created: {path}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f" Error creating mockup: {e}")
|
||||
return False
|
||||
|
||||
|
||||
def generate_layout_examples():
|
||||
"""Generate example layout screenshots"""
|
||||
print("\n" + "="*60)
|
||||
print("Generating Layout Examples")
|
||||
print("="*60)
|
||||
|
||||
output_dir = Path(__file__).parent / "screenshots"
|
||||
output_dir.mkdir(exist_ok=True)
|
||||
|
||||
# Example 1: Single large image
|
||||
print("\n1. Single Large Image Layout")
|
||||
create_visual_mockup(
|
||||
str(output_dir / "layout_single_large.png"),
|
||||
"Single Large Image Layout",
|
||||
"One large image with caption",
|
||||
[
|
||||
('image', 10, 10, 190, 250, 'Large Image'),
|
||||
('text', 10, 270, 190, 20, 'Caption Text')
|
||||
]
|
||||
)
|
||||
|
||||
# Example 2: Grid 2x2
|
||||
print("\n2. Grid 2x2 Layout")
|
||||
create_visual_mockup(
|
||||
str(output_dir / "layout_grid_2x2.png"),
|
||||
"Grid 2x2 Layout",
|
||||
"Four images in a 2x2 grid",
|
||||
[
|
||||
('image', 10, 10, 95, 95, 'Image 1'),
|
||||
('image', 105, 10, 95, 95, 'Image 2'),
|
||||
('image', 10, 110, 95, 95, 'Image 3'),
|
||||
('image', 105, 110, 95, 95, 'Image 4')
|
||||
]
|
||||
)
|
||||
|
||||
# Example 3: Mixed layout
|
||||
print("\n3. Mixed Layout")
|
||||
create_visual_mockup(
|
||||
str(output_dir / "layout_mixed.png"),
|
||||
"Mixed Layout",
|
||||
"Combination of images and text boxes",
|
||||
[
|
||||
('image', 10, 10, 190, 120, 'Header Image'),
|
||||
('text', 10, 140, 190, 25, 'Title'),
|
||||
('image', 10, 175, 90, 90, 'Image 1'),
|
||||
('image', 110, 175, 90, 90, 'Image 2'),
|
||||
('text', 10, 270, 190, 15, 'Footer')
|
||||
]
|
||||
)
|
||||
|
||||
# Example 4: Template with placeholders
|
||||
print("\n4. Template with Placeholders")
|
||||
create_visual_mockup(
|
||||
str(output_dir / "layout_template.png"),
|
||||
"Template Layout",
|
||||
"Page template with placeholder blocks",
|
||||
[
|
||||
('placeholder', 10, 10, 190, 140, 'Drop Image Here'),
|
||||
('placeholder', 10, 160, 90, 90, 'Image'),
|
||||
('placeholder', 110, 160, 90, 90, 'Image'),
|
||||
('text', 10, 260, 190, 25, 'Text Box')
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def generate_feature_examples():
|
||||
"""Generate feature demonstration screenshots"""
|
||||
print("\n" + "="*60)
|
||||
print("Generating Feature Examples")
|
||||
print("="*60)
|
||||
|
||||
output_dir = Path(__file__).parent / "screenshots"
|
||||
output_dir.mkdir(exist_ok=True)
|
||||
|
||||
# Alignment demonstration
|
||||
print("\n1. Alignment Features")
|
||||
create_visual_mockup(
|
||||
str(output_dir / "feature_alignment.png"),
|
||||
"Alignment Tools",
|
||||
"Align left, center, right, and distribute",
|
||||
[
|
||||
('image', 10, 10, 50, 50, 'Img 1'),
|
||||
('image', 70, 10, 50, 50, 'Img 2'),
|
||||
('image', 130, 10, 50, 50, 'Img 3'),
|
||||
('text', 10, 80, 170, 15, 'Aligned and distributed horizontally')
|
||||
]
|
||||
)
|
||||
|
||||
# Sizing demonstration
|
||||
print("\n2. Sizing Features")
|
||||
create_visual_mockup(
|
||||
str(output_dir / "feature_sizing.png"),
|
||||
"Sizing Tools",
|
||||
"Make same size, width, or height",
|
||||
[
|
||||
('image', 10, 10, 80, 80, 'Same Size'),
|
||||
('image', 100, 10, 80, 80, 'Same Size'),
|
||||
('image', 10, 100, 80, 60, 'Same Width'),
|
||||
('image', 100, 100, 80, 80, 'Same Width')
|
||||
]
|
||||
)
|
||||
|
||||
# Z-order demonstration
|
||||
print("\n3. Z-Order (Layering)")
|
||||
create_visual_mockup(
|
||||
str(output_dir / "feature_zorder.png"),
|
||||
"Z-Order / Layering",
|
||||
"Elements can be ordered in layers",
|
||||
[
|
||||
('image', 30, 30, 100, 100, 'Background'),
|
||||
('image', 60, 60, 100, 100, 'Middle'),
|
||||
('image', 90, 90, 100, 100, 'Foreground')
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def generate_workflow_example():
|
||||
"""Generate a complete workflow example"""
|
||||
print("\n" + "="*60)
|
||||
print("Generating Workflow Example")
|
||||
print("="*60)
|
||||
|
||||
output_dir = Path(__file__).parent / "screenshots"
|
||||
output_dir.mkdir(exist_ok=True)
|
||||
|
||||
# Step 1: Empty page
|
||||
print("\n1. Start with empty page")
|
||||
create_visual_mockup(
|
||||
str(output_dir / "workflow_01_empty.png"),
|
||||
"Step 1: Empty Page",
|
||||
"Start with a blank page",
|
||||
[]
|
||||
)
|
||||
|
||||
# Step 2: Apply template
|
||||
print("\n2. Apply template")
|
||||
create_visual_mockup(
|
||||
str(output_dir / "workflow_02_template.png"),
|
||||
"Step 2: Apply Template",
|
||||
"Add placeholder blocks using a template",
|
||||
[
|
||||
('placeholder', 10, 10, 90, 90, 'Drop Here'),
|
||||
('placeholder', 110, 10, 90, 90, 'Drop Here'),
|
||||
('placeholder', 10, 110, 90, 90, 'Drop Here'),
|
||||
('placeholder', 110, 110, 90, 90, 'Drop Here')
|
||||
]
|
||||
)
|
||||
|
||||
# Step 3: Add images
|
||||
print("\n3. Add images")
|
||||
create_visual_mockup(
|
||||
str(output_dir / "workflow_03_images.png"),
|
||||
"Step 3: Add Images",
|
||||
"Drag and drop images onto placeholders",
|
||||
[
|
||||
('image', 10, 10, 90, 90, 'Photo 1'),
|
||||
('image', 110, 10, 90, 90, 'Photo 2'),
|
||||
('image', 10, 110, 90, 90, 'Photo 3'),
|
||||
('placeholder', 110, 110, 90, 90, 'Drop Here')
|
||||
]
|
||||
)
|
||||
|
||||
# Step 4: Final layout
|
||||
print("\n4. Final layout")
|
||||
create_visual_mockup(
|
||||
str(output_dir / "workflow_04_final.png"),
|
||||
"Step 4: Final Layout",
|
||||
"Complete page with all images and text",
|
||||
[
|
||||
('image', 10, 10, 90, 90, 'Photo 1'),
|
||||
('image', 110, 10, 90, 90, 'Photo 2'),
|
||||
('image', 10, 110, 90, 90, 'Photo 3'),
|
||||
('image', 110, 110, 90, 90, 'Photo 4'),
|
||||
('text', 10, 210, 190, 20, 'My Photo Album - Summer 2024')
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def generate_template_examples():
|
||||
"""Generate template system examples"""
|
||||
print("\n" + "="*60)
|
||||
print("Generating Template Examples")
|
||||
print("="*60)
|
||||
|
||||
output_dir = Path(__file__).parent / "screenshots"
|
||||
output_dir.mkdir(exist_ok=True)
|
||||
|
||||
# Grid template
|
||||
print("\n1. Grid_2x2 Template")
|
||||
create_visual_mockup(
|
||||
str(output_dir / "template_grid_2x2.png"),
|
||||
"Grid_2x2 Template",
|
||||
"Built-in 2x2 grid template",
|
||||
[
|
||||
('placeholder', 10, 10, 95, 133, ''),
|
||||
('placeholder', 105, 10, 95, 133, ''),
|
||||
('placeholder', 10, 143, 95, 134, ''),
|
||||
('placeholder', 105, 143, 95, 134, '')
|
||||
]
|
||||
)
|
||||
|
||||
# Single large template
|
||||
print("\n2. Single_Large Template")
|
||||
create_visual_mockup(
|
||||
str(output_dir / "template_single_large.png"),
|
||||
"Single_Large Template",
|
||||
"Built-in single large image template",
|
||||
[
|
||||
('placeholder', 10, 10, 190, 240, 'Large Image'),
|
||||
('text', 10, 260, 190, 25, 'Title')
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def generate_project_structure_diagram():
|
||||
"""Generate project structure visualization"""
|
||||
print("\n" + "="*60)
|
||||
print("Generating Project Structure Diagram")
|
||||
print("="*60)
|
||||
|
||||
output_dir = Path(__file__).parent / "screenshots"
|
||||
output_dir.mkdir(exist_ok=True)
|
||||
|
||||
try:
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
||||
width, height = 800, 600
|
||||
img = Image.new('RGB', (width, height), color='white')
|
||||
draw = ImageDraw.Draw(img)
|
||||
|
||||
try:
|
||||
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 16)
|
||||
title_font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 20)
|
||||
except:
|
||||
font = ImageFont.load_default()
|
||||
title_font = ImageFont.load_default()
|
||||
|
||||
# Title
|
||||
draw.text((20, 20), "pyPhotoAlbum Project Structure", fill='black', font=title_font)
|
||||
|
||||
# Draw structure
|
||||
structure = [
|
||||
(50, "Project", 60),
|
||||
(100, "├─ Page 1", 100),
|
||||
(150, "│ ├─ PageLayout", 140),
|
||||
(200, "│ │ ├─ ImageData", 180),
|
||||
(250, "│ │ ├─ TextBoxData", 220),
|
||||
(300, "│ │ └─ PlaceholderData", 260),
|
||||
(100, "├─ Page 2", 320),
|
||||
(100, "└─ AssetManager", 360),
|
||||
(150, " └─ assets/", 400),
|
||||
]
|
||||
|
||||
for x, text, y in structure:
|
||||
draw.text((x, y), text, fill='#333333', font=font)
|
||||
|
||||
# Draw connecting lines (simplified)
|
||||
draw.line([(60, 90), (60, 380)], fill='#666666', width=2)
|
||||
draw.line([(110, 130), (110, 280)], fill='#666666', width=2)
|
||||
|
||||
path = output_dir / "project_structure.png"
|
||||
img.save(str(path))
|
||||
print(f" Created: {path}")
|
||||
|
||||
except Exception as e:
|
||||
print(f" Error creating diagram: {e}")
|
||||
|
||||
|
||||
def main():
|
||||
"""Generate all documentation screenshots"""
|
||||
print("\n" + "="*60)
|
||||
print("pyPhotoAlbum - Generate Documentation Screenshots")
|
||||
print("="*60)
|
||||
print("\nThis script creates visual examples for documentation.")
|
||||
print("For actual application screenshots, run the app and")
|
||||
print("use a screen capture tool.\n")
|
||||
|
||||
try:
|
||||
# Create output directory
|
||||
output_dir = Path(__file__).parent / "screenshots"
|
||||
output_dir.mkdir(exist_ok=True)
|
||||
print(f"Output directory: {output_dir}")
|
||||
|
||||
# Generate examples
|
||||
generate_layout_examples()
|
||||
generate_feature_examples()
|
||||
generate_workflow_example()
|
||||
generate_template_examples()
|
||||
generate_project_structure_diagram()
|
||||
|
||||
print("\n" + "="*60)
|
||||
print("Screenshot generation complete!")
|
||||
print("="*60)
|
||||
print(f"\nGenerated files are in: {output_dir}")
|
||||
print("\nThese mockups can be used in documentation to illustrate:")
|
||||
print(" - Page layouts")
|
||||
print(" - Template system")
|
||||
print(" - Feature demonstrations")
|
||||
print(" - Workflow examples")
|
||||
|
||||
except Exception as e:
|
||||
print(f"\nError generating screenshots: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,437 @@
|
||||
#!/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()
|
||||
Reference in New Issue
Block a user