tangxu
2024-10-22 4d9fe5ed98ceb6b8fe9dc52ebfb80860ad1aee99
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// THIS FILE IS PART OF SVG PROJECT
// THE SVG PROJECT IS AN OPENSOURCE LIBRARY LICENSED UNDER THE MS-PL License.
// COPYRIGHT (C) svg-net. ALL RIGHTS RESERVED.
// GITHUB: https://github.com/svg-net/SVG
 
using System;
using System.Collections.Generic;
using System.Globalization;
 
namespace AntdUI.Svg.Transforms
{
    internal class SvgTransformConverter
    {
        static IEnumerable<string> SplitTransforms(string transforms)
        {
            int transformEnd = 0;
 
            for (int i = 0; i < transforms.Length; i++)
            {
                if (transforms[i] == ')')
                {
                    yield return transforms.Substring(transformEnd, i - transformEnd + 1).Trim();
                    while (i < transforms.Length && !char.IsLetter(transforms[i])) i++;
                    transformEnd = i;
                }
            }
        }
 
        public static SvgTransformCollection Parse(string value)
        {
            SvgTransformCollection transformList = new SvgTransformCollection();
            foreach (string transform in SplitTransforms(value))
            {
                if (string.IsNullOrEmpty(transform)) continue;
                var parts = transform.Split('(', ')');
                string transformName = parts[0].Trim(), contents = parts[1].Trim();
                switch (transformName)
                {
                    case "translate":
                        var coords = contents.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
                        if (coords.Length == 0 || coords.Length > 2) throw new FormatException("Translate transforms must be in the format 'translate(x [,y])'");
                        if (coords.Length > 1)
                        {
                            string c1 = coords[0].Trim(), c2 = coords[1].Trim();
                            if (c1.EndsWith("%") || c2.EndsWith("%"))
                            {
                                if (c1.EndsWith("%") && c2.EndsWith("%"))
                                {
                                    float x = float.Parse(c1.TrimEnd('%'), NumberStyles.Float, CultureInfo.InvariantCulture), y = float.Parse(c2.TrimEnd('%'), NumberStyles.Float, CultureInfo.InvariantCulture);
                                    transformList.Add(new SvgTranslate(x, true, y, true));
                                }
                                else if (c1.EndsWith("%"))
                                {
                                    float x = float.Parse(c1.TrimEnd('%'), NumberStyles.Float, CultureInfo.InvariantCulture), y = float.Parse(c2, NumberStyles.Float, CultureInfo.InvariantCulture);
                                    transformList.Add(new SvgTranslate(x, true, y, false));
                                }
                                else
                                {
                                    float x = float.Parse(c1, NumberStyles.Float, CultureInfo.InvariantCulture), y = float.Parse(c2.TrimEnd('%'), NumberStyles.Float, CultureInfo.InvariantCulture);
                                    transformList.Add(new SvgTranslate(x, false, y, true));
                                }
                            }
                            else
                            {
                                float x = float.Parse(c1, NumberStyles.Float, CultureInfo.InvariantCulture), y = float.Parse(c2.TrimEnd('%'), NumberStyles.Float, CultureInfo.InvariantCulture);
                                transformList.Add(new SvgTranslate(x, false, y, false));
                            }
                        }
                        else
                        {
                            string c1 = coords[0].Trim();
                            if (c1.EndsWith("%"))
                            {
                                float x = float.Parse(c1.TrimEnd('%'), NumberStyles.Float, CultureInfo.InvariantCulture);
                                transformList.Add(new SvgTranslate(x, true, 0F, false));
                            }
                            else
                            {
                                float x = float.Parse(c1, NumberStyles.Float, CultureInfo.InvariantCulture);
                                transformList.Add(new SvgTranslate(x, false, 0F, false));
                            }
                        }
                        break;
                    case "rotate":
                        var args = contents.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
                        if (args.Length != 1 && args.Length != 3) throw new FormatException("Rotate transforms must be in the format 'rotate(angle [cx cy ])'");
                        float angle = float.Parse(args[0], NumberStyles.Float, CultureInfo.InvariantCulture);
                        if (args.Length == 1) transformList.Add(new SvgRotate(angle));
                        else
                        {
                            float cx = float.Parse(args[1], NumberStyles.Float, CultureInfo.InvariantCulture);
                            float cy = float.Parse(args[2], NumberStyles.Float, CultureInfo.InvariantCulture);
                            transformList.Add(new SvgRotate(angle, cx, cy));
                        }
                        break;
                    case "scale":
                        var scales = contents.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
                        if (scales.Length == 0 || scales.Length > 2) throw new FormatException("Scale transforms must be in the format 'scale(x [,y])'");
                        float sx = float.Parse(scales[0].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture);
                        if (scales.Length > 1)
                        {
                            float sy = float.Parse(scales[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture);
                            transformList.Add(new SvgScale(sx, sy));
                        }
                        else transformList.Add(new SvgScale(sx));
                        break;
                    case "matrix":
                        var points = contents.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
                        if (points.Length != 6) throw new FormatException("Matrix transforms must be in the format 'matrix(m11, m12, m21, m22, dx, dy)'");
                        List<float> mPoints = new List<float>();
                        foreach (string point in points) mPoints.Add(float.Parse(point.Trim(), NumberStyles.Float, CultureInfo.InvariantCulture));
                        transformList.Add(new SvgMatrix(mPoints));
                        break;
                    case "shear":
                        var shears = contents.Split(new char[] { ',', ' ' }, StringSplitOptions.RemoveEmptyEntries);
                        if (shears.Length == 0 || shears.Length > 2) throw new FormatException("Shear transforms must be in the format 'shear(x [,y])'");
                        float hx = float.Parse(shears[0].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture);
                        if (shears.Length > 1)
                        {
                            float hy = float.Parse(shears[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture);
                            transformList.Add(new SvgShear(hx, hy));
                        }
                        else transformList.Add(new SvgShear(hx));
                        break;
                    case "skewX":
                        float ax = float.Parse(contents, NumberStyles.Float, CultureInfo.InvariantCulture);
                        transformList.Add(new SvgSkew(ax, 0));
                        break;
                    case "skewY":
                        float ay = float.Parse(contents, NumberStyles.Float, CultureInfo.InvariantCulture);
                        transformList.Add(new SvgSkew(0, ay));
                        break;
                }
            }
            return transformList;
        }
    }
}