svgelements

repository·master·Indexed 41 days ago

https://github.com/meerk40t/svgelements

A high-fidelity SVG parsing and geometric rendering library for Python. It provides spec-compliant SVG elements such as Path, Matrix, Color, and Point for geometric manipulation and transcoding. Features include robust parsing of path data, support for various length and color units, matrix transformations, and the ability to flatten element trees or export objects back to XML.

Tokens
6.1K
Snippets
17
Records
25
Agent score
1%

What's inside svgelements

  1. Overview of supported SVG features

    master

    svgelements provides high-fidelity parsing and geometric rendering for a wide range of SVG and CSS elements. Key supported features include:

    • Parsing & Writing: Robust SVG parsing and basic SVG writing.
    • Lengths: Supports px, pt, pc, cm, mm, in, and %.
    • Colors: Supports keywords, #rrggbb, #rgb, rgb(r,g,b), rgb(r%,g%,b%), rgba(r,g,b,a), and hsl(hue, s, l).
    • Matrices: Full matrix support; all objects have a .transform object for cascading matrix operations (including viewport).
    • Angles: Supports deg, rad, grad, and turn (e.g., within rotate() commands).
    • Shapes:
      • Rect, Circle, Ellipse, Polygon, Polyline, Line (internally SimpleLine).
      • Path: Perfect path_d parsing (Relative/Absolute, Smooth BezierCurve) while preserving segment forms.
      • Shapes can be deconstructed into Paths using Path(shape) or shape.d().
    • Geometric Functions: Advanced functions for PathSegments such as point(), npoint(), bbox(), and reverse().
    • Styling: Supports .stroke, .fill, and .stroke_width for all shapes.
    • Structure: Supports Group objects, clipPath, <defs>, <use>, and ShadowDOM referencing.
  2. Use Colors and Lengths in SVG elements

    master

    svgelements supports a wide variety of color and length definitions that are automatically parsed into internal types.

    Colors

    You can define colors using:

    • XHTML names: 'red', 'blue', 'dark grey'
    • Hex codes: '#F00', '#FF00', '#FF0000', '#FFFF0000'
    • RGB functions: 'RGB(r,g,b)' or 'RGB(r%, g%, b%)'
    from svgelements import Circle, Point
    
    # Using a hex color
    c = Circle(center=Point(0,0), r=1, stroke="#ffff00")

    Lengths

    Linear space is defined using strings with units:

    • '20cm', '200mm', '3in', etc.
    from svgelements import Length
    
    l = Length('200mm')
  3. Handle SVG Viewport and Unit Scaling

    master

    To prevent errors where coordinate values differ from physical sizes (e.g., a viewbox of 100 units representing 50cm), use the Viewbox object.

    Viewbox objects can generate an equivalent transformation string via .transform(). This implementation follows the SVG 1.1 (7.2) and SVG 2.0 (8.2) algorithms and supports preserveAspectRatio, xMidYMid, and meetOrSlice values.

  4. Work with Path subpaths

    master

    Subpaths provide a window into a Path object. They are backed by the original Path, meaning any operations performed on a subpath (like scaling or reversing) are applied directly to that specific part of the parent path.

    Use .subpath(index) to access a specific subpath within a Path object.

    >>> p = Path('M 0,0 Q 50,50 100,0 M 20,20 v 20 h 20 v-20 h-20 z')
    >>> q = p.subpath(1) 
    >>> q *= "scale(2)"
    >>> print(p)
    # The second subpath in p is now scaled by 2
    M 0,0 Q 50,50 100,0 M 40,40 L 40,80 L 80,80 L 80,40 L 40,40 Z
  5. Understand svgelements requirements and soft dependencies

    master

    The library has no hard dependencies and is designed to be easily portable (e.g., by copying svgelements.py into a project). However, installing certain packages enables advanced functionality:

    • scipy: Provides exact, correct answers for arc length calculations.
    • Pillow (PIL): Enables SVGImage objects to load images via the .load() method.
    • numpy: Enables the npoint() command for high-speed linearization of Shapes.
  6. Work with Points, Matrices, and Paths via dunder methods

    master

    svgelements uses intuitive Python dunder methods to allow geometric operations between different types.

    Points

    The Point class wraps various inputs including tuples, lists, strings (e.g., 'x, y'), complex numbers, or objects with .x and .y attributes. You can apply transformations directly to points:

    # Rotate a point using a transform string
    new_point = Point(10, 10) * "rotate(90)"

    Matrices

    The Matrix class handles affine transformations. You can create matrices from transform strings:

    from svgelements import Matrix
    
    # Create from SVG transform string
    m = Matrix("rotate(100grad)")
    
    # Common operations
    m.scale(2)
    m.rotate(45)
    m.translate(10, 20)

    Paths

    Path objects can be constructed from Path() or a standard SVG path_d string. You can combine paths using the + operator:

    from svgelements import Path
    
    # Combine an empty path with a move-to command
    p = Path() + "M0,0z"
  7. Work with SVG Shapes (Rect, Ellipse, Circle, etc.)

    master

    The library provides specialized shape objects that can be converted to paths but retain their original properties for easier manipulation.

    Key shapes include:

    • Rect: Defined by x, y, width, height, and optional rounded corners rx, ry.
    • Ellipse: Defined by center and radii rx, ry.
    • Circle: A specialized Ellipse where radii are equal.
    • SimpleLine: A renamed version of the SVG Line shape to avoid conflict with Line (a PathSegment).
    • Polyline: An unclosed sequence of points.
    • Polygon: A closed sequence of points.

    Shapes can be compared to Path objects; they are considered equal if they decompose to the same path data.

    Shapes support transformation via multiplication by strings (e.g., * "rotate(45deg)") or matrices. You can extract path data using the .d() method.

    from svgelements import *
    
    # Rectangles with rounded corners
    rect = Rect(10, 10, 8, 4, 2, 1)
    print(rect.d())  # Returns path data string
    
    # Transforming shapes
    rotated_rect = Rect(10, 10, 8, 4) * "rotate(0.5turns)"
    print(rotated_rect.d())
    
    # Comparing shapes
    print(Circle(center=(0,0), r=10) == Ellipse(center=(0,0), rx=10, ry=10))
    
    # Polylines vs Polygons
    poly = Polygon(0, 0, 100, 0, 100, 100, 0, 100)
    polyline = Polyline(0, 0, 100, 0, 100, 100, 0, 100)
    print(poly.d())      # Ends with 'Z'
    print(polyline.d()) # Does not end with 'Z'
  8. Transform PathSegments with Matrices

    master

    You can apply transformations to PathSegment objects (like Line) by multiplying them with a Matrix. Transformations can be applied using a Matrix object, a parsed matrix string, or an implied SVG transformation string.

    • Using Matrix object: segment * Matrix.rotate(Angle.degrees(45))
    • Using parsed matrix string: segment * Matrix("Rotate(45)")
    • Using implied string: segment * "Rotate(45)"
    >>> Line((20,20), (40,40)) * Matrix.rotate(Angle.degrees(45))
    Line(start=Point(0,28.284271247462), end=Point(0,56.568542494924))
    
    >>> Line((20,20), (40,40)) * Matrix("Rotate(45)")
    Line(start=Point(0,28.284271247462), end=Point(0,56.568542494924))
    
    >>> Line((20,20), (40,40)) * "Rotate(45)"
    Line(start=Point(0,28.284271247462), end=Point(0,56.568542494924))
  9. Construct and combine Paths

    master

    Paths can be constructed by combining individual PathSegment objects or by using SVG path data strings. You can use the + operator to concatenate segments or shapes.

    • Combining segments: Move((2,2)) + Close()
    • Appending SVG text to segments: (Move((20,20)) + "L 40,40")
    • Defining via string: Path("M 20,20 L 40,40")
    • Combining shapes: Path("M10,10z") + Circle("12,12", 2)
    >>> Move((2,2)) + Close()
    Path(Move(end=Point(2,2)), Close())
    
    >>> print(Move((2,2)) + Close())
    M 2,2 Z
    
    >>> Path("M 20,20 L 40,40")
    Path(Move(end=Point(20,20)), Line(start=Point(20,20), end=Point(40,40)))
    
    >>> print(Path("M10,10z") + Circle("12,12", 2))
    M 10,10 Z M 14,12 A 2,2 0 0,1 12,14 A 2,2 0 0,1 10,12 A 2,2 0 0,1 12,10 A 2,2 0 0,1 14,12 Z
  10. Manipulate Path geometry

    master

    Paths and segments support several geometric operations:

    • Scaling: Multiply a path by a scale string, e.g., path * "scale(2)".
    • Reversing: Use .reverse() to reverse the direction of a path.
    • Subpaths: Use .subpath(index) to access a specific subpath within a complex path.
    • Length: Use .length() to get the total length of a path or segment.
    • Bounding Box: Use .bbox() to get the bounding box (x1, y1, x2, y2). Use .bbox(transformed=False) to get the bounding box of the original geometry before any transformations were applied.
    # Scale and reverse
    >>> p = (Path("M1,1 1,2 2,2 2,1z") * "scale(2)")
    >>> p.reverse()
    >>> print(p)
    M 4,2 L 4,4 L 2,4 L 2,2 Z
    
    # Length and Bounding Box
    >>> QuadraticBezier("0,0", "50,50", "100,0").length()
    114.7793574696319
    >>> QuadraticBezier("0,0", "50,50", "100,0").bbox()
    (0.0, 0.0, 100.0, 50.0)
    
    # Subpaths
    >>> p = Path('M 0,0 Q 50,50 100,0 M 20,20 v 20 h 20 v-20 h-20 z')
    >>> p.subpath(1).d()
    'M 20,20 L 20,40 L 40,40 L 40,20 L 20,20 Z'
  11. Convert shapes to path data with .d()

    master

    All shape objects and paths implement a .d() method to produce SVG path data strings.

    • Absolute mode (default): Returns absolute coordinates.
    • Relative mode: Use .d(relative=True) to return relative path data (using lowercase commands like m, l, a).
    from svgelements import Rect
    
    # Absolute path data
    print(Rect(10, 10, 8, 4).d())
    
    # Relative path data
    print(Rect(10, 10, 8, 4, 2, 1).d(relative=True))