Apply one deck's visual design -- logos, colors, fonts, layout patterns -- to another deck's content. Built on python-pptx.
Source content is the authority. Target style is the grammar. Zero target body text leaks.
Branded PPTX files store visual design (logos, decorative shapes, watermarks, backgrounds) as shapes inside slides, not in slide masters/layouts. Traditional layout/master transfer does nothing useful for these files.
The engine analyzes the target template's visual DNA (colors, fonts, logo, layout patterns) then rebuilds each slide from scratch using the source deck's content. Template slides are never copied -- they're only read for style extraction -- so zero template text can leak into the output.
Source PPTX (content) Target PPTX (style)
| |
Extract content Analyze visual DNA
Classify slide types Mine layout patterns
| |
+--------> Rebuild <------+
|
Output PPTX
(source meaning, target grammar)
- Python 3.10+
python-pptxandPillow
pip install -r requirements.txt# template = style source, content = content source
python -m pptx_template_transfer.cli template.pptx content.pptx output.pptx
# With verbose diagnostics
python -m pptx_template_transfer.cli template.pptx content.pptx output.pptx --verbose
# JSON report for automation
python -m pptx_template_transfer.cli template.pptx content.pptx output.pptx --report report.json
# Analyze template shape classifications
python -m pptx_template_transfer.cli --analyze template.pptx
# Extract structured content as JSON
python -m pptx_template_transfer.cli --extract content.pptxfrom pathlib import Path
from pptx_template_transfer import transfer, TransferConfig, Thresholds, BrandingPolicy
# Basic usage
report = transfer(
template=Path("template.pptx"), # style source
content=Path("content.pptx"), # content source
output=Path("output.pptx"),
)
# Full configuration
config = TransferConfig(
mode="recreate",
verbose=True,
preserve_notes=True,
thresholds=Thresholds(title_min_font_pt=18),
branding=BrandingPolicy(
mode="target",
footer_company_override="My Company",
confidentiality_label="Internal Only",
),
)
report = transfer(template, content, output, config)
# Report includes provenance, coverage, and quality
print(report["source_coverage"]["overall_pct"]) # e.g. 100.0
print(report["quality"]["overall_score"]) # e.g. 95.0pptx_template_transfer/
__init__.py # Public API re-exports
cli.py # CLI entry point and transfer() orchestrator
helpers.py # Shared utilities (text_of, word_count, style_runs, etc.)
models.py # All dataclasses (config, content, provenance, quality)
analysis/
theme_extractor.py # Extract visual DNA from template (fonts, colors, logo, footer)
slide_classifier.py # Classify shape roles and slide types
layout_patterns.py # Mine layout archetypes from template slides
extraction/
content_extractor.py # Extract structured content from source slides
semantic_blocks.py # Group paragraphs into semantic blocks
transform/
slide_builder.py # Recreate mode: build slides from scratch with type-specific renderers
clone_injector.py # Clone mode (legacy): clone template slides, inject content
layout_mapper.py # Map content to layout zones
overflow_resolver.py # Detect and resolve text overflow
validation/
contamination_checker.py # Detect target body-text contamination via Jaccard n-gram similarity
source_coverage.py # Track per-slide source content coverage
quality_report.py # Per-slide quality scoring with acceptance gates
overlap_checker.py # Detect shape overlaps
bounds_checker.py # Detect shapes extending beyond slide edges
Extracts the target deck's visual DNA:
- Fonts: Heading and body fonts from theme XML, with frequency-scan fallback
- Colors: Primary, secondary, text, muted, background, card, line -- using saturation-based classification
- Logo: Most frequently repeated image across slides
- Footer: Company name, confidentiality notice, page number format (requires 2+ slide repetition)
- Layout patterns: Column counts, zone roles, text capacities
Parses each source slide into structured data:
- Title: Multi-signal scoring (placeholder type, font size, position, word count)
- Body paragraphs: Ordered text with level, bold/italic, font size, per-run hyperlinks
- Tables: Cell text matrices with formatting
- Images: Content images above area threshold
- Charts: Chart elements for transfer
- Speaker notes: Full text from notes pane
- Slide type: title, agenda, content_narrative, metrics_dashboard, comparison, image_heavy, etc.
Each output slide is built from scratch using type-specific renderers:
| Slide Type | Renderer | Layout |
|---|---|---|
title |
Title slide | Centered title + subtitle |
section |
Section divider | Large section name |
agenda |
Agenda/TOC | Bullet list of items |
metrics_dashboard |
KPI cards | Numbered metric cards |
comparison |
KPI layout | Side-by-side analysis |
content_narrative |
Generic content | Section label + title + body |
image_heavy |
Generic content | Text + image placement |
| Incident slides | Incident renderer | Summary/Actions + Details cards |
Every slide gets:
- Background color from template
- Decorative accent shapes in template colors
- Logo in top-left
- Section label (auto-generated from slide type or title)
- Footer with company name, confidentiality label, page number
Every output block is tagged with its origin:
| Tag | Meaning |
|---|---|
source_content |
Body text, titles -- from source deck |
target_shell |
Footer, logo, decorative shapes -- from template |
converter_generated_bridge |
Section labels, bridge text -- generated |
Hard rule: Body content must come from source_content. Target deck body copy never appears in output.
After building, the pipeline automatically runs:
- Target contamination check: Jaccard 3-gram similarity between output and target body text. Flags if >40% similarity.
- Source coverage report: Per-slide word-level overlap tracking. Warns if overall coverage is weak.
- Quality scoring: Per-slide composite score (coverage - overlap/bounds/font penalties). Acceptance gate at 50/100.
- Text leakage detection: Finds non-boilerplate sentences duplicated across slides.
- Bounds/overlap checking: Detects shapes extending off-slide or overlapping.
All classification thresholds are configurable:
from pptx_template_transfer import Thresholds
th = Thresholds(
title_min_font_pt=16, # Min font size to consider as title
body_min_area_pct=3.0, # Min area % for body shapes
body_max_zones=3, # Max body text zones per slide
decorative_max_area_pct=2.0, # Max area % for decorative shapes
image_min_area_pct=1.5, # Min area % for content images
overflow_max_font_scale=0.70,# Min font scale before overflow warning
)Control how source and target branding appear in the output:
from pptx_template_transfer import BrandingPolicy
branding = BrandingPolicy(
mode="target", # "target" | "source" | "hybrid"
footer_company_override="My Company", # Override auto-detected footer text
confidentiality_label="Internal Only", # Override "Confidential" label
add_source_attribution=True, # Add "Presented by" on title slide
source_company="Acme Corp", # Source company name for attribution
)The transfer() function returns a comprehensive report:
{
"mode": "recreate",
"slides": [
{
"index": 1,
"source_slide": 1,
"content_type": "title",
"title": "Managed Detection and Response (MDR) Report",
"word_count": 17,
"status": "ok",
"provenance": {
"title": "source_content",
"body": "source_content",
"footer": "target_shell",
"section_label": "converter_generated_bridge"
}
}
],
"source_coverage": {
"overall_pct": 100.0,
"total_source_slides": 16,
"total_output_slides": 16,
"unmapped": [],
"entries": [...]
},
"quality": {
"overall_score": 100.0,
"native_count": 16,
"fallback_count": 0,
"slides_needing_review": []
},
"warnings": [],
"errors": []
}# Unit tests (76 tests)
python -m pytest test_pptx_template_transfer.py -v
# Regression tests (26 tests, requires sample decks)
python -m pytest test_regression.py -v
# All tests
python -m pytest -vRegression tests verify:
- Source content is the primary authority in output
- No target body-text contamination
- Source coverage >= 50%
- Content provenance is tracked correctly
- Target shell (fonts, colors, footer) is preserved
- Slide-type classification works
- Section labels are clean (no trailing punctuation/prepositions)
- Incident slides are labeled correctly
- Per-slide quality scores exist and pass acceptance gate
- Quality score >= 50/100
- No empty slides or text leakage
- Built on
python-pptxwithlxmlfor low-level XML manipulation - Run-level font styling via
style_runs()-- paragraph-level.font.namedoesn't persist in XML - Theme inheritance:
Presentation(template_path)preserves slide masters/theme - Aspect ratio detection: 4:3 vs 16:9 triggers reflowed layout (15% threshold)
- Density-aware font scaling based on line count
- Footer detection requires text repetition on 2+ slides to avoid false positives
- Per-slide error isolation: one failed slide doesn't abort the deck
MIT