pyPhotoAlbum/pyPhotoAlbum/EMBEDDED_TEMPLATES.md
Duncan Tourolle a7558e3c39
All checks were successful
Python CI / test (push) Successful in 1m11s
Lint / lint (push) Successful in 1m9s
Tests / test (3.10) (push) Successful in 55s
Tests / test (3.11) (push) Successful in 56s
Tests / test (3.9) (push) Successful in 53s
updated tests and installer
2025-11-11 13:21:35 +01:00

7.5 KiB

Embedded Templates Feature

Overview

The embedded templates feature allows templates to be stored within project files (.ppz) so they travel with the document. When loading projects, embedded templates take priority over local filesystem templates, ensuring projects can be opened on any machine without missing custom templates.

Key Benefits

Portability: Templates travel with project files
Self-contained: No dependency on local template files
Priority: Embedded templates override filesystem templates
Automatic: Templates are auto-embedded when used
Backward Compatible: Projects without embedded templates work as before

How It Works

Template Priority Order

When loading a template by name, the system checks in this order:

  1. Embedded templates in the current project (highest priority)
  2. User templates in ~/.pyphotoalbum/templates/
  3. Built-in templates in pyPhotoAlbum/templates/

Automatic Embedding

Templates are automatically embedded in projects when:

  • Applying a template to a page with apply_template_to_page()
  • Creating a new page from a template with create_page_from_template()

You can disable auto-embedding by passing auto_embed=False to these methods.

Template Naming

Templates are listed with prefixes indicating their source:

  • [Embedded] Template Name - Embedded in current project
  • [Built-in] Template Name - Built-in template
  • Template Name - User template from filesystem

Usage Examples

Basic Usage

from pyPhotoAlbum.project import Project, Page
from pyPhotoAlbum.template_manager import TemplateManager, Template

# Create a project
project = Project(name="My Album")

# Create template manager with project
template_manager = TemplateManager(project=project)

# Create a page from a template (auto-embeds by default)
template = template_manager.load_template("Grid_2x2")
page = template_manager.create_page_from_template(template, page_number=1)
project.add_page(page)

# The template is now embedded in the project!
print(project.embedded_templates.keys())
# Output: dict_keys(['Grid_2x2'])

Manual Embedding

# Manually embed a template
template = Template(name="Custom Layout")
# ... configure template ...
template_manager.embed_template(template)

Saving Templates

# Save to filesystem (default)
template_manager.save_template(template)

# Or embed in project instead
template_manager.save_template(template, embed_in_project=True)

Listing Templates

# List all available templates
templates = template_manager.list_templates()
# Returns: ['[Embedded] Custom', '[Built-in] Grid_2x2', 'MyUserTemplate', ...]

Loading Templates

# Load embedded template (priority)
template = template_manager.load_template("Custom")

# Load with explicit prefix
template = template_manager.load_template("[Embedded] Custom")
template = template_manager.load_template("[Built-in] Grid_2x2")

Disabling Auto-Embed

# Don't auto-embed when applying template
template_manager.apply_template_to_page(
    template, 
    page, 
    auto_embed=False
)

# Don't auto-embed when creating page
page = template_manager.create_page_from_template(
    template,
    page_number=1,
    auto_embed=False
)

Project Serialization

Embedded templates are automatically serialized when saving projects:

# Save project to ZIP file
from pyPhotoAlbum.project_serializer import save_to_zip

save_to_zip(project, "myalbum.ppz")
# Embedded templates are included in the .ppz file

When loading:

from pyPhotoAlbum.project_serializer import load_from_zip

project, error = load_from_zip("myalbum.ppz")
# Embedded templates are automatically restored

# Create template manager to access them
template_manager = TemplateManager(project=project)
templates = template_manager.list_templates()

Data Structure

Embedded templates are stored in the project's embedded_templates dictionary:

project.embedded_templates = {
    "Template Name": {
        "name": "Template Name",
        "description": "Template description",
        "page_size_mm": [210, 297],
        "elements": [
            {
                "type": "placeholder",
                "position": [10, 10],
                "size": [100, 100],
                # ... more element data
            },
            # ... more elements
        ]
    },
    # ... more templates
}

API Reference

TemplateManager

Constructor

TemplateManager(project=None)

Create a template manager. Pass a Project instance to enable embedded template support.

Methods

embed_template(template: Template)
Manually embed a template in the project.

load_template(name: str) -> Template
Load a template by name. Checks embedded templates first, then filesystem.

list_templates() -> List[str]
List all available templates with source prefixes.

save_template(template: Template, embed_in_project: bool = False)
Save template to filesystem or embed in project.

delete_template(name: str)
Delete a template (works with embedded and user templates).

apply_template_to_page(template, page, mode="replace", scale_mode="proportional", margin_percent=2.5, auto_embed=True)
Apply template to a page. Auto-embeds by default.

create_page_from_template(template, page_number=1, target_size_mm=None, scale_mode="proportional", auto_embed=True) -> Page
Create a new page from template. Auto-embeds by default.

Project

Attributes

embedded_templates: Dict[str, Dict[str, Any]]
Dictionary storing embedded template definitions.

Migration Guide

Existing Projects

Existing projects without embedded templates will continue to work normally. Templates will be auto-embedded when:

  1. You apply a template to a page
  2. You create a new page from a template
  3. You manually embed a template

Sharing Projects

When sharing projects:

  1. Templates are automatically embedded when used
  2. Save the project to .ppz format
  3. Share the .ppz file
  4. Recipients can open the project and all templates are available

No manual steps required!

Best Practices

  1. Let auto-embed work: The default behavior of auto-embedding templates ensures portability
  2. Save projects after using templates: Embedded templates are saved with the project
  3. Use descriptive template names: This helps identify templates in the list
  4. Test on different machines: Verify templates work when opening projects elsewhere

Troubleshooting

Q: Why isn't my template showing as embedded?
A: Ensure you're creating the TemplateManager with the project:

template_manager = TemplateManager(project=project)

Q: Can I convert filesystem templates to embedded?
A: Yes, just load and embed them:

template = template_manager.load_template("MyTemplate")
template_manager.embed_template(template)

Q: What happens if I have templates with the same name?
A: Embedded templates take priority over filesystem templates with the same name.

Q: Can I remove embedded templates?
A: Yes, use:

template_manager.delete_template("[Embedded] Template Name")

Implementation Details

  • Templates are stored as JSON in the project's embedded_templates dictionary
  • Serialization includes embedded templates in the project.json within .ppz files
  • Template manager checks embedded templates first when loading
  • Auto-embed only happens if the template isn't already embedded
  • All template operations preserve element properties (position, size, rotation, etc.)