Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
LatexRenderer.cs
1using SkiaSharp;
2using System;
3using System.Collections.Generic;
4using System.Text;
5using System.Threading.Tasks;
6using System.Xml;
13using Waher.Events;
14using Waher.Script;
18
20{
24 public class LatexRenderer : Renderer
25 {
30
36 : base()
37 {
38 this.LatexSettings = LatexSettings;
39 }
40
47 : base(Output)
48 {
49 this.LatexSettings = LatexSettings;
50 }
51
55 public override Task RenderDocumentHeader()
56 {
57 bool MakeTitle = false;
58
59 this.Output.Append("\\documentclass[");
60 this.Output.Append(this.LatexSettings.DefaultFontSize.ToString());
61 this.Output.Append("pt, ");
62
63 switch (this.LatexSettings.PaperFormat)
64 {
65 case LaTeXPaper.A4:
66 default:
67 this.Output.Append("a4paper");
68 break;
69
70 case LaTeXPaper.Letter:
71 this.Output.Append("letterpaper");
72 break;
73 }
74
75 this.Output.Append("]{");
76 switch (this.LatexSettings.DocumentClass)
77 {
78 case LaTeXDocumentClass.Article:
79 default:
80 this.Output.Append("article");
81 break;
82
83 case LaTeXDocumentClass.Report:
84 this.Output.Append("report");
85 break;
86
87 case LaTeXDocumentClass.Book:
88 this.Output.Append("book");
89 break;
90
91 case LaTeXDocumentClass.Standalone:
92 this.Output.Append("standalone");
93 break;
94 }
95 this.Output.AppendLine("}");
96
97 // Strike-out cf. https://tex.stackexchange.com/questions/546884/strikethrough-command-in-latex
98 this.Output.AppendLine("\\newlength{\\wdth}");
99 this.Output.AppendLine("\\newcommand{\\strike}[1]{\\settowidth{\\wdth}{#1}\\rlap{\\rule[.5ex]{\\wdth}{.4pt}}#1}");
100
101 if (this.Document.TryGetMetaData("TITLE", out KeyValuePair<string, bool>[] Values))
102 {
103 MakeTitle = true;
104
105 foreach (KeyValuePair<string, bool> P in Values)
106 {
107 this.Output.Append("\\title{");
108 this.Output.Append(P.Key);
109 this.Output.AppendLine("}");
110 }
111
112 if (this.Document.TryGetMetaData("SUBTITLE", out Values))
113 {
114 foreach (KeyValuePair<string, bool> P2 in Values)
115 {
116 this.Output.Append("\\subtitle{");
117 this.Output.Append(P2.Key);
118 this.Output.AppendLine("}");
119 }
120 }
121 }
122
123 if (this.Document.TryGetMetaData("AUTHOR", out Values))
124 {
125 MakeTitle = true;
126
127 foreach (KeyValuePair<string, bool> P in Values)
128 {
129 this.Output.Append("\\author{");
130 this.Output.Append(P.Key);
131 this.Output.AppendLine("}");
132 }
133 }
134
135 if (this.Document.TryGetMetaData("DATE", out Values))
136 {
137 MakeTitle = true;
138
139 foreach (KeyValuePair<string, bool> P in Values)
140 {
141 this.Output.Append("\\date{");
142 this.Output.Append(P.Key);
143 this.Output.AppendLine("}");
144 }
145 }
146
147 // Todo-lists in LaTeX, cf. https://tex.stackexchange.com/questions/247681/how-to-create-checkbox-todo-list
148
149 this.Output.AppendLine("\\usepackage{enumitem}");
150 this.Output.AppendLine("\\usepackage{amssymb}");
151 this.Output.AppendLine("\\usepackage{graphicx}");
152 this.Output.AppendLine("\\usepackage{pifont}");
153 this.Output.AppendLine("\\usepackage{multirow}");
154 this.Output.AppendLine("\\usepackage{ragged2e}");
155 this.Output.AppendLine("\\newlist{tasklist}{itemize}{2}");
156 this.Output.AppendLine("\\setlist[tasklist]{label=$\\square$}");
157 this.Output.AppendLine("\\newcommand{\\checkmarksymbol}{\\ding{51}}");
158 this.Output.AppendLine("\\newcommand{\\checked}{\\rlap{$\\square$}{\\raisebox{2pt}{\\large\\hspace{1pt}\\checkmarksymbol}}\\hspace{-2.5pt}}");
159 this.Output.AppendLine("\\begin{document}");
160
161 if (MakeTitle)
162 this.Output.AppendLine("\\maketitle");
163
164 if (this.Document.TryGetMetaData("DESCRIPTION", out Values))
165 {
166 this.Output.AppendLine("\\begin{abstract}");
167
168 foreach (KeyValuePair<string, bool> P in Values)
169 this.Output.AppendLine(EscapeLaTeX(P.Key));
170
171 this.Output.AppendLine("\\end{abstract}");
172 }
173
174 return Task.CompletedTask;
175 }
176
180 public override Task RenderDocumentFooter()
181 {
182 this.Output.AppendLine("\\end{document}");
183
184 return Task.CompletedTask;
185 }
186
192 public static string EscapeLaTeX(string s)
193 {
194 return CommonTypes.Escape(s, latexCharactersToEscape, latexCharacterEscapes);
195 }
196
197 private static readonly char[] latexCharactersToEscape = new char[] { '\\', '#', '$', '%', '&', '{', '}' };
198 private static readonly string[] latexCharacterEscapes = new string[] { "\\,", "\\#", "\\$", "\\%", "\\&", "\\{", "\\}" };
199
200 #region Span Elements
201
206 public override Task Render(Abbreviation Element)
207 {
208 return this.RenderChildren(Element);
209 }
210
215 public override Task Render(AutomaticLinkMail Element)
216 {
217 this.Output.AppendLine(EscapeLaTeX(Element.EMail));
218
219 return Task.CompletedTask;
220 }
221
226 public override Task Render(AutomaticLinkUrl Element)
227 {
228 this.Output.AppendLine(EscapeLaTeX(Element.URL));
229
230 return Task.CompletedTask;
231 }
232
237 public override async Task Render(Delete Element)
238 {
239 this.Output.Append("\\strike{");
240 await this.RenderChildren(Element);
241 this.Output.Append('}');
242 }
243
248 public override Task Render(DetailsReference Element)
249 {
250 if (!(this.Document.Detail is null))
251 return this.RenderDocument(this.Document.Detail, true);
252 else
253 return this.Render((MetaReference)Element);
254 }
255
260 public override Task Render(EmojiReference Element)
261 {
262 this.Output.AppendLine(EscapeLaTeX(Element.Emoji.Unicode));
263
264 return Task.CompletedTask;
265 }
266
271 public override async Task Render(Emphasize Element)
272 {
273 this.Output.Append("\\emph{");
274 await this.RenderChildren(Element);
275 this.Output.Append('}');
276 }
277
282 public override async Task Render(FootnoteReference Element)
283 {
284 if (this.Document?.TryGetFootnote(Element.Key, out Footnote Footnote) ?? false)
285 {
286 if (Element.AutoExpand)
287 await this.Render(Footnote);
288 else
289 {
290 this.Output.Append("\\footnote");
291
292 if (this.Document?.TryGetFootnoteNumber(Element.Key, out int Nr) ?? false)
293 {
294 this.Output.Append('[');
295 this.Output.Append(Nr.ToString());
296 this.Output.Append(']');
297 }
298
299 this.Output.Append('{');
300 await this.Render(Footnote);
301 this.Output.Append('}');
302 }
303 }
304 }
305
310 public override Task Render(HashTag Element)
311 {
312 this.Output.Append("\\#");
313 this.Output.Append(Element.Tag);
314
315 return Task.CompletedTask;
316 }
317
322 public override Task Render(HtmlEntity Element)
323 {
324 string s = Html.HtmlEntity.EntityToCharacter(Element.Entity);
325 if (!string.IsNullOrEmpty(s))
326 this.Output.Append(EscapeLaTeX(s));
327
328 return Task.CompletedTask;
329 }
330
335 public override Task Render(HtmlEntityUnicode Element)
336 {
337 this.Output.Append(EscapeLaTeX(new string((char)Element.Code, 1)));
338
339 return Task.CompletedTask;
340 }
341
346 public override Task Render(InlineCode Element)
347 {
348 this.Output.Append("\\texttt{");
349 this.Output.Append(EscapeLaTeX(Element.Code));
350 this.Output.Append('}');
351
352 return Task.CompletedTask;
353 }
354
359 public override Task Render(InlineHTML Element)
360 {
361 return Task.CompletedTask;
362 }
363
368 public override async Task Render(InlineScript Element)
369 {
370 object Result = await Element.EvaluateExpression();
371
372 await this.RenderObject(Result, Element.AloneInParagraph, Element.Variables);
373 }
374
381 public async Task RenderObject(object Result, bool AloneInParagraph, Variables Variables)
382 {
383 if (Result is null)
384 return;
385
386 if (Result is XmlDocument Xml)
387 Result = await MarkdownDocument.TransformXml(Xml, Variables);
388 else if (Result is IToMatrix ToMatrix)
389 Result = ToMatrix.ToMatrix();
390
391 if (Result is Graph G)
392 {
393 PixelInformation Pixels = G.CreatePixels(out GraphSettings GraphSettings);
394 byte[] Bin = Pixels.EncodeAsPng();
395 string FileName = await ImageContent.GetTemporaryFile(Bin, ImageCodec.FileExtensionPng);
396
397 if (AloneInParagraph)
398 {
399 this.Output.AppendLine("\\begin{figure}[h]");
400 this.Output.AppendLine("\\centering");
401 }
402
403 this.Output.Append("\\fbox{\\includegraphics[width=");
404 this.Output.Append(((GraphSettings.Width * 3) / 4).ToString());
405 this.Output.Append("pt, height=");
406 this.Output.Append(((GraphSettings.Height * 3) / 4).ToString());
407 this.Output.Append("pt]{");
408 this.Output.Append(FileName.Replace('\\', '/'));
409 this.Output.Append("}}");
410
411 if (AloneInParagraph)
412 {
413 this.Output.AppendLine("\\end{figure}");
414 this.Output.AppendLine();
415 }
416 }
417 else if (Result is PixelInformation Pixels)
418 {
419 byte[] Bin = Pixels.EncodeAsPng();
420 string FileName = await ImageContent.GetTemporaryFile(Bin, ImageCodec.FileExtensionPng);
421
422 if (AloneInParagraph)
423 {
424 this.Output.AppendLine("\\begin{figure}[h]");
425 this.Output.AppendLine("\\centering");
426 }
427
428 this.Output.Append("\\fbox{\\includegraphics[width=");
429 this.Output.Append(((Pixels.Width * 3) / 4).ToString());
430 this.Output.Append("pt, height=");
431 this.Output.Append(((Pixels.Height * 3) / 4).ToString());
432 this.Output.Append("pt]{");
433 this.Output.Append(FileName.Replace('\\', '/'));
434 this.Output.Append("}}");
435
436 if (AloneInParagraph)
437 {
438 this.Output.AppendLine("\\end{figure}");
439 this.Output.AppendLine();
440 }
441 }
442 else if (Result is SKImage Img)
443 {
444 using (SKData Data = Img.Encode(SKEncodedImageFormat.Png, 100))
445 {
446 byte[] Bin = Data.ToArray();
447 string FileName = await ImageContent.GetTemporaryFile(Bin, ImageCodec.FileExtensionPng);
448
449 if (AloneInParagraph)
450 {
451 this.Output.AppendLine("\\begin{figure}[h]");
452 this.Output.AppendLine("\\centering");
453 }
454
455 this.Output.Append("\\fbox{\\includegraphics[width=");
456 this.Output.Append(((Img.Width * 3) / 4).ToString());
457 this.Output.Append("pt, height=");
458 this.Output.Append(((Img.Height * 3) / 4).ToString());
459 this.Output.Append("pt]{");
460 this.Output.Append(FileName.Replace('\\', '/'));
461 this.Output.Append("}}");
462
463 if (AloneInParagraph)
464 {
465 this.Output.AppendLine("\\end{figure}");
466 this.Output.AppendLine();
467 }
468 }
469 }
470 else if (Result is MarkdownDocument Doc)
471 {
472 await this.RenderDocument(Doc, true); // Does not call ProcessAsyncTasks()
473 Doc.ProcessAsyncTasks();
474 }
475 else if (Result is MarkdownContent Markdown)
476 {
477 Doc = await MarkdownDocument.CreateAsync(Markdown.Markdown, Markdown.Settings ?? new MarkdownSettings());
478 await this.RenderDocument(Doc, true); // Does not call ProcessAsyncTasks()
479 Doc.ProcessAsyncTasks();
480 }
481 else if (Result is Exception ex)
482 {
483 bool First = true;
484
485 ex = Log.UnnestException(ex);
486
487 this.Output.AppendLine("\\texttt{\\color{red}");
488
489 if (ex is AggregateException ex2)
490 {
491 foreach (Exception ex3 in ex2.InnerExceptions)
492 {
493 foreach (string Row in ex3.Message.Replace("\r\n", "\n").
494 Replace('\r', '\n').Split('\n'))
495 {
496 if (First)
497 First = false;
498 else
499 this.Output.AppendLine("\\\\");
500
501 this.Output.Append(EscapeLaTeX(Row));
502 }
503 }
504 }
505 else
506 {
507 foreach (string Row in ex.Message.Replace("\r\n", "\n").
508 Replace('\r', '\n').Split('\n'))
509 {
510 if (First)
511 First = false;
512 else
513 this.Output.AppendLine("\\\\");
514
515 this.Output.Append(EscapeLaTeX(Row));
516 }
517 }
518
519 this.Output.AppendLine("}");
520
521 if (AloneInParagraph)
522 {
523 this.Output.AppendLine();
524 this.Output.AppendLine();
525 }
526 }
527 else if (Result is ObjectMatrix M && !(M.ColumnNames is null))
528 {
529 this.Output.AppendLine("\\begin{table}[!h]");
530 this.Output.AppendLine("\\centering");
531 this.Output.Append("\\begin{tabular}{");
532 foreach (string _ in M.ColumnNames)
533 this.Output.Append("|c");
534
535 this.Output.AppendLine("|}");
536 this.Output.AppendLine("\\hline");
537
538 bool First = true;
539
540 foreach (string Name in M.ColumnNames)
541 {
542 if (First)
543 First = false;
544 else
545 this.Output.Append(" & ");
546
547 this.Output.Append(EscapeLaTeX(Name));
548 }
549
550 this.Output.AppendLine("\\\\");
551 this.Output.AppendLine("\\hline");
552
553 int x, y;
554
555 for (y = 0; y < M.Rows; y++)
556 {
557 for (x = 0; x < M.Columns; x++)
558 {
559 if (x > 0)
560 this.Output.Append(" & ");
561
562 object Item = M.GetElement(x, y).AssociatedObjectValue;
563 if (!(Item is null))
564 {
565 if (Item is string s2)
566 this.Output.Append(EscapeLaTeX(s2));
567 else if (Item is MarkdownElement Element)
568 {
569 this.Output.Append('{');
570 await Element.Render(this);
571 this.Output.Append('}');
572 }
573 else
574 {
575 this.Output.Append('{');
576 this.Output.Append(EscapeLaTeX(Expression.ToString(Item)));
577 this.Output.Append('}');
578 }
579 }
580
581 this.Output.Append("</td>");
582 }
583
584 this.Output.AppendLine("\\\\");
585 }
586
587 this.Output.AppendLine("\\hline");
588 this.Output.AppendLine("\\end{tabular}");
589 this.Output.AppendLine("\\end{table}");
590 this.Output.AppendLine();
591 }
592 else if (Result is Array A)
593 {
594 foreach (object Item in A)
595 await this.RenderObject(Item, false, Variables);
596 }
597 else
598 this.Output.Append(EscapeLaTeX(Result?.ToString() ?? string.Empty));
599
600 if (AloneInParagraph)
601 {
602 this.Output.AppendLine();
603 this.Output.AppendLine();
604 }
605 }
606
611 public override Task Render(InlineText Element)
612 {
613 this.Output.Append(EscapeLaTeX(Element.Value));
614 return Task.CompletedTask;
615 }
616
621 public override async Task Render(Insert Element)
622 {
623 this.Output.Append("\\emph{");
624 await this.RenderChildren(Element);
625 this.Output.Append('}');
626 }
627
632 public override Task Render(LineBreak Element)
633 {
634 this.Output.AppendLine("\\newline");
635 return Task.CompletedTask;
636 }
637
642 public override Task Render(Link Element)
643 {
644 return this.RenderChildren(Element);
645 }
646
651 public override Task Render(LinkReference Element)
652 {
653 return this.RenderChildren(Element);
654 }
655
660 public override Task Render(MetaReference Element)
661 {
662 bool FirstOnRow = true;
663
664 if (Element.TryGetMetaData(out KeyValuePair<string, bool>[] Values))
665 {
666 foreach (KeyValuePair<string, bool> P in Values)
667 {
668 if (FirstOnRow)
669 FirstOnRow = false;
670 else
671 this.Output.Append(' ');
672
673 this.Output.Append(EscapeLaTeX(P.Key));
674
675 if (P.Value)
676 {
677 this.Output.AppendLine();
678 FirstOnRow = true;
679 }
680 }
681 }
682
683 return Task.CompletedTask;
684 }
685
690 public override Task Render(Model.SpanElements.Multimedia Element)
691 {
692 IMultimediaLatexRenderer Renderer = Element.MultimediaHandler<IMultimediaLatexRenderer>();
693 if (Renderer is null)
694 return this.RenderChildren(Element);
695 else
696 return Renderer.RenderLatex(this, Element.Items, Element.Children, Element.AloneInParagraph, Element.Document);
697 }
698
703 public override Task Render(MultimediaReference Element)
704 {
706
707 if (!(Multimedia is null))
708 {
710 if (!(Renderer is null))
711 return Renderer.RenderLatex(this, Multimedia.Items, Element.Children, Element.AloneInParagraph, Element.Document);
712 }
713
714 return this.RenderChildren(Element);
715 }
716
721 public override async Task Render(StrikeThrough Element)
722 {
723 this.Output.Append("\\strike{");
724 await this.RenderChildren(Element);
725 this.Output.Append('}');
726 }
727
732 public override async Task Render(Strong Element)
733 {
734 this.Output.Append("\\textbf{");
735 await this.RenderChildren(Element);
736 this.Output.Append('}');
737 }
738
743 public override async Task Render(SubScript Element)
744 {
745 this.Output.Append("\\textsubscript{");
746 await this.RenderChildren(Element);
747 this.Output.Append('}');
748 }
749
754 public override async Task Render(SuperScript Element)
755 {
756 this.Output.Append("\\textsuperscript{");
757 await this.RenderChildren(Element);
758 this.Output.Append('}');
759 }
760
765 public override async Task Render(Underline Element)
766 {
767 this.Output.Append("\\underline{");
768 await this.RenderChildren(Element);
769 this.Output.Append('}');
770 }
771
772 #endregion
773
774 #region Block elements
775
780 public override async Task Render(BlockQuote Element)
781 {
782 this.Output.AppendLine("\\begin{quote}");
783
784 await this.RenderChildren(Element);
785
786 this.Output.AppendLine("\\end{quote}");
787 this.Output.AppendLine();
788 }
789
794 public override async Task Render(BulletList Element)
795 {
796 this.Output.AppendLine("\\begin{itemize}");
797
798 await this.RenderChildren(Element);
799
800 this.Output.AppendLine("\\end{itemize}");
801 this.Output.AppendLine();
802 }
803
808 public override async Task Render(CenterAligned Element)
809 {
810 this.Output.AppendLine("\\begin{center}");
811
812 await this.RenderChildren(Element);
813
814 this.Output.AppendLine("\\end{center}");
815 this.Output.AppendLine();
816 }
817
822 public override async Task Render(CodeBlock Element)
823 {
824 ICodeContentLatexRenderer Renderer = Element.CodeContentHandler<ICodeContentLatexRenderer>();
825
826 if (!(Renderer is null))
827 {
828 try
829 {
830 if (await Renderer.RenderLatex(this, Element.Rows, Element.Language, Element.Indent, Element.Document))
831 return;
832 }
833 catch (Exception ex)
834 {
835 bool First = true;
836
837 ex = Log.UnnestException(ex);
838
839 this.Output.AppendLine("\\texttt{\\color{red}");
840
841 if (ex is AggregateException ex2)
842 {
843 foreach (Exception ex3 in ex2.InnerExceptions)
844 {
845 foreach (string Row in ex3.Message.Replace("\r\n", "\n").
846 Replace('\r', '\n').Split('\n'))
847 {
848 if (First)
849 First = false;
850 else
851 this.Output.AppendLine("\\\\");
852
853 this.Output.Append(EscapeLaTeX(Row));
854 }
855 }
856 }
857 else
858 {
859 foreach (string Row in ex.Message.Replace("\r\n", "\n").
860 Replace('\r', '\n').Split('\n'))
861 {
862 if (First)
863 First = false;
864 else
865 this.Output.AppendLine("\\\\");
866
867 this.Output.Append(EscapeLaTeX(Row));
868 }
869 }
870
871 this.Output.AppendLine("}");
872 this.Output.AppendLine();
873 }
874 }
875
876 this.Output.Append("\\texttt{");
877
878 int i;
879
880 for (i = Element.Start; i <= Element.End; i++)
881 {
882 this.Output.Append(Element.IndentString);
883 this.Output.AppendLine(Element.Rows[i]);
884 }
885
886 this.Output.AppendLine("}");
887 this.Output.AppendLine();
888 }
889
894 public override Task Render(CommentBlock Element)
895 {
896 return Task.CompletedTask;
897 }
898
903 public override Task Render(DefinitionDescriptions Element)
904 {
905 return this.RenderChildren(Element);
906 }
907
912 public override async Task Render(DefinitionList Element)
913 {
914 int State = 0;
915
916 this.Output.AppendLine("\\begin{description}");
917
918 foreach (MarkdownElement E in Element.Children)
919 {
920 if (E is DefinitionTerms Terms)
921 {
922 switch (State)
923 {
924 case 0:
925 this.Output.Append("\\item[");
926 await Terms.Render(this);
927 State++;
928 break;
929
930 case 1:
931 this.Output.Append(", ");
932 await Terms.Render(this);
933 break;
934
935 case 2:
936 this.Output.AppendLine("}");
937 this.Output.Append("\\item[");
938 State--;
939 await Terms.Render(this);
940 break;
941 }
942 }
943 else if (E is DefinitionDescriptions Descriptions)
944 {
945 switch (State)
946 {
947 case 0:
948 this.Output.Append("\\item{");
949 await Descriptions.Render(this);
950 State += 2;
951 break;
952
953 case 1:
954 this.Output.Append("]{");
955 await Descriptions.Render(this);
956 State++;
957 break;
958
959 case 2:
960 this.Output.AppendLine();
961 await Descriptions.Render(this);
962 break;
963 }
964 }
965 }
966
967 switch (State)
968 {
969 case 1:
970 this.Output.AppendLine("]{}");
971 break;
972
973 case 2:
974 this.Output.AppendLine("}");
975 break;
976 }
977
978 this.Output.AppendLine("\\end{description}");
979 this.Output.AppendLine();
980 }
981
986 public override Task Render(DefinitionTerms Element)
987 {
988 return this.RenderChildren(Element);
989 }
990
995 public override async Task Render(DeleteBlocks Element)
996 {
997 this.Output.Append("\\strike{");
998 await this.RenderChildren(Element);
999 this.Output.Append('}');
1000 }
1001
1006 public override Task Render(Footnote Element)
1007 {
1008 return this.RenderChildren(Element);
1009 }
1010
1015 public override async Task Render(Header Element)
1016 {
1017 string Command;
1018
1019 switch (this.LatexSettings.DocumentClass)
1020 {
1021 case LaTeXDocumentClass.Book:
1022 case LaTeXDocumentClass.Report:
1023 switch (Element.Level)
1024 {
1025 case 1:
1026 Command = "part";
1027 break;
1028
1029 case 2:
1030 Command = "chapter";
1031 break;
1032
1033 case 3:
1034 Command = "section";
1035 break;
1036
1037 case 4:
1038 Command = "subsection";
1039 break;
1040
1041 case 5:
1042 Command = "subsubsection";
1043 break;
1044
1045 case 6:
1046 Command = "paragraph";
1047 break;
1048
1049 case 7:
1050 default:
1051 Command = "subparagraph";
1052 break;
1053 }
1054 break;
1055
1056 case LaTeXDocumentClass.Article:
1057 case LaTeXDocumentClass.Standalone:
1058 default:
1059 switch (Element.Level)
1060 {
1061 case 1:
1062 Command = "section";
1063 break;
1064
1065 case 2:
1066 Command = "subsection";
1067 break;
1068
1069 case 3:
1070 Command = "subsubsection";
1071 break;
1072
1073 case 4:
1074 Command = "paragraph";
1075 break;
1076
1077 case 5:
1078 default:
1079 Command = "subparagraph";
1080 break;
1081 }
1082 break;
1083 }
1084
1085 this.Output.Append('\\');
1086 this.Output.Append(Command);
1087 this.Output.Append("*{");
1088
1089 await this.RenderChildren(Element);
1090
1091 this.Output.AppendLine("}");
1092 this.Output.AppendLine();
1093 }
1094
1099 public override Task Render(HorizontalRule Element)
1100 {
1101 this.Output.AppendLine("\\hrulefill");
1102 return Task.CompletedTask;
1103 }
1104
1109 public override async Task Render(HtmlBlock Element)
1110 {
1111 await this.RenderChildren(Element);
1112
1113 this.Output.AppendLine();
1114 this.Output.AppendLine();
1115 }
1116
1121 public override async Task Render(InsertBlocks Element)
1122 {
1123 this.Output.Append("\\emph{");
1124 await this.RenderChildren(Element);
1125 this.Output.Append('}');
1126 }
1127
1132 public override Task Render(InvisibleBreak Element)
1133 {
1134 return Task.CompletedTask;
1135 }
1136
1141 public override async Task Render(LeftAligned Element)
1142 {
1143 this.Output.AppendLine("\\begin{flushleft}");
1144
1145 await this.RenderChildren(Element);
1146
1147 this.Output.AppendLine("\\end{flushleft}");
1148 this.Output.AppendLine();
1149 }
1150
1155 public override async Task Render(MarginAligned Element)
1156 {
1157 this.Output.AppendLine("\\begin{justify}");
1158
1159 await this.RenderChildren(Element);
1160
1161 this.Output.AppendLine("\\end{justify}");
1162 this.Output.AppendLine();
1163 }
1164
1169 public override Task Render(NestedBlock Element)
1170 {
1171 return this.RenderChildren(Element);
1172 }
1173
1178 public override async Task Render(NumberedItem Element)
1179 {
1180 if (Element.NumberExplicit)
1181 {
1182 this.Output.Append("\\item[");
1183 this.Output.Append(Element.Number.ToString());
1184 this.Output.Append("]{");
1185 }
1186 else
1187 this.Output.Append("\\item{");
1188
1189 await this.RenderChild(Element);
1190
1191 this.Output.AppendLine("}");
1192 }
1193
1198 public override async Task Render(NumberedList Element)
1199 {
1200 this.Output.AppendLine("\\begin{enumerate}");
1201
1202 await this.RenderChildren(Element);
1203
1204 this.Output.AppendLine("\\end{enumerate}");
1205 this.Output.AppendLine();
1206 }
1207
1212 public override async Task Render(Paragraph Element)
1213 {
1214 await this.RenderChildren(Element);
1215
1216 this.Output.AppendLine();
1217 this.Output.AppendLine();
1218 }
1219
1224 public override async Task Render(RightAligned Element)
1225 {
1226 this.Output.AppendLine("\\begin{flushright}");
1227
1228 await this.RenderChildren(Element);
1229
1230 this.Output.AppendLine("\\end{flushright}");
1231 this.Output.AppendLine();
1232 }
1233
1238 public override Task Render(Sections Element)
1239 {
1240 return this.RenderChildren(Element);
1241 }
1242
1247 public override Task Render(SectionSeparator Element)
1248 {
1249 this.Output.AppendLine();
1250 this.Output.AppendLine("\\newpage");
1251 this.Output.AppendLine();
1252
1253 return Task.CompletedTask;
1254 }
1255
1260 public override async Task Render(Table Element)
1261 {
1263 MarkdownElement[] Row;
1264 TextAlignment?[] CellAlignments;
1265 int NrRows, RowIndex;
1266 int NrColumns = Element.Columns;
1267 string s;
1268 int i, j, k;
1269
1270 this.Output.AppendLine("\\begin{table}[!h]");
1271 this.Output.AppendLine("\\centering");
1272 this.Output.Append("\\begin{tabular}{");
1273 foreach (TextAlignment Alignment in Element.ColumnAlignments)
1274 {
1275 this.Output.Append('|');
1276 this.RenderAlignment(Alignment);
1277 }
1278
1279 this.Output.AppendLine("|}");
1280 this.Output.AppendLine("\\hline");
1281
1282 NrRows = Element.Headers.Length;
1283 for (RowIndex = 0; RowIndex < NrRows; RowIndex++)
1284 {
1285 Row = Element.Headers[RowIndex];
1286 CellAlignments = Element.HeaderCellAlignments[RowIndex];
1287
1288 for (i = 0; i < NrColumns; i++)
1289 {
1290 if (i > 0)
1291 this.Output.Append(" & ");
1292
1293 k = 1;
1294 j = i + 1;
1295 while (j < NrColumns && Row[j++] is null)
1296 k++;
1297
1298 if (k > 1)
1299 {
1300 this.Output.Append("\\multicolumn{");
1301 this.Output.Append(k.ToString());
1302 this.Output.Append("}{|");
1303 this.RenderAlignment(CellAlignments[i] ?? Element.ColumnAlignments[i]);
1304 this.Output.Append("|}{");
1305 }
1306
1307 E = Row[i];
1308 if (!(E is null))
1309 await E.Render(this);
1310
1311 if (k > 1)
1312 this.Output.Append('}');
1313 }
1314
1315 this.Output.AppendLine("\\\\");
1316 }
1317
1318 this.Output.AppendLine("\\hline");
1319
1320 NrRows = Element.Rows.Length;
1321 for (RowIndex = 0; RowIndex < NrRows; RowIndex++)
1322 {
1323 Row = Element.Rows[RowIndex];
1324 CellAlignments = Element.RowCellAlignments[RowIndex];
1325
1326 for (i = 0; i < NrColumns; i++)
1327 {
1328 if (i > 0)
1329 this.Output.Append(" & ");
1330
1331 k = 1;
1332 j = i + 1;
1333 while (j < NrColumns && Row[j++] is null)
1334 k++;
1335
1336 if (k > 1)
1337 {
1338 this.Output.Append("\\multicolumn{");
1339 this.Output.Append(k.ToString());
1340 this.Output.Append("}{|");
1341 this.RenderAlignment(CellAlignments[i] ?? Element.ColumnAlignments[i]);
1342 this.Output.Append("|}{");
1343 }
1344
1345 E = Row[i];
1346 if (!(E is null))
1347 await E.Render(this);
1348
1349 if (k > 1)
1350 this.Output.Append('}');
1351 }
1352
1353 this.Output.AppendLine("\\\\");
1354 }
1355
1356 this.Output.AppendLine("\\hline");
1357 this.Output.AppendLine("\\end{tabular}");
1358
1359 if (!string.IsNullOrEmpty(Element.Id))
1360 {
1361 this.Output.Append("\\caption{");
1362
1363 s = string.IsNullOrEmpty(Element.Caption) ? Element.Id : Element.Caption;
1364
1365 this.Output.Append(EscapeLaTeX(s));
1366
1367 this.Output.AppendLine("}");
1368 this.Output.Append("\\label{");
1369
1370 this.Output.Append(EscapeLaTeX(Element.Id));
1371
1372 this.Output.AppendLine("}");
1373 }
1374
1375 this.Output.AppendLine("\\end{table}");
1376 this.Output.AppendLine();
1377 }
1378
1379 private void RenderAlignment(TextAlignment Alignment)
1380 {
1381 switch (Alignment)
1382 {
1383 case TextAlignment.Left:
1384 default:
1385 this.Output.Append('l');
1386 break;
1387
1388 case TextAlignment.Center:
1389 this.Output.Append('c');
1390 break;
1391
1392 case TextAlignment.Right:
1393 this.Output.Append('r');
1394 break;
1395 }
1396 }
1397
1402 public override async Task Render(TaskItem Element)
1403 {
1404 this.Output.Append("\\item");
1405
1406 if (Element.IsChecked)
1407 this.Output.Append("[\\checked]");
1408
1409 this.Output.Append('{');
1410 await this.RenderChild(Element);
1411 this.Output.AppendLine("}");
1412 }
1413
1418 public override async Task Render(TaskList Element)
1419 {
1420 this.Output.AppendLine("\\begin{tasklist}");
1421
1422 await this.RenderChildren(Element);
1423
1424 this.Output.AppendLine("\\end{tasklist}");
1425 this.Output.AppendLine();
1426 }
1427
1432 public override async Task Render(UnnumberedItem Element)
1433 {
1434 this.Output.Append("\\item{");
1435 await this.RenderChild(Element);
1436 this.Output.AppendLine("}");
1437 }
1438
1439 #endregion
1440
1441 }
1442}
Helps with parsing of commong data types.
Definition: CommonTypes.cs:13
static string Escape(string s, char[] CharactersToEscape, string EscapeSequence)
Escapes a set of characters in a string.
Definition: CommonTypes.cs:828
Image encoder/decoder.
Definition: ImageCodec.cs:14
const string FileExtensionPng
png
Definition: ImageCodec.cs:75
Contains settings that the LaTeX export uses to customize LaTeX output.
Renders LaTeX from a Markdown document.
override Task Render(HtmlEntity Element)
Renders Element .
override async Task Render(SubScript Element)
Renders Element .
override async Task Render(BlockQuote Element)
Renders Element .
override Task Render(EmojiReference Element)
Renders Element .
override async Task Render(InsertBlocks Element)
Renders Element .
override async Task Render(Insert Element)
Renders Element .
override async Task Render(Strong Element)
Renders Element .
override Task Render(NestedBlock Element)
Renders Element .
LatexRenderer(LaTeXSettings LatexSettings)
Renders LaTeX from a Markdown document.
override async Task Render(CenterAligned Element)
Renders Element .
override Task Render(LinkReference Element)
Renders Element .
override Task Render(InlineText Element)
Renders Element .
override Task Render(HtmlEntityUnicode Element)
Renders Element .
override async Task Render(FootnoteReference Element)
Renders Element .
override async Task Render(InlineScript Element)
Renders Element .
override async Task Render(TaskItem Element)
Renders Element .
override Task Render(LineBreak Element)
Renders Element .
override Task Render(Footnote Element)
Renders Element .
override Task Render(Sections Element)
Renders Element .
override async Task Render(RightAligned Element)
Renders Element .
override Task Render(InlineCode Element)
Renders Element .
override async Task Render(StrikeThrough Element)
Renders Element .
override Task Render(Link Element)
Renders Element .
async Task RenderObject(object Result, bool AloneInParagraph, Variables Variables)
Generates HTML from Script output.
override async Task Render(BulletList Element)
Renders Element .
override Task Render(AutomaticLinkUrl Element)
Renders Element .
override Task Render(DefinitionTerms Element)
Renders Element .
override async Task Render(Table Element)
Renders Element .
override async Task Render(Emphasize Element)
Renders Element .
override async Task Render(MarginAligned Element)
Renders Element .
override Task Render(Model.SpanElements.Multimedia Element)
Renders Element .
override async Task Render(HtmlBlock Element)
Renders Element .
override Task Render(InvisibleBreak Element)
Renders Element .
override Task Render(Abbreviation Element)
Renders Element .
override async Task Render(DefinitionList Element)
Renders Element .
override Task Render(MetaReference Element)
Renders Element .
override async Task Render(TaskList Element)
Renders Element .
override Task RenderDocumentHeader()
Renders the document header.
LatexRenderer(StringBuilder Output, LaTeXSettings LatexSettings)
Renders LaTeX from a Markdown document.
override Task Render(MultimediaReference Element)
Renders Element .
override async Task Render(UnnumberedItem Element)
Renders Element .
override Task Render(DefinitionDescriptions Element)
Renders Element .
override Task Render(AutomaticLinkMail Element)
Renders Element .
static string EscapeLaTeX(string s)
Escapes text for output in a LaTeX document.
override Task Render(InlineHTML Element)
Renders Element .
override async Task Render(LeftAligned Element)
Renders Element .
override async Task Render(Delete Element)
Renders Element .
readonly LaTeXSettings LatexSettings
LaTeX settings.
override async Task Render(NumberedList Element)
Renders Element .
override async Task Render(DeleteBlocks Element)
Renders Element .
override async Task Render(Underline Element)
Renders Element .
override Task Render(HashTag Element)
Renders Element .
override Task RenderDocumentFooter()
Renders the document header.
override async Task Render(SuperScript Element)
Renders Element .
override async Task Render(Header Element)
Renders Element .
override async Task Render(Paragraph Element)
Renders Element .
override async Task Render(NumberedItem Element)
Renders Element .
override Task Render(CommentBlock Element)
Renders Element .
override Task Render(SectionSeparator Element)
Renders Element .
override Task Render(DetailsReference Element)
Renders Element .
override Task Render(HorizontalRule Element)
Renders Element .
override async Task Render(CodeBlock Element)
Renders Element .
Class that can be used to encapsulate Markdown to be returned from a Web Service, bypassing any encod...
Contains a markdown document. This markdown document class supports original markdown,...
static async Task< object > TransformXml(XmlDocument Xml, Variables Variables)
Transforms XML to an object that is easier to visualize.
bool TryGetMetaData(string Key, out KeyValuePair< string, bool >[] Value)
Tries to get a meta-data value given its key.
MarkdownDocument Detail
Detail document of a master document.
Multimedia GetReference(string Label)
Gets the multimedia information referenced by a label.
static Task< MarkdownDocument > CreateAsync(string MarkdownText, params Type[] TransparentExceptionTypes)
Contains a markdown document. This markdown document class supports original markdown,...
Contains settings that the Markdown parser uses to customize its behavior.
Represents a block quote in a markdown document.
Definition: BlockQuote.cs:11
Represents a bullet list in a markdown document.
Definition: BulletList.cs:11
Represents a center-aligned set of blocks in a markdown document.
Represents a code block in a markdown document.
Definition: CodeBlock.cs:16
string IndentString
String used for indentation.
Definition: CodeBlock.cs:273
Represents a comment block in a markdown document.
Definition: CommentBlock.cs:10
Represents a definition list in a markdown document.
Represents inserted blocks in a markdown document.
Definition: DeleteBlocks.cs:11
Represents a header in a markdown document.
Definition: Header.cs:15
Represents a block of HTML in a markdown document.
Definition: HtmlBlock.cs:11
Represents inserted blocks in a markdown document.
Definition: InsertBlocks.cs:11
Represents a left-aligned set of blocks in a markdown document.
Definition: LeftAligned.cs:11
Represents a margin-aligned set of blocks in a markdown document.
Represents a nested block with no special formatting rules in a markdown document.
Definition: NestedBlock.cs:11
Represents a numbered item in an ordered list.
Definition: NumberedItem.cs:10
bool NumberExplicit
If number is explicitly provided (true) or inferred (false).
Definition: NumberedItem.cs:40
Represents a numbered list in a markdown document.
Definition: NumberedList.cs:11
Represents a paragraph in a markdown document.
Definition: Paragraph.cs:11
Represents a right-aligned set of blocks in a markdown document.
Definition: RightAligned.cs:11
Represents a sequence of sections.
Definition: Sections.cs:11
Represents a table in a markdown document.
Definition: Table.cs:11
Represents a task item in a task list.
Definition: TaskItem.cs:10
bool IsChecked
If the item is checked or not.
Definition: TaskItem.cs:31
Represents a task list in a markdown document.
Definition: TaskList.cs:11
Represents an unnumbered item in an ordered list.
override IEnumerable< MarkdownElement > Children
Any children of the element.
Abstract base class for all markdown elements.
abstract Task Render(IRenderer Output)
Renders the element.
virtual IEnumerable< MarkdownElement > Children
Any children of the element.
MarkdownDocument Document
Markdown document.
static Task< string > GetTemporaryFile(byte[] BinaryImage)
Stores an image in binary form as a temporary file. Files will be deleted when application closes.
Definition: ImageContent.cs:88
bool AutoExpand
If the footnote should automatically be expanded when rendered, if format supports auto-expansion.
Represents an HTML entity in Unicode format.
bool AloneInParagraph
If the element is alone in a paragraph.
Definition: InlineScript.cs:55
async Task< object > EvaluateExpression()
Evaluates the script expression.
Definition: InlineScript.cs:71
bool TryGetMetaData(out KeyValuePair< string, bool >[] Values)
Tries to get meta-data from the document.
MultimediaItem[] Items
Multimedia items.
Definition: Multimedia.cs:40
bool AloneInParagraph
If the element is alone in a paragraph.
Abstract base class for Markdown renderers.
Definition: Renderer.cs:14
readonly StringBuilder Output
Renderer output.
Definition: Renderer.cs:18
Task RenderChild(MarkdownElementSingleChild Element)
Renders the child of Element .
Definition: Renderer.cs:175
async Task RenderChildren(MarkdownElementChildren Element)
Renders the children of Element .
Definition: Renderer.cs:147
virtual async Task RenderDocument(MarkdownDocument Document, bool Inclusion)
Renders a document.
Definition: Renderer.cs:75
override string ToString()
Returns the renderer output.
Definition: Renderer.cs:130
MarkdownDocument Document
Reference to Markdown document being processed.
Definition: Renderer.cs:23
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:13
static Exception UnnestException(Exception Exception)
Unnests an exception, to extract the relevant inner exception.
Definition: Log.cs:818
Class managing a script expression.
Definition: Expression.cs:39
static string ToString(double Value)
Converts a value to a string, that can be parsed as part of an expression.
Definition: Expression.cs:4496
Base class for graphs.
Definition: Graph.cs:79
Contains pixel information
virtual byte[] EncodeAsPng()
Encodes the pixels into a binary PNG image.
ToMatrix(ScriptNode Operand, bool NullCheck, int Start, int Length, Expression Expression)
To-Matrix operator.
Definition: ToMatrix.cs:22
Collection of variables.
Definition: Variables.cs:25
Interface for multimedia content LaTeX renderers.
Interface for objects that can be converted into matrices.
Definition: IToMatrix.cs:9
LaTeXDocumentClass
Document class of LaTeX output.
Definition: LaTeXSettings.cs:7
LaTeXPaper
LaTeX output paper format
TextAlignment
Text alignment of contents.