HTML-Deck → natives, bearbeitbares PPTX
Die Regel, die diese Fähigkeit durchsetzt: Füge niemals Folienbilder in PowerPoint ein. Jedes Quadrat, jeder Balken, jeder Punkt, jede Pille, jede Linie und jeder Textblock muss ein echtes PowerPoint-Objekt sein, das der Benutzer verschieben, umfärben und neu tippen kann. Der Konverter liest die gerenderte Seite (Playwright + das berechnete Layout des Browsers), anstatt das CSS neu zu erraten, und schreibt dann python-pptx-Formen an die exakt gleichen Koordinaten.
Ausführen
python scripts/html_to_pptx.py <deck.html> <out.pptx> [all | 1,3,5]
Erforderlich: pip install -r requirements.txt und playwright install chromium.
Folien sind die Elemente, die auf .slide passen (1280x720 px). Lege die .html-Datei mit ihren Bildern inline (data:-URIs) oder auf der Festplatte daneben ab. examples/sample-deck.html ist ein kleines Deck zum Testen.
So muss die Seite beim Erfassen aussehen (das Skript erledigt dies für dich): anim-Klasse vom <html> entfernt, CSS-Animationen/-Übergänge ausgeschaltet, window beforeprint ausgelöst (Decks zeigen oft Diagramme beim Drucken), Druckmedien, Zoom 1, Elemente mit der Klasse .mode oder .jump ausgeblendet (Themenumschalter, Foliennavigator). Decks mit einem Hell/Dunkel-Umschalter konvertieren im aktuell angezeigten Thema – stelle sicher, dass es das vom Benutzer gewünschte ist.
Was wird was
| Im HTML | Im PPTX |
|---|---|
| div / Karte mit Hintergrund, Rahmen, Radius | Rechteck / abgerundetes Rechteck (Radius → Eckenanpassung) |
| Gradientenhintergrund (linear) | nativer Gradientenfüllung |
| einseitiger Rahmen (Akzentstreifen) | dünnes Rechteck; Haarlinien-/gestrichelte Rahmen → echte Linien |
border-radius:999px-Pillen, Kreise | Pille / Oval |
Text (jeder Block, mit fett/farbigen Läufen, <br>, Links) | ein Textfeld pro Block, Läufe erhalten, Hyperlinks behalten |
<li> | echte PowerPoint-Aufzählungspunkte (Farbe des Aufzählungszeichens erhalten) |
| Inline-SVG rect/circle/line/polyline/path/text | Rechteck, Oval, Verbinder (Pfeilspitzen erhalten), Freihandform mit echten Bezier-Kurven, Textfeld |
SVG <textPath> (Text auf einer Kurve) | PowerPoint-gebogener Text (Arch Up/Down-Warp) |
CSS clip-path: polygon(...) (Winkel, diagonale Schnitte) | Freihandform; ein Foto darin wird auf das Polygon zugeschnitten |
<img>, Fotos, Icon-PNGs | Bilder (es sind Bitmaps – das ist zu erwarten) |
text-transform, Buchstabenabstand, Durchstreichung, Opazität/Alpha | auf die Läufe / Füllungen angewendet |
Zwei-Ansichten-Umschalter (.vtog mit data-view=code und data-view=time-Buttons) | zweite Folie für die andere Ansicht |
| JS-Animationen | nur der endgültige Ruhezustand |
Hart erkämpfte Regeln (jede hat echte Zeit gekostet – behalte sie)
- Textposition ist kalibriert, „korrigiere“ sie nicht nach Augenmaß. PowerPoint 100 % Zeilenabstand = 1,2 × Schriftgröße (gleichermaßen für Arial und Arial Black). Ein Textfeld muss platziert werden bei
top = rangeTop + (ascent-cap)*fs - lineHeight + K*fsmit(ascent-cap, K) = (0,189, 0,95)für Arial und(0,385, 1,0)für Arial Black undline_spacing = cssLineHeight / (1.2*fs). Einzeiliger Text verwendet Abstand 100 % undwrap=nonemit Spielraum, damit er nie umbricht. - Chrome unter Windows rendert
font-family: Arialmit Gewicht 800/900 als ARIAL BLACK. Der Konverter ordnet es Arial Black (nicht fett) zu. Ohne dies sieht jede schwere Überschrift zu dünn und mit falscher Breite aus. - Schlucke niemals Inline-Block-Kinder in einen Textblock. Nur
display:inline-Kinder werden in einem Textfeld zusammengefasst; Inline-Block/Flex-Kinder werden separat behandelt. - Messe Textknoten an Ort und Stelle (Range auf dem Knoten). Das Einwickeln eines Knotens in ein temporäres
<span>verändert das Grid/Flex-Layout. - Öffne das Ergebnis in PowerPoint, um seine Gültigkeit zu beweisen. python-pptx schreibt bereitwillig eine Datei, die PowerPoint ablehnt („PowerPoint konnte die Datei nicht öffnen“). Bekannte Ursachen: negative/NaN-Formgrößen (clampen, NaN-Punkte entfernen) und
calc()innerhalb vonclip-path(auswerten). Eingrenzen durch Löschen von Formen in Hälften und erneutes Öffnen. - Ein Bild mit benutzerdefinierter Geometrie füllt die Bounding Box seines Pfads, nicht seinen Rahmen aus. Um ein Foto auf ein Polygon zuzuschneiden, dimensioniere das Bild auf die Bounding Box des Polygons und setze eine Quellzuschneidung (
srcRect) für den Rest. - Screenshot-erfasse keine Formen („rasterisiere die Ausreißer“). Konvertiere stattdessen SVG-Pfade und Clip-Path-Polygone von Logos in Freihandformen. Der
raster-Branch ist letzter Ausweg. - Überspringe beschnittenen Geistertext (große verblasste Zahlen, die durch ihre Karte abgeschnitten sind) – PowerPoint kann Textfelder nicht beschneiden.
- PowerPoint
a:lnkommt nach der Füllung inspPr; lösche das Themep:style, sonst erhalten Formen Schatten. - Überschreibe niemals eine .pptx, die der Benutzer geöffnet hat – schreibe stattdessen einen neuen Dateinamen.
Überprüfen (immer – niemals ungesehen ausliefern)
Windows mit installiertem PowerPoint:
powershell -NoProfile -File scripts/render_pptx.ps1 -pptx <out.pptx> -outdir <png_dir> # PowerPoint-Export nach PNG
python scripts/compare.py <deck.html> <png_dir> 1,2,3 <out.png> # HTML | PPTX nebeneinander
python scripts/compare.py <deck.html> <png_dir> 6:6,7:8 <out.png> # html:pptx wenn Foliennummern abweichen
render_pptx.ps1 lässt PowerPoint laufen, falls der Benutzer es bereits geöffnet hatte. Ohne PowerPoint rendere die .pptx auf andere Weise (z. B. LibreOffice headless) in s1.png, s2.png … und führe compare.py aus.
Lies das Vergleichs-PNG, korrigiere, baue neu. Typische Nachbesserung nach einem Durchlauf: Text geringfügig breiter in PowerPoint (Kerning), nichts Strukturelles.
Bekannte Grenzen (dem Benutzer mitteilen)
- Die Textplatzierung ist für Arial und Arial Black kalibriert. Andere Schriftarten konvertieren, aber der Text kann einige Pixel zu hoch oder zu niedrig sitzen, bis diese Schriftart kalibriert ist (Versalhöhe und Zeilenabstand in PowerPoint messen).
- Fotos, Icons und Logos, die als Bitmaps geliefert werden, bleiben Bilder. Text sitzt in seiner eigenen Box oben auf seiner Karte (nicht gruppiert).
- Animationen/Umschalter werden auf einen Frame reduziert (die zweite Ansicht eines Umschalters wird zu einer zusätzlichen Folie).
- Radiale Verläufe und per-Ecke-Radien werden angenähert; Box-Schatten werden entfernt.
- Die Foliengröße ist fest auf 1280x720 px → 13,333 × 7,5 Zoll eingestellt.
Danksagung
Erstellt von Impera Business Services. MIT-Lizenz – siehe LICENSE.