Deck HTML → PPTX natif et éditable
La règle imposée par ce skill : ne jamais coller d'images de diapositives dans PowerPoint. Chaque carré, barre, point, pastille, ligne et bloc de texte doit être un véritable objet PowerPoint que l'utilisateur peut déplacer, recolorer et retaper. Le convertisseur lit la page rendue (Playwright + la mise en page calculée par le navigateur) au lieu de réinterpréter le CSS, puis écrit des formes python-pptx aux mêmes coordonnées exactes.
Exécution
python scripts/html_to_pptx.py <deck.html> <out.pptx> [all | 1,3,5]
Nécessite : pip install -r requirements.txt et playwright install chromium.
Les diapositives sont les éléments correspondant à .slide (1280x720 px). Placez le .html avec ses images inline
(data: URIs) ou sur le disque à côté. examples/sample-deck.html est un petit deck pour essayer d'abord.
Ce à quoi la page doit ressembler lors de la capture (le script le fait pour vous) : classe anim retirée de
<html>, animations/transitions CSS désactivées, window beforeprint déclenché (les decks révèlent souvent des graphiques à l'impression),
média d'impression, zoom 1, éléments avec classe .mode ou .jump masqués (bascule de thème, navigateur de diapositives). Les decks
avec un basculement clair/sombre convertissent dans le thème affiché — assurez-vous que c'est celui que l'utilisateur souhaite.
Correspondances
| Dans le HTML | Dans le PPTX |
|---|---|
| div / carte avec fond, bordure, rayon | rectangle / rectangle arrondi (rayon → ajustement de coin) |
| fond dégradé (linéaire) | remplissage dégradé natif |
| bordure unilatérale (bande d'accent) | rectangle fin ; bordures fines/tirets → lignes réelles |
pastilles, cercles border-radius:999px | pastille / ovale |
texte (tout bloc, avec gras/couleur, <br>, liens) | une zone de texte par bloc, styles préservés, hyperliens conservés |
<li> | puces PowerPoint réelles (couleur du marqueur conservée) |
| SVG inline rect/circle/line/polyline/path/text | rectangle, ovale, connecteur (pointes de flèche conservées), forme libre avec courbes de Bézier réelles, zone de texte |
SVG <textPath> (texte sur une courbe) | texte curviligne PowerPoint (déformation Arc vers haut/bas) |
CSS clip-path: polygon(...) (chevrons, coupes diagonales) | forme libre ; une photo à l'intérieur est recadrée selon le polygone |
<img>, photos, icônes PNG | images (ce sont des bitmaps — c'est attendu) |
text-transform, letter-spacing, barré, opacité/alpha | appliqué aux segments / remplissages |
Basculement à deux vues (.vtog avec data-view=code et data-view=time boutons) | seconde diapositive pour l'autre vue |
| Animations JS | état final fixe uniquement |
Règles durement acquises (chacune a coûté du temps réel — gardez-les)
- La position du texte est calibrée, ne la "corrigez" pas à l'œil. L'interligne PowerPoint à 100 % = 1,2 x taille de police
(Arial et Arial Black pareil). Une zone de texte doit être placée à
top = rangeTop + (ascent-cap)*fs - lineHeight + K*fsavec(ascent-cap, K) = (0,189, 0,95)pour Arial et(0,385, 1,0)pour Arial Black, etline_spacing = cssLineHeight / (1.2*fs). Le texte sur une ligne utilise un interligne 100 % etwrap=noneavec du mou pour qu'il ne se réenroule jamais. - Chrome sous Windows interprète
font-family: Arialaux poids 800/900 comme ARIAL BLACK. Le convertisseur le mappe sur Arial Black (pas gras). Sans cela, tout titre lourd semble trop fin et de mauvaise largeur. - Ne jamais absorber les enfants inline-block dans un bloc de texte. Seuls les enfants
display:inlinesont fusionnés en une seule zone de texte ; les enfants inline-block/flex sont traités séparément. - Mesurez les nœuds de texte sur place (Range sur le nœud). Envelopper un nœud dans un
<span>temporaire modifie la disposition grid/flex. - Ouvrez le résultat dans PowerPoint pour prouver qu'il est valide. python-pptx peut écrire un fichier que PowerPoint
refuse (« PowerPoint n'a pas pu ouvrir le fichier »). Causes connues : tailles de forme négatives/NaN (clamp, supprimer les points NaN),
et
calc()dansclip-path(évaluez-le). Éliminez en supprimant des formes par moitiés et en rouvrant. - Une image avec une géométrie personnalisée remplit la boîte englobante de son chemin, pas son cadre. Pour recadrer une photo selon un polygone,
dimensionnez l'image à la boîte englobante du polygone et définissez un recadrage source (
srcRect) pour le reste. - Ne capturez pas les formes par capture d'écran (« rastérisez les formes bizarres »). Convertissez les chemins SVG des logos et les polygones
clip-pathen formes libres à la place. La brancherasterest un dernier recours. - Ignorez le texte fantôme rogné (grands chiffres délavés rognés par leur carte) — PowerPoint ne peut pas rogner les zones de texte.
- PowerPoint
a:lnvient après le remplissage dansspPr; supprimez le thèmep:styleou les formes prennent des ombres. - Ne jamais écraser un .pptx que l'utilisateur a ouvert — écrivez un nouveau nom de fichier à la place.
Vérification (toujours — ne jamais livrer sans voir)
Windows avec PowerPoint installé :
powershell -NoProfile -File scripts/render_pptx.ps1 -pptx <out.pptx> -outdir <png_dir> # Export PowerPoint vers PNG
python scripts/compare.py <deck.html> <png_dir> 1,2,3 <out.png> # HTML | PPTX côte à côte
python scripts/compare.py <deck.html> <png_dir> 6:6,7:8 <out.png> # html:pptx quand les numéros de diapositives diffèrent
render_pptx.ps1 laisse PowerPoint en cours d'exécution si l'utilisateur l'avait déjà ouvert. Sans PowerPoint, rendez le
.pptx vers des PNG autrement (par exemple LibreOffice en mode headless) en s1.png, s2.png… et exécutez compare.py.
Lisez le PNG de comparaison, corrigez, reconstruisez. Nettoyage typique après une exécution : texte légèrement plus large dans PowerPoint (crénage), rien de structurel.
Limites connues (dites-le à l'utilisateur)
- Le placement du texte est calibré pour Arial et Arial Black. Les autres polices sont converties, mais le texte peut être décalé de quelques pixels vers le haut ou le bas jusqu'à ce que cette police soit calibrée (mesurez la hauteur des majuscules et l'interligne dans PowerPoint).
- Les photos, icônes et logos fournis sous forme de bitmaps restent des images. Le texte se trouve dans sa propre zone au-dessus de sa carte (non groupé).
- Les animations/basculements sont aplatis en une seule image (la deuxième vue d'un basculement devient une diapositive supplémentaire).
- Les dégradés radiaux et les coins par coin sont approximés ; les ombres de boîtes sont supprimées.
- La taille de la diapositive est fixée à 1280x720 px -> 13,333 x 7,5 pouces.
Crédits
Construit par Impera Business Services. Licence MIT — voir LICENSE.