Skip to main content

Lightweight library for arbitrary geometric SVG transformations

Project description

🦎 SVGecko

PyPI version Python Support License: MIT

A lightweight Python library for arbitrary geometric SVG transformations. SVGecko enables you to apply any mathematical transformation function to SVG files, going beyond simple affine transformations to support complex geometric operations.

✨ Features

  • Arbitrary Transformations: Apply any mathematical function (x, y) → (x', y') to SVG coordinates
  • Comprehensive SVG Support: Handles path commands, coordinate attributes, and CSS transforms
  • Multiple Command Types: Supports absolute, relative, and arc path commands
  • Style Transform Support: Transforms CSS translate() functions in style attributes
  • Easy Integration: Simple API with PIL Image conversion
  • Type Safety: Full type annotations for better development experience

🚀 Installation

pip install svgecko

📖 Quick Start

Basic Transformation

import matplotlib.pyplot as plt
from svgecko import SVG

# Load an SVG file
svg = SVG.from_file('example.svg')

# Apply a transformation (shift by 1 unit in both directions)
transformation = lambda point: (point[0] + 1, point[1] + 1)
transformed_svg = svg.transform(transformation)

# Convert to PIL Image and display
image = transformed_svg.to_pil_image()
plt.imshow(image)
plt.show()

Advanced Transformations

import math
from svgecko import SVG

svg = SVG.from_file('logo.svg')

# Rotate around origin by 45 degrees
def rotate_45(point):
    x, y = point
    angle = math.radians(45)
    new_x = x * math.cos(angle) - y * math.sin(angle)
    new_y = x * math.sin(angle) + y * math.cos(angle)
    return (new_x, new_y)

# Scale by factor of 2
def scale_2x(point):
    return (point[0] * 2, point[1] * 2)

# Apply transformations
rotated_svg = svg.transform(rotate_45)
scaled_svg = svg.transform(scale_2x)

# Save results
rotated_svg.to_file('rotated_logo.svg')
scaled_svg.to_file('scaled_logo.svg')

Working with Different SVG Elements

from svgecko import SVG

# SVG with various elements
svg_content = """
<svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg">
    <!-- Path with absolute commands -->
    <path d="M10 10 L20 20 L30 10 Z" fill="blue"/>
    
    <!-- Path with relative commands -->
    <path d="M50 50 l10 10 l10 -10 z" fill="red"/>
    
    <!-- Path with arc commands -->
    <path d="M70 70 A10 10 0 0 1 90 70" fill="green"/>
    
    <!-- Element with CSS transform -->
    <rect x="10" y="80" width="20" height="10" 
          style="transform: translate(5, 5)" fill="orange"/>
</svg>
"""

svg = SVG.from_string(svg_content)

# Apply transformation to all elements
def complex_transform(point):
    x, y = point
    # Apply a wave-like transformation
    new_x = x + math.sin(y * 0.1) * 5
    new_y = y + math.cos(x * 0.1) * 5
    return (new_x, new_y)

transformed_svg = svg.transform(complex_transform)

📚 API Reference

SVG Class

The main class for working with SVG files.

Methods

  • from_file(file_path: str, encoding: str = 'utf-8') -> SVG

    • Load SVG from a file
  • from_string(svg_string: str, encoding: str = 'utf-8') -> SVG

    • Load SVG from a string
  • transform(transformation: Callable[[Tuple[float, float]], Tuple[float, float]], inplace: bool = False) -> SVG

    • Apply a transformation function to all coordinates
    • transformation: Function that takes (x, y) and returns (x', y')
    • inplace: If True, modify the current SVG; if False, return a new SVG
  • to_file(file_path: str, encoding: str = 'utf-8') -> None

    • Save SVG to a file
  • to_string(encoding: str = 'utf-8') -> str

    • Convert SVG to XML string
  • to_pil_image(**kwargs) -> Image.Image

    • Convert SVG to PIL Image
    • Supports all cairosvg.svg2png parameters (scale, width, height, etc.)

Properties

  • xml: Access to the underlying XML element tree
  • shape: Tuple of (width, height) as floats

Path and PathCommand Classes

For working with SVG path data directly.

from svgecko import Path, PathCommand

# Parse a path string
path = Path.from_command_string('M10 10 L20 20 Z')

# Transform the path
transformed_path = path.transform(lambda p: (p[0] + 5, p[1] + 5))

# Get the command string
print(transformed_path.command_string)  # "M 15.0 15.0 L 25.0 25.0 Z"

🎯 Supported SVG Features

✅ Fully Supported

  • Absolute path commands: M, L, C, S, Q, T, H, V, Z
  • Relative path commands: m, l, c, s, q, t, h, v (converted to absolute)
  • Arc commands: A, a (approximated as line segments)
  • Coordinate attributes: x, y, x1, y1, x2, y2, cx, cy, fx, fy
  • Points attributes: polyline/polygon points
  • CSS transforms: translate(), translateX(), translateY() in style and transform attributes
  • File I/O: Load from/save to files and strings
  • Image conversion: Convert to PIL Image objects

🔄 Automatic Conversions

  • Relative commands (l, m, etc.) → Absolute commands (L, M, etc.)
  • Horizontal/Vertical commands (H, V) → Line commands (L)
  • Arc commands (A, a) → Line segments (approximation)

🧪 Examples

Mathematical Transformations

# Spiral transformation
def spiral(point, turns=2):
    x, y = point
    r = math.sqrt(x*x + y*y)
    angle = math.atan2(y, x) + r * turns * 2 * math.pi / 100
    return (r * math.cos(angle), r * math.sin(angle))

# Wave distortion
def wave_distort(point):
    x, y = point
    return (x + math.sin(y * 0.1) * 10, y + math.cos(x * 0.1) * 10)

# Perspective projection
def perspective(point, focal_length=100):
    x, y = point
    z = 50  # Assume z-coordinate
    scale = focal_length / (focal_length + z)
    return (x * scale, y * scale)

Visualization Scripts

Install matplotlib and run:

python examples/visualize_transformations.py
python examples/visualize_points.py

The scripts save PNGs into examples/output/ and also display them.

Batch Processing

import os
from pathlib import Path

def process_svg_directory(input_dir, output_dir, transformation):
    """Apply transformation to all SVG files in a directory."""
    input_path = Path(input_dir)
    output_path = Path(output_dir)
    output_path.mkdir(exist_ok=True)
    
    for svg_file in input_path.glob('*.svg'):
        svg = SVG.from_file(str(svg_file))
        transformed_svg = svg.transform(transformation)
        
        output_file = output_path / f'transformed_{svg_file.name}'
        transformed_svg.to_file(str(output_file))
        print(f'Processed: {svg_file.name}')

# Usage
process_svg_directory('input/', 'output/', lambda p: (p[0] * 1.5, p[1] * 1.5))

🛠️ Development

Setup Development Environment

git clone https://github.com/josef-ondrej/svgecko.git
cd svgecko
pip install -e ".[dev]"

Running Tests

pytest

Code Quality

# Format code
black svgecko tests

# Sort imports
isort svgecko tests

# Type checking
mypy svgecko

# Linting
flake8 svgecko tests

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.

📝 Changelog

v0.4.0

  • ✅ Added support for relative path commands
  • ✅ Added support for arc path commands (approximated as line segments)
  • ✅ Added support for CSS translate() functions in style attributes
  • ✅ Improved type annotations throughout the codebase
  • ✅ Added comprehensive Google-style documentation
  • ✅ Enhanced test coverage
  • ✅ Modernized project structure with pyproject.toml

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

svgecko-0.4.0.tar.gz (22.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

svgecko-0.4.0-py3-none-any.whl (17.0 kB view details)

Uploaded Python 3

File details

Details for the file svgecko-0.4.0.tar.gz.

File metadata

  • Download URL: svgecko-0.4.0.tar.gz
  • Upload date:
  • Size: 22.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.25

File hashes

Hashes for svgecko-0.4.0.tar.gz
Algorithm Hash digest
SHA256 24ba69856511f6cb7fd1e71211da0ecab11793796fbea9ee7e0f86c64bb979c6
MD5 2b897889f3ec75d260422cad45300dee
BLAKE2b-256 524bacb9055cd687911f883ffc8556ad5e3aa6bb872f9d5ef84e28c51e5a4c3a

See more details on using hashes here.

File details

Details for the file svgecko-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: svgecko-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 17.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.9.25

File hashes

Hashes for svgecko-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 42dd02d78dc077b7247d5b2fbb846eda3eee27a3ac5452960d332ae9d9483e6d
MD5 cc49626ebb3265184c3563104c8e55d3
BLAKE2b-256 4b889aa2cfae02cf5ee5d5d9832a1e51cf33b9c3667055ab1dfbc42b682b60ad

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page