#!/usr/bin/env python3 """Maakt een PowerPoint-bestand van een gebouwde presentatie uit deze repository. Elke dia wordt als beeld op een 16:9-slide gezet en de sprekersnotities komen in het notitieveld, zodat PowerPoint ze in de sprekersweergave op jouw scherm toont terwijl de zaal alleen de dia ziet. Het beeld is een afbeelding: de opmaak is precies gelijk aan de PDF, maar de tekst is in PowerPoint niet te bewerken. Wijzigen doe je in maak_dias.py en dan opnieuw bouwen. Gebruik: python3 ../_gereedschap/maak_pptx.py Bijvoorbeeld in 00-sessie: python3 ../_gereedschap/maak_pptx.py sessie-agents-en-projecten.pdf Staat er een notities-begeleider.json naast maak_dias.py, dan gebruikt het script die uitgebreide notities en zegt het erbij; dat bestand is privé, dus deel die pptx niet. Vereist: pdftoppm (Poppler) en python-pptx. """ import json import re import subprocess import sys import tempfile from pathlib import Path try: from pptx import Presentation from pptx.util import Inches except ImportError: sys.exit("python-pptx ontbreekt. Bijvoorbeeld: ~/.local/venvs/uitlegvideo/bin/python " "../_gereedschap/maak_pptx.py ") pdf = Path(sys.argv[1]).resolve() if not pdf.exists(): sys.exit(f"niet gevonden: {pdf}") MAP = pdf.parent P = MAP / "project" PRIVE = (MAP / "notities-begeleider.json").exists() # 1. dia's en PDF opnieuw bouwen, zodat beeld en notities bij elkaar horen subprocess.run([sys.executable, str(MAP / "maak_dias.py")] + (["--notities"] if PRIVE else []), check=True, capture_output=True) deck = json.loads((P / "deck.json").read_text(encoding="utf-8")) faces = "".join(f'' for f in deck["faces"].values()) tmp = Path(tempfile.mkdtemp(prefix="pptx-")) css = """ @page { size: 1920px 1080px; margin: 0; } html, body { margin: 0; padding: 0; } * { box-sizing: border-box; margin: 0; padding: 0; } section { position: relative; width: 1920px; height: 1080px; overflow: hidden; page-break-after: always; break-after: page; } section:last-child { page-break-after: auto; } aside { display: none; } ul { padding-left: 1.1em; } table { border-collapse: collapse; width: 100%; } th, td { border: 1px solid #D8D2C4; padding: 12px 18px; text-align: left; vertical-align: top; } img { max-width: 100%; } """ (tmp / "dias.html").write_text( f'{faces}' + "".join((P / "slides" / f"{sid}.html").read_text(encoding="utf-8") for sid in deck["order"]) + "", encoding="utf-8") subprocess.run(["google-chrome", "--headless=new", "--disable-gpu", "--no-pdf-header-footer", "--virtual-time-budget=8000", f"--print-to-pdf={tmp / 'dias.pdf'}", (tmp / "dias.html").as_uri()], check=True, capture_output=True) # 2. elke pagina als beeld subprocess.run(["pdftoppm", "-r", "100", "-jpeg", "-jpegopt", "quality=88", str(tmp / "dias.pdf"), str(tmp / "dia")], check=True) beelden = sorted(tmp.glob("dia-*.jpg")) if len(beelden) != len(deck["order"]): sys.exit(f"{len(beelden)} beelden voor {len(deck['order'])} dia's; bouw de dia's opnieuw") def notities(sid): tekst = re.search(r"", (P / "slides" / f"{sid}.html").read_text(encoding="utf-8"), re.S) tekst = (tekst.group(1).strip() if tekst else "") tekst = re.sub(r"<[^>]+>", "", tekst) # de privénotities staan als BEDOELING: ... | ZEGGEN: ... op één regel; leesbaar maken return "\n\n".join(d.strip() for d in tekst.split(" | ") if d.strip()) # 3. de pptx: 16:9, elk beeld schermvullend, notities in het notitieveld prs = Presentation() prs.slide_width, prs.slide_height = Inches(13.333), Inches(7.5) leeg = prs.slide_layouts[6] # blank for n, sid in enumerate(deck["order"]): dia = prs.slides.add_slide(leeg) dia.shapes.add_picture(str(beelden[n]), 0, 0, width=prs.slide_width, height=prs.slide_height) dia.notes_slide.notes_text_frame.text = notities(sid) uit = pdf.with_suffix(".pptx") prs.save(str(uit)) # 4. de dia-bestanden terugzetten op de publieke versie subprocess.run([sys.executable, str(MAP / "maak_dias.py")], check=True, capture_output=True) soort = "uitgebreide begeleidersnotities (privé, niet delen)" if PRIVE else "de notities uit de dia's" print(f"{uit.name}: {uit.stat().st_size // 1024} kB, {len(deck['order'])} dia's, met {soort}")