Skip to main content

Pure-Rust PowerPoint (.pptx / OOXML) structural parser with local image OCR, via PyO3.

Project description

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 (theme/scheme colors, gradients), hyperlinks, charts, SmartArt, comments.

Project details


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.2.0.tar.gz (129.5 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.2.0-cp311-abi3-win_amd64.whl (10.4 MB view details)

Uploaded CPython 3.11+Windows x86-64

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

Uploaded CPython 3.11+manylinux: glibc 2.28+ ARM64

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

Uploaded CPython 3.11+macOS 11.0+ ARM64

pptspine-0.2.0-cp311-abi3-macosx_10_12_x86_64.whl (10.9 MB view details)

Uploaded CPython 3.11+macOS 10.12+ x86-64

File details

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

File metadata

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

File hashes

Hashes for pptspine-0.2.0.tar.gz
Algorithm Hash digest
SHA256 a5b07747a23116f2f5a62720349ae1c7bf54d7f7b49df878c1e7903250b353cc
MD5 503ea37ac9c82d6b47fbb132e892c375
BLAKE2b-256 045b4fb0fc5008efaf77bde6fb95779f38e02b2fc524e13a4c0a3d2c91efdbd2

See more details on using hashes here.

File details

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

File metadata

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

File hashes

Hashes for pptspine-0.2.0-cp311-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 9997247864174f81d88aff720994f70e58db063a00b1bea5e7c7681874c1486c
MD5 624129891831159b7deb5a882637fffd
BLAKE2b-256 4bae38d6e588550d1ca163206e2360b1881087563e8190118f4d29b1eedf0e14

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pptspine-0.2.0-cp311-abi3-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 e9f30813e224ae4c14bf00bc2f486073482fd8859e16d49d0ede24ba2e810c5b
MD5 12e860267cc966fb6f6ff1803a07f22e
BLAKE2b-256 bdd10b9ad9284821b2cc522cc165b55f610e1ceba1602d051e14315719cab865

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pptspine-0.2.0-cp311-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 eb4f9faff2421020a3afe1c077e8ace3cd24b559b2cab49651fd14e19c077ac2
MD5 c34729ba2bc0832b32646dcd37d162b4
BLAKE2b-256 12557783b0db7064b280b6fef4c124fb81272e7d66b4c0fa3274ca6fc945b6e3

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pptspine-0.2.0-cp311-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 bd1e997e78896cb542d002a09842f2e6e7a8485ccab19beaf529c25d7c39e80f
MD5 705833add02bf4833e86d9222e3ab6fe
BLAKE2b-256 14baf4714a06476c24ed1d75ccf60bc459ea2ec6670ceb81b040f8b58f3d4c89

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for pptspine-0.2.0-cp311-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 799eed1dcd53683d4067b8b652d3d95b5bf33ca703c3b405f2ad49c69da484aa
MD5 34a238e25cc70259d30dc100bdbb8a6f
BLAKE2b-256 fa3f020de4fe5c11ba252a6a16d3c23ca68163e38922d390ccc75024ed0ae79e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page