ParseSVGPath parses an SVG path data string.
(s string)
| 2082 | |
| 2083 | // ParseSVGPath parses an SVG path data string. |
| 2084 | func ParseSVGPath(s string) (*Path, error) { |
| 2085 | if len(s) == 0 { |
| 2086 | return &Path{}, nil |
| 2087 | } |
| 2088 | |
| 2089 | i := 0 |
| 2090 | path := []byte(s) |
| 2091 | i += skipCommaWhitespace(path[i:]) |
| 2092 | if path[0] == ',' || path[i] < 'A' { |
| 2093 | return nil, fmt.Errorf("bad path: path should start with command") |
| 2094 | } |
| 2095 | |
| 2096 | cmdLens := map[byte]int{ |
| 2097 | 'M': 2, |
| 2098 | 'Z': 0, |
| 2099 | 'L': 2, |
| 2100 | 'H': 1, |
| 2101 | 'V': 1, |
| 2102 | 'C': 6, |
| 2103 | 'S': 4, |
| 2104 | 'Q': 4, |
| 2105 | 'T': 2, |
| 2106 | 'A': 7, |
| 2107 | } |
| 2108 | f := [7]float64{} |
| 2109 | |
| 2110 | p := &Path{} |
| 2111 | var q, c Point |
| 2112 | var p0, p1 Point |
| 2113 | prevCmd := byte('z') |
| 2114 | for { |
| 2115 | i += skipCommaWhitespace(path[i:]) |
| 2116 | if len(path) <= i { |
| 2117 | break |
| 2118 | } |
| 2119 | |
| 2120 | cmd := prevCmd |
| 2121 | repeat := true |
| 2122 | if cmd == 'z' || cmd == 'Z' || !(path[i] >= '0' && path[i] <= '9' || path[i] == '.' || path[i] == '-' || path[i] == '+') { |
| 2123 | cmd = path[i] |
| 2124 | repeat = false |
| 2125 | i++ |
| 2126 | i += skipCommaWhitespace(path[i:]) |
| 2127 | } |
| 2128 | |
| 2129 | CMD := cmd |
| 2130 | if 'a' <= cmd && cmd <= 'z' { |
| 2131 | CMD -= 'a' - 'A' |
| 2132 | } |
| 2133 | for j := 0; j < cmdLens[CMD]; j++ { |
| 2134 | if CMD == 'A' && (j == 3 || j == 4) { |
| 2135 | // parse largeArc and sweep booleans for A command |
| 2136 | if i < len(path) && path[i] == '1' { |
| 2137 | f[j] = 1.0 |
| 2138 | } else if i < len(path) && path[i] == '0' { |
| 2139 | f[j] = 0.0 |
| 2140 | } else { |
| 2141 | return nil, fmt.Errorf("bad path: largeArc and sweep flags should be 0 or 1 in command '%c' at position %d", cmd, i+1) |