|
1 | 1 | package svg
|
2 | 2 |
|
3 | 3 | import (
|
| 4 | + "fmt" |
| 5 | + "os" |
4 | 6 | "strings"
|
5 | 7 | "testing"
|
6 | 8 |
|
@@ -29,3 +31,191 @@ func TestParse(t *testing.T) {
|
29 | 31 | is.NoErr(err)
|
30 | 32 | is.NotNil(svg)
|
31 | 33 | }
|
| 34 | + |
| 35 | +func TestTransform(t *testing.T) { |
| 36 | + content := `<?xml version="1.0" standalone="no"?> |
| 37 | + <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" |
| 38 | + "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> |
| 39 | + <svg version="1.0" xmlns="http://www.w3.org/2000/svg" |
| 40 | + width="684.000000pt" height="630.000000pt" viewBox="0 0 684.000000 630.000000" |
| 41 | + preserveAspectRatio="xMidYMid meet"> |
| 42 | + <g transform="translate(0.000000,630.000000) scale(0.100000,-0.100000)" |
| 43 | + fill="#ff0000" stroke="none"> |
| 44 | + <path d="M1705 6274 c-758 -115 -1377 -637 -1614 -1360 -74 -227 -86 -311 -86 |
| 45 | + -624 0 -248 2 -286 23 -389 64 -315 210 -626 414 -880 34 -42 715 -731 1515 |
| 46 | + -1531 l1453 -1455 1444 1445 c794 795 1473 1481 1510 1524 98 117 189 259 261 |
| 47 | + 409 233 479 267 1011 99 1516 -240 718 -861 1235 -1615 1345 -138 21 -430 21 |
| 48 | + -564 1 -213 -32 -397 -87 -580 -174 -188 -90 -319 -177 -478 -316 l-77 -66 |
| 49 | + -77 66 c-309 270 -657 431 -1054 489 -132 20 -447 20 -574 0z"/> |
| 50 | + </g> |
| 51 | + </svg> |
| 52 | + ` |
| 53 | + s, err := ParseSvg(content, "transformed heart", 0) |
| 54 | + if err != nil { |
| 55 | + t.Fatalf("cannot parse svg %v", content) |
| 56 | + } |
| 57 | + if len(s.Groups) < 1 { |
| 58 | + t.Fatal("group not found") |
| 59 | + } |
| 60 | + g := s.Groups[0] |
| 61 | + t.Logf("original: transform=\"%v\"", g.TransformString) |
| 62 | + m := *g.Transform |
| 63 | + a, c, e := m[0][0], m[0][1], m[0][2] |
| 64 | + b, d, f := m[1][0], m[1][1], m[1][2] |
| 65 | + // see https://www.w3.org/TR/SVGTiny12 for [a b c d e f] vector notation |
| 66 | + t.Logf("accumulated: transform=\"matrix(%v %v %v %v %v %v)\"", a, b, c, d, e, f) |
| 67 | + if !(a == 0.1 && d == -0.1 && f == 630) { |
| 68 | + t.Error("mismatch expected transform matrix(0.1 0 0 -0.1 0 630)") |
| 69 | + } |
| 70 | +} |
| 71 | + |
| 72 | +func Test2Curves(t *testing.T) { |
| 73 | + content := `<?xml version="1.0" standalone="no"?> |
| 74 | + <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" |
| 75 | + "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> |
| 76 | + <svg version="1.0" xmlns="http://www.w3.org/2000/svg" |
| 77 | + viewBox="0 -450 1000 1000"> |
| 78 | + <path fill="none" stroke="red" stroke-width="5" |
| 79 | + d="M100 200 C25 100 400 100 400 200 400 100 775 100 700 200 L400 450z" /> |
| 80 | + </svg> |
| 81 | + ` |
| 82 | + s, err := ParseSvg(content, "heart", 1) |
| 83 | + if err != nil { |
| 84 | + t.Fatalf("cannot parse svg %v", content) |
| 85 | + } |
| 86 | + dis, _ := s.ParseDrawingInstructions() |
| 87 | + strux := []*DrawingInstruction{} |
| 88 | + for di := range dis { |
| 89 | + strux = append(strux, di) |
| 90 | + } |
| 91 | + curveIdx := 2 |
| 92 | + di := strux[curveIdx] |
| 93 | + if di.Kind != CurveInstruction { |
| 94 | + t.Fatalf("expect curve drawing instructions, got %v", di) |
| 95 | + } |
| 96 | + p := di.CurvePoints // 400 100 775 100 700 200 |
| 97 | + if !(p.C1[0] == 400 && p.C2[0] == 775 && p.T[0] == 700) { |
| 98 | + t.Fatalf("expect [400 100] [775 100] [700 200], got %v %v %v", *p.C1, *p.C2, *p.T) |
| 99 | + } |
| 100 | +} |
| 101 | + |
| 102 | +func TestPathRelScale(t *testing.T) { |
| 103 | + content := `<?xml version="1.0" standalone="no"?> |
| 104 | + <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" |
| 105 | + "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> |
| 106 | + <svg version="1.0" xmlns="http://www.w3.org/2000/svg" |
| 107 | + viewBox="0 -600 800 500"> |
| 108 | + <g transform="scale(1,-1)"> |
| 109 | + <path fill="none" stroke="red" stroke-width="5" |
| 110 | + d="M100 200 c-75 -100 300 -100 300 0 0 -100 375 -100 300 0 l-300 350z" /> |
| 111 | + </g> |
| 112 | + </svg> |
| 113 | + ` |
| 114 | + s, err := ParseSvg(content, "", 1) |
| 115 | + if err != nil { |
| 116 | + t.Fatalf("cannot parse svg %v", content) |
| 117 | + } |
| 118 | + dis, _ := s.ParseDrawingInstructions() |
| 119 | + strux := []*DrawingInstruction{} |
| 120 | + for di := range dis { |
| 121 | + strux = append(strux, di) |
| 122 | + } |
| 123 | + curveIdx := 1 // Move Curve*2 Line Close Paint |
| 124 | + di := strux[curveIdx] |
| 125 | + if di.Kind != CurveInstruction { |
| 126 | + t.Fatalf("expect curve (c) instruction at %v, got %v", curveIdx, di) |
| 127 | + } |
| 128 | + if di.CurvePoints.T[1] != -200 { // [100+300, 200+0] scale by [1, -1] |
| 129 | + t.Fatalf("expect 1st curve terminating at [400, -200], got %v", |
| 130 | + *di.CurvePoints.T) |
| 131 | + } |
| 132 | +} |
| 133 | + |
| 134 | +func TestPathRelTranslate(t *testing.T) { |
| 135 | + content := `<?xml version="1.0" standalone="no"?> |
| 136 | + <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" |
| 137 | + "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> |
| 138 | + <svg version="1.0" xmlns="http://www.w3.org/2000/svg" |
| 139 | + viewBox="0 400 600 600"> |
| 140 | + <g fill="#ff0000" stroke="none" transform="translate(0,200)"> |
| 141 | + <path d="M170 627 c-75 -11 -137 -63 -161 -136 -7 -22 -8 -31 -8 |
| 142 | + -62 0 -24 0.2 -28 2 -38 z"/> |
| 143 | + </g> |
| 144 | + </svg> |
| 145 | + ` |
| 146 | + s, err := ParseSvg(content, "", 1) |
| 147 | + if err != nil { |
| 148 | + t.Fatalf("cannot parse svg %v", content) |
| 149 | + } |
| 150 | + dis, errChan := s.ParseDrawingInstructions() |
| 151 | + for e := range errChan { |
| 152 | + t.Fatalf("parse drawing instruction: %v", e) |
| 153 | + } |
| 154 | + strux := []*DrawingInstruction{} |
| 155 | + for di := range dis { |
| 156 | + strux = append(strux, di) |
| 157 | + } |
| 158 | + c1 := strux[1] |
| 159 | + c3 := strux[3] |
| 160 | + if c1.CurvePoints.C1[1] != 816 || c3.CurvePoints.T[1] != 591 { |
| 161 | + expect := "C95 816 33 764 9 691 C2 669 1 660 1 629 C1 605 1.2 601 3 591" |
| 162 | + got := fmt.Sprintf("C%v %v ... %v", c1.CurvePoints.C1[0], |
| 163 | + c1.CurvePoints.C1[1], c3.CurvePoints.T[1]) |
| 164 | + t.Fatalf("expect %v: got %v", expect, got) |
| 165 | + } |
| 166 | +} |
| 167 | + |
| 168 | +func TestParsedPathString(t *testing.T) { |
| 169 | + header := `<?xml version="1.0" standalone="no"?> |
| 170 | + <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" |
| 171 | + "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd"> |
| 172 | + <svg version="1.0" xmlns="http://www.w3.org/2000/svg" |
| 173 | + width="684pt" height="630pt" viewBox="0 0 684 630" |
| 174 | + preserveAspectRatio="xMidYMid meet"> |
| 175 | + ` |
| 176 | + path := `<g transform="translate(0,630) scale(0.1,-0.1)" |
| 177 | + fill="#ff0000" stroke="none"> |
| 178 | + <path d="M1705 6274 c-758 -115 -1377 -637 -1614 -1360 -74 -227 -86 -311 -86 |
| 179 | + -624 0 -248 2 -286 23 -389 64 -315 210 -626 414 -880 34 -42 715 -731 1515 |
| 180 | + -1531 l1453 -1455 1444 1445 c794 795 1473 1481 1510 1524 98 117 189 259 261 |
| 181 | + 409 233 479 267 1011 99 1516 -240 718 -861 1235 -1615 1345 -138 21 -430 21 |
| 182 | + -564 1 -213 -32 -397 -87 -580 -174 -188 -90 -319 -177 -478 -316 l-77 -66 |
| 183 | + -77 66 c-309 270 -657 431 -1054 489 -132 20 -447 20 -574 0z"/> |
| 184 | + </g> |
| 185 | + ` |
| 186 | + tail := `</svg> |
| 187 | + ` |
| 188 | + content := header + path + tail |
| 189 | + s, err := ParseSvg(content, "heart", 1) |
| 190 | + if err != nil { |
| 191 | + t.Fatalf("cannot parse svg %v", content) |
| 192 | + } |
| 193 | + dis, errChan := s.ParseDrawingInstructions() |
| 194 | + for e := range errChan { |
| 195 | + t.Fatalf("drawing instruction error: %v", e) |
| 196 | + } |
| 197 | + strux := []*DrawingInstruction{} |
| 198 | + for di := range dis { |
| 199 | + strux = append(strux, di) |
| 200 | + } |
| 201 | + tmpdir := os.TempDir() + string(os.PathSeparator) |
| 202 | + f0 := tmpdir + "heart.svg" |
| 203 | + f, err := os.Create(f0) |
| 204 | + if err != nil { |
| 205 | + t.Errorf("error %v", err) |
| 206 | + } |
| 207 | + f.WriteString(content) |
| 208 | + f.Close() |
| 209 | + t.Logf("original shape in %v", f0) |
| 210 | + |
| 211 | + parsed := PathStringFromDrawingInstructions(strux) |
| 212 | + f1 := tmpdir + "parsedheart.svg" |
| 213 | + f, err = os.Create(f1) |
| 214 | + if err != nil { |
| 215 | + t.Errorf("error %v", err) |
| 216 | + } |
| 217 | + f.WriteString(header + parsed + tail) |
| 218 | + f.Close() |
| 219 | + t.Logf("parsed shape in %v", f1) |
| 220 | + t.Log("Please check consistency of above files, with web browser or eog") |
| 221 | +} |
0 commit comments