Image Workflow Examples¶
This guide provides practical examples for working with images in the Glyph SDK.
Basic Image Rendering¶
Simple Image Insertion¶
Insert an image with basic sizing:
from glyph.core.markup.engine.integration import render_markup_to_docx, ImageRegistry
# Register images
registry = ImageRegistry()
registry.register("logo", "assets/company_logo.png")
# Create markup
markup = """
$glyph-bold-font-size-24-align-center
Company Annual Report
$glyph
$glyph-image-id-logo-image-width-2in-image-align-center
$glyph
$glyph-align-center
Fiscal Year 2025
$glyph
"""
# Render
render_markup_to_docx(markup, output_path="report.docx", image_registry=registry)
Multiple Images¶
Include several images in a document:
from glyph.core.markup.engine.integration import render_markup_to_docx, ImageRegistry
# Register multiple images
registry = ImageRegistry()
registry.register("chart1", "charts/revenue_chart.png")
registry.register("chart2", "charts/expenses_chart.png")
registry.register("chart3", "charts/profit_chart.png")
markup = """
$glyph-bold-font-size-18
Financial Overview
$glyph
$glyph-image-id-chart1-image-width-5in-image-height-3in-image-align-center
Figure 1: Revenue Growth
$glyph
Our revenue increased by 25% year-over-year.
$glyph-image-id-chart2-image-width-5in-image-height-3in-image-align-center
Figure 2: Expense Breakdown
$glyph
Operating expenses were well-controlled.
$glyph-image-id-chart3-image-width-5in-image-height-3in-image-align-center
Figure 3: Net Profit Margin
$glyph
We achieved record profitability this year.
"""
render_markup_to_docx(markup, output_path="financial_report.docx", image_registry=registry)
Images with Captions¶
Add descriptive captions to images:
registry = ImageRegistry()
registry.register("diagram", "assets/architecture_diagram.png")
markup = """
$glyph-bold-font-size-18
System Architecture
$glyph
The following diagram shows our microservices architecture:
$glyph-image-id-diagram-image-width-6in-image-align-center-image-caption-below
Figure 1: Microservices Architecture showing API Gateway, Auth Service, and Data Layer
$glyph
$glyph-italic
Note: All services communicate via REST APIs with JWT authentication.
$glyph
"""
render_markup_to_docx(markup, output_path="architecture.docx", image_registry=registry)
Image Extraction¶
Extract from DOCX¶
Extract images and metadata from an existing DOCX file:
from glyph.core.schema import GlyphSchemaBuilder
from glyph.core.workspace.storage.fs import FilesystemWorkspace
from zipfile import ZipFile
# Extract DOCX
with ZipFile("source.docx", 'r') as zip_ref:
zip_ref.extractall("extracted/")
# Create workspace
workspace = FilesystemWorkspace(root_dir="./workspace", use_uuid=True)
# Build schema with image extraction
builder = GlyphSchemaBuilder(
document_xml_path="extracted/word/document.xml",
docx_extract_dir="extracted",
tag="project_alpha"
)
schema = builder.run(workspace=workspace, copy_images=True)
# Inspect extracted images
print(f"Found {len(schema['images'])} images:\n")
for img in schema["images"]:
print(f"ID: {img['id']}")
print(f" Name: {img['name']}")
print(f" Size: {img['width_inches']:.2f} x {img['height_inches']:.2f} inches")
print(f" Path: {img['workspace_path']}")
print(f" Alt text: {img['alt_text']}")
print()
Process Extracted Images¶
Modify extracted images before rendering:
from PIL import Image
from glyph.core.markup.engine.integration import ImageRegistry
# Extract images (as above)
schema = builder.run(workspace=workspace, copy_images=True)
# Process images
registry = ImageRegistry()
for img in schema["images"]:
# Open and process
pil_image = Image.open(img["workspace_path"])
# Convert to grayscale
grayscale = pil_image.convert('L')
# Save processed version
processed_path = img["workspace_path"].replace(".png", "_gray.png")
grayscale.save(processed_path)
# Register processed image
registry.register(img["id"], processed_path)
# Use in markup...
Round-Trip Workflows¶
Complete DOCX Round-Trip¶
Extract from DOCX, generate plaintext, edit, and render back:
from glyph.core.schema import GlyphSchemaBuilder
from glyph.core.workspace.storage.fs import FilesystemWorkspace
from glyph.runner import schema_to_plaintext
from glyph.core.markup.engine.integration import render_markup_to_docx, ImageRegistry
from zipfile import ZipFile
from pathlib import Path
# 1. Extract source DOCX
source_docx = "source_template.docx"
extract_dir = "extracted/"
with ZipFile(source_docx, 'r') as zip_ref:
zip_ref.extractall(extract_dir)
# 2. Create workspace
workspace = FilesystemWorkspace(root_dir="./workspace", use_uuid=True)
# 3. Build schema with images
builder = GlyphSchemaBuilder(
document_xml_path=f"{extract_dir}/word/document.xml",
docx_extract_dir=extract_dir,
source_docx=source_docx,
tag="template_v1"
)
schema = builder.run(workspace=workspace, copy_images=True)
print(f"✓ Extracted {len(schema['images'])} images")
print(f"✓ Analyzed {len(schema['pattern_descriptors'])} paragraphs")
# 4. Generate editable plaintext
plaintext_path = Path(workspace.directory("output_plaintext")) / "editable.glyph.txt"
plaintext = schema_to_plaintext(schema, output_path=str(plaintext_path))
print(f"✓ Generated plaintext: {plaintext_path}")
print("\nYou can now edit the plaintext file.")
print("Example edits:")
print(" - Change text content")
print(" - Adjust image sizes (image-width-4in → image-width-5in)")
print(" - Change alignment (image-align-left → image-align-center)")
print("\nPress Enter when ready to render...")
input()
# 5. Create image registry
registry = ImageRegistry()
for img in schema["images"]:
registry.register(img["id"], img["workspace_path"])
# 6. Render edited plaintext to DOCX
with open(plaintext_path) as f:
edited_markup = f.read()
output_path = Path(workspace.directory("output_docx")) / "final.docx"
render_markup_to_docx(
edited_markup,
output_path=str(output_path),
image_registry=registry,
validate=False # Skip validation for schema-generated markup
)
print(f"✓ Generated final DOCX: {output_path}")
Template-Based Generation¶
Use extracted schema as a template for multiple documents:
# Extract template schema once
template_schema = builder.run(workspace=workspace, copy_images=True)
# Create registry from template
base_registry = ImageRegistry()
for img in template_schema["images"]:
base_registry.register(img["id"], img["workspace_path"])
# Generate multiple documents with different content
documents = [
{"title": "Q1 Report", "revenue": 1.2, "chart": "q1_chart.png"},
{"title": "Q2 Report", "revenue": 1.5, "chart": "q2_chart.png"},
{"title": "Q3 Report", "revenue": 1.8, "chart": "q3_chart.png"},
{"title": "Q4 Report", "revenue": 2.1, "chart": "q4_chart.png"},
]
for doc in documents:
# Clone base registry
registry = ImageRegistry(images=base_registry.images.copy())
# Add quarter-specific chart
registry.register("quarterly_chart", f"charts/{doc['chart']}")
# Generate markup
markup = f"""
$glyph-bold-font-size-24-align-center
{doc['title']}
$glyph
$glyph-image-id-logo-image-width-2in-image-align-center
$glyph
$glyph-bold-font-size-18
Financial Summary
$glyph
Revenue: ${doc['revenue']}M
$glyph-image-id-quarterly_chart-image-width-5in-image-height-3in-image-align-center
Quarterly Performance
$glyph
"""
# Render
output_file = f"reports/{doc['title'].replace(' ', '_').lower()}.docx"
render_markup_to_docx(markup, output_path=output_file, image_registry=registry)
print(f"✓ Generated {output_file}")
Dynamic Image Generation¶
Generate Charts with Matplotlib¶
Create charts programmatically and include in documents:
import matplotlib.pyplot as plt
from glyph.core.markup.engine.integration import render_markup_to_docx, ImageRegistry
# Generate revenue chart
def create_revenue_chart(quarters, revenues, output_path):
plt.figure(figsize=(6, 4))
plt.bar(quarters, revenues, color='steelblue')
plt.xlabel('Quarter')
plt.ylabel('Revenue ($M)')
plt.title('Quarterly Revenue')
plt.grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.savefig(output_path, dpi=300, bbox_inches='tight')
plt.close()
# Generate profit chart
def create_profit_chart(quarters, profits, output_path):
plt.figure(figsize=(6, 4))
plt.plot(quarters, profits, marker='o', linewidth=2, color='green')
plt.xlabel('Quarter')
plt.ylabel('Profit ($M)')
plt.title('Quarterly Profit Trend')
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.savefig(output_path, dpi=300, bbox_inches='tight')
plt.close()
# Data
quarters = ['Q1', 'Q2', 'Q3', 'Q4']
revenues = [1.2, 1.5, 1.8, 2.1]
profits = [0.3, 0.4, 0.5, 0.7]
# Generate charts
revenue_chart = "/tmp/revenue_chart.png"
profit_chart = "/tmp/profit_chart.png"
create_revenue_chart(quarters, revenues, revenue_chart)
create_profit_chart(quarters, profits, profit_chart)
# Register and render
registry = ImageRegistry()
registry.register("revenue", revenue_chart)
registry.register("profit", profit_chart)
markup = """
$glyph-bold-font-size-24-align-center
2025 Financial Report
$glyph
$glyph-bold-font-size-18
Revenue Analysis
$glyph
$glyph-image-id-revenue-image-width-5in-image-align-center
Figure 1: Quarterly Revenue
$glyph
Revenue showed consistent growth throughout the year.
$glyph-bold-font-size-18
Profitability
$glyph
$glyph-image-id-profit-image-width-5in-image-align-center
Figure 2: Profit Trend
$glyph
Profit margins improved significantly in Q4.
"""
render_markup_to_docx(markup, output_path="financial_report.docx", image_registry=registry)
QR Code Generation¶
Generate and embed QR codes:
import qrcode
from glyph.core.markup.engine.integration import render_markup_to_docx, ImageRegistry
def generate_qr_code(data, output_path):
qr = qrcode.QRCode(version=1, box_size=10, border=4)
qr.add_data(data)
qr.make(fit=True)
img = qr.make_image(fill_color="black", back_color="white")
img.save(output_path)
# Generate QR codes
website_qr = "/tmp/website_qr.png"
contact_qr = "/tmp/contact_qr.png"
generate_qr_code("https://example.com", website_qr)
generate_qr_code("mailto:contact@example.com", contact_qr)
# Register and render
registry = ImageRegistry()
registry.register("website", website_qr)
registry.register("contact", contact_qr)
markup = """
$glyph-bold-font-size-18-align-center
Connect With Us
$glyph
$glyph-align-center
Visit our website:
$glyph
$glyph-image-id-website-image-width-1.5in-image-align-center
$glyph
$glyph-align-center
Or email us:
$glyph
$glyph-image-id-contact-image-width-1.5in-image-align-center
$glyph
"""
render_markup_to_docx(markup, output_path="contact_card.docx", image_registry=registry)
Batch Processing¶
Process Multiple DOCX Files¶
Extract images from multiple documents:
from pathlib import Path
from glyph.core.schema import GlyphSchemaBuilder
from glyph.core.workspace.storage.fs import FilesystemWorkspace
from zipfile import ZipFile
import json
# Create workspace
workspace = FilesystemWorkspace(root_dir="./batch_workspace", use_uuid=True)
# Process all DOCX files
docx_files = Path("templates/").glob("*.docx")
results = []
for docx_path in docx_files:
print(f"Processing {docx_path.name}...")
# Extract
extract_dir = f"extracted/{docx_path.stem}"
with ZipFile(docx_path, 'r') as zip_ref:
zip_ref.extractall(extract_dir)
# Build schema
builder = GlyphSchemaBuilder(
document_xml_path=f"{extract_dir}/word/document.xml",
docx_extract_dir=extract_dir,
tag=docx_path.stem
)
schema = builder.run(workspace=workspace, copy_images=True)
# Save schema
schema_path = f"schemas/{docx_path.stem}.json"
Path("schemas").mkdir(exist_ok=True)
with open(schema_path, 'w') as f:
json.dump(schema, f, indent=2)
results.append({
"file": docx_path.name,
"images": len(schema["images"]),
"paragraphs": len(schema["pattern_descriptors"]),
"schema_path": schema_path
})
print(f" ✓ Extracted {len(schema['images'])} images")
# Summary
print("\nBatch Processing Summary:")
print(f"Processed {len(results)} documents")
print(f"Total images: {sum(r['images'] for r in results)}")
for r in results:
print(f" {r['file']}: {r['images']} images → {r['schema_path']}")
Bulk Image Optimization¶
Optimize images for all documents:
from PIL import Image
from pathlib import Path
def optimize_image(src_path, max_width=1200, quality=85):
"""Optimize image size and quality."""
img = Image.open(src_path)
# Resize if too large
if img.width > max_width:
ratio = max_width / img.width
new_height = int(img.height * ratio)
img = img.resize((max_width, new_height), Image.LANCZOS)
# Optimize
optimized_path = src_path.replace(".png", "_opt.png")
if src_path.endswith('.png'):
img.save(optimized_path, "PNG", optimize=True)
elif src_path.endswith(('.jpg', '.jpeg')):
img.save(optimized_path.replace('.png', '.jpg'), "JPEG", quality=quality, optimize=True)
return optimized_path
# Process all workspace images
image_dir = Path(workspace.directory("input_images"))
for img_file in image_dir.glob("*.png"):
optimized = optimize_image(str(img_file))
original_size = img_file.stat().st_size
optimized_size = Path(optimized).stat().st_size
savings = (1 - optimized_size / original_size) * 100
print(f"{img_file.name}: {original_size:,} → {optimized_size:,} bytes ({savings:.1f}% reduction)")