Skip to main content

pptspine

PyPI

A pure-Rust PowerPoint (.pptx) parser with Python bindings (PyO3 / maturin, abi3-py311). A .pptx file is OOXML — a zip archive of XML parts — and pptspine walks that XML directly to produce a structured, information-preserving model: slides, text frames (paragraphs + styled runs), tables (cells, merges, fills), pictures, and autoshapes. A parsed deck can also be exported to PDF (to_pdf() / save_pdf(), one page per slide) through the shared pure-Rust pdf-typeset engine from the sibling pdfspine — no LibreOffice, no cloud converter. Embedded images can additionally be OCR'd locally, offline, and deterministically via the sibling ocrspine crate (PP-OCRv5 through tract-onnx — no cloud, no network).

Capabilities

Area Status
Slides + slide size parsed
Text frames: paragraphs, runs, text parsed
Run styling: font, size, bold, italic, solid-fill color parsed
Paragraph level + alignment parsed
Tables: rows, cells, cell text parsed
Table merges: gridSpan / rowSpan / hMerge / vMerge parsed
Cell solid-fill color parsed
Pictures: r:embed rel → media name; raw bytes via Presentation.image_bytes() parsed
Autoshapes: geometry name, fill, stroke, optional text parsed (best-effort)
Groups (p:grpSp): recursive parsed
Speaker notes (notesSlideSlide.notes) parsed
Structured export: to_text() / to_markdown() (GFM + HTML tables for merges) working
PDF export: to_pdf() / save_pdf() — one page per slide; placeholder/theme inheritance, shape transforms (rot/flip/adj/dash/srcRect), group affine, tables, slide backgrounds, body-anchor/autofit working
Image OCR (embedded pictures → words + boxes) working (ocr_image)
Image-table geometry reconstruction from OCR boxes deferred (stub)

Parsing is tolerant: unknown elements are skipped, missing attributes become None, and malformed input yields a typed PptError rather than a panic.

Install

pip install pptspine

pptspine is on PyPI. OCR works out of the box: the PP-OCRv5 weights ship in the shared ocrspine-models data package — a runtime dependency pip pulls in automatically — so the wheel itself ships no models. To build from source instead, see below.

Build (from the package root)

uv venv .venv
VIRTUAL_ENV="$(pwd)/.venv" uv pip install maturin pytest
# Structural parsing needs no models. The OCR path resolves models from
# ../ocrspine/models by default (or set OCRSPINE_MODELS).
OCRSPINE_MODELS="$(cd ../ocrspine && pwd)/models" \
  VIRTUAL_ENV="$(pwd)/.venv" .venv/bin/maturin develop --release

Use from Python

import pptspine

pres = pptspine.open("deck.pptx")
print(pres.slide_count, pres.slide_size)   # e.g. 2 (9144000, 6858000)  # EMU

for slide in pres.slides():
    for shape in slide.shapes():           # list[dict], introspectable
        if shape["kind"] == "text":
            for para in shape["paragraphs"]:
                for run in para["runs"]:
                    print(run["text"], run["bold"], run["color"])
        elif shape["kind"] == "table":
            for row in shape["rows"]:
                print([cell["text"] for cell in row])
        elif shape["kind"] == "picture":
            print("image:", shape["media"])

# Structured export + speaker notes:
print(pres.to_text())          # slides joined by "--- slide N ---"
print(pres.to_markdown())      # one section per slide; GFM / HTML tables
print(pres.slides()[0].text)   # all text on a slide (convenience)
print(pres.slides()[0].notes)  # speaker notes, or None

# Run OCR on raw image bytes (PNG/JPEG), offline:
items = pptspine.ocr_image(open("scan.png", "rb").read())
print(" ".join(i["text"] for i in items))

# End-to-end: pull an embedded image's bytes and OCR them, offline:
for shape in pres.slides()[0].shapes():
    if shape["kind"] == "picture" and shape["media"]:
        data = pres.image_bytes(shape["media"])   # bytes | None
        if data:
            print([i["text"] for i in pptspine.ocr_image(data)])

Export to PDF

pres = pptspine.open("deck.pptx")
pres.save_pdf("deck.pdf")          # one PDF page per slide
pdf_bytes = pres.to_pdf()          # or in-memory bytes

# Optional: map a requested font family to a local font file (or to another
# installed family), layered on top of the built-in substitution table:
pres.save_pdf("deck.pdf", font_map={"Aptos": "/path/to/Aptos.ttf"})

Rendering is deterministic and fully offline. Missing fonts degrade gracefully: an available face is substituted and a Python UserWarning is emitted once per warning kind — the export never fails on a missing font.

Rust workspace

crates/
  ppt-core    domain model + geometry (EMU) + typed PptError. No IO/zip/XML.
  ppt-parse   OOXML reader: zip extract + quick-xml walk -> Presentation.
  ppt-ocr     image-OCR bridge over ocrspine (PaddleOcr).
  ppt-render  slide -> PDF renderer over the shared pdf-typeset engine (from pdfspine).
  py-bindings PyO3 _core extension (the FFI chokepoint).

Deferred / follow-up

  • Image-table geometry reconstruction from OCR boxes (ppt_ocr::reconstruct_table_from_image, currently a typed Unsupported stub).
  • Richer color models (gradients), hyperlinks, charts, SmartArt, comments.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pptspine-0.5.0.tar.gz (139.0 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

pptspine-0.5.0-cp311-abi3-win_amd64.whl (10.5 MB view details)

Uploaded CPython 3.11+Windows x86-64

pptspine-0.5.0-cp311-abi3-manylinux_2_28_aarch64.whl (9.5 MB view details)

Uploaded CPython 3.11+manylinux: glibc 2.28+ ARM64

pptspine-0.5.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (10.5 MB view details)

Uploaded CPython 3.11+manylinux: glibc 2.17+ x86-64

pptspine-0.5.0-cp311-abi3-macosx_11_0_arm64.whl (9.3 MB view details)

Uploaded CPython 3.11+macOS 11.0+ ARM64

pptspine-0.5.0-cp311-abi3-macosx_10_12_x86_64.whl (10.1 MB view details)

Uploaded CPython 3.11+macOS 10.12+ x86-64

File details

Details for the file pptspine-0.5.0.tar.gz.

File metadata

  • Download URL: pptspine-0.5.0.tar.gz
  • Upload date:
  • Size: 139.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for pptspine-0.5.0.tar.gz
Algorithm Hash digest
SHA256 964c2e0eb704b19b49ff7486eddfc44dcfd64f21d2a2a0141a6bfcdaab4b3970
MD5 869b1e08e90f4264a854f056e3222f47
BLAKE2b-256 84b66e3896975de1330916f2d9c059bc901f2d8fba421fed92ff33536d8852f9

See more details on using hashes here.

File details

Details for the file pptspine-0.5.0-cp311-abi3-win_amd64.whl.

File metadata

  • Download URL: pptspine-0.5.0-cp311-abi3-win_amd64.whl
  • Upload date:
  • Size: 10.5 MB
  • Tags: CPython 3.11+, Windows x86-64
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for pptspine-0.5.0-cp311-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 bbeff03afe7e23160428802f734deda745d8a43e034c3e0abadd9d06e53f7da9
MD5 3fb40e1c13b7a093f6524b8fca374c7e
BLAKE2b-256 c8991d53bfce37006ce62f53b180e247ba6fdf4a28f48085f832dd8aa1847aaa

See more details on using hashes here.

File details

Details for the file pptspine-0.5.0-cp311-abi3-manylinux_2_28_aarch64.whl.

File metadata

File hashes

Hashes for pptspine-0.5.0-cp311-abi3-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 f6e4f584277dc82fee6a830a94ee4a7ea5afe662f94d64846e3f118e3dedc1d2
MD5 64b7eecb8adb168ea9b98cdc2e8d216f
BLAKE2b-256 46865e53ee8f25fc8366bc402e0e04a420c8d04f66b42472e33433c9b0204bd8

See more details on using hashes here.

File details

Details for the file pptspine-0.5.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for pptspine-0.5.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 87bb966ac6fe1ac67f8a095d141701787d0c904ed73e172db26b55f2a6844c77
MD5 7ac2d6c4a6dcec3a84aab7f91219727c
BLAKE2b-256 81cf14eadbfbabdd8b52982673f72e59ae9cad14e4b96828de8b193619e0fc37

See more details on using hashes here.

File details

Details for the file pptspine-0.5.0-cp311-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for pptspine-0.5.0-cp311-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 d0c60e2fd5df246f6f338ebb35f2187d8647279de68be35688d482db90fed089
MD5 edfa305651f5b7234f43871faf1e12d4
BLAKE2b-256 9b06be1cf6f3c8b68a504bccef17c74b67c420992957071411209f05857b4362

See more details on using hashes here.

File details

Details for the file pptspine-0.5.0-cp311-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for pptspine-0.5.0-cp311-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 f7f8a3104c72310d3362028aeb316e4835893736594a195aa11e4590ae1962d1
MD5 699976037e80bce042f2a52e3dcd9d6d
BLAKE2b-256 349ae12f647eb980caf340730c04abcccb9aef554171d2378022fa3d0ad33c46

See more details on using hashes here.

Release history Release notifications | RSS feed

0.5.1

6 files

This release

0.5.0 This release

6 files

0.4.0

6 files

0.3.0

6 files

0.2.0

6 files

0.1.1

6 files

0.1.0

5 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page