PDF export
Render a .pptx deck to PDF with Presentation.to_pdf and save_pdf — one page per slide, font maps, degradation warnings, and the rendering features covered.
Presentation.to_pdf() renders a parsed deck to PDF: one page per slide, at
the exact slide size (EMU → points, 12700 EMU per point), with every shape
drawn at its absolute resolved position.
API
class Presentation:
def to_pdf(self, *, font_map: dict[str, str] | None = None) -> bytes: ...
def save_pdf(
self, path: str | os.PathLike[str], *, font_map: dict[str, str] | None = None
) -> None: ...Both take zero required arguments. to_pdf() returns the PDF as bytes;
save_pdf(path) writes it to disk.
import pptspine
pres = pptspine.open("deck.pptx")
pdf_bytes = pres.to_pdf() # -> bytes, starts with b"%PDF-"
pres.save_pdf("deck.pdf") # writes the same bytes to a fileThe page count always equals the slide count, and each page's rectangle equals
the slide size in points — a 16:9 deck yields 960 × 540 pt pages, a 4:3 deck
720 × 540 pt:
pres = pptspine.open("widescreen.pptx")
assert pres.slide_size_points == (960.0, 540.0)
assert pres.to_pdf().startswith(b"%PDF-") # page_count == slide_countFonts and the font_map
By default the renderer resolves each requested font family through a built-in
substitution table (e.g. 宋体 → Songti SC) and embeds each used face once,
subset to the glyphs actually drawn. Pass font_map to override family
resolution — each entry maps a requested family name to either a font file
path or another family name:
pdf = pres.to_pdf(font_map={"Calibri": "Helvetica"})font_map is keyword-only and defaults to None.
Degradation warnings
When a font is substituted, or when a shape uses a preset the renderer does not
yet draw, pptspine emits a Python warning through warnings.warn — one per
unique kind, not one per shape. Export never raises for these; it degrades and
warns. Suppress or capture them with the standard warnings module when
rendering decks in bulk.
import warnings
with warnings.catch_warnings():
warnings.simplefilter("ignore")
pdf = pres.to_pdf()What the renderer covers
| Feature | Support |
|---|---|
| Slide geometry | One page per slide at the exact slide size (EMU → pt). |
| Placeholder inheritance | ph capture resolved up the slideLayout → slideMaster chain. |
| Theme | clrScheme + clrMap / clrMapOvr, fontScheme (incl. east-Asian), p:style fill / line / font references. |
| Shape transforms | rot, flipH / flipV, avLst adjust values, dashed strokes, picture srcRect / stretch. |
| Groups | Nested group affine remap: (child − chOff) · (ext / chExt) + off. |
| Text bodies | bodyPr anchor / insets / wrap and normAutofit font-scale. A stored fontScale is applied as stored; when normAutofit is on but no scale was stored, the text is recomputed to fit — fontScale steps down (95% → 25%) and lnSpcReduction escalates (0 → 10 → 20%) until the measured content height fits its box. |
| Tables | Absolute cell x from tblGrid, per-side borders, fills, cell margins, anchoring. Row height is content-adaptive — each row grows to max(declared height, measured content height) so long cell text is not clipped; rowSpan cells distribute their content height evenly across the rows they span. |
| Backgrounds | Slide / layout / master bg solid and picture fills, bgRef via theme. |
| Text extraction | ToUnicode always written, so output is selectable and searchable. |
Rendering is deterministic per font environment: the same deck and the same installed fonts always produce the same PDF bytes.
On main, unreleased
These export changes are merged on main after 0.5.1 and are not yet on PyPI:
- Run-level
spc,baselineandcapare parsed, inherited throughtxStyles/lstStyle, exposed in the run dict (char_spacing_pt/baseline/cap) and rendered.cap="small"is approximated as all caps with a one-timesmall-capswarning. - Line ends
a:headEnd/a:tailEnd(triangle, stealth, diamond, oval, arrow; three sizes) are drawn on open outlines; unsupported kinds warn withline-end-degraded. a:custGeomis no longer silently drawn as a rectangle: it is approximated by its bounding box (connectors as a straight line) with acustom-geometry-approximatedwarning.
Decks that use none of these render byte-identical PDFs.