API Reference
This section documents the public API of psd2svg.
Main API
convert()
- psd2svg.convert(input_path, output_path, image_prefix=None, enable_text=True, enable_live_shapes=True, enable_title=False, enable_class=False, image_format='webp', text_letter_spacing_offset=0.0, text_wrapping_mode=0, font_mapping=None, embed_fonts=False, font_format='woff2', resource_limits=None)[source]
Convenience method to convert a PSD file to an SVG file.
- Parameters:
input_path (
str) – Path to the input PSD file.output_path (
str) – Path to the output SVG file.image_prefix (
str|None) – Optional path prefix to save extracted images. If None, images will be embedded.enable_text (
bool) – Enable text layer conversion. If False, text layers are rasterized as images. Default is True.enable_live_shapes (
bool) – Enable live shape conversion when possible. Disabling live shapes results in <path> elements instead of shape primitives like <rect> or <circle>. This may be more accurate, but less editable. Default is True.enable_title (
bool) – Enable insertion of <title> elements with layer names. When False (default), title elements are omitted to reduce file size. Set to True to include <title> elements containing the Photoshop layer name for accessibility and debugging.enable_class (
bool) – Enable insertion of class attributes on SVG elements for debugging purposes. When False (default), elements will not have class attributes, producing cleaner SVG output. Set to True to add class attributes for layer types, effects, and semantic roles (e.g., “shape-layer”, “drop-shadow-effect”, “fill”) for debugging or styling.image_format (
str) – Image format to use when embedding or saving images. Supported formats: ‘webp’, ‘png’, ‘jpeg’. Default is ‘webp’.text_letter_spacing_offset (
float) – Global offset (in pixels) to add to all letter-spacing values. This can be used to compensate for differences between Photoshop’s text rendering and SVG’s text rendering. Typical values range from -0.02 to 0.02. Default is 0.0 (no offset).text_wrapping_mode (
int) – Text wrapping mode for bounding box text. Use 0 for no wrapping (default, native SVG <text>), or 1 for <foreignObject> with XHTML wrapping. Import TextWrappingMode from psd2svg.core.text for enum values. Only affects bounding box text (ShapeType=1); point text always uses native SVG <text> elements.font_mapping (
dict[str,dict[str,float|str]] |None) – Optional custom font mapping dictionary for resolving PostScript font names to font families without fontconfig. Useful on Windows or when fonts are not installed. Format: {“PostScriptName”: {“family”: str, “style”: str, “weight”: float}}. When not provided, uses built-in mapping for common fonts.embed_fonts (
bool) – Enable font embedding in SVG. When True, fonts used in text layers are embedded as base64-encoded data URIs in @font-face rules. Default is False. Requires fontconfig on Linux/macOS for font file discovery.font_format (
str) – Font format for embedding. Supported formats: ‘woff2’ (best compression, default), ‘woff’, ‘ttf’, ‘otf’. Only used when embed_fonts=True. WOFF2 provides 90%+ size reduction through automatic font subsetting.resource_limits (
ResourceLimits|None) – Optional resource limits for DoS prevention. If None, uses ResourceLimits.default() which enables limits (2GB file size, 3 minute timeout, 100 layer depth, 16K image dimension). Use ResourceLimits.unlimited() to disable all limits for trusted input.
- Raises:
ValueError – If file size, layer depth, or image dimensions exceed limits.
TimeoutError – If conversion exceeds timeout limit.
- Return type:
SVGDocument
- class psd2svg.SVGDocument(svg, images=<factory>)[source]
Bases:
objectSVG document and resources.
Example usage:
from psd_tools import PSDImage from psd2svg import SVGDocument # Create from PSDImage. psdimage = PSDImage.open("input.psd") document = SVGDocument.from_psd(psdimage) # Save to file or get as string. document.save("output.svg") # Images embedded by default svg_string = document.tostring() # Rasterize to PIL Image. rasterized = document.rasterize() # Export and load back. exported = document.export() document = SVGDocument.load(exported["svg"], exported["images"])
- static from_psd(psdimage, enable_live_shapes=True, enable_text=True, enable_title=False, enable_class=False, text_letter_spacing_offset=0.0, text_wrapping_mode=0, font_mapping=None, resource_limits=None)[source]
Create a new SVGDocument from a PSDImage.
- Parameters:
psdimage (
PSDImage) – PSDImage object to convert.enable_live_shapes (
bool) – Enable live shape conversion when possible. Disabling live shapes results in <path> elements instead of shape primitives like <rect> or <circle>. This may be more accurate, but less editable.enable_text (
bool) – Enable text layer conversion. If False, text layers are rasterized as images.enable_title (
bool) – Enable insertion of <title> elements with layer names. When False (default), title elements are omitted to reduce file size. Set to True to include <title> elements containing the Photoshop layer name for accessibility and debugging.enable_class (
bool) – Enable insertion of class attributes on SVG elements for debugging purposes. When False (default), elements will not have class attributes, producing cleaner SVG output. Set to True to add class attributes for layer types, effects, and semantic roles (e.g., “shape-layer”, “drop-shadow-effect”, “fill”) for debugging or styling.text_letter_spacing_offset (
float) – Global offset (in pixels) to add to all letter-spacing values. This can be used to compensate for differences between Photoshop’s text rendering and SVG’s text rendering. Typical values range from -0.02 to 0.02. Default is 0.0 (no offset).text_wrapping_mode (
int) – Text wrapping mode for bounding box text. Use 0 for no wrapping (default, native SVG <text>), or 1 for <foreignObject> with XHTML wrapping. Import TextWrappingMode from psd2svg.core.text for enum values. Only affects bounding box text (ShapeType=1); point text always uses native SVG <text> elements.font_mapping (
dict[str,dict[str,float|str]] |None) – Optional custom font mapping dictionary for resolving PostScript font names to font families. Takes priority over built-in static mapping. Useful for providing custom fonts or overriding default mappings. Format: {“PostScriptName”: {“family”: str, “style”: str, “weight”: float}}. Example: {“ArialMT”: {“family”: “Arial”, “style”: “Regular”, “weight”: 80.0}}. When not provided, uses built-in mapping for ~4,950 fonts (539 default + 370 Hiragino + 4,042 Morisawa), with automatic fallback to system font resolution (fontconfig/Windows registry) if needed.resource_limits (
ResourceLimits|None) – Optional resource limits for DoS prevention. If None, uses ResourceLimits.default() which enables limits (2GB file size, 3 minute timeout, 100 layer depth, 16K image dimension). Use ResourceLimits.unlimited() to disable all limits for trusted input.
- Return type:
- Returns:
SVGDocument object containing the converted SVG and images.
- Raises:
ValueError – If layer depth or image dimensions exceed limits.
TimeoutError – If conversion exceeds timeout limit.
- append_css(css)[source]
Append custom CSS rules to the SVG <style> element.
This method allows you to inject custom CSS rules into the SVG document. The CSS is appended to an existing <style> element if present, or a new <style> element is created as the first child of the root SVG element.
- Parameters:
css (
str) – CSS rules to append. Can be any valid CSS including selectors, media queries, keyframes, etc.- Return type:
Example
>>> from psd_tools import PSDImage >>> from psd2svg import SVGDocument >>> >>> psdimage = PSDImage.open("input.psd") >>> svg_doc = SVGDocument.from_psd(psdimage) >>> >>> # Add custom CSS for Japanese text >>> svg_doc.append_css( ... "text { font-variant-east-asian: proportional-width; }" ... ) >>> >>> # Add more custom CSS >>> svg_doc.append_css("@media print { .no-print { display: none; } }") >>> >>> svg_doc.save("output.svg")
Note
This method is idempotent - if the same CSS is appended multiple times, it will only appear once in the output (duplicate detection).
- tostring(embed_images=True, embed_fonts=False, subset_fonts=True, font_format='woff2', image_prefix=None, image_format='webp', indent=' ', optimize=True)[source]
Convert SVG document to string.
- Parameters:
embed_images (
bool) – If True, embed images as base64 data URIs. Default is True since string output has no file system context for external images.embed_fonts (
bool) – If True, embed fonts as @font-face rules in <style> element. WARNING: Font embedding may be subject to licensing restrictions. Ensure you have appropriate rights before distributing SVG files with embedded fonts.subset_fonts (
bool) – If True, subset fonts to only include glyphs used in the SVG. Requires embed_fonts=True. This significantly reduces file size (typically 90%+ reduction). Default is True.font_format (
str) – Font format for embedding: “woff2” (default), “woff”, “ttf”, or “otf”. WOFF2 provides best compression and is recommended for web use.image_prefix (
str|None) – If provided, save images to files with this prefix. When specified, embed_images is ignored.image_format (
str) – Image format to use when embedding or saving images.indent (
str) – Indentation string for pretty-printing the SVG.optimize (
bool) – If True, apply SVG optimizations (consolidate defs, etc.). Default is True.
- Return type:
- save(filepath, embed_images=True, embed_fonts=False, subset_fonts=True, font_format='woff2', image_prefix=None, image_format='webp', indent=' ', optimize=True)[source]
Save the SVG to a file.
- Parameters:
filepath (
str) – Path to the output SVG file.embed_images (
bool) – If True, embed images as base64 data URIs. Default is True. Set to False and provide image_prefix to save images as external files.embed_fonts (
bool) – If True, embed fonts as @font-face rules in <style> element. WARNING: Font embedding may be subject to licensing restrictions. Ensure you have appropriate rights before distributing SVG files with embedded fonts.subset_fonts (
bool) – If True, subset fonts to only include glyphs used in the SVG. Requires embed_fonts=True. This significantly reduces file size (typically 90%+ reduction). Default is True.font_format (
str) – Font format for embedding: “woff2” (default), “woff”, “ttf”, or “otf”. WOFF2 provides best compression and is recommended for web use.image_prefix (
str|None) – If provided, save images to files with this prefix relative to the output SVG file’s directory.image_format (
str) – Image format to use when embedding or saving images.indent (
str) – Indentation string for pretty-printing the SVG.optimize (
bool) – If True, apply SVG optimizations (consolidate defs, etc.). Default is True.
- Return type:
- rasterize(dpi=0, rasterizer=None)[source]
Rasterize the SVG document to PIL Image.
- Parameters:
dpi (
int) – Dots per inch for rendering. If 0 (default), uses the rasterizer’s default (96 DPI for ResvgRasterizer). Higher values produce larger, higher resolution images (e.g., 300 DPI for print quality). Only used if rasterizer is None.rasterizer (
BaseRasterizer|None) – Optional custom rasterizer instance. If None, uses ResvgRasterizer with the specified dpi. Use this to specify alternative rasterizers like PlaywrightRasterizer for better SVG 2.0 feature support.
- Return type:
- Returns:
PIL Image object in RGBA mode containing the rasterized SVG.
Note
When using PlaywrightRasterizer, fonts are automatically embedded using local file:// URLs for optimal performance (60-80% faster than data URIs, 99% smaller SVG strings).
Example
>>> # Default resvg rasterization >>> image = document.rasterize()
>>> # High DPI rasterization >>> image = document.rasterize(dpi=300)
>>> # Browser-based rasterization (fonts auto-embedded with file URLs) >>> from psd2svg.rasterizer import PlaywrightRasterizer >>> browser_rasterizer = PlaywrightRasterizer(dpi=96) >>> image = document.rasterize(rasterizer=browser_rasterizer)
- export(image_format='webp', indent=' ')[source]
Export the SVG document in a serializable format.
Note: Font information is now embedded in SVG font-family attributes, so no separate fonts list is exported.
- classmethod load(svg, images)[source]
Load an SVGDocument from SVG content and image bytes.
- Parameters:
- Return type:
Note
Font information is stored in SVG font-family attributes, not as a separate parameter.
- __init__(svg, images=<factory>)
Rasterizers
Base Rasterizer
- class psd2svg.rasterizer.BaseRasterizer[source]
Bases:
ABCBase class for SVG rasterizer implementations.
This abstract base class defines the interface for converting SVG documents to raster images (PIL Image objects). Subclasses must implement the from_file method to provide the actual rasterization logic.
- from_string(svg_content)[source]
Rasterize SVG content from a string or bytes to a PIL Image.
This is a convenience method that writes the SVG content to a temporary file and calls from_file. Subclasses may override this for more efficient implementations.
Resvg Rasterizer
- class psd2svg.rasterizer.ResvgRasterizer(dpi=0)[source]
Bases:
BaseRasterizerHigh-performance SVG rasterizer using resvg.
This rasterizer uses the resvg library (via resvg-py) to convert SVG documents to raster images. Resvg is a fast, accurate SVG renderer written in Rust that provides excellent quality with minimal dependencies.
Note
Resvg does not support CSS @font-face rules with embedded fonts (data URIs). This implementation automatically extracts font file paths from @font-face src: url(”file://…”) declarations and passes them to resvg’s native font loading API. The @font-face CSS rules themselves are ignored by resvg. Data URIs (data:font/…) are not supported and will be silently ignored.
Example
>>> rasterizer = ResvgRasterizer(dpi=96) >>> image = rasterizer.from_file('input.svg') >>> image.save('output.png')
>>> svg_content = '<svg>...</svg>' >>> image = rasterizer.from_string(svg_content) >>> image.save('output.png')
- __init__(dpi=0)[source]
Initialize the resvg rasterizer.
- Parameters:
dpi (
int) – Dots per inch for rendering. If 0 (default), uses resvg’s default of 96 DPI. Higher values produce larger, higher resolution images (e.g., 300 DPI for print quality).
- from_file(filepath, font_files=None)[source]
Rasterize an SVG file to a PIL Image.
- Parameters:
- Return type:
- Returns:
PIL Image object in RGBA mode containing the rasterized SVG.
- Raises:
ValueError – If the SVG file does not exist or the content is invalid.
- from_string(svg_content, font_files=None)[source]
Rasterize SVG content from a string to a PIL Image.
This method provides an optimized implementation that directly rasterizes the SVG content without creating a temporary file.
If font_files is not provided, this method automatically extracts font file paths from @font-face CSS rules in the SVG content (file:// URLs).
- Parameters:
- Return type:
- Returns:
PIL Image object in RGBA mode containing the rasterized SVG.
- Raises:
ValueError – If the SVG content is invalid.
Fast, production-ready SVG rasterizer using the resvg rendering engine.
Example:
from psd2svg.rasterizer import ResvgRasterizer
# Create rasterizer instance
rasterizer = ResvgRasterizer(dpi=96)
# Rasterize from string
image = rasterizer.from_string(svg_string)
# Rasterize from file
image = rasterizer.from_file('input.svg')
Playwright Rasterizer
- class psd2svg.rasterizer.PlaywrightRasterizer(dpi=96, browser_type='chromium')[source]
Bases:
BaseRasterizerBrowser-based SVG rasterizer using Playwright.
This rasterizer uses Playwright’s headless Chromium to render SVG documents, providing accurate support for advanced SVG features including vertical text, text-orientation, dominant-baseline, and other SVG 2.0 features that may not be supported by native rasterizers.
Note
Requires Playwright to be installed: uv sync –group browser After installation, run: uv run playwright install chromium
- Advantages:
Full SVG 2.0 feature support
Accurate vertical text rendering
Matches browser rendering exactly
- Disadvantages:
Slower than native rasterizers (browser startup overhead)
Requires Chromium binary (~300MB)
More resource intensive
Example
>>> rasterizer = PlaywrightRasterizer(dpi=96) >>> image = rasterizer.from_file('input.svg') >>> image.save('output.png')
>>> # Use as context manager for automatic cleanup >>> with PlaywrightRasterizer(dpi=96) as rasterizer: ... image = rasterizer.from_string('<svg>...</svg>') ... image.save('output.png')
- classmethod is_available()[source]
Check if Playwright is available.
- Return type:
- Returns:
True if Playwright is installed and can be used, False otherwise.
Example
>>> if PlaywrightRasterizer.is_available(): ... rasterizer = PlaywrightRasterizer() ... else: ... print("Playwright not available")
- __init__(dpi=96, browser_type='chromium')[source]
Initialize the Playwright rasterizer.
- Parameters:
dpi (
int) – Dots per inch for rendering. Higher values produce larger, higher resolution images (e.g., 300 DPI for print quality). Default is 96 DPI (standard screen resolution).browser_type (
Literal['chromium','firefox','webkit']) – Browser engine to use. Options are: - “chromium”: Best SVG support (recommended) - “firefox”: Good compatibility - “webkit”: Safari engine Default is “chromium”.
- from_file(filepath)[source]
Rasterize an SVG file to a PIL Image.
- Parameters:
filepath (
str) – Path to the SVG file to rasterize.- Return type:
- Returns:
PIL Image object in RGBA mode containing the rasterized SVG.
- Raises:
FileNotFoundError – If the SVG file does not exist.
ImportError – If Playwright is not installed.
- from_string(svg_content)[source]
Rasterize SVG content from a string to a PIL Image.
This method renders the SVG by loading it into a headless browser page and taking a screenshot.
- Parameters:
svg_content (
Union[str,bytes]) – SVG content as string or bytes.- Return type:
- Returns:
PIL Image object in RGBA mode containing the rasterized SVG.
- Raises:
ImportError – If Playwright is not installed.
ValueError – If the SVG content is invalid.
- close()[source]
Close the browser and cleanup resources.
This method should be called when the rasterizer is no longer needed to free browser resources. Alternatively, use the context manager interface (with statement) for automatic cleanup.
- Return type:
Browser-based SVG rasterizer with full SVG 2.0 support using Playwright/Chromium.
Installation:
pip install psd2svg[browser]
playwright install chromium
Example:
from psd2svg.rasterizer import PlaywrightRasterizer
# Use as context manager (automatically cleans up browser)
with PlaywrightRasterizer(dpi=96) as rasterizer:
image = rasterizer.from_file('input.svg')
image.save('output.png')
# Or with SVGDocument
from psd2svg import SVGDocument
from psd_tools import PSDImage
psdimage = PSDImage.open('input.psd')
document = SVGDocument.from_psd(psdimage)
with PlaywrightRasterizer(dpi=96) as rasterizer:
image = document.rasterize(rasterizer=rasterizer)
image.save('output.png')
When to use:
Testing SVG 2.0 features (vertical text, text-orientation, dominant-baseline)
Quality assurance against browser rendering
Better support for advanced SVG features not supported by resvg
Utility Modules
SVG Utilities
- psd2svg.svg_utils.safe_utf8(text)[source]
Remove illegal and problematic XML characters from text.
This function filters out characters that are illegal or problematic in XML documents by replacing them with spaces. The filtering is intentionally conservative, removing more characters than strictly required by the XML 1.0 specification.
- Characters filtered (replaced with space):
C0 controls (0x00-0x08, 0x0B-0x1F): NULL, control characters Exception: TAB (0x09), LF (0x0A) are preserved
C1 controls (0x7F-0x9F): DEL and C1 control block including NEL (0x85)
UTF-16 surrogates (0xD800-0xDFFF): Illegal in UTF-8/XML
Non-characters (0xFDD0-0xFDDF, 0xFFFE-0xFFFF): Illegal in XML
- Characters preserved:
TAB (0x09): Horizontal spacing
LF (0x0A): Line breaks
Normal printable characters (0x20 and above, excluding filtered ranges)
- Note on CR (0x0D):
CR (Carriage Return) is filtered despite being technically legal in XML 1.0. This is an intentional conservative design choice because: 1. XML processors normalize CR to LF per XML 1.0 spec (section 2.11) 2. Filtering CR prevents line-ending confusion attacks 3. TAB and LF are sufficient for all whitespace needs in SVG 4. Historical issues with CR in PSD text conversion (see commit d81e4b5)
- Args:
text: Input string that may contain illegal XML characters.
- Returns:
Sanitized string with illegal characters replaced by spaces.
- Example:
>>> safe_utf8("Hello\x00World\x85Test") 'Hello World Test' >>> safe_utf8("Tab\there\nNewline") 'Tab here
Newline’
- Return type:
- psd2svg.svg_utils.num2str(num, digit=2)[source]
Convert a number to a string, using the specified format for floats.
- Return type:
- psd2svg.svg_utils.num2str_with_unit(num, unit='px', digit=2)[source]
Convert a number to a string with a CSS unit appended.
- Parameters:
- Return type:
- Returns:
Formatted string with unit (e.g., “10px”, “1.5em”, “100%”)
Examples
>>> num2str_with_unit(10.0, "px") '10px' >>> num2str_with_unit(1.5, "em") '1.5em' >>> num2str_with_unit(100, "%") '100%'
- psd2svg.svg_utils.seq2str(seq, sep=',', digit=2)[source]
Convert a sequence of numbers to a string.
Uses the specified format for floats.
- Return type:
- psd2svg.svg_utils.create_node(tag, parent=None, class_='', title='', text='', desc='', xml_space=None, **kwargs)[source]
Create an XML node with attributes.
- psd2svg.svg_utils.create_xhtml_node(tag, parent=None, text='', xml_space=None, **kwargs)[source]
Create an XHTML node with proper namespace.
This helper creates elements in the XHTML namespace for use within SVG <foreignObject> elements. The namespace is required for proper rendering in modern browsers (Chrome, Firefox, Safari, Edge). Note: resvg/resvg-py does not support foreignObject rendering.
- Parameters:
tag (
str) – HTML tag name (e.g., ‘div’, ‘p’, ‘span’).parent (
Optional[Element]) – Optional parent element to append this node to.text (
str) – Optional text content.xml_space (
Optional[str]) – Set xml:space attribute with proper XML namespace. Use “preserve” to preserve whitespace.**kwargs (
Any) – Additional attributes. Underscores in keys are converted to hyphens (e.g., ‘font_size’ becomes ‘font-size’).
- Return type:
- Returns:
XHTML element with namespace prefix.
Example
>>> foreign_obj = create_node("foreignObject", x=0, y=0, width=100, height=50) >>> div = create_xhtml_node("div", parent=foreign_obj) >>> p = create_xhtml_node("p", parent=div, text="Hello") >>> span = create_xhtml_node("span", parent=p, text="World", style="color: red")
- psd2svg.svg_utils.styles_to_string(styles)[source]
Convert a dictionary of CSS styles to a CSS string.
- Parameters:
styles (
dict[str,str]) – Dictionary of CSS property names to values.- Return type:
- Returns:
CSS string suitable for use in a ‘style’ attribute.
Example
>>> styles = {"color": "red", "font-size": "12px"} >>> styles_to_string(styles) 'color: red; font-size: 12px'
- psd2svg.svg_utils.add_style(node, key, value)[source]
Add a CSS property to an XML node.
- Return type:
- psd2svg.svg_utils.set_attribute(node, key, value)[source]
Add an attribute to an XML node.
- Return type:
- psd2svg.svg_utils.append_attribute(node, key, value, separator=' ')[source]
Append a value to an existing attribute of an XML node.
- Return type:
- psd2svg.svg_utils.set_transform_with_origin(element, transform_attr, transforms, origin=None)[source]
Set transform attribute with optional transform-origin.
This function sets transform operations on gradient, pattern, or other SVG elements using the modern SVG 2.0 transform-origin attribute instead of translate wrappers.
- Parameters:
element (
Element) – SVG element to modify (e.g., linearGradient, pattern)transform_attr (
str) – Name of the transform attribute (e.g., “gradientTransform”, “patternTransform”)transforms (
list[str]) – List of transform functions (e.g., [‘rotate(45)’, ‘scale(2)’])origin (
tuple[float,float] |None) – Transform origin point (x, y). If provided, sets transform-origin attribute. Default SVG transform-origin is (0, 0).
- Return type:
Example
- Instead of: gradientTransform=”translate(50,50) rotate(45)
translate(-50,-50)”
Produces: gradientTransform=”rotate(45)” transform-origin=”50 50”
Note
SVG 2.0 feature. Supported by modern browsers and resvg-py. When origin is provided but no transforms, uses translate() instead. When the attribute already exists (from append_attribute), appends to it instead.
- psd2svg.svg_utils.wrap_element(node, parent, wrapper)[source]
Wrap the given existing node in the wrapper element.
- Usage::
wrapper = svg_utils.create_node(“g”) wrapped_node = svg_utils.wrap_element(node, parent, wrapper)
- psd2svg.svg_utils.merge_attribute_less_children(element)[source]
Recursively merge children without attributes into their parent nodes.
This utility removes redundant wrapper elements that have no attributes, moving their text content directly into the parent element. This helps produce cleaner, more compact SVG output.
The function preserves document order by properly handling both element.text and child.tail to ensure text appears in the correct sequence.
Example
Before: <text><tspan x=”10”><tspan>Hello</tspan></tspan></text> After: <text><tspan x=”10”>Hello</tspan></text>
Before: <text><tspan font-weight=”700”>Bold</tspan><tspan> text</tspan></text> After: <text><tspan font-weight=”700”>Bold</tspan> text</text>
- psd2svg.svg_utils.merge_common_child_attributes(element, excludes=None)[source]
Recursively merge common child attributes to their parent node.
This utility hoists attributes that are common to ALL children (with the same value) to the parent element. This helps produce cleaner, more compact SVG output by reducing redundant attribute declarations.
- Parameters:
- Return type:
Example
- Before: <text><tspan fill=”red”>A</tspan><tspan fill=”red”>B</tspan>
</text>
After: <text fill=”red”><tspan>A</tspan><tspan>B</tspan></text>
- Before (with excludes={“x”}):
- <text><tspan x=”10” fill=”red”>A</tspan><tspan x=”20”
fill=”red”>B</tspan></text>
- After: <text fill=”red”><tspan x=”10”>A</tspan><tspan x=”20”>B
</tspan></text>
- psd2svg.svg_utils.merge_consecutive_siblings(element)[source]
Recursively merge consecutive sibling elements with identical attributes.
This utility consolidates sequences of consecutive child elements that have the same tag and identical attributes by merging their text content. This is particularly useful for optimizing SVG <tspan> elements.
Example
- Before: <text>
<tspan font-size=”18” letter-spacing=”0.72”>す</tspan> <tspan font-size=”18” letter-spacing=”0.72”>だ</tspan> <tspan font-size=”18” letter-spacing=”0.72”>け</tspan>
</text>
- After: <text>
<tspan font-size=”18” letter-spacing=”0.72”>すだけ </tspan>
</text>
- Before: <text>
- <tspan font-size=”18” baseline-shift=”-0.36”
letter-spacing=”0.72”>さ</tspan>
<tspan font-size=”18” letter-spacing=”0.72”>す</tspan> <tspan font-size=”18” letter-spacing=”0.72”>だ</tspan>
</text>
- After: <text>
- <tspan font-size=”18” baseline-shift=”-0.36”
letter-spacing=”0.72”>さ</tspan>
<tspan font-size=”18” letter-spacing=”0.72”>すだ</tspan>
</text>
Note
Only merges elements with the same tag name
Only merges elements with identical attribute sets
Preserves document order
Does not merge elements with child elements
Empty elements (no text or tail) are removed
- psd2svg.svg_utils.merge_singleton_children(element)[source]
Recursively merge singleton child nodes into their parent nodes.
This utility removes redundant wrapper elements when a parent has exactly one child and there are no conflicting attributes. The child’s attributes and text content are moved to the parent element.
Example
Before: <text><tspan>Hello</tspan></text> After: <text>Hello</text>
Before: <text x=”10”><tspan font-weight=”700”>Bold</tspan></text> After: <text x=”10” font-weight=”700”>Bold</text>
Not merged (conflicting attributes): Before: <text x=”10”><tspan x=”20”>Text</tspan></text> After: <text x=”10”><tspan x=”20”>Text</tspan></text> (unchanged)
Not merged (child has children): Before: <text><tspan><tspan>A</tspan><tspan>B</tspan></tspan></text> After: <text><tspan><tspan>A</tspan><tspan>B</tspan></tspan></text>
(unchanged)
- psd2svg.svg_utils.consolidate_defs(svg)[source]
Consolidate all <defs> and definition elements into a global <defs>.
This optimization improves SVG structure by: 1. Creating a single global <defs> element at the beginning of the SVG 2. Moving all definition elements (filters, gradients, patterns, etc.) into it 3. Removing now-empty inline <defs> elements
Definition elements that are moved: - <defs> (contents merged into global defs) - <filter> - <linearGradient> - <radialGradient> - <pattern> - <clipPath> - <marker> - <symbol>
Note
This function preserves all id references and element ordering within defs.
Mask Element Exclusion:
This function does NOT move <mask> elements for the following technical reasons:
Coordinate Systems: Masks use
maskContentUnits="userSpaceOnUse"by default, meaning mask content coordinates are evaluated at reference time (wheremask="url(#id)"is applied), not at definition time. Moving masks to a different DOM position could affect coordinate system evaluation.Property Inheritance: Masks inherit CSS properties (fill, stroke, opacity, etc.) from their DOM ancestors. Moving a mask to <defs> changes its inheritance chain, which can alter rendering for masks with styled content.
Transform Handling: psd2svg uses special transform workarounds for masked elements that rely on specific mask positioning in the DOM tree.
Renderer Compatibility: Known compatibility issues exist with some SVG renderers regarding mask positioning and interactions with other elements (e.g., clipPath-mask interactions).
Nested Definitions Are Consolidated:
While <mask> elements themselves are not moved, any nested <defs> and definition elements (filters, gradients, etc.) WITHIN masks ARE moved to the global defs. This provides optimization benefits while preserving mask rendering fidelity. See
test_consolidate_complex_real_world_examplein tests/test_optimize.py for demonstration.Example
- Before:
- <svg>
<rect fill=”url(#g1)”/> <linearGradient id=”g1”>…</linearGradient> <defs><filter id=”f1”>…</filter></defs>
</svg>
- After:
- <svg>
- <defs>
<linearGradient id=”g1”>…</linearGradient> <filter id=”f1”>…</filter>
</defs> <rect fill=”url(#g1)”/>
</svg>
- psd2svg.svg_utils.deduplicate_definitions(svg)[source]
Deduplicate identical definition elements in <defs>.
Identifies structurally identical definition elements (filter, gradients, patterns, clipPath, marker, symbol) and merges duplicates by keeping the first occurrence and updating all url(#id) references throughout the SVG tree.
This function should be called AFTER consolidate_defs() to ensure all definition elements are in a single global <defs>.
Priority order (based on PSD per-layer structure): 1. filter, linearGradient, radialGradient, pattern (most common duplicates) 2. clipPath, marker, symbol (less common but still beneficial)
Note
Elements are considered identical if they have: - Same tag - Same attributes (except ‘id’) - Same child structure and content
Example
- Before:
- <defs>
<linearGradient id=”g1”><stop offset=”0%”/></linearGradient> <linearGradient id=”g2”><stop offset=”0%”/></linearGradient>
</defs> <rect fill=”url(#g1)”/> <circle fill=”url(#g2)”/>
- After:
- <defs>
<linearGradient id=”g1”><stop offset=”0%”/></linearGradient>
</defs> <rect fill=”url(#g1)”/> <circle fill=”url(#g1)”/>
- psd2svg.svg_utils.unwrap_groups(svg)[source]
Unwrap <g> elements that have no meaningful attributes.
This optimization removes redundant <g> wrapper elements that don’t affect rendering, moving their children directly to the parent level. This reduces SVG nesting depth and file size.
Groups are unwrapped if they have NO attributes (or only empty class), AND no <title> child elements. Groups with rendering attributes (opacity, style, filter, mask, clip-path, transform) or identity attributes (id) are preserved.
Empty groups (no children) are removed entirely.
Example
- Before:
- <svg>
- <g>
<rect x=”0” y=”0” width=”100” height=”100”/>
</g>
</svg>
- After:
- <svg>
<rect x=”0” y=”0” width=”100” height=”100”/>
</svg>
- Preserved (has opacity):
- <svg>
- <g opacity=”0.5”>
<rect x=”0” y=”0” width=”100” height=”100”/>
</g>
</svg>
Note
This function is automatically called when optimize=True in save() and tostring(). It processes the tree recursively, unwrapping all eligible groups in a single pass.
- psd2svg.svg_utils.extract_font_families(svg)[source]
Extract all unique font families from font-family attributes in SVG tree.
Scans the SVG element tree for all font-family attributes (both as direct attributes and within style attributes) and extracts all font families from comma-separated lists.
- Parameters:
svg (
Element) – The SVG element tree to scan.- Return type:
- Returns:
Set of unique font family names found in the SVG.
Note
Extracts ALL fonts from comma-separated font-family lists
Strips quotes from font family names
Searches both font-family attributes and CSS style attributes
Example
>>> svg = fromstring( ... '<svg><text font-family="Arial, sans-serif">Hi</text></svg>' ... ) >>> families = extract_font_families(svg) >>> "Arial" in families True >>> "sans-serif" in families True
- psd2svg.svg_utils.find_elements_with_font_family(svg, font_family, include_inherited=True)[source]
Find all text/tspan and XHTML text elements that use the given font family.
This function searches for text, tspan, and XHTML text elements (p, span from foreignObject) that have the specified font-family applied, either directly via attributes or through CSS inheritance from parent elements.
- Parameters:
svg (
Element) – SVG element tree to search.font_family (
str) – Font family name to search for (case-insensitive).include_inherited (
bool) – If True, include elements that inherit the font from parents. If False, only include elements with direct font-family declarations. Default is True for backward compatibility.
- Return type:
- Returns:
List of text/tspan/p/span elements that use the specified font family.
Note
Searches both font-family attributes and style attributes
Supports CSS inheritance (walks up parent chain) when include_inherited=True
Case-insensitive font family matching
Only returns text and tspan elements (not their parents)
Example
>>> svg = svg_utils.fromstring( ... '<svg><text font-family="Arial">Hi</text></svg>' ... ) >>> elements = find_elements_with_font_family(svg, "Arial") >>> len(elements) 1 >>> elements = find_elements_with_font_family( ... svg, "Arial", include_inherited=False ... ) >>> len(elements) 1
- psd2svg.svg_utils.extract_text_characters(element)[source]
Extract text characters from an element for font subsetting.
This function extracts both element.text and element.tail with HTML entity decoding. The tail is included because it’s rendered using the element’s font-family (not the parent’s), which is important for accurate font subsetting.
Control characters, format characters, and combining marks (like variation selectors) are filtered out as they are not rendered in SVG text elements and should not be included in charset matching for font resolution.
- Parameters:
element (
Element) – XML element to extract text from (typically text or tspan).- Return type:
- Returns:
Text content (text + tail) with HTML entities decoded and non-renderable characters removed.
Note
Extracts element.text (content before first child element)
ALSO extracts tail (content after element’s closing tag)
Does NOT include text from child elements
Decodes HTML/XML entities (e.g., < → <, 一 → 一)
Filters out: * Control characters (Cc, Cf): newlines, tabs, format controls * Surrogate characters (Cs): invalid in UTF-8 * Unassigned characters (Cn): not valid Unicode * Combining marks (Mn, Mc, Me): variation selectors, diacritics
Tail is included because SVG inherits font-family: the tail is rendered using the element’s font, not the parent’s font
Example
>>> elem = ET.fromstring('<text>Hello & world</text>') >>> extract_text_characters(elem) 'Hello & world'
>>> root = ET.fromstring('<text><tspan>A</tspan>B</text>') >>> tspan = root[0] >>> extract_text_characters(tspan) # Returns 'AB' (text + ... # tail) 'AB'
>>> elem = ET.fromstring('<text>Hello\nWorld</text>') >>> extract_text_characters(elem) # Newline filtered 'HelloWorld'
>>> elem = ET.fromstring('<text>©\uFE0E</text>') >>> # Copyright + variation selector >>> extract_text_characters(elem) # Variation selector filtered '©'
- psd2svg.svg_utils.replace_font_family(element, old_font_family, new_font_family)[source]
Replace a font family with another in the given element.
This function modifies an SVG text/tspan element by replacing occurrences of old_font_family with new_font_family in font-family specifications. It handles both font-family attributes and style attributes.
- Parameters:
- Return type:
Example
Before: <text font-family=”ArialMT”>Hello</text> After: <text font-family=”Arial”>Hello</text>
Before: <text font-family=”ArialMT, Helvetica”>Hello</text> After: <text font-family=”Arial, Helvetica”>Hello</text>
Before: <text style=”font-family: ArialMT”>Hello</text> After: <text style=”font-family: ‘Arial’”>Hello</text>
Note
Replaces first occurrence of old_font_family in comma-separated list
If old_font_family not found, does nothing
For font-family attributes: no quotes (attribute delimiter is sufficient)
For style attributes: quotes font names for CSS compliance
Updates font-family attribute with higher priority than style
- psd2svg.svg_utils.add_font_family(element, font_family)[source]
Add font family to font-family specification in the given element.
This function modifies an SVG text/tspan element by appending a font family to its existing font-family specification if not already present. It handles both font-family attributes and font-family declarations within style attributes.
- Behavior:
If element has font-family attribute: append font to it
Else if element has font-family in style: append font to style
Else: create new font-family attribute with the font
If both attribute and style exist: append to attribute (higher priority)
- Parameters:
- Return type:
Example
Before: <text font-family=”Arial”>Hello</text> After: <text font-family=”Arial, Helvetica”>Hello</text>
Before: <text style=”font-family: Arial”>Hello</text> After: <text style=”font-family: ‘Arial’, ‘Helvetica’”>Hello</text>
Before: <text>Hello</text> After: <text font-family=”Helvetica”>Hello</text>
Note
Updates font-family attribute with higher priority than style
For font-family attributes: no quotes (attribute delimiter is sufficient)
For style attributes: quotes font names for CSS compliance
Idempotent: does not add font if already present in the chain
Ignores CSS ‘font’ shorthand property, only handles ‘font-family’
- psd2svg.svg_utils.insert_or_update_style_element(svg, css_content)[source]
Insert or update a <style> element in the SVG root.
- Parameters:
- Return type:
Note
If a <style> element exists as first child, appends to it
Otherwise creates a new <style> element as first child
Idempotent: skips if CSS content already present
Image Utilities
- psd2svg.image_utils.encode_image(image, format='WEBP')[source]
Encode a PIL image to bytes in the specified format.
For JPEG format, RGBA images are automatically converted to RGB with a white background.
- Return type:
- psd2svg.image_utils.encode_data_uri(image, format='WEBP')[source]
Encode a PIL image as a base64 data URI.
For JPEG format, RGBA images are automatically converted to RGB with a white background.
- Return type:
- psd2svg.image_utils.decode_image(data, mode=None)[source]
Decode image data from bytes to a PIL image.
- Return type:
- psd2svg.image_utils.decode_data_uri(data_uri, mode=None)[source]
Decode a base64 data URI to a PIL image.
- Return type:
Font Subsetting
Font subsetting utilities for reducing embedded font file sizes.
- psd2svg.font_subsetting.extract_used_unicode(svg_tree)[source]
Extract Unicode characters per font-family from SVG text elements.
This function analyzes all <text>, <tspan>, and XHTML text elements (p, span from foreignObject) in the SVG tree to determine which Unicode characters are used by each font family.
- Parameters:
svg_tree (
Element) – Root SVG element to analyze.- Return type:
- Returns:
Dictionary mapping font-family names to sets of Unicode characters. Example: {“Arial”: {“A”, “B”, “C”}, “Noto Sans JP”: {“あ”, “い”}}
Note
Handles nested <tspan> elements and XHTML elements
Decodes XML entities (e.g., <, 一)
Extracts font-family from style attributes
Returns empty dict if no text elements found
- psd2svg.font_subsetting.subset_font(input_path, output_format, unicode_codepoints)[source]
Subset a font file to include only specified Unicode codepoints.
This function uses fontTools (pyftsubset) to create a minimal font file containing only the glyphs needed for the specified codepoints.
- Parameters:
- Return type:
- Returns:
Subset font file as bytes.
- Raises:
ImportError – If fonttools package is not installed.
Exception – If subsetting fails (invalid font, I/O error, etc.).
Example
>>> codepoints = {0x41, 0x42, 0x43, 0x3042} # A, B, C, あ >>> font_bytes = subset_font("/usr/share/fonts/arial.ttf", "woff2", codepoints) >>> len(font_bytes) # Much smaller than original 8432
- psd2svg.font_subsetting.get_font_usage_from_svg(svg_tree)[source]
Get font usage information from SVG for subsetting.
This is a convenience wrapper around extract_used_unicode() that logs appropriate messages about font usage.
Font subsetting reduces embedded font file sizes by 90%+ by including only the glyphs actually used in the SVG.
Note: Font subsetting is enabled by default when embedding fonts. The required fonttools package is automatically installed with psd2svg.
Usage Example:
from psd2svg.font_subsetting import extract_used_unicode, subset_font
import xml.etree.ElementTree as ET
# Parse SVG
svg_tree = ET.parse("output.svg").getroot()
# Extract Unicode characters per font
font_usage = extract_used_unicode(svg_tree)
# => {"Arial": {"H", "e", "l", "o"}, "Times": {"W", "r", "d"}}
# Subset a font file
font_bytes = subset_font(
input_path="/usr/share/fonts/arial.ttf",
output_format="woff2",
unicode_chars={"H", "e", "l", "o"}
)
# => b'wOF2...' (WOFF2 font bytes)
Note: This module is typically used internally by SVGDocument.save() and tostring() methods. Direct usage is only needed for advanced use cases.
Quality Evaluation
- psd2svg.eval.compute_conversion_quality(psdimage, metric)[source]
Test conversion quality in the raster format.
- Return type:
- psd2svg.eval.create_diff_image(psdimage, amplify=1.0)[source]
Create a diff image between the original and rasterized images.
For debugging purposes.
- psd2svg.eval.compare_raster_images(input1, input2, metric='MSE')[source]
Compare two raster images in numpy array format.
- Return type:
Utilities for evaluating the quality of PSD to SVG conversion by comparing rasterized outputs.
Usage Example:
from psd2svg.eval import compute_conversion_quality, create_diff_image
from psd_tools import PSDImage
# Load PSD
psdimage = PSDImage.open("input.psd")
# Compute quality score (0.0 to 1.0, higher is better)
score = compute_conversion_quality(psdimage, metric="mse")
print(f"Quality score: {score:.4f}")
# Create visual diff image for debugging
diff_image = create_diff_image(psdimage, amplify=5.0)
diff_image.save("diff.png")
Supported metrics:
mse- Mean Squared Error (default)rmse- Root Mean Squared Errorpsnr- Peak Signal-to-Noise Ratiossim- Structural Similarity Index
Note: This module is primarily intended for testing and quality assurance purposes.
Internal Modules
The following modules are internal implementation details and may change without notice. They are documented here for reference but should not be used directly.
Core Converter
- class psd2svg.core.converter.Converter(psdimage, enable_live_shapes=True, enable_text=True, enable_title=False, enable_class=False, text_letter_spacing_offset=0.0, text_wrapping_mode=0, font_mapping=None, resource_limits=None)[source]
Bases:
AdjustmentConverter,LayerConverter,PaintConverter,ShapeConverter,TextConverter,EffectConverterConverter main class.
Example usage:
from psd2svg.core.converter import Converter
Converter.convert(“example.psd”, “output.svg”)
Example usage:
from psd_tools import PSDImage from psd2svg.core.conveter import Converter
psd = PSDImage.open(“example.psd”) converter = Converter(psd) document = converter.build() document.embed_images() # or document.export_images(“output/image_%02d”) svg_string = document.export()
- Parameters:
psdimage (
PSDImage) – Source PSDImage to convert.enable_live_shapes (
bool) – Enable live shape conversion when possible.enable_text (
bool) – Enable text layer conversion when possible.enable_title (
bool) – Enable insertion of <title> elements with layer names. When True (default), each layer in the SVG will have a <title> element containing the Photoshop layer name for accessibility and debugging. Set to False to omit title elements and reduce file size.enable_class (
bool) – Enable insertion of class attributes on SVG elements for debugging purposes. When False (default), elements will not have class attributes, producing cleaner SVG output. Set to True to add class attributes for layer types, effects, and semantic roles (e.g., “shape-layer”, “drop-shadow-effect”, “fill”) for debugging or styling.text_letter_spacing_offset (
float) – Global offset (in pixels) to add to all letter-spacing values. This can be used to compensate for differences between Photoshop’s text rendering and SVG’s text rendering. Typical values range from -0.02 to 0.02. Default is 0.0 (no offset).text_wrapping_mode (
int) – Text wrapping mode for bounding box text. Use 0 for no wrapping (default, native SVG <text>), or 1 for <foreignObject> with XHTML wrapping. Import TextWrappingMode from psd2svg.core.text for enum values. Only affects bounding box text (ShapeType=1); point text always uses native SVG <text> elements.font_mapping (
dict[str,dict[str,float|str]] |None) – Optional custom font mapping dictionary. Takes priority over built-in static mapping. Format: {“PostScriptName”: {“family”: str, “style”: str, “weight”: float}}. When not provided, uses built-in mapping for ~4,950 fonts (539 default + 370 Hiragino + 4,042 Morisawa) with automatic fallback to system font resolution (fontconfig/Windows registry) if needed.
- __init__(psdimage, enable_live_shapes=True, enable_text=True, enable_title=False, enable_class=False, text_letter_spacing_offset=0.0, text_wrapping_mode=0, font_mapping=None, resource_limits=None)[source]
Initialize the converter internal state.
- create_node(tag, parent=None, class_='', title='', text='', desc='', **kwargs)[source]
Create an SVG node with the current element as default parent.
This is a convenience wrapper around svg_utils.create_node that automatically uses self.current as the parent if no parent is specified.
- Parameters:
tag (
str) – The XML tag name.parent (
Element|None) – Optional parent element. Defaults to self.current.class – Optional class attribute.
title (
str) – Optional title element.text (
str) – Optional text content.desc (
str) – Optional description element.**kwargs (
Any) – Additional attributes to pass to svg_utils.create_node.
- Return type:
- Returns:
The created XML element.
- _abc_impl = <_abc._abc_data object>
- _is_protocol = False
Layer Converter
- class psd2svg.core.layer.LayerConverter(*args, **kwargs)[source]
Bases:
ConverterProtocolMain layer converter mixin.
- add_children(group, depth=0)[source]
Add child layers to the current node.
- Parameters:
group (
Group|Artboard|PSDImage) – Group/Artboard/PSDImage to process.depth (
int) – Current nesting depth (for resource limit checking).
- Raises:
ValueError – If depth exceeds resource_limits.max_layer_depth.
- Return type:
- add_clip_path(layer)[source]
Add a clipping path and associated elements.
Usage:
with self.add_clip_path(layer) as clip_attrib: # Create elements inside the clipping mask. for clip_layer in layer.clip_layers: self.add_layer(clip_layer, ..., **clip_attrib)
- Parameters:
layer (
ShapeLayer) – The shape layer to use as a clipping path.- Yields:
Dictionary with clip-path attribute to apply to clipped elements.
- Return type:
- NOTE: Due to the bad interactions between clip-path and masks in SVG,
we recommend using add_clip_mask instead of this method.
- add_clip_mask(layer)[source]
Add a clipping mask and associated elements.
Usage:
with self.add_clip_mask(layer) as clip_attrib: # Create elements inside the clipping mask. for clip_layer in layer.clip_layers: self.add_layer(clip_layer, ..., **clip_attrib)
- set_layer_attributes(layer, node)[source]
Set common layer attributes to a layer node.
- Return type:
- set_blend_mode(psd_mode, node)[source]
Set blend mode style to the node.
- Parameters:
- Raises:
ValueError – If the blend mode is not supported.
- Return type:
- set_isolation(layer, node)[source]
Add isolation to a group.
Note
The default blending mode of a PSD group is passthrough, which corresponds to SVG isolation: auto (default)
When the group has blending mode normal, it corresponds to SVG isolation: isolate.
Other blending modes also isolate the group, and in SVG setting mix-blend-mode on a <g> to a value other than normal isolates the group by default.
- Return type:
Shape Converter
Mixin module for geometric methods related to shape layers.
Handles conversion of Photoshop vector shapes to SVG path elements:
Basic shapes (ellipse, rectangle, rounded rectangle, line, polygon)
Custom paths with Bezier curves
Multi-path shapes with boolean operations
Path operations (combine, subtract, intersect, exclude)
The module processes vector mask data from shape layers and converts Photoshop’s knot points and control points to SVG path syntax.
- class psd2svg.core.shape.ShapeConverter(*args, **kwargs)[source]
Bases:
ConverterProtocolMixin for shape layers.
- create_shape(layer, **attrib)[source]
Create a shape element from the layer’s vector mask or origination data.
- Return type:
- create_composite_shape(layer, **attrib)[source]
Create a composite shape element from multiple paths with operations.
If the layer has a mask, it will be applied to the composite mask node, creating a mask chain: layer_mask -> composite_mask -> paths.
- Return type:
- apply_union_operation(layer, path_group, current, rule)[source]
Apply Union (OR) operation to combine shapes.
- Return type:
- apply_subtract_operation(layer, path_group, current, rule)[source]
Apply Subtract (NOT OR) operation to create holes.
- Return type:
- apply_intersect_operation(layer, path_group, current, previous, rule)[source]
Apply Intersect (AND) operation to find overlapping regions.
- Return type:
- apply_xor_operation(layer, path_group, current, previous, rule)[source]
Apply XOR (exclusive-or) operation using (A OR B) AND NOT (A AND B).
- Return type:
- create_single_shape(layer, path, **attrib)[source]
Create a single shape element from the layer’s vector mask or origination data.
- Return type:
- create_origination_rectangle(origination, reference, **attrib)[source]
Create a rectangle shape from origination data.
- Return type:
- create_origination_rounded_rectangle(origination, reference, **attrib)[source]
Create a rounded rectangle shape from origination data.
- Return type:
- create_origination_ellipse(origination, reference, **attrib)[source]
Create an ellipse shape from origination data.
- Return type:
- psd2svg.core.shape.generate_path(path, width, height, command='C')[source]
Sequence generator for SVG path constructor.
Text Converter
SVG text conversion logic for PSD text layers.
This module contains the TextConverter mixin class that converts Photoshop text layers (TypeLayer) to SVG text elements. It supports two rendering modes:
Native SVG <text> elements (default) - Uses SVG text/tspan for accurate text rendering
Foreign object mode - Uses <foreignObject> with XHTML for text wrapping support
The TextConverter works with TypeSetting and related data structures from the typesetting module to extract PSD text data and generate corresponding SVG markup.
Key features: - Point text and bounding box text - Paragraph alignment and justification - Text styling (font, color, size, decoration, etc.) - Vertical and horizontal text direction - Letter spacing, tracking, and kerning - Font effects (superscript, subscript, small caps)
- Note: This module re-exports TypeSetting and TextWrappingMode for backward
compatibility. New code should import these directly from psd2svg.core.typesetting.
- class psd2svg.core.text.TextConverter(*args, **kwargs)[source]
Bases:
ConverterProtocolMixin for text layers.
- class psd2svg.core.text.TextWrappingMode(*values)[source]
Bases:
IntEnumText wrapping mode values.
- NONE = 0
- FOREIGN_OBJECT = 1
- class psd2svg.core.text.TypeSetting(setting)[source]
Bases:
objectType tool object setting wrapper.
Example:
setting = TypeSetting(type_tool_object_setting) for span in setting: print(span.start, span.end, span.text, span.paragraph, span.style)
- property bounding_box: Rectangle
Text bounding box rectangle.
This is a bounding box around the text content.
- property bounds: Rectangle
Text bounds rectangle.
This is a user-defined bounds that may differ from the bounding box. Use bounds for positioning the text content by justification settings.
- property box_bounds: Rectangle
Box bounds from shape structure in engine data.
- property document_resources: DictElement
Document resource dictionary from engine data.
- property engine_data: EngineData
Engine data dictionary.
- property engine_dict: DictElement
Engine dictionary from engine data.
- get_font_info(font_index, font_mapping=None)[source]
Get the font family name for the given font index.
- property resources: DictElement
Resource dictionary from engine data.
- property shape_type: ShapeType
Shape type from engine data.
- property transform: Transform
Affine transform matrix.
- property warp_style: str | None
Warp style.
Example warp content:
warp=DescriptorBlock(b'warp'){ 'warpStyle': (b'warpStyle', b'warpArc'), 'warpValue': -100.0, 'warpPerspective': 0.0, 'warpPerspectiveOther': 0.0, 'warpRotate': (b'Ornt', b'Hrzn') }
- property writing_direction: WritingDirection
Writing direction from engine data.
Values are: - 0: Horizontal Top to Bottom - 2: Vertical Right to Left
NOTE: There could be other values, need to verify.
Effects Converter
- class psd2svg.core.effects.EffectConverter(*args, **kwargs)[source]
Bases:
ConverterProtocolEffect converter mixin.
- apply_background_effects(layer, target, insert_before_target=True)[source]
Apply background effects to the target element.
- Return type:
- apply_overlay_effects(layer, target)[source]
Apply overlay effects to the target element.
- Return type:
- apply_color_overlay_effect(layer, target)[source]
Apply color overlay effect to the target element.
- Return type:
- add_raster_color_overlay_effect(effect, target)[source]
Add a color overlay filter to the SVG document.
SVG does not allow coloring a raster image directly, so we create a filter.
- Return type:
- add_vector_color_overlay_effect(effect, target)[source]
Add a color overlay effect to the current element using vector path.
- Return type:
- apply_stroke_effect(layer, target)[source]
Apply stroke effects to the target element.
- Return type:
- add_raster_stroke_effect(layer, effect, target)[source]
Add a stroke filter to the SVG document.
SVG does not allow stroking a raster image directly, so we create a filter.
- Return type:
- add_vector_stroke_effect(layer, effect, target)[source]
Add a stroke effect to the current element using vector path.
- Return type:
- apply_drop_shadow_effect(layer, target, insert_before_target=False)[source]
Apply drop shadow effect to the current element.
- Return type:
- add_raster_drop_shadow_effect(effect, target)[source]
Add a drop shadow filter to the SVG document.
- Return type:
- apply_outer_glow_effect(layer, target, insert_before_target=False)[source]
Apply outer glow effect to the current element.
- Return type:
- add_raster_outer_glow_effect(effect, target)[source]
Add an outer glow filter to the SVG document.
- Return type:
- set_gradient_transform(layer, gradient, effect)[source]
Set gradient transformations based on the effect properties.
- Return type:
- set_pattern_effect_transform(pattern, effect, reference)[source]
Set pattern transformations based on the effect properties.
Note: For patterns, reference and phase are simple translates, not pivot points.
- Return type:
- add_raster_inner_shadow_effect(effect, target)[source]
Add an inner shadow filter to the SVG document.
- Return type:
Adjustment Converter
Mixin for adjustment layers conversion.
Due to the limited support of BackgroundImage in SVG filters, our approach wraps the backdrop elements into a symbol, and use two <use> elements to apply the filter.
When we have a layer structure like this:
<layer 1 />
<layer 2 />
<adjustment />
We convert it into the following SVG structure:
<symbol id="backdrop">
<image id="layer1" ... />
<image id="layer2" ... />
</symbol>
<filter id="adjustment"></filter>
<use href="#backdrop" />
<use href="#backdrop" filter="url(#adjustment)" />
This approach may have limitations when the backdrop has transparency, as the stacked use elements may not produce the intended visual result.
- class psd2svg.core.adjustment.AdjustmentConverter(*args, **kwargs)[source]
Bases:
ConverterProtocolMixin for adjustment layers.
- add_posterize_adjustment(layer, **attrib)[source]
Add a posterize adjustment layer to the svg document.
- add_threshold_adjustment(layer, **attrib)[source]
Add a threshold adjustment layer to the svg document.
Threshold converts the image to high-contrast black and white by comparing each pixel’s luminance against a threshold value. Pixels below the threshold become black (0), and pixels at or above become white (255).
- add_hue_saturation_adjustment(layer, **attrib)[source]
Add a hue/saturation adjustment layer to the svg document.
Supports two modes: - Normal mode: Adjusts hue, saturation, and lightness using master values - Colorize mode: Desaturates then applies colorization tint
Note: Per-range color adjustments (layer.data) are not yet supported.
- add_exposure_adjustment(layer, **attrib)[source]
Add an exposure adjustment layer to the svg document.
Applies exposure, offset, and gamma correction to simulate Photoshop’s Exposure adjustment layer. Operations are applied in linear RGB space to match Photoshop’s behavior.
The three parameters are applied in sequence: 1. Exposure: output = input × 2^exposure 2. Offset: output = input + offset 3. Gamma: output = input^(1/gamma)
- add_brightness_contrast_adjustment(layer, **attrib)[source]
Add a brightness/contrast adjustment layer to the svg document.
Applies brightness and contrast adjustments using SVG feComponentTransfer filters with linear transfer functions. Operations are applied sequentially: brightness first, then contrast.
- Brightness adds a constant value to all RGB channels:
output = input + (brightness / 255)
- Contrast scales values around the midpoint (0.5):
output = (input - 0.5) * factor + 0.5 where factor = (259 * (contrast + 255)) / (255 * (259 - contrast))
Note: Photoshop’s modern (non-legacy) brightness/contrast uses a complex curves-based algorithm. Our linear approximation works well for most cases but may have higher error for extreme negative brightness values.
- add_color_balance_adjustment(layer, **attrib)[source]
Add a color balance adjustment layer to the svg document.
Applies color balance adjustments to shadows, midtones, and highlights using SVG feComponentTransfer filters with lookup tables.
Note: Uses grayscale approximation for luminance due to SVG’s independent channel processing. Accuracy ~95% for typical adjustments.
- add_black_and_white_adjustment(layer, **attrib)[source]
Add a black and white adjustment layer to the svg document.
Note: This adjustment layer type is not yet implemented.
- add_channel_mixer_adjustment(layer, **attrib)[source]
Add a channel mixer adjustment layer to the svg document.
Note: This adjustment layer type is not yet implemented.
- add_color_lookup_adjustment(layer, **attrib)[source]
Add a color lookup adjustment layer to the svg document.
Note: This adjustment layer type is not yet implemented.
- add_curves_adjustment(layer, **attrib)[source]
Add a curves adjustment layer to the svg document.
Applies tonal curve adjustments using SVG feComponentTransfer filters with lookup tables generated from control points. Supports both composite (RGB) curves and per-channel (R/G/B) curves, matching Photoshop’s curve application order.
- add_gradient_map_adjustment(layer, **attrib)[source]
Add a gradient map adjustment layer to the svg document.
Note: This adjustment layer type is not yet implemented.
- add_levels_adjustment(layer, **attrib)[source]
Add a levels adjustment layer to the svg document.
Applies tonal adjustments using input/output ranges and gamma correction. Supports both composite (RGB) and per-channel (R/G/B) adjustments, matching Photoshop’s application order.
- add_photo_filter_adjustment(layer, **attrib)[source]
Add a photo filter adjustment layer to the svg document.
Note: This adjustment layer type is not yet implemented.
Paint Converter
Mixin module for paint methods, such as fill and stroke.
Photoshop supports the following paint types:
Solid color
Gradient (linear and radial)
Pattern
This module handles paint application for: - Shape layer fills (VECTOR_STROKE_CONTENT_DATA) - Shape layer strokes - Fill adjustment layers
(SOLID_COLOR_SHEET_SETTING, GRADIENT_FILL_SETTING, PATTERN_FILL_SETTING)
Note layer effects also support similar paint types, but the data structures and descriptors are different.
- class psd2svg.core.paint.PaintConverter(*args, **kwargs)[source]
Bases:
ConverterProtocolMixin for paint methods.
- apply_vector_stroke(layer, target)[source]
Apply stroke effects to the target element.
- Return type:
- set_fill_stroke_content(layer, node)[source]
Set fill or stroke content from VECTOR_STROKE_CONTENT_DATA.
- Return type:
- set_fill_setting(layer, node)[source]
Set fill attribute from fill settings tagged blocks.
- Return type:
- add_linear_gradient(gradient)[source]
Add linear gradient definition to the SVG document.
- Return type:
- add_radial_gradient(gradient)[source]
Add radial gradient definition to the SVG document.
- Return type:
- set_gradient_stops(gradient, node)[source]
Set gradient stops to the given gradient element.
- Return type:
- set_gradient_attributes(layer, setting, gradient)[source]
Set gradient settings such as angle to the gradient element.
- Return type: