Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
GraphViz.cs
1using System;
2using System.Collections.Generic;
3using System.Diagnostics;
4using System.IO;
5using System.Text;
6using System.Threading.Tasks;
7using System.Xml;
8using SkiaSharp;
19using Waher.Events;
22using Waher.Script;
24using Waher.Security;
25
27{
28 internal enum ResultType
29 {
30 Svg,
31 Png
32 }
33
34 internal class GraphInfo
35 {
36 public string FileName;
37 public string Title;
38 public string MapFileName;
39 public string Hash;
40 }
41
47 {
48 private static readonly Random rnd = new Random();
49 private static Scheduler scheduler = null;
50 private static string installationFolder = null;
51 private static string binFolder = null;
52 private static string graphVizFolder = null;
53 private static string contentRootFolder = null;
54 private static bool supportsDot = false;
55 private static bool supportsNeato = false;
56 private static bool supportsFdp = false;
57 private static bool supportsSfdp = false;
58 private static bool supportsTwopi = false;
59 private static bool supportsCirco = false;
60 private static IMarkdownAsynchronousOutput asyncHtmlOutput = null;
61
65 public GraphViz()
66 {
67 }
68
74 public static void Init(string ContentRootFolder)
75 {
76 try
77 {
78 contentRootFolder = ContentRootFolder;
79
80 if (scheduler is null)
81 {
82 if (Types.TryGetModuleParameter("Scheduler", out object Obj) && Obj is Scheduler Scheduler)
83 scheduler = Scheduler;
84 else
85 {
86 scheduler = new Scheduler();
87
88 Log.Terminating += (Sender, e) =>
89 {
90 scheduler?.Dispose();
91 scheduler = null;
92 };
93 }
94 }
95
96 string Folder = SearchForInstallationFolder();
97
98 if (string.IsNullOrEmpty(Folder))
99 Log.Warning("GraphViz not found. GraphViz support will not be available in Markdown.");
100 else
101 {
102 SetInstallationFolder(Folder);
103
104 Log.Informational("GraphViz found. Integration with Markdown added.",
105 new KeyValuePair<string, object>("Installation Folder", installationFolder),
106 new KeyValuePair<string, object>("Binary Folder", binFolder),
107 new KeyValuePair<string, object>("dot", supportsDot),
108 new KeyValuePair<string, object>("neato", supportsNeato),
109 new KeyValuePair<string, object>("fdp", supportsFdp),
110 new KeyValuePair<string, object>("sfdp", supportsSfdp),
111 new KeyValuePair<string, object>("twopi", supportsTwopi),
112 new KeyValuePair<string, object>("circo", supportsCirco));
113
115 }
116 }
117 catch (Exception ex)
118 {
119 Log.Exception(ex);
120 }
121 }
122
129 public static void SetInstallationFolder(string Folder)
130 {
131 if (!string.IsNullOrEmpty(installationFolder) && Folder != installationFolder)
132 throw new Exception("GraphViz installation folder has already been set.");
133
134 string Suffix = FileSystem.ExecutableExtension;
135
136 installationFolder = Folder;
137
138 switch (Environment.OSVersion.Platform)
139 {
140 case PlatformID.Win32S:
141 case PlatformID.Win32Windows:
142 case PlatformID.Win32NT:
143 case PlatformID.WinCE:
144 default:
145 binFolder = Path.Combine(installationFolder, "bin");
146 break;
147
148 case PlatformID.Unix:
149 case PlatformID.MacOSX:
150 binFolder = installationFolder;
151 break;
152 }
153
154 supportsDot = File.Exists(Path.Combine(binFolder, "dot" + Suffix));
155 supportsNeato = File.Exists(Path.Combine(binFolder, "neato" + Suffix));
156 supportsFdp = File.Exists(Path.Combine(binFolder, "fdp" + Suffix));
157 supportsSfdp = File.Exists(Path.Combine(binFolder, "sfdp" + Suffix));
158 supportsTwopi = File.Exists(Path.Combine(binFolder, "twopi" + Suffix));
159 supportsCirco = File.Exists(Path.Combine(binFolder, "circo" + Suffix));
160
161 graphVizFolder = Path.Combine(contentRootFolder, "GraphViz");
162
163 if (!Directory.Exists(graphVizFolder))
164 Directory.CreateDirectory(graphVizFolder);
165
166 DeleteOldFiles(TimeSpan.FromDays(7));
167 }
168
169 private static void DeleteOldFiles(object P)
170 {
171 if (P is TimeSpan MaxAge)
172 DeleteOldFiles(MaxAge, true);
173 }
174
180 public static void DeleteOldFiles(TimeSpan MaxAge, bool Reschedule)
181 {
182 if (string.IsNullOrEmpty(graphVizFolder))
183 return;
184
185 DateTime Limit = DateTime.Now - MaxAge;
186 int Count = 0;
187
188 DirectoryInfo GraphVizFolder = new DirectoryInfo(graphVizFolder);
189 FileInfo[] Files = GraphVizFolder.GetFiles("*.*");
190
191 foreach (FileInfo FileInfo in Files)
192 {
193 if (FileInfo.LastAccessTime < Limit)
194 {
195 try
196 {
197 File.Delete(FileInfo.FullName);
198 Count++;
199 }
200 catch (Exception ex)
201 {
202 Log.Error("Unable to delete old file: " + ex.Message, FileInfo.FullName);
203 }
204 }
205 }
206
207 if (Count > 0)
208 Log.Informational(Count.ToString() + " old file(s) deleted.", graphVizFolder);
209
210 if (Reschedule)
211 {
212 lock (rnd)
213 {
214 scheduler.Add(DateTime.Now.AddDays(rnd.NextDouble() * 2), DeleteOldFiles, MaxAge);
215 }
216 }
217 }
218
223 public static string SearchForInstallationFolder()
224 {
225 string InstallationFolder;
226
227 switch (Environment.OSVersion.Platform)
228 {
229 case PlatformID.Win32S:
230 case PlatformID.Win32Windows:
231 case PlatformID.Win32NT:
232 case PlatformID.WinCE:
233 default:
234 InstallationFolder = SearchForInstallationFolder(Environment.SpecialFolder.ProgramFilesX86);
235 if (string.IsNullOrEmpty(InstallationFolder))
236 {
237 InstallationFolder = SearchForInstallationFolder(Environment.SpecialFolder.ProgramFiles);
238 if (string.IsNullOrEmpty(InstallationFolder))
239 {
240 InstallationFolder = SearchForInstallationFolder(Environment.SpecialFolder.Programs);
241 if (string.IsNullOrEmpty(InstallationFolder))
242 {
243 InstallationFolder = SearchForInstallationFolder(Environment.SpecialFolder.CommonProgramFilesX86);
244 if (string.IsNullOrEmpty(InstallationFolder))
245 {
246 InstallationFolder = SearchForInstallationFolder(Environment.SpecialFolder.CommonProgramFiles);
247 if (string.IsNullOrEmpty(InstallationFolder))
248 InstallationFolder = SearchForInstallationFolder(Environment.SpecialFolder.CommonPrograms);
249 }
250 }
251 }
252 }
253 break;
254
255 case PlatformID.Unix:
256 case PlatformID.MacOSX:
257 InstallationFolder = "/opt/local/bin";
258 if (!Directory.Exists(InstallationFolder))
259 InstallationFolder = null;
260 break;
261 }
262
263 return InstallationFolder;
264 }
265
266 private static string SearchForInstallationFolder(Environment.SpecialFolder SpecialFolder)
267 {
268 string Folder;
269
270 try
271 {
272 Folder = Environment.GetFolderPath(SpecialFolder);
273 }
274 catch (Exception)
275 {
276 return null; // Folder not defined for the operating system.
277 }
278
279 string Result = SearchForInstallationFolder(Folder);
280
281 if (string.IsNullOrEmpty(Result) && Types.TryGetModuleParameter("Runtime", out object Obj) && Obj is string RuntimeFolder)
282 Result = SearchForInstallationFolder(Path.Combine(RuntimeFolder, SpecialFolder.ToString()));
283
284 return Result;
285 }
286
287 private static string SearchForInstallationFolder(string Folder)
288 {
289 if (string.IsNullOrEmpty(Folder))
290 return null;
291
292 if (!Directory.Exists(Folder))
293 return null;
294
295 string FolderName;
296 string BestFolder = null;
297 double BestVersion = 0;
298 string[] SubFolders;
299
300 try
301 {
302 SubFolders = Directory.GetDirectories(Folder);
303 }
304 catch (UnauthorizedAccessException)
305 {
306 return null;
307 }
308 catch (Exception ex)
309 {
310 Log.Exception(ex);
311 return null;
312 }
313
314 foreach (string SubFolder in SubFolders)
315 {
316 FolderName = Path.GetFileName(SubFolder);
317 if (!FolderName.StartsWith("Graphviz", StringComparison.CurrentCultureIgnoreCase))
318 continue;
319
320 if (!CommonTypes.TryParse(FolderName.Substring(8), out double Version))
321 Version = 1.0;
322
323 if (BestFolder is null || Version > BestVersion)
324 {
325 BestFolder = SubFolder;
326 BestVersion = Version;
327 }
328 }
329
330 return BestFolder;
331 }
332
338 public Grade Supports(string Language)
339 {
340 int i = Language.IndexOf(':');
341 if (i > 0)
342 Language = Language.Substring(0, i).TrimEnd();
343
344 switch (Language.ToLower())
345 {
346 case "dot":
347 if (supportsDot)
348 return Grade.Excellent;
349 break;
350
351 case "neato":
352 if (supportsNeato)
353 return Grade.Excellent;
354 break;
355
356 case "fdp":
357 if (supportsFdp)
358 return Grade.Excellent;
359 break;
360
361 case "sfdp":
362 if (supportsSfdp)
363 return Grade.Excellent;
364 break;
365
366 case "twopi":
367 if (supportsTwopi)
368 return Grade.Excellent;
369 break;
370
371 case "circo":
372 if (supportsCirco)
373 return Grade.Excellent;
374 break;
375 }
376
377 return Grade.NotAtAll;
378 }
379
383 public bool EvaluatesScript => false;
384
389 public void Register(MarkdownDocument Document)
390 {
391 // Do nothing.
392 }
393
403 public async Task<bool> RenderHtml(HtmlRenderer Renderer, string[] Rows, string Language, int Indent, MarkdownDocument Document)
404 {
405 GraphInfo Info = await GetFileName(Language, Rows, ResultType.Svg, asyncHtmlOutput is null, Document.Settings?.Variables);
406 if (!(Info is null))
407 {
408 await this.GenerateHTML(Renderer.Output, Info);
409 return true;
410 }
411
412 string Title;
413 int i = Language.IndexOf(':');
414 if (i > 0)
415 Title = Language.Substring(i + 1).Trim();
416 else
417 Title = null;
418
419 string Id = await asyncHtmlOutput.GenerateStub(MarkdownOutputType.Html, Renderer.Output, Title, Document);
420
421 Document.QueueAsyncTask(this.ExecuteGraphViz, new AsyncState()
422 {
423 Id = Id,
424 Language = Language,
425 Rows = Rows,
426 Document = Document
427 });
428
429 return true;
430 }
431
432 private class AsyncState
433 {
434 public string Id;
435 public string Language;
436 public string[] Rows;
437 public MarkdownDocument Document;
438 }
439
440 private async Task ExecuteGraphViz(object State)
441 {
442 AsyncState AsyncState = (AsyncState)State;
443 StringBuilder Output = new StringBuilder();
444
445 try
446 {
447 GraphInfo Info = await GetFileName(AsyncState.Language, AsyncState.Rows, ResultType.Svg, true,
448 AsyncState.Document.Settings?.Variables);
449
450 if (!(Info is null))
451 await this.GenerateHTML(Output, Info);
452 }
453 catch (Exception ex)
454 {
455 using (HtmlRenderer Renderer = new HtmlRenderer(Output, new HtmlSettings()
456 {
457 XmlEntitiesOnly = true
458 }))
459 {
460 await Renderer.RenderObject(ex, true, new Variables());
461 }
462 }
463
464 await asyncHtmlOutput.ReportResult(MarkdownOutputType.Html, AsyncState.Id, Output.ToString());
465 }
466
467 private async Task GenerateHTML(StringBuilder Output, GraphInfo Info)
468 {
469 Info.FileName = Info.FileName.Substring(contentRootFolder.Length).Replace(Path.DirectorySeparatorChar, '/');
470 if (!Info.FileName.StartsWith("/"))
471 Info.FileName = "/" + Info.FileName;
472
473 Output.Append("<figure>");
474 Output.Append("<img src=\"");
475 Output.Append(XML.HtmlAttributeEncode(Info.FileName));
476
477 if (!string.IsNullOrEmpty(Info.Title))
478 {
479 Output.Append("\" alt=\"");
480 Output.Append(XML.HtmlAttributeEncode(Info.Title));
481
482 Output.Append("\" title=\"");
483 Output.Append(XML.HtmlAttributeEncode(Info.Title));
484 }
485 else
486 Output.Append("\" alt=\"GraphViz graph");
487
488 if (!string.IsNullOrEmpty(Info.MapFileName))
489 {
490 Output.Append("\" usemap=\"#Map");
491 Output.Append(Info.Hash);
492 }
493
494 Output.Append("\" class=\"aloneUnsized\"/>");
495
496 if (!string.IsNullOrEmpty(Info.Title))
497 {
498 Output.Append("<figcaption>");
499 Output.Append(XML.HtmlValueEncode(Info.Title));
500 Output.Append("</figcaption>");
501 }
502
503 Output.AppendLine("</figure>");
504
505 if (!string.IsNullOrEmpty(Info.MapFileName))
506 {
507 Output.Append("<map id=\"Map");
508 Output.Append(Info.Hash);
509 Output.Append("\" name=\"Map");
510 Output.Append(Info.Hash);
511 Output.AppendLine("\">");
512
513 string Map = await Resources.ReadAllTextAsync(Info.MapFileName);
514 string[] MapRows = Map.Split(CommonTypes.CRLF, StringSplitOptions.RemoveEmptyEntries);
515 int i, c;
516
517 for (i = 1, c = MapRows.Length - 1; i < c; i++)
518 Output.AppendLine(MapRows[i]);
519
520 Output.AppendLine("</map>");
521 }
522 }
523
524 internal static Task<GraphInfo> GetFileName(string Language, string[] Rows, ResultType Type, bool GenerateIfNotExists, Variables Variables)
525 {
526 return GetFileName(Language, MarkdownDocument.AppendRows(Rows), Type, GenerateIfNotExists, Variables);
527 }
528
529 internal static async Task<GraphInfo> GetFileName(string Language, string GraphText, ResultType Type, bool GenerateIfNotExists, Variables Variables)
530 {
531 GraphInfo Result = new GraphInfo();
532 int i = Language.IndexOf(':');
533
534 if (i > 0)
535 {
536 Result.Title = Language.Substring(i + 1).Trim();
537 Language = Language.Substring(0, i).TrimEnd();
538 }
539 else
540 Result.Title = string.Empty;
541
542 string GraphBgColor = GetColor(Graph.GraphBgColorVariableName, Variables);
543 string GraphFgColor = GetColor(Graph.GraphFgColorVariableName, Variables);
544
545 Result.Hash = Hashes.ComputeSHA256HashString(Encoding.UTF8.GetBytes(GraphText + Language + GraphBgColor + GraphFgColor));
546
547 string GraphVizFolder = Path.Combine(contentRootFolder, "GraphViz");
548 string FileName = Path.Combine(GraphVizFolder, Result.Hash);
549
550 switch (Type)
551 {
552 case ResultType.Svg:
553 default:
554 Result.FileName = FileName + "." + ImageCodec.FileExtensionSvg;
555 break;
556
557 case ResultType.Png:
558 Result.FileName = FileName + "." + ImageCodec.FileExtensionPng;
559 break;
560 }
561
562 Result.MapFileName = FileName + ".map";
563
564 if (File.Exists(Result.FileName))
565 {
566 if (!File.Exists(Result.MapFileName))
567 Result.MapFileName = null;
568
569 return Result;
570 }
571
572 if (!GenerateIfNotExists)
573 return null;
574
575 string TxtFileName = FileName + ".txt";
576 await Resources.WriteAllTextAsync(TxtFileName, GraphText, Encoding.Default);
577
578 StringBuilder Arguments = new StringBuilder();
579
580 Arguments.Append("-Tcmapx -o\"");
581 Arguments.Append(Result.MapFileName);
582 Arguments.Append("\" -T");
583 Arguments.Append(Type.ToString().ToLower());
584
585 if (!string.IsNullOrEmpty(GraphBgColor))
586 {
587 Arguments.Append(" -Gbgcolor=\"");
588 Arguments.Append(GraphBgColor);
589 Arguments.Append('"');
590 }
591
592 if (!string.IsNullOrEmpty(GraphFgColor))
593 {
594 Arguments.Append(" -Gcolor=\"");
595 Arguments.Append(GraphFgColor);
596 //Arguments.Append("\" -Nfillcolor=\"");
597 //Arguments.Append(defaultFgColor);
598 Arguments.Append("\" -Nfontcolor=\"");
599 Arguments.Append(GraphFgColor);
600 Arguments.Append("\" -Nlabelfontcolor=\"");
601 Arguments.Append(GraphFgColor);
602 Arguments.Append("\" -Npencolor=\"");
603 Arguments.Append(GraphFgColor);
604 Arguments.Append("\" -Efontcolor=\"");
605 Arguments.Append(GraphFgColor);
606 Arguments.Append("\" -Elabelfontcolor=\"");
607 Arguments.Append(GraphFgColor);
608 Arguments.Append("\" -Epencolor=\"");
609 Arguments.Append(GraphFgColor);
610 Arguments.Append("\"");
611 }
612
613 Arguments.Append(" -q -o\"");
614 Arguments.Append(Result.FileName);
615 Arguments.Append("\" \"");
616 Arguments.Append(TxtFileName + "\"");
617
618 ProcessStartInfo ProcessInformation = new ProcessStartInfo()
619 {
620 FileName = Path.Combine(binFolder, Language.ToLower() + FileSystem.ExecutableExtension),
621 Arguments = Arguments.ToString(),
622 UseShellExecute = false,
623 RedirectStandardError = true,
624 RedirectStandardOutput = true,
625 RedirectStandardInput = false,
626 WorkingDirectory = GraphVizFolder,
627 CreateNoWindow = true,
628 WindowStyle = ProcessWindowStyle.Hidden
629 };
630
631 Process P = new Process();
632 TaskCompletionSource<GraphInfo> ResultSource = new TaskCompletionSource<GraphInfo>();
633
634 P.ErrorDataReceived += (Sender, e) =>
635 {
636 ResultSource.TrySetException(new Exception("Unable to generate graph:\r\n\r\n" + e.Data));
637 };
638
639 P.Exited += async (Sender, e) =>
640 {
641 try
642 {
643 if (P.ExitCode != 0)
644 {
645 string ErrorText = await P.StandardError.ReadToEndAsync();
646 ResultSource.TrySetException(new Exception("Unable to generate graph. Exit code: " + P.ExitCode.ToString() + "\r\n\r\n" + ErrorText));
647 }
648 else
649 {
650 string Map = await Resources.ReadAllTextAsync(Result.MapFileName);
651 string[] MapRows = Map.Split(CommonTypes.CRLF, StringSplitOptions.RemoveEmptyEntries);
652 if (MapRows.Length <= 2)
653 {
654 File.Delete(Result.MapFileName);
655 Result.MapFileName = null;
656 }
657
658 ResultSource.TrySetResult(Result);
659 }
660 }
661 catch (Exception ex)
662 {
663 Log.Exception(ex);
664 }
665 };
666
667 Task _ = Task.Delay(10000).ContinueWith(Prev => ResultSource.TrySetException(new TimeoutException("GraphViz process did not terminate properly.")));
668
669 P.StartInfo = ProcessInformation;
670 P.EnableRaisingEvents = true;
671 P.Start();
672
673 return await ResultSource.Task;
674 }
675
676 private static string GetColor(string VariableName, Variables Variables)
677 {
678 if (Variables is null)
679 return null;
680
681 if (!Variables.TryGetVariable(VariableName, out Variable v))
682 return null;
683
684 if (v.ValueObject is SKColor Color)
685 return Graph.ToRGBAStyle(Color);
686 else if (v.ValueObject is string s)
687 return s;
688 else
689 return null;
690 }
691
701 public async Task<bool> RenderText(TextRenderer Renderer, string[] Rows, string Language, int Indent, MarkdownDocument Document)
702 {
703 GraphInfo Info = await GetFileName(Language, Rows, ResultType.Svg, true, Document.Settings?.Variables);
704 if (Info is null)
705 return false;
706
707 Renderer.Output.AppendLine(Info.Title);
708
709 return true;
710 }
711
721 public async Task<bool> RenderMarkdown(MarkdownRenderer Renderer, string[] Rows, string Language, int Indent, MarkdownDocument Document)
722 {
723 GraphInfo Info = await GetFileName(Language, Rows, ResultType.Png, true, Document.Settings?.Variables);
724 if (Info is null)
725 return false;
726
727 return await ImageContent.GenerateMarkdownFromFile(Renderer.Output, Info.FileName, Info.Title);
728 }
729
739 public async Task<bool> RenderWpfXaml(WpfXamlRenderer Renderer, string[] Rows, string Language, int Indent, MarkdownDocument Document)
740 {
741 GraphInfo Info = await GetFileName(Language, Rows, ResultType.Png, true, Document.Settings?.Variables);
742 if (Info is null)
743 return false;
744
745 XmlWriter Output = Renderer.XmlOutput;
746
747 Output.WriteStartElement("Image");
748 Output.WriteAttributeString("Source", Info.FileName);
749 Output.WriteAttributeString("Stretch", "None");
750
751 if (!string.IsNullOrEmpty(Info.Title))
752 Output.WriteAttributeString("ToolTip", Info.Title);
753
754 Output.WriteEndElement();
755
756 return true;
757 }
758
768 public async Task<bool> RenderXamarinFormsXaml(XamarinFormsXamlRenderer Renderer, string[] Rows, string Language, int Indent, MarkdownDocument Document)
769 {
770 GraphInfo Info = await GetFileName(Language, Rows, ResultType.Png, true, Document.Settings?.Variables);
771 if (Info is null)
772 return false;
773
774 XmlWriter Output = Renderer.XmlOutput;
775
776 Output.WriteStartElement("Image");
777 Output.WriteAttributeString("Source", Info.FileName);
778 Output.WriteEndElement();
779
780 return true;
781 }
782
792 public async Task<bool> RenderLatex(LatexRenderer Renderer, string[] Rows, string Language, int Indent, MarkdownDocument Document)
793 {
794 GraphInfo Info = await GetFileName(Language, Rows, ResultType.Png, true, Document.Settings?.Variables);
795 StringBuilder Output = Renderer.Output;
796
797 Output.AppendLine("\\begin{figure}[h]");
798 Output.AppendLine("\\centering");
799
800 Output.Append("\\fbox{\\includegraphics{");
801 Output.Append(Info.FileName.Replace('\\', '/'));
802 Output.AppendLine("}}");
803
804 if (!string.IsNullOrEmpty(Info.Title))
805 {
806 Output.Append("\\caption{");
807 Output.Append(LatexRenderer.EscapeLaTeX(Info.Title));
808 Output.AppendLine("}");
809 }
810
811 Output.AppendLine("\\end{figure}");
812 Output.AppendLine();
813
814 return true;
815 }
816
824 public async Task<PixelInformation> GenerateImage(string[] Rows, string Language, MarkdownDocument Document)
825 {
826 GraphInfo Info = await GetFileName(Language, Rows, ResultType.Png, true, Document.Settings?.Variables);
827 if (Info is null)
828 return null;
829
830 byte[] Data = await Resources.ReadAllBytesAsync(Info.FileName);
831
832 using (SKBitmap Bitmap = SKBitmap.Decode(Data))
833 {
834 return new PixelInformationPng(Data, Bitmap.Width, Bitmap.Height);
835 }
836 }
837
847 public async Task<bool> RenderContractXml(ContractsRenderer Renderer, string[] Rows, string Language, int Indent, MarkdownDocument Document)
848 {
849 try
850 {
851 GraphInfo Info = await GetFileName(Language, Rows, ResultType.Png, true, Document.Settings?.Variables);
852 if (Info is null)
853 return false;
854
855 byte[] Data = await Resources.ReadAllBytesAsync(Info.FileName);
856 string ContentType = ImageCodec.ContentTypePng;
857
858 if (!(await InternetContent.DecodeAsync(ContentType, Data, null) is SKImage Image))
859 return false;
860
861 XmlWriter Output = Renderer.XmlOutput;
862 int Width = Image.Width;
863 int Height = Image.Height;
864
865 Output.WriteStartElement("imageStandalone");
866
867 Output.WriteAttributeString("contentType", ContentType);
868 Output.WriteAttributeString("width", Width.ToString());
869 Output.WriteAttributeString("height", Height.ToString());
870
871 Output.WriteStartElement("binary");
872 Output.WriteValue(Convert.ToBase64String(Data));
873 Output.WriteEndElement();
874
875 Output.WriteStartElement("caption");
876 if (string.IsNullOrEmpty(Info.Title))
877 Output.WriteElementString("text", "Graph");
878 else
879 Output.WriteElementString("text", Info.Title);
880
881 Output.WriteEndElement();
882 Output.WriteEndElement();
883
884 return true;
885 }
886 catch (Exception ex)
887 {
888 Log.Exception(ex);
889 return false;
890 }
891 }
892 }
893}
Helps with parsing of commong data types.
Definition: CommonTypes.cs:13
static readonly char[] CRLF
Contains the CR LF character sequence.
Definition: CommonTypes.cs:17
static bool TryParse(string s, out double Value)
Tries to decode a string encoded double.
Definition: CommonTypes.cs:46
Image encoder/decoder.
Definition: ImageCodec.cs:14
const string FileExtensionPng
png
Definition: ImageCodec.cs:75
const string ContentTypePng
image/png
Definition: ImageCodec.cs:30
const string FileExtensionSvg
svg
Definition: ImageCodec.cs:120
Static class managing encoding and decoding of internet content.
static Task< object > DecodeAsync(string ContentType, byte[] Data, Encoding Encoding, KeyValuePair< string, string >[] Fields, Uri BaseUri)
Decodes an object.
Renders Contracts XML from a Markdown document.
Class managing GraphViz integration into Markdown documents.
Definition: GraphViz.cs:47
async Task< bool > RenderLatex(LatexRenderer Renderer, string[] Rows, string Language, int Indent, MarkdownDocument Document)
Generates LaTeX for the code content.
Definition: GraphViz.cs:792
GraphViz()
Class managing GraphViz integration into Markdown documents.
Definition: GraphViz.cs:65
bool EvaluatesScript
If script is evaluated for this type of code block.
Definition: GraphViz.cs:383
async Task< bool > RenderWpfXaml(WpfXamlRenderer Renderer, string[] Rows, string Language, int Indent, MarkdownDocument Document)
Generates WPF XAML for the code content.
Definition: GraphViz.cs:739
async Task< bool > RenderHtml(HtmlRenderer Renderer, string[] Rows, string Language, int Indent, MarkdownDocument Document)
Generates HTML for the code content.
Definition: GraphViz.cs:403
static string SearchForInstallationFolder()
Searches for the installation folder on the local machine.
Definition: GraphViz.cs:223
static void SetInstallationFolder(string Folder)
Sets the installation folder of GraphViz.
Definition: GraphViz.cs:129
async Task< bool > RenderXamarinFormsXaml(XamarinFormsXamlRenderer Renderer, string[] Rows, string Language, int Indent, MarkdownDocument Document)
Generates Xamarin.Forms XAML for the code content.
Definition: GraphViz.cs:768
static void DeleteOldFiles(TimeSpan MaxAge, bool Reschedule)
Deletes generated files older than MaxAge .
Definition: GraphViz.cs:180
Grade Supports(string Language)
Checks how well the handler supports multimedia content of a given type.
Definition: GraphViz.cs:338
async Task< bool > RenderContractXml(ContractsRenderer Renderer, string[] Rows, string Language, int Indent, MarkdownDocument Document)
Generates smart contract XML for the code content.
Definition: GraphViz.cs:847
async Task< bool > RenderMarkdown(MarkdownRenderer Renderer, string[] Rows, string Language, int Indent, MarkdownDocument Document)
Generates Markdown for the code content.
Definition: GraphViz.cs:721
static void Init(string ContentRootFolder)
Initializes the GraphViz-Markdown integration.
Definition: GraphViz.cs:74
void Register(MarkdownDocument Document)
Is called on the object when an instance of the element has been created in a document.
Definition: GraphViz.cs:389
async Task< bool > RenderText(TextRenderer Renderer, string[] Rows, string Language, int Indent, MarkdownDocument Document)
Generates plain text for the code content.
Definition: GraphViz.cs:701
async Task< PixelInformation > GenerateImage(string[] Rows, string Language, MarkdownDocument Document)
Generates an image of the contents.
Definition: GraphViz.cs:824
Renders LaTeX from a Markdown document.
static string EscapeLaTeX(string s)
Escapes text for output in a LaTeX document.
Contains a markdown document. This markdown document class supports original markdown,...
static string AppendRows(string[] Rows)
Appends a set of rows into a single string with newlines between rows.
MarkdownSettings Settings
Markdown settings.
void QueueAsyncTask(AsyncMarkdownProcessing Callback, object State)
Queues an asynchronous task to be executed. Asynchronous tasks will be executed after the main docume...
Variables Variables
Collection of variables. Providing such a collection enables script execution inside markdown documen...
static async Task< bool > GenerateMarkdownFromFile(StringBuilder Output, string FileName, string Title)
Generates Markdown embedding an image available in a file.
Definition: ImageContent.cs:56
Renders HTML from a Markdown document.
Definition: HtmlRenderer.cs:24
Contains settings that the HTML export uses to customize HTML output.
Definition: HtmlSettings.cs:7
Renders portable Markdown from a Markdown document.
Abstract base class for Markdown renderers.
Definition: Renderer.cs:14
readonly StringBuilder Output
Renderer output.
Definition: Renderer.cs:18
Renders plain text from a Markdown document.
Definition: TextRenderer.cs:16
Renders XAML (WPF flavour) from a Markdown document.
Renders XAML (Xamarin.Forms flavour) from a Markdown document.
Static class managing loading of resources stored as embedded resources or in content files.
Definition: Resources.cs:15
static async Task< byte[]> ReadAllBytesAsync(string FileName)
Reads a binary file asynchronously.
Definition: Resources.cs:183
static async Task< string > ReadAllTextAsync(string FileName)
Reads a text file asynchronously.
Definition: Resources.cs:205
static Task WriteAllTextAsync(string FileName, string Text)
Creates a text file asynchronously.
Definition: Resources.cs:267
Static class helping modules to find files installed on the system.
Definition: FileSystem.cs:12
static string ExecutableExtension
Extension used by executable files on the platform.
Definition: FileSystem.cs:229
Helps with common XML-related tasks.
Definition: XML.cs:19
static string HtmlValueEncode(string s)
Differs from Encode(String), in that it does not encode the aposotrophe or the quote.
Definition: XML.cs:209
static string HtmlAttributeEncode(string s)
Differs from Encode(String), in that it does not encode the aposotrophe.
Definition: XML.cs:119
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:13
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
Definition: Log.cs:1647
static void Warning(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs a warning event.
Definition: Log.cs:566
static void Error(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs an error event.
Definition: Log.cs:682
static void Informational(string Message, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, string StackTrace, params KeyValuePair< string, object >[] Tags)
Logs an informational event.
Definition: Log.cs:334
Static class that dynamically manages types and interfaces available in the runtime environment.
Definition: Types.cs:14
static bool TryGetModuleParameter(string Name, out object Value)
Tries to get a module parameter value.
Definition: Types.cs:583
Class that can be used to schedule events in time. It uses a timer to execute tasks at the appointed ...
Definition: Scheduler.cs:26
void Dispose()
IDisposable.Dispose
Definition: Scheduler.cs:46
DateTime Add(DateTime When, ScheduledEventCallback Callback, object State)
Adds an event.
Definition: Scheduler.cs:66
Base class for graphs.
Definition: Graph.cs:79
const string GraphFgColorVariableName
Variable name for graph foreground color.
Definition: Graph.cs:98
const string GraphBgColorVariableName
Variable name for graph background color.
Definition: Graph.cs:93
static string ToRGBAStyle(SKColor Color)
Converts a color to an RGB(A) style string.
Definition: Graph.cs:903
Contains pixel information in PNG format
Contains information about a variable.
Definition: Variable.cs:10
Collection of variables.
Definition: Variables.cs:25
virtual bool TryGetVariable(string Name, out Variable Variable)
Tries to get a variable object, given its name.
Definition: Variables.cs:52
Contains methods for simple hash calculations.
Definition: Hashes.cs:59
static string ComputeSHA256HashString(byte[] Data)
Computes the SHA-256 hash of a block of binary data.
Definition: Hashes.cs:328
Interface for classes that help output asynchronous markdown output.
Task< string > GenerateStub(MarkdownOutputType Type, StringBuilder Output, string Title, MarkdownDocument Document)
Generates a stub in the output, that will be filled with the asynchronously generated content,...
Task ReportResult(MarkdownOutputType Type, string Id, string Result)
Method called when asynchronous result has been generated in a Markdown document.
Interface for all markdown handlers of code content that generates an image output.
Interface for code content plain text renderers.
Interface for code content WPF XAML renderers.
MarkdownOutputType
Markdown output type.
Grade
Grade enumeration
Definition: Grade.cs:7