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.1.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.1-cp311-abi3-win_amd64.whl (10.5 MB view details)

Uploaded CPython 3.11+Windows x86-64

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

Uploaded CPython 3.11+manylinux: glibc 2.28+ ARM64

pptspine-0.5.1-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.1-cp311-abi3-macosx_11_0_arm64.whl (9.3 MB view details)

Uploaded CPython 3.11+macOS 11.0+ ARM64

pptspine-0.5.1-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.1.tar.gz.

File metadata

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

File hashes

Hashes for pptspine-0.5.1.tar.gz
Algorithm Hash digest
SHA256 ca7677f82db4d7c30e4218b55f2125d016f68e0af2c7ab07b18b8de97c233a2a
MD5 225b5af9f3c0f210ccc5a67f51765b28
BLAKE2b-256 b3bbd675a4fd043c37ba08e0479135e36a944e63b5f7c003b8fdc8fb25324001

See more details on using hashes here.

File details

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

File metadata

  • Download URL: pptspine-0.5.1-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/7.0.0 CPython/3.13.14

File hashes

Hashes for pptspine-0.5.1-cp311-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 0e28f808dc95245a19ab92806684b830a2c7cc2ac531d0d656d4591d44044840
MD5 3fbc5b003e394069af79abea780a062b
BLAKE2b-256 a96cb8ab0e0a4adcfd51be917792167ce45b891dd9a383d7e817989641cd403e

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pptspine-0.5.1-cp311-abi3-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 39a4712b2dcafa92154ff38d320029a521ec93f3d27573ba93bdc1e53726b1f7
MD5 96cbde96869ada7962018152a087a823
BLAKE2b-256 a1d6d78a4e25eb8796240fa7689ffd8c7edda2e8cb14200447134db89a805e1b

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pptspine-0.5.1-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 066780bcbeec871655e570f66e2429bd3f31ea07619d13bbc583da125991fd86
MD5 ff77b58095b5d69c373a06da731ae947
BLAKE2b-256 0e9461250946bf6bfb8751ed5764a637bff06170752ba65e480f0ee1794a3f84

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pptspine-0.5.1-cp311-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 abe887d2104aaaa129e7938dce0d122f49bcedf5d7c6c1a0f741025813fa8d34
MD5 28f8a08f37277239025090c4e191f732
BLAKE2b-256 07e5c69abd8917bf92dd62f989b5cbedbb1aed58a78726ff51c1c3ab00b3ec89

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pptspine-0.5.1-cp311-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 c0ef3c6951ff5d5e20931d30ad656b105187c9a12e02d51d8ed7483f4d9d3f2d
MD5 a8eee2f1cdaf0766f132a29c26bd1461
BLAKE2b-256 5ee567bb5329c34b724d29f3b20612c9f92807406a2e004486fae42f9014936c

See more details on using hashes here.

Release history Release notifications | RSS feed

This release

0.5.1 This release

6 files

0.5.0

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