Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
SvgPath.cs
1using SkiaSharp;
2using System;
3using System.Text;
4
6{
7 internal enum SvgPathState
8 {
9 ExpectCommand,
10 ExpectNumber
11 }
12
16 public static class SvgPath
17 {
27 public static SKImage SvgPathToImage(string SvgPath, int Width, int Height,
28 SKColor Foreground, SKColor Background)
29 {
30 return SvgPathToImage(SvgPath, Width, Height, Foreground, Background, 0, 0, 1, 1);
31 }
32
46 public static SKImage SvgPathToImage(string SvgPath, int Width, int Height,
47 SKColor Foreground, SKColor Background, float OffsetX, float OffsetY, float ScaleX, float ScaleY)
48 {
49 SKSurface Surface = SKSurface.Create(new SKImageInfo(Width, Height, SKImageInfo.PlatformColorType, SKAlphaType.Premul));
50 try
51 {
52 SKCanvas Canvas = Surface.Canvas;
53 Canvas.Clear(Background);
54
55 SKPath Path = Parse(SvgPath, OffsetX, OffsetY, ScaleX, ScaleY);
56
57 SKPaint IconFill = new SKPaint()
58 {
59 FilterQuality = SKFilterQuality.High,
60 IsAntialias = true,
61 Style = SKPaintStyle.Fill,
62 Color = Foreground
63 };
64
65 Canvas.DrawPath(Path, IconFill);
66
67 return Surface.Snapshot();
68 }
69 finally
70 {
71 Surface.Dispose();
72 }
73 }
74
84 public static SKBitmap SvgPathToBitmap(string SvgPath, int Width, int Height,
85 SKColor Foreground, SKColor Background)
86 {
87 return SvgPathToBitmap(SvgPath, Width, Height, Foreground, Background, 0, 0, 1, 1);
88 }
89
103 public static SKBitmap SvgPathToBitmap(string SvgPath, int Width, int Height,
104 SKColor Foreground, SKColor Background, float OffsetX, float OffsetY, float ScaleX, float ScaleY)
105 {
106 using (SKImage Image = SvgPathToImage(SvgPath, Width, Height, Foreground, Background, OffsetX, OffsetY, ScaleX, ScaleY))
107 {
108 return SKBitmap.FromImage(Image);
109 }
110 }
111
120 public static SKPath Parse(string Path)
121 {
122 return Parse(Path, 0, 0, 1, 1);
123 }
124
137 public static SKPath Parse(string Path, float OffsetX, float OffsetY, float ScaleX, float ScaleY)
138 {
139 SKPath Result = new SKPath();
140 SvgPathState State = SvgPathState.ExpectCommand;
141 StringBuilder sb = new StringBuilder();
142 float[] Numbers = new float[7];
143 float LastX = 0;
144 float LastY = 0;
145 int NumberIndex = 0;
146 int NrNumbers = 0;
147 char Command = (char)0;
148 bool Again;
149
150 foreach (char ch in Path)
151 {
152 do
153 {
154 Again = false;
155 switch (State)
156 {
157 case SvgPathState.ExpectCommand:
158 Command = ch;
159 switch (Command)
160 {
161 case ' ':
162 case '\t':
163 case '\a':
164 case '\b':
165 case '\v':
166 case '\f':
167 case '\r':
168 case '\n':
169 case ',':
170 break;
171
172 case 'M': // Move-to Absolute
173 case 'm': // Move-to Relative
174 case 'L': // Line-to Absolute
175 case 'l': // Line-to Relative
176 NrNumbers = 2;
177 NumberIndex = 0;
178 State = SvgPathState.ExpectNumber;
179 break;
180
181 case 'H': // Horizontal Line-to Absolute
182 case 'h': // Horizontal Line-to Relative
183 case 'V': // Vertical Line-to Absolute
184 case 'v': // Vertical Line-to Relative
185 NrNumbers = 1;
186 NumberIndex = 0;
187 State = SvgPathState.ExpectNumber;
188 break;
189
190 case 'Z': // Close loop
191 AddCommand(Result, Command, Numbers, ref LastX, ref LastY, OffsetX, OffsetY, ScaleX, ScaleY);
192 break;
193
194 case 'C': // Bezier curve Absolute
195 case 'c': // Bezier curve Relative
196 NrNumbers = 6;
197 NumberIndex = 0;
198 State = SvgPathState.ExpectNumber;
199 break;
200
201 case 'S': // Short-hand Bezier curve Absolute
202 case 's': // Short-hand Bezier curve Relative
203 Numbers[0] = 2 * Numbers[4] - Numbers[2];
204 Numbers[1] = 2 * Numbers[5] - Numbers[3];
205 NrNumbers = 4;
206 NumberIndex = 2;
207 State = SvgPathState.ExpectNumber;
208 break;
209
210 case 'Q': // Quadratic curve Absolute
211 case 'q': // Quadratic curve Relative
212 NrNumbers = 4;
213 NumberIndex = 0;
214 State = SvgPathState.ExpectNumber;
215 break;
216
217 case 'T': // Short-hand Quadratic curve Absolute
218 case 't': // Short-hand Quadratic curve Relative
219 Numbers[0] = 2 * Numbers[2] - Numbers[0];
220 Numbers[1] = 2 * Numbers[3] - Numbers[1];
221 NrNumbers = 2;
222 NumberIndex = 2;
223 State = SvgPathState.ExpectNumber;
224 break;
225
226 case 'A': // Arc Absolute
227 case 'a': // Arc Relative
228 NrNumbers = 7;
229 NumberIndex = 0;
230 State = SvgPathState.ExpectNumber;
231 break;
232
233 default:
234 Result.Dispose();
235 throw new Exception("Unexpected draw command: " + Command);
236 }
237 break;
238
239 case SvgPathState.ExpectNumber:
240 switch (ch)
241 {
242 case ' ':
243 case '\t':
244 case '\a':
245 case '\b':
246 case '\v':
247 case '\f':
248 case '\r':
249 case '\n':
250 case ',':
251 if (!CommonTypes.TryParse(sb.ToString(), out float f))
252 {
253 Result.Dispose();
254 throw new Exception("Invalid number: " + sb.ToString());
255 }
256
257 sb.Clear();
258 Numbers[NumberIndex++] = f;
259 NrNumbers--;
260
261 if (NrNumbers == 0)
262 {
263 AddCommand(Result, Command, Numbers, ref LastX, ref LastY, OffsetX, OffsetY, ScaleX, ScaleY);
264 State = SvgPathState.ExpectCommand;
265 }
266 break;
267
268 case '+':
269 case '-':
270 case '.':
271 case '0':
272 case '1':
273 case '2':
274 case '3':
275 case '4':
276 case '5':
277 case '6':
278 case '7':
279 case '8':
280 case '9':
281 case 'e':
282 case 'E':
283 sb.Append(ch);
284 break;
285
286 default:
287 if (!CommonTypes.TryParse(sb.ToString(), out f))
288 {
289 Result.Dispose();
290 throw new Exception("Invalid number: " + sb.ToString());
291 }
292
293 sb.Clear();
294 Numbers[NumberIndex++] = f;
295 NrNumbers--;
296
297 if (NrNumbers != 0)
298 throw new Exception("Unexpected numerical character: " + ch);
299
300 AddCommand(Result, Command, Numbers, ref LastX, ref LastY, OffsetX, OffsetY, ScaleX, ScaleY);
301 State = SvgPathState.ExpectCommand;
302
303 Again = true;
304 break;
305 }
306 break;
307
308 default:
309 Result.Dispose();
310 throw new Exception("Unexpected state: " + State.ToString());
311 }
312 }
313 while (Again);
314 }
315
316 return Result;
317 }
318
319 private static void AddCommand(SKPath Path, char Command, float[] Numbers,
320 ref float LastX, ref float LastY, float OffsetX, float OffsetY, float ScaleX, float ScaleY)
321 {
322 switch (Command)
323 {
324 case 'M': // Move-to Absolute
325 LastX = Numbers[0] * ScaleX + OffsetX;
326 LastY = Numbers[1] * ScaleY + OffsetY;
327 Path.MoveTo(LastX, LastY);
328 break;
329
330 case 'm': // Move-to Relative
331 LastX += Numbers[0] * ScaleX;
332 LastY += Numbers[1] * ScaleY;
333 Path.MoveTo(LastX, LastY);
334 break;
335
336 case 'L': // Line-to Absolute
337 LastX = Numbers[0] * ScaleX + OffsetX;
338 LastY = Numbers[1] * ScaleY + OffsetY;
339 Path.LineTo(LastX, LastY);
340 break;
341
342 case 'l': // Line-to Relative
343 LastX += Numbers[0] * ScaleX;
344 LastY += Numbers[1] * ScaleY;
345 Path.LineTo(LastX, LastY);
346 break;
347
348 case 'H': // Horizontal Line-to Absolute
349 LastX = Numbers[0] * ScaleX + OffsetX;
350 Path.LineTo(LastX, LastY);
351 break;
352
353 case 'h': // Horizontal Line-to Relative
354 LastX += Numbers[0] * ScaleX;
355 Path.LineTo(LastX, LastY);
356 break;
357
358 case 'V': // Vertical Line-to Absolute
359 LastY = Numbers[0] * ScaleY + OffsetY;
360 Path.LineTo(LastX, LastY);
361 break;
362
363 case 'v': // Vertical Line-to Relative
364 LastY += Numbers[0] * ScaleY;
365 Path.LineTo(LastX, LastY);
366 break;
367
368 case 'Z': // Close loop
369 Path.Close();
370 break;
371
372 case 'C': // Bezier curve Absolute
373 case 'S': // Short-hand Bezier curve Absolute
374 float x1 = Numbers[0] * ScaleX + OffsetX;
375 float y1 = Numbers[1] * ScaleY + OffsetY;
376 float x2 = Numbers[2] * ScaleX + OffsetX;
377 float y2 = Numbers[3] * ScaleY + OffsetY;
378 LastX = Numbers[4] * ScaleX + OffsetX;
379 LastY = Numbers[5] * ScaleY + OffsetY;
380 Path.CubicTo(x1, y1, x2, y2, LastX, LastY);
381 break;
382
383 case 'c': // Bezier curve Relative
384 case 's': // Short-hand Bezier curve Relative
385 x1 = LastX + Numbers[0] * ScaleX;
386 y1 = LastY + Numbers[1] * ScaleY;
387 x2 = LastX + Numbers[2] * ScaleX;
388 y2 = LastY + Numbers[3] * ScaleY;
389
390 LastX += Numbers[4] * ScaleX;
391 LastY += Numbers[5] * ScaleY;
392
393 Path.CubicTo(x1, y1, x2, y2, LastX, LastY);
394 break;
395
396 case 'Q': // Quadratic curve Absolute
397 case 'T': // Short-hand Quadratic curve Absolute
398 x1 = Numbers[0] * ScaleX + OffsetX;
399 y1 = Numbers[1] * ScaleY + OffsetY;
400 LastX = Numbers[2] * ScaleX + OffsetX;
401 LastY = Numbers[3] * ScaleY + OffsetY;
402 Path.QuadTo(x1, y1, LastX, LastY);
403 break;
404
405 case 'q': // Quadratic curve Relative
406 case 't': // Short-hand Quadratic curve Relative
407 x1 = LastX + Numbers[0] * ScaleX;
408 y1 = LastY + Numbers[1] * ScaleY;
409
410 LastX += Numbers[2] * ScaleX;
411 LastY += Numbers[3] * ScaleY;
412
413 Path.QuadTo(x1, y1, LastX, LastY);
414 break;
415
416 case 'A': // Arc Absolute
417 LastX = Numbers[5] * ScaleX + OffsetX;
418 LastY = Numbers[6] * ScaleY + OffsetY;
419 Path.ArcTo(Numbers[0] * ScaleX, Numbers[1] * ScaleY, Numbers[2],
420 Numbers[3] == 0 ? SKPathArcSize.Large : SKPathArcSize.Small,
421 Numbers[4] == 0 ? SKPathDirection.CounterClockwise : SKPathDirection.Clockwise,
422 LastX, LastY);
423 break;
424
425 case 'a': // Arc Relative
426 LastX += Numbers[5] * ScaleX;
427 LastY += Numbers[6] * ScaleY;
428 Path.ArcTo(Numbers[0] * ScaleX, Numbers[1] * ScaleY, Numbers[2],
429 Numbers[3] == 0 ? SKPathArcSize.Small : SKPathArcSize.Large,
430 Numbers[4] == 0 ? SKPathDirection.CounterClockwise : SKPathDirection.Clockwise,
431 LastX, LastY);
432 break;
433 }
434 }
435
436 }
437}
Helps with parsing of commong data types.
Definition: CommonTypes.cs:13
static bool TryParse(string s, out double Value)
Tries to decode a string encoded double.
Definition: CommonTypes.cs:46
Processes SVG paths.
Definition: SvgPath.cs:17
static SKImage SvgPathToImage(string SvgPath, int Width, int Height, SKColor Foreground, SKColor Background)
Parses an SVG Path and generates an image from it.
Definition: SvgPath.cs:27
static SKPath Parse(string Path)
Parses an SVG Path.
Definition: SvgPath.cs:120
static SKPath Parse(string Path, float OffsetX, float OffsetY, float ScaleX, float ScaleY)
Parses an SVG Path.
Definition: SvgPath.cs:137
static SKBitmap SvgPathToBitmap(string SvgPath, int Width, int Height, SKColor Foreground, SKColor Background, float OffsetX, float OffsetY, float ScaleX, float ScaleY)
Parses an SVG Path and generates a bitmap image from it.
Definition: SvgPath.cs:103
static SKImage SvgPathToImage(string SvgPath, int Width, int Height, SKColor Foreground, SKColor Background, float OffsetX, float OffsetY, float ScaleX, float ScaleY)
Parses an SVG Path and generates an image from it.
Definition: SvgPath.cs:46
static SKBitmap SvgPathToBitmap(string SvgPath, int Width, int Height, SKColor Foreground, SKColor Background)
Parses an SVG Path and generates a bitmap image from it.
Definition: SvgPath.cs:84