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 (notesSlide → Slide.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.

Metadata

Release files for pptspine 0.5.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for pptspine 0.5.1
File Size Uploaded
pptspine-0.5.1.tar.gz 139.0 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for pptspine 0.5.1
File
pptspine-0.5.1-cp311-abi3-win_amd64.whl CPython 3.11 abi3 Windows x86-64 Details
pptspine-0.5.1-cp311-abi3-manylinux_2_28_aarch64.whl CPython 3.11 abi3 Linux glibc 2.28+ ARM64 Details
pptspine-0.5.1-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl CPython 3.11 abi3 Linux glibc 2.17+ x86-64 Details
pptspine-0.5.1-cp311-abi3-macosx_11_0_arm64.whl CPython 3.11 abi3 macOS 11.0+ ARM64 Details
pptspine-0.5.1-cp311-abi3-macosx_10_12_x86_64.whl CPython 3.11 abi3 macOS 10.12+ x86-64 Details

Total release size: 50.0 MB

Release files / pptspine-0.5.1.tar.gz

Download URL pptspine-0.5.1.tar.gz
Size 139.0 kB
Tags Source
SHA-256 checksum
How to use checksums
ca7677f82db4d7c30e4218b55f2125d016f68e0af2c7ab07b18b8de97c233a2a
BLAKE2b-256 checksum
How to use checksums
b3bbd675a4fd043c37ba08e0479135e36a944e63b5f7c003b8fdc8fb25324001
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / pptspine-0.5.1-cp311-abi3-win_amd64.whl

Download URL pptspine-0.5.1-cp311-abi3-win_amd64.whl
Size 10.5 MB
Tags CPython 3.11 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
0e28f808dc95245a19ab92806684b830a2c7cc2ac531d0d656d4591d44044840
BLAKE2b-256 checksum
How to use checksums
a96cb8ab0e0a4adcfd51be917792167ce45b891dd9a383d7e817989641cd403e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / pptspine-0.5.1-cp311-abi3-manylinux_2_28_aarch64.whl

Download URL pptspine-0.5.1-cp311-abi3-manylinux_2_28_aarch64.whl
Size 9.5 MB
Tags CPython 3.11 Linux glibc 2.28+ ARM64 abi3
SHA-256 checksum
How to use checksums
39a4712b2dcafa92154ff38d320029a521ec93f3d27573ba93bdc1e53726b1f7
BLAKE2b-256 checksum
How to use checksums
a1d6d78a4e25eb8796240fa7689ffd8c7edda2e8cb14200447134db89a805e1b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / pptspine-0.5.1-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl

Download URL pptspine-0.5.1-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Size 10.5 MB
Tags CPython 3.11 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
066780bcbeec871655e570f66e2429bd3f31ea07619d13bbc583da125991fd86
BLAKE2b-256 checksum
How to use checksums
0e9461250946bf6bfb8751ed5764a637bff06170752ba65e480f0ee1794a3f84
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / pptspine-0.5.1-cp311-abi3-macosx_11_0_arm64.whl

Download URL pptspine-0.5.1-cp311-abi3-macosx_11_0_arm64.whl
Size 9.3 MB
Tags CPython 3.11 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
abe887d2104aaaa129e7938dce0d122f49bcedf5d7c6c1a0f741025813fa8d34
BLAKE2b-256 checksum
How to use checksums
07e5c69abd8917bf92dd62f989b5cbedbb1aed58a78726ff51c1c3ab00b3ec89
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / pptspine-0.5.1-cp311-abi3-macosx_10_12_x86_64.whl

Download URL pptspine-0.5.1-cp311-abi3-macosx_10_12_x86_64.whl
Size 10.1 MB
Tags CPython 3.11 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
c0ef3c6951ff5d5e20931d30ad656b105187c9a12e02d51d8ed7483f4d9d3f2d
BLAKE2b-256 checksum
How to use checksums
5ee567bb5329c34b724d29f3b20612c9f92807406a2e004486fae42f9014936c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

This release

0.5.1 This release

6 release files

0.5.0

6 release files

0.4.0

6 release files

0.3.0

6 release files

0.2.0

6 release files

0.1.1

6 release files

0.1.0

5 release 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