Mathematischer Formelsatz
^/_, \frac,
\sqrt (auch mit Wurzelexponent), \left…\right,
\sum/\prod/\int, Akzente
(\hat, \vec, \widehat …),
\overline/\underline, die Matrix-Umgebungen,
griechische Buchstaben und rund 90 benannte Zeichen.
- Die Formel traegt ihre LaTeX-Quelle als /ActualText — sie ist kein Text, ihre Glyphen sind teilweise Bauteile ohne Codepunkt.
- Mathe-Schrift: TeX Gyre Termes Math (GUST Font License). Die Bibliothek liefert keine Schrift mit; der Aufrufer stellt sie bereit.
Die unterstuetzte LaTeX-Teilmenge ist eng und benannt. Was nicht dazugehoert, wird uebersprungen und hier gemeldet — die uebrige Formel wird trotzdem gesetzt, statt die ganze Eingabe abzulehnen.
Bericht leer — die Eingabe wurde vollstaendig verstanden.
using Kuonen.PDFTools.Authoring;
using Kuonen.PDFTools.Formula;
using Kuonen.PDFTools.Pages;
// Eine Schrift MIT MATH-Tabelle ist Voraussetzung. Die Bibliothek liefert
// keine mit (lizenziert) — hier etwa TeX Gyre Termes Math.
byte[] mathFont = File.ReadAllBytes("texgyretermes-math.otf");
var options = new FormulaOptions(
mathFont,
SizePt: 22,
Display: true);
MathFormula formel = MathFormula.Compose(
"\\sum_{i=1}^{n} \\left( \\frac{x_i - \\bar{x}}{\\sigma} \\right)^2 \\leq \\sqrt[3]{\\alpha}", options);
var builder = new PdfDocumentBuilder { Title = "Formelsatz" };
PageCanvas page = builder.AddPage(PageSize.A4);
// (x, y) ist die GRUNDLINIE, nicht die Unterkante — ein Bruch ragt darunter.
page.DrawFormula(formel, 56, 640);
// Hoehe und Tiefe stehen VOR dem Zeichnen bereit — daraus baut man den Kasten.
FormulaMetrics m = formel.Metrics; // Width / Height / Depth / TotalHeight
byte[] pdf = builder.Build();
FormulaReport report = formel.Report; // unbekannte Befehle stehen hierStufe 1 — die OpenType-MATH-Tabelle lesen
(Protokoll 92, öffentlich in Kuonen.PDFTools.Fonts). Aus einer
Mathe-Schrift werden die rund fünfzig Konstanten, die Kursivkorrektur, die
Größenvarianten und das Glyph-Assembly gelesen — byte-genau gegen
fontTools geprüft.
Stufe 2 — das Satzmodell (Protokoll 128): Box-Modell mit
Höhe und Tiefe, Atomtypen und Abstandsmatrix, Indizes/Exponenten und Brüche
— jede Position aus den MATH-Konstanten, Stelle für Stelle
von Hand gegen fontTools gerechnet (etwa x²: der Exponent sitzt
exakt auf SuperscriptShiftUp, verschoben um die Kursivkorrektur). Das ist heute
intern (Namensraum Formula) — nach dem Vorbild des
CSS-Bausteins wird es öffentlich, wenn ein Konsument es braucht.
Stufe 3 — Wurzeln, mitwachsende Klammern, große Operatoren
(Protokoll 162). Eine Klammer wächst auf ihren Inhalt: erst über die fertigen
Größenvarianten der Schrift, und reicht keine, aus Bauteilen
(Fuß, Mittelstück, Kopf) mit der vorgeschriebenen Überlappung. Der Wurzelhaken
hängt an seiner Oberkante am Überstrich, Klammern sitzen auf der
Achse statt auf der Grundlinie, und das Summenzeichen wächst im Display-Stil auf
DisplayOperatorMinHeight und trägt seine Grenzen darüber und darunter.
Neun Prüfungen, jede von Hand aus den fontTools-Werten gerechnet; das
gerenderte PDF von pypdfium2 bestätigt.
Stufe 4 — Akzente, Ueber-/Unterstriche und Matrizen
(Protokoll 163). Ein Akzent richtet sich nach dem TopAccentAttachment-Punkt,
den die Schrift für Grundzeichen und Akzent angibt — wer statt dessen mittig
zentriert, setzt das Dach über einem geneigten f sichtbar zu weit links;
über einem hohen Grundzeichen fährt er mit, gedeckelt auf
AccentBaseHeight, und auf Wunsch wächst er in der Breite mit.
Matrizen sind das einzige, wofür zwei Maße nicht aus der Schrift
stammen können: die MATH-Tabelle sagt zu ihnen nichts, Spalten- und
Zeilenabstand sind deshalb benannte TeX-Konventionen im Geviert.
Stufe 5 — LaTeX als Eingabe (Protokoll 164). Eine
benannte Teilmenge: Gruppen, ^/_,
\frac, \sqrt (auch mit Wurzelexponent),
\left…\right, die großen Operatoren, Akzente,
\overline/\underline, die Matrix-Umgebungen, die griechischen
Buchstaben und rund 90 benannte Zeichen. Was nicht dazugehört, wird gemeldet
— nie still verschluckt, und der Rest der Formel wird trotzdem gesetzt.
Kein Makro-System, keine Textbefehle, keine Ausrichtungsumgebungen.
(Protokoll 165.) MathFormula.Compose liest und setzt,
PageCanvas.DrawFormula zeichnet, FormulaFrame und
FlowDocument.Formula setzen sie in den Fließtext. Die Maße
(Metrics) stehen vor dem Zeichnen bereit — Höhe und Tiefe
getrennt, denn ein Bruch ragt unter die Grundlinie.
Der Knackpunkt war das Zeichnen selbst. Der Setzer liefert rohe
Glyph-IDs — die gedehnten Klammern und ihre Bauteile stammen aus
MathVariants und haben gar keinen Codepunkt, während der Zeichenweg
Glyphen sonst über Text auflöst. Gelöst über ein Segment für rohe
IDs samt der Abbildung Original→Subset, die im selben Durchlauf entsteht wie
die eingebettete Schrift: getrennt gerechnet könnte sie
»umnummeriert« sagen, während die Bytes das Original sind — und
dann stünden lautlos die falschen Zeichen auf dem Blatt.
Eine Formel ist kein Text. Deshalb trägt sie ihre LaTeX-Quelle als
/ActualText und wird als /Formula ausgezeichnet — sonst
wäre sie beim Kopieren und für Screenreader stumm.
Voraussetzung bleibt eine Schrift mit MATH-Tabelle. Die Bibliothek
liefert keine mit (Zero-NuGet, lizenziert); die stellt der Aufrufer bereit. Diese
Seite benutzt TeX Gyre Termes Math aus dem
Werkzeugprojekt (GUST Font License = LPPL 1.3c). Ebenfalls frei lizenziert und
geeignet: Latin Modern Math (GUST) oder
STIX Two Math (SIL OFL).