LayerD supports exporting decomposed layers to two formats:
- SVG - Scalable Vector Graphics with embedded or external images
- PSD - Adobe Photoshop Document with editable layers
Both formats preserve the layer structure and can be edited in design tools. Export is performed through PipelineResult methods after running the pipeline.
from layerd import LayerDPipeline
pipeline = LayerDPipeline()
result = pipeline(image)
# Export to either format
result.save("output.svg") # SVG
result.save("output.psd") # PSDSVG export creates a standards-compliant SVG file with images embedded as data URIs (default) or external file references:
# Default: base64 embedded images
result.save("output.svg")
# Or get the SVG string
svg_string = result.to_svg()
with open("output.svg", "w") as f:
f.write(svg_string)Images are embedded as data URIs directly in the SVG:
result.save("output.svg") # Uses base64 by default
# Explicit base64 mode
svg_string = result.to_svg(image_mode="base64")Advantages:
- Single self-contained file
- No external dependencies
- Easy to share and view
Disadvantages:
- Larger file size (~33% larger than binary)
- Not suitable for very large images
Images are saved as separate PNG files and referenced by path:
# Save with external images
result.save("output.svg", image_mode="external", image_dir="./images")
# Or using to_svg()
svg_string = result.to_svg(image_mode="external", image_dir="./images")
with open("output.svg", "w") as f:
f.write(svg_string)This creates:
./output.svg
./images/element_0.png
./images/element_1.png
./images/element_2.png
...
Advantages:
- Smaller SVG file size
- Images can be edited separately
- Better for version control (text diff-able SVG)
Disadvantages:
- Multiple files to manage
- Requires preserving directory structure
The generated SVG has a clean structure with metadata:
<svg width="800" height="600" xmlns="http://www.w3.org/2000/svg">
<image x="10" y="20" width="100" height="50"
href="data:image/png;base64,..."
data-type="text"
data-id="0" />
<image x="150" y="80" width="200" height="150"
href="data:image/png;base64,..."
data-type="vector"
data-id="1" />
...
</svg>Metadata Attributes:
data-type: Element type ("text", "vector", or "image")data-id: Unique element identifier
These attributes enable round-trip conversion and programmatic manipulation.
SVG files can be opened in:
- Web Browsers - Chrome, Firefox, Safari, Edge (native support)
- Vector Editors - Adobe Illustrator, Inkscape, Figma
- Image Viewers - Most modern image viewers
- Design Tools - Sketch, Affinity Designer
PSD export creates an Adobe Photoshop document with each element as a separate layer:
# Export to PSD
result.save("output.psd")
# Or get PSD bytes
psd_bytes = result.to_psd()
with open("output.psd", "wb") as f:
f.write(psd_bytes)In Photoshop, you'll see:
- Each element as a separate layer
- Layers named by element ID and type (e.g., "element_0_text")
- Original positioning preserved
- RGBA transparency maintained
PSD files are typically larger than SVG because they store full raster data:
- SVG with base64: ~33% larger than PNG
- SVG with external: Small text file + PNG images
- PSD: Similar to sum of all PNGs + overhead
For a design with 10 elements:
- SVG (base64): ~500 KB
- SVG (external): ~50 KB SVG + 450 KB images
- PSD: ~600 KB
PSD files can be opened in:
- Adobe Photoshop - Native format
- GIMP - Open source image editor
- Affinity Photo - Professional photo editor
- Photopea - Web-based Photoshop alternative
| Feature | SVG | PSD |
|---|---|---|
| File size | Small-Medium | Large |
| Web display | Native browser support | Requires conversion |
| Editing tools | Browsers, Illustrator, Figma | Photoshop, GIMP |
| Text preservation | As raster images | As raster images |
| Layer metadata | Yes (data attributes) | Limited |
| Scalability | Vector format (scalable) | Raster format (fixed resolution) |
| Transparency | Full RGBA support | Full RGBA support |
| Single file | Optional (base64 mode) | Yes |
| Version control | Good (especially external mode) | Poor (binary format) |
- You need web compatibility
- File size is important
- You want version control-friendly output
- You'll edit in vector tools (Illustrator, Figma)
- You want programmatic manipulation
- You're working in Photoshop
- You need native Adobe ecosystem support
- You want full raster editing capabilities
- Single-file distribution is important
Export to both formats for maximum flexibility:
result.save("output.svg")
result.save("output.psd")The save() method auto-detects format from file extension:
# Auto-detection
result.save("output.svg") # Calls to_svg()
result.save("output.psd") # Calls to_psd()
# Explicit format (overrides extension)
result.save("output.dat", format="svg")
# Format-specific options
result.save("output.svg", image_mode="external", image_dir="./images")For large projects with many images:
from pathlib import Path
# Process multiple designs
designs_dir = Path("./designs")
output_dir = Path("./output")
pipeline = LayerDPipeline(device="cuda")
for design_path in designs_dir.glob("*.png"):
image = Image.open(design_path)
result = pipeline(image)
# Create dedicated image directory per design
design_name = design_path.stem
svg_path = output_dir / f"{design_name}.svg"
img_dir = output_dir / f"{design_name}_images"
result.save(str(svg_path), image_mode="external", image_dir=str(img_dir))This creates:
./output/
design1.svg
design1_images/
element_0.png
element_1.png
design2.svg
design2_images/
element_0.png
element_1.png
Export the same decomposition to multiple formats:
result = pipeline(image)
# Export to all formats
formats = {
"svg_base64": ("output_base64.svg", {"image_mode": "base64"}),
"svg_external": ("output_external.svg", {"image_mode": "external", "image_dir": "./images"}),
"psd": ("output.psd", {}),
}
for name, (path, kwargs) in formats.items():
result.save(path, **kwargs)
print(f"Saved {name}: {path}")Organize exported files by element type:
result = pipeline(image)
# Group elements by type
from collections import defaultdict
by_type = defaultdict(list)
for elem in result.elements:
by_type[elem["type"]].append(elem)
# Export each type separately
for elem_type, elements in by_type.items():
# Create custom PipelineResult with filtered elements
filtered_result = PipelineResult(
elements=elements,
layers=result.layers,
ocr_result=result.ocr_result,
canvas_size=result.canvas_size
)
filtered_result.save(f"output_{elem_type}.svg")def to_svg(
self,
image_mode: Literal["base64", "external"] = "base64",
image_dir: str | None = None,
) -> strGenerate SVG string representation.
Parameters:
image_mode: Image embedding mode"base64"(default): Embed images as data URIs"external": Save images to directory and reference by path
image_dir: Directory for external images (required ifimage_mode="external")
Returns:
- SVG string
Raises:
ValueError: Ifimage_mode="external"butimage_dirnot provided
def to_psd(self) -> bytesGenerate PSD bytes representation.
Returns:
- PSD file as bytes
def save(
self,
path: str,
format: str | None = None,
**kwargs: Any,
) -> NoneSave result to file with format auto-detection.
Parameters:
path: Output file path (supports various file systems viafsspec: local paths,gs://,s3://,abfs://,https://)format: Export format ("svg"or"psd"), auto-detected from extension ifNone**kwargs: Format-specific options passed toto_svg()orto_psd()
Raises:
ValueError: If format cannot be determined or is unsupported
Note: This method supports various file systems through fsspec, allowing you to save directly to cloud storage (e.g., Google Cloud Storage, Amazon S3, Azure Blob Storage) or HTTP endpoints.
from layerd import LayerDPipeline
from PIL import Image
pipeline = LayerDPipeline()
image = Image.open("design.png")
result = pipeline(image)
# Simple save (default base64)
result.save("output.svg")
# Explicit base64
svg_string = result.to_svg(image_mode="base64")
with open("output_explicit.svg", "w") as f:
f.write(svg_string)# Save with external images
result.save("output.svg", image_mode="external", image_dir="./images")
# Verify files
from pathlib import Path
print(f"SVG size: {Path('output.svg').stat().st_size} bytes")
print(f"Images: {list(Path('./images').glob('*.png'))}")# Simple PSD export
result.save("output.psd")
# Or with explicit bytes
psd_bytes = result.to_psd()
with open("output_manual.psd", "wb") as f:
f.write(psd_bytes)
print(f"PSD size: {len(psd_bytes)} bytes")import os
result = pipeline(image)
# Export to all formats
result.save("output_base64.svg", image_mode="base64")
result.save("output_external.svg", image_mode="external", image_dir="./images")
result.save("output.psd")
# Compare file sizes
formats = ["output_base64.svg", "output_external.svg", "output.psd"]
for fmt in formats:
size = os.path.getsize(fmt)
print(f"{fmt}: {size:,} bytes ({size/1024:.1f} KB)")- Pipeline Guide - LayerDPipeline usage and configuration
- Architecture - Export module architecture
- Troubleshooting - Common export issues