svg

package module
v0.0.0-...-8b17861 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 5, 2025 License: MIT Imports: 10 Imported by: 10

README

SVG Parser for Go

Go

A comprehensive Go library for parsing SVG (Scalable Vector Graphics) files with support for path parsing, shape elements, transformations, and Bezier curve rasterization.

Warning: Readme is AI generated

Features

  • SVG Parsing: Parse SVG files from strings or readers
  • Shape Support: Full support for all major SVG shapes:
    • <path> with complete path command support (M, L, H, V, C, S, Q, T, A, Z)
    • <rect>, <circle>, <ellipse>, <line>
    • <polygon>, <polyline>
  • Transformations: Complete SVG transform support (translate, rotate, scale, matrix)
  • Groups: Nested group (<g>) support with inheritance
  • Styling: Stroke, fill, opacity, stroke-width, and other styling attributes
  • Bezier Curves: Advanced Bezier curve rasterization with recursive interpolation
  • Drawing Instructions: Generate drawing instructions suitable for graphics libraries
  • ViewBox Support: Proper viewport and coordinate system handling

Installation

go get github.com/rustyoz/svg

Quick Start

Basic SVG Parsing
package main

import (
    "fmt"
    "log"
    "github.com/rustyoz/svg"
)

func main() {
    svgContent := `<svg width="100" height="100" viewBox="0 0 100 100">
        <rect x="10" y="10" width="30" height="30" fill="red"/>
        <circle cx="70" cy="25" r="15" fill="blue"/>
        <path d="M10 70 L50 70 L30 90 Z" fill="green"/>
    </svg>`
    
    // Parse SVG from string
    parsed, err := svg.ParseSvg(svgContent, "example", 1.0)
    if err != nil {
        log.Fatal(err)
    }
    
    fmt.Printf("SVG dimensions: %s x %s\n", parsed.Width, parsed.Height)
    fmt.Printf("ViewBox: %s\n", parsed.ViewBox)
}
Working with Drawing Instructions

Drawing instructions provide a higher-level interface suitable for graphics libraries:

// Parse drawing instructions from SVG
instructions, errors := parsed.ParseDrawingInstructions()

// Process instructions
go func() {
    for err := range errors {
        log.Printf("Error: %v", err)
    }
}()

for instruction := range instructions {
    switch instruction.Kind {
    case svg.MoveInstruction:
        // Move to instruction.M
    case svg.LineInstruction:
        // Line to instruction.L
    case svg.CurveInstruction:
        // Bezier curve with control points
        fmt.Printf("Curve: %v -> %v -> %v\n", 
            instruction.CurvePoints.C1,
            instruction.CurvePoints.C2, 
            instruction.CurvePoints.T)
    case svg.PaintInstruction:
        // Apply styling (stroke, fill, etc.)
    }
}
Working with Path Segments

For lower-level access, you can work directly with path segments:

// Assuming you have a Path element
segments := path.Parse()

for segment := range segments {
    fmt.Printf("Segment with %d points, width: %.2f, closed: %t\n", 
        len(segment.Points), segment.Width, segment.Closed)
    
    for _, point := range segment.Points {
        fmt.Printf("  Point: (%.2f, %.2f)\n", point[0], point[1])
    }
}

Advanced Usage

Custom Transformations

The library properly handles SVG transformations:

svgWithTransforms := `<svg viewBox="0 0 100 100">
    <g transform="translate(50,50) rotate(45) scale(2,1)">
        <rect x="-10" y="-10" width="20" height="20"/>
    </g>
</svg>`

parsed, _ := svg.ParseSvg(svgWithTransforms, "transformed", 1.0)
// Transformations are automatically applied to drawing instructions
Reading from File
import (
    "os"
    "github.com/rustyoz/svg"
)

file, err := os.Open("drawing.svg")
if err != nil {
    log.Fatal(err)
}
defer file.Close()

parsed, err := svg.ParseSvgFromReader(file, "drawing", 1.0)
if err != nil {
    log.Fatal(err)
}
Bezier Curve Rasterization

The library includes sophisticated Bezier curve rasterization:

// Bezier curves in paths are automatically rasterized
// with configurable precision based on angle thresholds
svgWithCurves := `<svg viewBox="0 0 200 200">
    <path d="M50 50 C 50 10, 150 10, 150 50 S 250 90, 150 90"/>
</svg>`

parsed, _ := svg.ParseSvg(svgWithCurves, "curves", 1.0)
instructions, _ := parsed.ParseDrawingInstructions()

for instruction := range instructions {
    if instruction.Kind == svg.CurveInstruction {
        // Access rasterized curve points
        points := instruction.CurvePoints
        // Use points for rendering
    }
}

Supported SVG Elements

Element Support Notes
<svg> Root element with viewBox, width, height
<g> Groups with transformations and styling
<path> Complete path command support
<rect> Rectangles with rounded corners
<circle> Circles
<ellipse> Ellipses
<line> Lines
<polygon> Closed polygons
<polyline> Open polygons
<text> ⚠️ Parsed but not rasterized

Path Commands

All SVG path commands are supported:

  • M/m: Move to (absolute/relative)
  • L/l: Line to (absolute/relative)
  • H/h: Horizontal line to (absolute/relative)
  • V/v: Vertical line to (absolute/relative)
  • C/c: Cubic Bezier curve (absolute/relative)
  • S/s: Smooth cubic Bezier curve (absolute/relative)
  • Q/q: Quadratic Bezier curve (absolute/relative)
  • T/t: Smooth quadratic Bezier curve (absolute/relative)
  • A/a: Elliptical arc (absolute/relative)
  • Z/z: Close path

API Reference

Main Functions
// Parse SVG from string
func ParseSvg(svgString, name string, scale float64) (*Svg, error)

// Parse SVG from io.Reader
func ParseSvgFromReader(r io.Reader, name string, scale float64) (*Svg, error)
Core Types
type Svg struct {
    Title    string
    Groups   []Group
    Width    string
    Height   string
    ViewBox  string
    Elements []DrawingInstructionParser
    // ...
}

type DrawingInstruction struct {
    Kind           InstructionType
    M              *[2]float64     // Move to point
    L              *[2]float64     // Line to point
    CurvePoints    *CurvePoints    // Bezier curve points
    StrokeWidth    *float64
    Stroke         *string
    Fill           *string
    Opacity        *float64
    // ...
}

Dependencies

  • github.com/rustyoz/Mtransform - Matrix transformations
  • github.com/rustyoz/genericlexer - Lexical analysis for path parsing
  • Standard Go XML parsing

Applications

This library is actively used in:

  • svg2kicad - Convert SVG to KiCad PCB format
  • svg2gcode - convert SVG to gcode
  • svg2laser - Software to streamline hte process of cutting FRC Robotics prototypes designed in Onshape on an Epilog Helix 18"x24" laser cutter.
  • Spiffy - Spiffy is a SVG to GCode converter.
  • goimage - Image manipulation library

Send a pull request on the readme to be mentioned

Contributing

Contributions are welcome! Please feel free to submit issues or pull requests.

License

See LICENCE file for details.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func PathStringFromDrawingInstructions

func PathStringFromDrawingInstructions(dis []*DrawingInstruction) string

PathStringFromDrawingInstructions converts drawing instructions obtained from svg <path/> element back into <path/> form

Types

type Circle

type Circle struct {
	ID        string  `xml:"id,attr"`
	Transform string  `xml:"transform,attr"`
	Style     string  `xml:"style,attr"`
	Cx        float64 `xml:"cx,attr"`
	Cy        float64 `xml:"cy,attr"`
	Radius    float64 `xml:"r,attr"`
	Fill      string  `xml:"fill,attr"`
	// contains filtered or unexported fields
}

Circle is an SVG circle element

func (*Circle) ParseDrawingInstructions

func (c *Circle) ParseDrawingInstructions() (chan *DrawingInstruction, chan error)

ParseDrawingInstructions implements the DrawingInstructionParser interface

type CurvePoints

type CurvePoints struct {
	C1 *Tuple
	C2 *Tuple
	T  *Tuple
}

CurvePoints are the points needed by a bezier curve.

type DrawingInstruction

type DrawingInstruction struct {
	Kind           InstructionType
	M              *Tuple
	CurvePoints    *CurvePoints
	Radius         *float64
	StrokeWidth    *float64
	Opacity        *float64
	Fill           *string
	Stroke         *string
	StrokeLineCap  *string
	StrokeLineJoin *string
}

DrawingInstruction contains enough information that a simple drawing library can draw the shapes contained in an SVG file.

The struct contains all necessary fields but only the ones needed (as indicated byt the InstructionType) will be non-nil.

func (*DrawingInstruction) String

func (di *DrawingInstruction) String() string

type DrawingInstructionParser

type DrawingInstructionParser interface {
	ParseDrawingInstructions() (chan *DrawingInstruction, chan error)
}

DrawingInstructionParser allow getting segments and drawing instructions from them. All SVG elements should implement this interface.

type Ellipse

type Ellipse struct {
	ID        string `xml:"id,attr"`
	Transform string `xml:"transform,attr"`
	Style     string `xml:"style,attr"`
	Cx        string `xml:"cx,attr"`
	Cy        string `xml:"cy,attr"`
	Rx        string `xml:"rx,attr"`
	Ry        string `xml:"ry,attr"`
	// contains filtered or unexported fields
}

Ellipse is an SVG ellipse XML element

type Group

type Group struct {
	ID              string
	Stroke          string
	StrokeWidth     float64
	Fill            string
	Opacity         float64
	FillRule        string
	Elements        []DrawingInstructionParser
	TransformString string
	Transform       *mt.Transform // row, column
	Parent          *Group
	Owner           *Svg
	// contains filtered or unexported fields
}

Group represents an SVG group (usually located in a 'g' XML element)

func (*Group) ParseDrawingInstructions

func (g *Group) ParseDrawingInstructions() (chan *DrawingInstruction, chan error)

ParseDrawingInstructions implements the DrawingInstructionParser interface

This method makes it easier to get all the drawing instructions.

func (*Group) SetOwner

func (g *Group) SetOwner(svg *Svg)

SetOwner sets the owner of a SVG Group

func (*Group) UnmarshalXML

func (g *Group) UnmarshalXML(decoder *xml.Decoder, start xml.StartElement) error

UnmarshalXML implements the encoding.xml.Unmarshaler interface

type InstructionType

type InstructionType int

InstructionType tells our path drawing library which function it has to call

const (
	MoveInstruction InstructionType = iota
	CircleInstruction
	CurveInstruction
	LineInstruction
	CloseInstruction
	PaintInstruction
)

These are instruction types that we use with our path drawing library

type Line

type Line struct {
	ID        string `xml:"id,attr"`
	Transform string `xml:"transform,attr"`
	Style     string `xml:"style,attr"`
	X1        string `xml:"x1,attr"`
	X2        string `xml:"x2,attr"`
	Y1        string `xml:"y1,attr"`
	Y2        string `xml:"y2,attr"`
	// contains filtered or unexported fields
}

Line is an SVG XML line element

type Path

type Path struct {
	ID              string `xml:"id,attr"`
	D               string `xml:"d,attr"`
	Style           string `xml:"style,attr"`
	TransformString string `xml:"transform,attr"`

	StrokeWidth    float64  `xml:"stroke-width,attr"`
	Fill           *string  `xml:"fill,attr"`
	Opacity        *float64 `xml:"opacity,attr"`
	Stroke         *string  `xml:"stroke,attr"`
	StrokeLineCap  *string  `xml:"stroke-linecap,attr"`
	StrokeLineJoin *string  `xml:"stroke-linejoin,attr"`
	Segments       chan Segment
	// contains filtered or unexported fields
}

Path is an SVG XML path element

func (*Path) Parse

func (p *Path) Parse() chan Segment

Parse interprets path description, transform and style atttributes to create a channel of segments.

func (*Path) ParseDrawingInstructions

func (p *Path) ParseDrawingInstructions() (chan *DrawingInstruction, chan error)

ParseDrawingInstructions returns two channels. One is a channel of Segments identical to the one returned by Parse() and the other one is a channel of DrawingInstruction. The latter should be used to pass to a path drawing library (like Cairo or something comparable)

type PolyLine

type PolyLine struct {
	ID        string `xml:"id,attr"`
	Transform string `xml:"transform,attr"`
	Style     string `xml:"style,attr"`
	Points    string `xml:"points,attr"`
	// contains filtered or unexported fields
}

PolyLine is a set of connected line segments that typically form a closed shape

type Polygon

type Polygon struct {
	ID        string `xml:"id,attr"`
	Transform string `xml:"transform,attr"`
	Style     string `xml:"style,attr"`
	Points    string `xml:"points,attr"`
	// contains filtered or unexported fields
}

Polygon is a closed shape of straight line segments

type Rect

type Rect struct {
	ID        string `xml:"id,attr"`
	Width     string `xml:"width,attr"`
	Height    string `xml:"height,attr"`
	Transform string `xml:"transform,attr"`
	Style     string `xml:"style,attr"`
	Rx        string `xml:"rx,attr"`
	Ry        string `xml:"ry,attr"`
	// contains filtered or unexported fields
}

Rect is an SVG XML rect element

func (*Rect) ParseDrawingInstructions

func (r *Rect) ParseDrawingInstructions() (chan *DrawingInstruction, chan error)

ParseDrawingInstructions implements the DrawingInstructionParser interface

type Segment

type Segment struct {
	Width  float64
	Closed bool
	Points [][2]float64
}

A Segment of a path that contains a list of connected points, its stroke Width and if the segment forms a closed loop. Points are defined in world space after any matrix transformation is applied.

type Svg

type Svg struct {
	Title     string  `xml:"title"`
	Groups    []Group `xml:"g"`
	Width     string  `xml:"width,attr"`
	Height    string  `xml:"height,attr"`
	ViewBox   string  `xml:"viewBox,attr"`
	Elements  []DrawingInstructionParser
	Name      string
	Transform *mt.Transform
	// contains filtered or unexported fields
}

Svg represents an SVG file containing at least a top level group or a number of Paths

func ParseSvg

func ParseSvg(str string, name string, scale float64) (*Svg, error)

ParseSvg parses an SVG string into an SVG struct

func ParseSvgFromReader

func ParseSvgFromReader(r io.Reader, name string, scale float64) (*Svg, error)

ParseSvgFromReader parses an SVG struct from an io.Reader

func (*Svg) ParseDrawingInstructions

func (s *Svg) ParseDrawingInstructions() (chan *DrawingInstruction, chan error)

ParseDrawingInstructions implements the DrawingInstructionParser interface

This method makes it easier to get all the drawing instructions.

func (*Svg) UnmarshalXML

func (s *Svg) UnmarshalXML(decoder *xml.Decoder, start xml.StartElement) error

UnmarshalXML implements the encoding.xml.Unmarshaler interface

func (*Svg) ViewBoxValues

func (s *Svg) ViewBoxValues() ([]float64, error)

ViewBoxValues returns all the numerical values in the viewBox attribute.

type Tuple

type Tuple [2]float64

Tuple is an X,Y coordinate

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL