major
#29854
PowerPoint-Präsentationen aus TL-Script erzeugen: deklarative Folienbausteine, Export in eine Firmenvorlage, Analyse von Vorlagen
Kontext
Aus TopLogic-Anwendungen entstehen regelmäßig Präsentationen und Berichte aus Fachdaten: Statusberichte, Entscheidungsvorlagen, Risikoübersichten. Heute geschieht das entweder von Hand (Daten abschreiben und in Folien übertragen) oder über fest programmierte Office-Exporte. Diese Exporte sind aufwendig und starr: Jede Änderung, etwa eine zusätzliche Folie, eine andere Kennzahl oder ein neues Corporate Design, braucht einen Entwickler und eine neue Version der Anwendung. Außerdem passen die Daten oft nicht in die festen Platzhalter der Vorlage (zu lange Texte, mehr Zeilen als vorgesehen).
Nach dieser Erweiterung kann eine Anwendung Präsentationen in der Firmenvorlage des Kunden aus TL-Script erzeugen. Die Folien werden als Daten beschrieben, aus fachlichen Bausteinen zusammengesetzt und mit den Fachdaten des Modells gefüllt. Das Ergebnis ist eine normale, voll bearbeitbare PowerPoint-Datei mit Sprechernotizen, die zum Download angeboten oder in der Anwendung abgelegt wird. Eine solche Beschreibung kann im Modell gespeichert und ohne neue Anwendungsversion geändert werden. Ein KI-Agent in der Anwendung kann sie ebenso erzeugen wie ein Mensch.
Außerdem kann eine Anwendung eine beliebige PowerPoint-Vorlage analysieren: Struktur und Stil der Vorlage stehen als Daten zur Verfügung, Layouts und Beispielfolien lassen sich als Bilder ansehen. Darauf baut das Einlesen von Vorlagen durch einen Agenten (#29855) auf.
Verhalten
Präsentation erzeugen
Ein TL-Script beschreibt eine Präsentation als Aufruf von Funktionen mit literalen Listen und Strukturen. Im Skript steht kein XML. Skizze (Funktionsnamen vorläufig):
pptDeck(
template: $projekt.berichtsvorlage,
footer: "Statusbericht " + $projekt.name,
slides: [
pptTitle("Statusbericht", $projekt.name),
pptContent("Termine", "Stand " + dateFormat(today(), "dd.MM.yyyy"),
pptRow([
pptCard("Meilensteine", pptBullets($projekt.meilensteine.map(m -> $m.name)), role: "themaA"),
pptStat(value: $projekt.budgetVerbraucht, label: "Budget verbraucht", role: "risiko")
]),
notes: "Die Meilensteine im Überblick ..."
),
pptContent("Risiken", "Die größten Abweichungen",
pptTable(columns: ["Risiko", "Bewertung"],
rows: $projekt.risiken.map(r -> [$r.name, pptRating($r.stufe)])))
])
- Das Ergebnis ist ein Binärwert (tl.core:Binary). Als Ergebnis eines Kommandos wird er zum Download angeboten, er kann aber auch in einem Attribut abgelegt werden.
- Eine zweite Funktion liefert Vorschaubilder der Folien, z. B. zur Prüfung vor der Freigabe.
- Die Folien liegen auf den Layouts der Vorlage (Titel, Agenda, Inhalt). Logo, Hintergrund, Titelstil und Fußzeile kommen aus der Vorlage. Die Beispielfolien der Vorlage werden entfernt.
Vorlage analysieren
- Eine Funktion liefert die Analyse einer Vorlage als Daten:
- Foliengröße, Theme-Farben und -Schriften;
- die Layouts mit Namen und Platzhaltern (Rolle, Position, Größe, Textstil);
- die Deko-Elemente der Master, z. B. den Logo-Bereich;
- die Beispielfolien der Vorlage mit ihren Formen und deren Stil (Füllung, Rahmen, Schatten, Schrift).
- Die Render-Funktion liefert auch Bilder der Layouts und Beispielfolien einer Vorlage. Damit lassen sich Layouts auch visuell beurteilen, z. B. ein Layout mit eingeblendetem Hilfsraster, das für Inhalte unbrauchbar ist.
- Zusammen mit der Textmessung lässt sich ermitteln, wie viel Text Titel, Untertitel und typische Kartenbreiten bei den Schriften der Vorlage fassen.
Technische Umsetzung
Bausteine in Java, Beschreibung als Daten
- Die Funktionen sind in Java implementiert, als TLScriptFunctions-Klasse mit eigenem Präfix (z. B. ppt).
- Sie liefern unveränderliche Werte, die Folien und Bausteine beschreiben, keine XML-Fragmente. Erst der Export erzeugt daraus DrawingML und PresentationML.
- Diese Beschreibungen sind Daten: im Modell speicherbar (Berichtsdefinition), per toJson/`parseJson` für Agenten les- und erzeugbar und vor dem Export prüfbar (Messen, Einpassen, Abgleich gegen die freigegebenen Layouts).
Zwei Schichten
- Präsentationsbausteine für das Skript: Titel-, Agenda- und Inhaltsfolie, Karte, Banner/Kernaussage, Kennzahl, Aufzählung, Tabelle mit Bewertungszellen, Balken- und Säulendiagramm, Zeitachse, Ablaufkette, Stärken/Grenzen, Sprechernotizen.
- Farben werden über Rollen angegeben (z. B. Thema A/B/C, Risiko, erledigt), die auf Theme-Farben der Vorlage abgebildet werden.
- Primitive darunter (Form, Textrahmen, Tabelle, Bild), aus denen die Bausteine in Java gebaut sind. Im Skript sind sie nur als Ausnahme gedacht.
Deklarative Anordnung
- Die Anordnung wird über Zeilen, Spalten und Gewichte beschrieben (analog zu stack/`grid` im View-Layer), nicht über absolute Koordinaten.
- Nur so kann der Export Platz verteilen, Texte kürzen und Inhalte, die nicht passen, auf Folgefolien umbrechen.
- Absolute Positionen bleiben als Ausnahme möglich.
Paket-Buchhaltung im Werkzeug
Diesen Teil übernimmt das Werkzeug vollständig, das Skript sieht davon nichts:
- Relationen und IDs;
- die Folienliste der Präsentation und die Content-Type-Einträge;
- Notizfolien;
- das Entfernen der Beispielfolien der Vorlage samt nicht mehr referenzierter Medien;
- die Reihenfolge der ZIP-Einträge.
Fehlende Atome
- Textmessung: Breite einer Zeile und Zeilenzahl eines Textes in Schrift, Größe und Breite der Vorlage, auf Basis von Java-AWT-Schriftmetriken. Darauf beruht das automatische Einpassen. DrawingML legt Zeilenumbrüche nicht fest, sie entstehen erst beim Rendern. Ohne eigene Messung lässt sich deshalb nicht vorab wissen, ob ein Text passt.
- Bildmaße aus Binärdaten, für Bilder und Logos mit korrektem Seitenverhältnis.
- Rendern Folie → Bild für Vorschau und Prüfung, auch für Layouts und Beispielfolien einer Vorlage (siehe unten).
- Vorlage analysieren: Struktur und Stil einer Vorlage als Daten (siehe oben), ohne XML im Skript.
Evaluation des Renderns: Apache POI vs. gekapseltes LibreOffice
Beide Wege werden an denselben Referenz-Decks gegen Screenshots aus PowerPoint verglichen. Kriterien:
- Treue: Verläufe, Schatten, abgerundete Formen, Tabellen und vor allem die Zeilenumbrüche.
- Übereinstimmung mit der Textmessung:
- POI (XSLFSlide.draw) rendert mit denselben AWT-Metriken, die die Textmessung verwendet. Messung und Vorschau stimmen damit überein.
- LibreOffice hat ein eigenes Satzsystem, Messung und Vorschau können also voneinander abweichen.
- Betrieb:
- POI läuft im selben Prozess.
- LibreOffice braucht eine Installation und eine Prozessverwaltung (Zeitlimits, parallele Aufträge, Absturzbehandlung). Dafür ist der getrennte Prozess eine natürliche Abschottung, wenn fremde Vorlagen verarbeitet werden.
- Laufzeit und Speicher: Vorschau eines Decks mit ca. 20 Folien beim Bearbeiten.
- Schriften: Die Vorlagenschrift muss auf dem Server installiert sein, in beiden Varianten.
- Lizenz: POI steht unter Apache 2.0, LibreOffice unter MPL 2.0 (als separater Prozess).
Grundlagen
- Apache POI (poi-ooxml-full, Version im Root-POM) ist bereits Abhängigkeit.
- Die älteren Vorlagen-Exporte in com.top_logic.base.office.ppt (POIPowerpointX, SlideReplacerX) ersetzen Platzhalter-Token in vorgefertigten Folien. Für den deklarativen Aufbau sind sie nicht geeignet, können aber für die Layout-Auswahl der Vorlage als Referenz dienen.
- Echte, bearbeitbare PowerPoint-Diagramme und Notizfolien gibt es bisher nicht. Für Diagramme mit Datentabelle kann die eingebettete Arbeitsmappe mit den vorhandenen Excel-Funktionen erzeugt werden.
- Ein Prototyp der Bausteine und der Paket-Buchhaltung existiert in Python. Mit ihm wurden zwei Präsentationen in der TopLogic-Vorlage erzeugt (19 und 15 Folien). Er dient als Referenz für Umfang, Bausteine und die beim Rendern beobachteten Layout-Regeln, z. B. maximale Titellängen, Silbentrennung in schmalen Karten und das zu meidende Hilfsraster-Layout der Vorlage.
Lösung
Neues Modul com.top_logic.presentation (tl-presentation) auf Basis von tl-model-search und tl-layout-wysiwyg. Eine Anwendung, die Präsentationen erzeugen will, nimmt es als Abhängigkeit auf. Alle Längen sind in Punkt (pt) angegeben.
Skriptfunktionen (Präfix `ppt`)
- Export: pptDeck(template, slides, footer, profile, name) liefert die .pptx als Binärwert; ohne Vorlage wird eine leere 16:9-Präsentation verwendet. pptProfile(template) liefert das aus der Vorlage abgeleitete Profil.
- Folien: pptTitle, pptAgenda, pptContent, pptSection, pptClosing, allgemein pptSlide (Layout per Index, Name oder Rolle; Platzhalter, Sprechernotizen).
- Bausteine: pptCard, pptBanner, pptBadge, pptStat, pptBullets, pptRating, pptLegend, pptArrow, pptTimeline, pptFlow, pptProCon, Diagramme pptBarChart, pptColumnChart, pptSeries.
- Strukturierter Text: pptHtml(html, font, size, color, gap) wandelt HTML (ein StructuredText, z. B. der Wert eines tl.model.wysiwyg:Html-Attributs, ein I18NStructuredText oder eine Zeichenkette) in Folieninhalt um, siehe unten.
- Anordnung: pptRow, pptColumn mit Gewichten, festen Größen, Abständen und height: "auto"; absolute Positionen bleiben möglich.
- Primitive: pptShape, pptTextBox, pptTable, pptCell, pptImage, pptParagraph, pptRun, pptColor, pptGradient, pptLine, pptShadow.
- Analyse und Vorschau: pptAnalyze(template), pptRender(presentation, slides, width), pptRenderLayouts(template, layouts, width), pptMeasureText(...); allgemein binaryImageSize(data).
Beschreibung als Daten
- Alle Funktionen liefern JSON-kompatible Strukturen (Dictionaries mit Typ-Schlüssel, Listen). Sie lassen sich per toJson/`parseJson` austauschen und im Modell speichern.
- Farben, Füllungen, Linien, Schatten und Geometrie verwenden dieselben Schlüssel wie die Ausgabe von pptAnalyze; ein Stil kann direkt aus der Analyse einer Beispielfolie übernommen werden.
- Der Export liest die Beschreibung in unveränderliche Java-Werte ein und prüft sie. Fehler nennen den Pfad des fehlerhaften Eintrags (z. B. slides[2].content[0].rows[1][3].fill.color), auch unbekannte Schlüssel werden gemeldet.
Vorlagenprofil
Das Profil ist Daten, wird aus der Vorlage abgeleitet und kann pro Präsentation teilweise überschrieben werden:
- Layoutrollen (Titel, Inhalt, Abschnitt, Abschluss), Agenda-Layouts nach Anzahl der Einträge;
- je Layout Untertitel- und Fußzeilen-Platzhalter und Inhaltsbereich;
- Farbrollen (topicA–`topicF`, risk, warning, done, muted, text, inverse, accent), benannte Stile (card, stat, banner, badge, arrow, timeline), Bewertungen für Tabellenzellen, Abstand, Mindestschriftgröße, Fortsetzungs-Suffix.
Export
- Das Paket wird mit Apache POI (XSLF) geschrieben. Die Beispielfolien der Vorlage werden entfernt, danach alle nicht mehr erreichbaren Teile des Pakets (Medien, Diagramme, eingebettete Dateien) und verwaiste Relationen. Eine .potx ergibt eine .pptx.
- Formen ohne Füllung oder Linie in der Beschreibung bleiben ohne Füllung oder Linie (kein implizites Standard-Formformat).
- Passt ein Text nicht, wird die Schrift proportional bis zur Mindestgröße verkleinert und anschließend an einer Wortgrenze mit „…“ gekürzt (overflow: shrink, ellipsis, visible, error). Die berechneten Schriftgrößen werden explizit geschrieben; die automatische Anpassung von PowerPoint wird nicht verwendet.
- Jede Tabellenzeile ist genau so hoch wie der höchste Zellentext (gemessen bei der Spaltenbreite) zuzüglich der Zellenränder; die Zellen schließen lückenlos aneinander an. Kopfzellen mit langen Wörtern in schmalen Spalten werden verkleinert, bis kein Wort mehr getrennt wird.
- Folgefolien: Zu lange Tabellen, als teilbar markierte Texte und Aufzählungen (split: true) und teilbare Spalten (pptColumn(..., split: true)) werden auf Folgefolien fortgesetzt; jede Folie fasst so viel, wie tatsächlich passt. Folgefolien wiederholen die Kopfzeilen einer Tabelle, die Platzhaltertexte und den Untertitel der Folie; der Titel erhält das Suffix „(Forts.)“.
- Eine teilbare Spalte wird Element für Element fortgesetzt: Texte und Tabellen werden absatz- bzw. zeilenweise geteilt, ein Bild wandert als Ganzes auf die nächste Folie (und wird verkleinert, wenn es allein nicht passt). Ein Spaltenelement ist nie breiter als seine Spalte.
- Ein Absatz mit keepWithNext (z. B. eine Überschrift) beendet keine Folie: Er wandert zusammen mit dem folgenden Absatz bzw. Element auf die Folgefolie.
- Aufzählungen können automatisch nummeriert werden (Aufzählungszeichen autoNumber mit PowerPoint-Nummerierungsschema und optionalem start), auch über Folgefolien hinweg.
- Balken- und Säulendiagramme sind echte PowerPoint-Diagramme mit eingebetteter Arbeitsmappe; Serienfarben bleiben Theme-Farben.
Strukturierter Text (HTML)
pptHtml liefert eine teilbare Spalte aus Textrahmen, Tabellen und Bildern in Dokumentreihenfolge:
- Absätze, Zeilenumbrüche, Überschriften (h1–h6, mit keepWithNext), fett, kursiv, unterstrichen, Links, Code und vorformatierter Text, Zitate;
- Aufzählungen (ul) und nummerierte Listen (ol, mit start und Nummerierungsart) mit Verschachtelungsebenen;
- HTML-Tabellen werden zu Tabellen (Kopfzeilen aus thead/`th`);
- Bilder werden aus den Bildern des StructuredText oder aus data:-URIs aufgelöst, auf die Spaltenbreite begrenzt, mit Seitenverhältnis; nicht auflösbare Bilder werden mit einer Warnung im Log übersprungen;
- unbekannte Elemente tragen ihren Text bei.
Grenzen: colspan/`rowspan` werden nicht zusammengefasst (das Tabellenmodell kennt keine verbundenen Zellen), Durchstreichung entfällt, Bilder und Tabellen in Tabellenzellen tragen nur ihren Text bei.
Textmessung und Vorschau
- Die Textmessung verwendet das Textlayout von POI selbst; Messung und Vorschau stimmen damit überein. Wo POI von PowerPoint abweicht, gleichen Messung und Rendering dies über eine gemeinsame Anpassung aus:
- Zeichenabstand (spc) und Unterschneidung (kern, ab der Kerning-Größe des Laufs) werden angewendet;
- Zeilen werden genau bei der Breite des Textrahmens umbrochen (POI lässt einen Punkt mehr zu);
- eine Zeile ist so hoch wie Ober-, Unterlänge und Zeilenabstand der Schrift (POI rechnet bei Schriften ohne Zeilenabstand 15 % mehr), und die erste Zeile eines Absatzes folgt der letzten des vorigen im normalen Zeilenabstand.
- Die Vorschau zeichnet Diagramme selbst (POI zeichnet keine) und SVG-Bilder aus der mitgespeicherten PNG-Ersatzgrafik. Tabellen werden mit denselben Zeilenhöhen gezeichnet, mit denen sie geschrieben wurden.
- Gerendert wird mit POI im selben Prozess, Ergebnis des Vergleichs mit LibreOffice siehe Kommentar. Die Schriften der Vorlage müssen auf dem Server installiert sein; fehlende Schriften werden beim Rendern protokolliert.
Demo und Dokumentation
- React-Demo: Projekte haben ein optionales Attribut „Berichtsvorlage (PowerPoint)“. Das Kommando „Statusbericht (PowerPoint)“ in der Projektliste erzeugt aus den Projektdaten eine Präsentation zum Download: Kennzahlen, Meilensteine als Zeitachse, Tickets je Meilenstein als Diagramm, die offenen Tickets als Tabelle (Nr., Titel, Meilenstein, Fälligkeit, Bearbeiter, Dringlichkeit) und je offenem Ticket eine Folie „#Nr. Titel“ mit der formatierten Beschreibung.
- Tickets der Demo haben eine pro Projekt fortlaufende Nummer (Standardwert aus einer Sequenz im Kontext des Projekts) und eine Beschreibung als strukturierten Text. Tickets eines Meilensteins lassen sich anlegen und löschen. Bearbeiter eines Tickets ist ein Personenkontakt (Contacts:PersonContact); ein Klick auf den Bearbeiter öffnet einen Kontaktdialog mit den ihm zugewiesenen Tickets. Die Tabellenspalten-Demo zeigt ihre Beispiele an den Personenkontakten. Die Projektkachel im Projekt-Cockpit zeigt alle Felder des Projekts vollständig.
- Entwicklerartikel im Kapitel presentation/ (Präsentation erzeugen, Inhalt aus HTML, Anordnung und Einpassen, Vorlagenprofil, Analyse und Vorschau einer Vorlage); er dient zugleich als Referenz für Agenten.
Änderungen außerhalb des Moduls
- Instanz-Import: XMLInstanceImporter legt ein Objekt, das Wert einer Kompositionsreferenz ist, im Kontext seines Besitzers an – wie die Oberfläche und TL-Script (new(type, context: ...)). Kontextabhängige Standardwerte, z. B. Sequenznummern pro Container, gelten damit auch für importierte Daten (*.objects.xml, Initialdaten). Objekte auf oberster Ebene werden weiterhin ohne Kontext angelegt.
- HTMLConstants um weitere Element- und Attributnamen ergänzt.
- ImageUtils.getImageSize als gemeinsame Bildmaß-Hilfe, genutzt von binaryImageSize, FlowFactory und den PPT-Hilfsklassen in tl-core.
- PowerPoint in der Akronymliste des Doclets.
Bekannte Grenzen
- Die Vorschau zeichnet weiche Schatten hart, gepunktete Linien durchgezogen und Kartenverläufe flach.
- Die erzeugten Dateien wurden mit POI und LibreOffice geprüft, nicht mit PowerPoint selbst.
Abgrenzung
- Kein freier „Text-zu-Folien“-Assistent. Ausgangspunkt sind Fachdaten der Anwendung und eine Beschreibung der Folien.
- Keine Videoerzeugung.
- Die KI-Seite ist Gegenstand von #29855: das Modell für Vorlagen und vorlagenspezifische Bausteinbibliotheken, deren Freigabe, die Gebrauchsanweisung für Agenten und der Ausführungs-Scope „nur lesend“. Die Analyse- und Render-Funktionen, auf denen das Einlesen einer Vorlage aufbaut, entstehen in diesem Ticket. Die Bausteine dieses Tickets sind so angelegt, dass Agenten sie nutzen können. Zahlen, Termine, Tabellen und Diagramme kommen immer aus den Daten.