Metadata-Version: 2.4
Name: svglab
Version: 0.17.0
Classifier: Development Status :: 3 - Alpha
Classifier: Framework :: Pydantic :: 2
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: 3.15
Classifier: Topic :: Multimedia :: Graphics
Classifier: Topic :: Multimedia :: Graphics :: Editors :: Vector-Based
Classifier: Topic :: Scientific/Engineering :: Image Processing
Classifier: Topic :: Text Processing :: Markup :: XML
Classifier: Typing :: Typed
Requires-Dist: beautifulsoup4>=4.11.1
Requires-Dist: bidict>=0.22.0,<0.25.0
Requires-Dist: lark>=1.1.8
Requires-Dist: lxml>=5.1.0,!=6.0.0,!=6.0.1
Requires-Dist: more-itertools>=9.0.0
Requires-Dist: numpy>=2.0.0
Requires-Dist: pillow>=9.2.0
Requires-Dist: pydantic>=2.12.0,<3.0.0
Requires-Dist: pydantic-extra-types>=2.2.0,<3.0.0
Requires-Dist: rfc3986>=1.5.0
Requires-Dist: typing-extensions>=4.6.0
Requires-Dist: useful-types>=0.1.0,<0.3.0
Requires-Dist: html5lib>=1.1 ; extra == 'html5lib'
Provides-Extra: html5lib
License-File: LICENSE
Summary: The Python library for parsing, manipulating, and optimizing SVG files.
Keywords: affine transformation,image optimization,image processing,svg,svg manipulation,vector graphics
Author-email: Tomáš Režňák <tomas.reznak@proton.me>
License-Expression: MIT
Requires-Python: >=3.11
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
Project-URL: Documentation, https://svglab.rocks/
Project-URL: GitHub, https://github.com/reznakt/svglab
Project-URL: Issues, https://github.com/reznakt/svglab/issues

<div align="center">
  <img width="200" src="https://raw.githubusercontent.com/reznakt/svglab/refs/heads/main/assets/logo.svg" />

  <h1 align="center">
    <picture>
      <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/reznakt/svglab/refs/heads/main/assets/wordmark-dark.svg" />
      <img alt="svglab" width="260" src="https://raw.githubusercontent.com/reznakt/svglab/refs/heads/main/assets/wordmark-light.svg" />
    </picture>
  </h1>

  <p align="center">
    <em>The Python library for parsing, manipulating, and optimizing SVG files</em>
  </p>

  <p align="center">
    <a href="https://pypi.org/project/svglab/"><img alt="PyPI - Version" src="https://img.shields.io/pypi/v/svglab" /></a>
    <a href="https://pypi.org/project/svglab/"><img alt="PyPI - Python Version" src="https://img.shields.io/pypi/pyversions/svglab" /></a>
    <a href="https://pypi.org/project/svglab/"><img alt="PyPI - Types" src="https://img.shields.io/pypi/types/svglab" /></a>
    <a href="https://codecov.io/github/reznakt/svglab"><img alt="Test coverage" src="https://codecov.io/github/reznakt/svglab/graph/badge.svg" /></a>
    <br />
    <a href="https://svglab.rocks/"><img alt="Documentation" src="https://img.shields.io/badge/docs-svglab.rocks-blue" /></a>
    <a href="https://pepy.tech/project/svglab"><img alt="PyPI - Downloads" src="https://img.shields.io/pepy/dt/svglab" /></a>
    <a href="https://github.com/reznakt/svglab/blob/main/LICENSE"><img alt="License" src="https://img.shields.io/pypi/l/svglab" /></a>
  </p>
</div>

<br />

## About the project

### Features

- SVG parsing, manipulation, and writing
- Support for all SVG 1.1 elements and attributes
- Partial support for SVG 2
- Support for special XML entities (`CDATA`, comments, text)
- Attributes are parsed into native Python types for easy manipulation
- Highly configurable formatting options:
    - indentation level
    - maximum precision for floating-point numbers
    - color mode (`named`, `hex-short`, `hex-long`, `rgb`, `hsl`, `auto`, `original`)
    - relative/absolute path commands
    - scientific notation for small/large numbers
    - and many more...
- Strong type safety:
    - one class per distinct SVG element
    - typed attributes
    - runtime validation thanks to [pydantic](https://pypi.org/project/pydantic/)
- Support for all [beautifulsoup4](https://pypi.org/project/beautifulsoup4/) parsers (e.g., `html.parser`, `lxml`, `html5lib` via the `html5lib` extra)
- SVG can be rendered into a raster image using [resvg](https://lib.rs/crates/resvg), through bindings that ship with the library
- Support for calculating the bounding box and mask of an element
- Support for applying transformations in the `transform` attribute ("reification")

```mermaid
---
title: Entity hierarchy
---

graph TD
  Entity:::abc --> CharacterData
  Entity --> Element

  Element:::abc --> G
  Element --> Svg
  Element --> Rect
  Element --> Circle
  Element --> etc1[...]

  CharacterData:::abc --> RawText
  CharacterData --> Comment
  CharacterData --> CData

  etc1:::etc

  classDef abc stroke-dasharray:5 5,stroke-width:2px;
  classDef etc stroke:gray,stroke-width:2px;
  classDef default stroke:orange,stroke-width:2px;
```

## Getting started

### Prerequisites

- [CPython](https://www.python.org/) 3.11+
- [Rust](https://rustup.rs/) 1.85+ and a C compiler for linking (source builds only; when `cargo` is missing, the build downloads Rust itself)
- `clippy` and `rustfmt` (development only; used by `just lint` and `just format`)
- [uv](https://docs.astral.sh/uv/) (development only)
- [just](https://just.systems/) (development only; optional)

### Installation

**From PyPI**:

```sh
pip install svglab
```

**From source**:

```sh
# Via HTTPS
pip install git+https://github.com/reznakt/svglab.git

# Via SSH
pip install git+ssh://git@github.com/reznakt/svglab.git
```

## Usage

### Parsing

```python
svg = parse_svg(
    """
    <svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
      <g>
          <rect
            id="background"
            width="100cm"
            height="100%"
            transform="rotate(45)"
            stroke="red"
          />
          <rect color="hsl(0, 100%, 100%)"/>
          <!-- This is a comment -->
          <![CDATA[.background { fill: blue; }]]>
          Hello SVG!
          <path d="M 10,10 H 10 L 100,100 Q 100,100 50,50 v 100 Z"/>
          <path d="M0,0 10,10 20,20 S 100,100 50,50 t 100,100 M 50,50 z"/>
          <path d="M0,0A50,50 90 1 0 100,100v100h-10z"/>
          <polygon points="0,0 100,0 100,100 0,100"/>
      </g>
    </svg>
"""
)

print(svg)
```

### Building elements

```python
group = G().add_children(
    Rect(
        width=Length(15, "px"),
        height=Length(20),
        transform=[SkewX(45.123), Translate(10, 20)],
        color=Color("#ff0000"),
    ),
    Comment("This is a comment"),
    CData(".background { fill: blue; }"),
    RawText("Hello SVG!"),
    Path(
        d=PathData()
        .move_to(Point(10, 10))
        .line_to(Point(100, 100))
        .quadratic_bezier_to(Point(100, 100), Point(50, 50))
        .smooth_quadratic_bezier_to(Point(100, 100))
        .move_to(Point(50, 50))
        .cubic_bezier_to(Point(100, 100), Point(100, 100), Point(10, 10))
        .smooth_cubic_bezier_to(Point(100, 100), Point(50, 50))
        .arc_to(
            Point(50, 50), 90, Point(100, 100), large=True, sweep=False
        )
        .vertical_line_to(100)
        .horizontal_line_to(-10, relative=True)
        .close()
    ),
    Polyline(
        points=[
            Point(0, 0),
            Point(100, 0),
            Point(100, 100),
            Point(0, 100),
        ],
        stroke_linecap="square",
        opacity=0.5,
    ),
)

# Add the element to the SVG
svg.add_child(group)
```

### Attributes and output

```python
print(svg.xmlns)  # http://www.w3.org/2000/svg
svg.x = Length(10, "px")

# Save to a file
svg.save(sys.stdout)
```

### Searching the tree

```python
print(*svg.find_all(Rect), sep="\n")
rect = svg.find(G).find(Rect)
```

### Geometry and rendering

```python
print(rect.get_bbox())
print(rect.get_mask())

# Render the SVG to an image
image = svg.render()
print(image)
```

### Transformations

```python
svg.reify()
print(svg.to_xml())

# Change the view box
svg.set_viewbox((0, 0, 50, 50))
print(svg.to_xml())
```

## Development

### Setup

```sh
# Install dependencies
uv sync

# Activate the virtual environment
source .venv/bin/activate

# Optional: Install the pre-commit hooks
prek install
```

### Common tasks

```sh
# Rebuild the Rust extension after changing the crate
just build

# Run tests
just test

# Run type checker
just typecheck

# Run linter
just lint

# Fix linting errors
just lint-fix

# Run formatter
just format

# Fix formatting errors
just format-fix
```

## License

This software is distributed under the MIT License. See [`LICENSE`](LICENSE) for more information.

