This release is a pre-release and may not be stable for production use.
gopptx
A PowerPoint (.pptx) engine written in Go, with a first-class Python API and a stable JSON command bridge.
gopptx creates, reads, edits and exports OOXML presentations. The engine is pure Go — no Microsoft Office, no LibreOffice and no headless browser is required to produce a valid deck. The Python package is a thin, typed layer over the same engine through a C shared library, so Python code runs at Go speed without reimplementing any logic.
from gopptx import Presentation
with Presentation.new("Quarterly Update") as pres:
pres.add_bullet_slide("Highlights", ["Revenue +12%", "Retention +4%"])
pres.save("deck.pptx")
Table of contents
- Why gopptx
- What it can do
- Installation
- Quickstart — Python
- Quickstart — Go
- Editing an existing deck
- Exporting to PDF and HTML
- Throughput and batching
- Architecture
- Documentation map
- Development
- License
Why gopptx
| One engine, two languages | The Go package and the Python package are the same code. Behaviour, validation and output bytes are identical. |
| No Office dependency for authoring | Decks are generated from OOXML primitives directly. Office is only needed if you choose the PowerPoint PDF driver. |
| Reads and writes | Most libraries do one or the other. gopptx opens an existing deck, walks its shape tree, edits in place and writes it back. |
| Batching for throughput | Write-heavy Python workloads cross the FFI boundary once per batch, not once per operation. |
| Validated output | validate() checks OPC package rules, part relationships and content types before you ship a file. repair() fixes what it can. |
What it can do
| Area | Capability |
|---|---|
| Slides | Add, insert, remove, move, duplicate, hide, copy between decks, merge decks, rebind layouts |
| Text | Runs with bold/italic/underline/strike/caps/sub/superscript, fonts, sizes, colours, highlight, paragraph alignment/indent/spacing, autofit, anchors, RTL and complex-script handling |
| Shapes | ~200 preset geometries, freeforms, groups, connectors (straight/elbow/curved, auto-routing), solid/gradient/pattern/picture fills, lines, shadows, glow, soft edges, rotation, flips, z-order |
| Tables | Row/column insert and remove, cell merge and split, widths and heights, borders, banding flags, built-in and custom table styles, load from rows or dicts |
| Charts | 24 chart types, combo charts, multiple charts per slide, an embedded Excel workbook so the data stays editable in PowerPoint, axes, legends, data labels, trendlines, error bars, per-point formatting |
| Images & media | Local files, bytes, base64, URLs, natural-size placement, crops, effects, video, audio, online video, OLE objects, media extraction |
| Diagrams | SmartArt (every layout PowerPoint offers, node-level edits, quick styles, colour styles) and native Mermaid rendering |
| Layouts & themes | Slide masters, layouts, placeholders and overrides, notes master, handout master, colour schemes, font schemes, built-in theme presets, grid/stack/distribute layout helpers |
| Deck metadata | Core and app document properties, sections, comments and authors, speaker notes, headers and footers, custom XML parts, VBA projects, digital-signature detection, mark-as-final, modify password |
| Motion | Slide transitions (including morph), entrance/emphasis/exit animations, slide-show settings and custom shows |
| Import | Markdown → slides, HTML → slides, URL fetch → slides, Jinja2-style templating |
| Export | PDF (native Go renderer, LibreOffice or PowerPoint COM), HTML, flat XML, grayscale conversion, package compression and size analysis |
Every area above has a runnable example under examples/ — 96 of them.
Installation
Prerequisites
| Requirement | |
|---|---|
| Go | 1.25 or later |
| Python | 3.10 or later (only for the Python package) |
| C toolchain | Required to build the shared library for Python (cgo) |
| Platforms | Windows, Linux, macOS |
Go
go get github.com/djinn-soul/gopptx
That is all — the Go package has no cgo requirement and no native dependency.
Python
The Python package calls into a Go shared library, which must be built first.
# Windows (PowerShell)
.\scripts\build_python.ps1
pip install -e .
# Linux / macOS
./scripts/build_python.sh
pip install -e .
Optionally install orjson for faster JSON encoding on the bridge:
pip install orjson
The library filename is platform-specific — gopptx.dll, libgopptx.so or libgopptx.dylib.
Set GOPPTX_LIB_PATH if you keep it outside the package directory. See
Installation for details and
Troubleshooting if the library is not found.
Quickstart — Python
Create a deck
from gopptx import ChartType, Inches, Presentation
with Presentation.new("Quarterly Update") as pres:
pres.add_bullet_slide("Highlights", ["Revenue +12%", "Retention +4%"])
slide = pres.add_slide("Numbers")
pres.add_table_from_rows(
slide.index,
[["Region", "Revenue"], ["EMEA", "4.1M"], ["APAC", "2.8M"]],
bounds=(Inches(0.5), Inches(1.5), Inches(4.0), Inches(2.0)),
)
pres.add_chart(
slide.index,
ChartType.COLUMN,
["Q1", "Q2", "Q3", "Q4"],
[12.0, 15.5, 18.0, 21.0],
bounds=(Inches(5.0), Inches(1.5), Inches(4.0), Inches(3.0)),
title="Quarterly trend",
)
pres.save("quarterly.pptx")
Four things worth knowing straight away:
- All geometry is in EMU (English Metric Units, 914 400 per inch). Raw numbers like
(40, 120, 600, 220)are 600 EMU wide — smaller than a pixel, and the shape will appear to be missing. Always wrap coordinates inInches(),Point()orEmu(). Presentationis a context manager. Leaving thewithblock releases the native handle;save()writes the file. Both are explicit — nothing is written implicitly.Presentation.new(title)already contains a title slide at index0. Your firstadd_slide()becomes slide1.- Pass a
ChartTypemember, not a bare string. Strings still work but are deprecated and will be rejected in a future release.
The object layer
Alongside the flat pres.* methods there is a navigable object layer:
with Presentation("deck.pptx") as pres:
for slide in pres.slides:
print(slide.index, slide.title, len(slide.list_shapes()))
first = pres.slides[0]
first.set_transition("fade")
first.notes = "Open with the revenue number."
Quickstart — Go
Generate a deck in one call
package main
import (
"os"
"github.com/djinn-soul/gopptx/pkg/pptx"
)
func main() {
slides := []pptx.SlideContent{
pptx.NewSlide("Hello from gopptx").AddBullet("Created with gopptx"),
}
data, err := pptx.CreateWithSlides("My Deck", slides)
if err != nil {
panic(err)
}
if err := os.WriteFile("output.pptx", data, 0o600); err != nil {
panic(err)
}
}
Build a deck fluently
SlideBuilder mutates in place, so a dropped return value cannot silently discard content —
unlike SlideContent's value-receiver methods.
package main
import "github.com/djinn-soul/gopptx/pkg/pptx"
func main() {
intro := pptx.NewSlideBuilder("Agenda")
intro.AddBullet("Results")
intro.AddBullet("Outlook")
intro.WithNotes("Keep this to two minutes.")
err := pptx.NewPresentationBuilder("Quarterly Update").
WithTheme(pptx.ThemeCorporate).
WithSlideSize(pptx.SlideSize16x9()).
AddTitleSlide("FY26 Q3").
AddSlide(intro.Build()).
WriteToFile("quarterly.pptx")
if err != nil {
panic(err)
}
}
See the Go library guide for shapes, charts, tables and layout helpers.
Editing an existing deck
Python
from gopptx import Presentation
with Presentation("input.pptx") as pres:
pres.set_slide_title(0, "Updated Title")
pres.find_and_replace("Draft", "Final")
pres.update_chart_data_by_index(
2,
0,
{"categories": ["Q1", "Q2"], "series": [{"name": "Revenue", "values": [10.0, 14.0]}]},
)
pres.save("edited.pptx")
Go
p, err := pptx.Open("input.pptx")
if err != nil {
panic(err)
}
defer p.Close()
p.SetTitle("Updated Title")
p.SetAuthor("Reporting Bot")
if err := p.SaveAs("edited.pptx"); err != nil {
panic(err)
}
pptx.Open returns a metadata-and-charts facade. For full shape-level editing use
pptx.OpenEditor(path), which returns the PresentationEditor that also backs the JSON bridge.
Exporting to PDF and HTML
from gopptx import HTMLOptions, PDFOptions, Presentation
with Presentation("deck.pptx") as pres:
pres.export_pdf("deck.pdf", PDFOptions(driver="auto"))
pres.export_html("deck.html", HTMLOptions(embed_images=True))
export_pdf is the current name; save_as_pdf remains as a deprecated alias. There are
three real drivers, plus auto which
picks between them:
| Driver | Requires | Notes |
|---|---|---|
auto (default) |
— | Tries LibreOffice, then PowerPoint, then falls back to native. Use this in production. |
native |
nothing | Pure Go renderer. No external process, works in containers. Still maturing on layout-heavy decks — it emits a warning. |
libreoffice |
soffice on PATH |
Highest general fidelity without Office. On Windows add C:\Program Files\LibreOffice\program to PATH. |
powerpoint |
Microsoft PowerPoint + PowerShell (Windows) | Ground truth for fidelity; used to grade the native renderer. |
Full detail in the export guide.
Throughput and batching
Every Python call crosses a Python → C → Go boundary. For write-heavy loops, batch them so the crossing happens once:
from gopptx import Presentation
with Presentation.new("Batch Demo") as pres:
with pres.batch(stop_on_error=True) as batch:
for i in range(500):
batch.add_slide(f"Slide {i}")
pres.save("batch.pptx")
Read operations are rejected inside a batch() block by design — a buffered write has not
executed yet, so a read would see stale state. Use execute_batch() with an explicit command
list when you need reads and writes interleaved. See
Batch execution.
Architecture
┌──────────────────────────────┐
│ python/gopptx │ typed Python API — Presentation, Slide, Shape, Table, Chart
│ (ctypes → JSON envelopes) │
└───────────────┬──────────────┘
│ JSON command envelope, 179 operations
┌───────────────▼──────────────┐
│ bindings/c │ handle-based C ABI (cgo, c-shared)
└───────────────┬──────────────┘
│
┌───────────────▼──────────────┐
│ pkg/pptx/editor │ command dispatch over a loaded presentation
│ pkg/pptx │ high-level Go API — builders, shapes, charts, tables, text
│ internal/pptxxml │ OOXML serialisation
└──────────────────────────────┘
The JSON envelope is a stable contract, so any language that can call a C function or shell out
to the CLI can drive the engine. Operation identifiers and payload shapes are defined in
pkg/pptx/editor/opspec.go; the Python constants in python/gopptx/_ops_constants.py are
generated from it. See Bridge operations.
Documentation map
Start here
| Page | What it covers |
|---|---|
| Installation | Go module, Python shared library, environment variables |
| Quickstart | First deck in both languages |
| Core concepts | Handles, sessions, the command envelope, batching, units |
Guides
| Page | What it covers |
|---|---|
| Python library | The full Python workflow, method by area |
| Go library | Builders, the editor, shapes, charts, layout helpers |
| Batch execution | Throughput patterns and their limits |
| Export | PDF drivers, HTML options, fidelity notes |
Reference
| Page | What it covers |
|---|---|
| API overview | The three surfaces and when to use each |
Python Presentation API |
All 208 methods, grouped |
| Go API | Packages, types and constructors |
| Bridge operations | All 179 JSON operations |
| Feature matrix | Honest comparison against python-pptx |
Examples
examples/— 96 runnable Go and Python programs- Showcase — 30 annotated recipes, simple → complex, with screenshots
Development
task build:go # build the C shared library for Python
task test # Go + Python test suites
task lint # golangci-lint, ruff, basedpyright, generated-code drift
task generate # regenerate everything derived from Go declarations
task docs:serve # MkDocs Material on http://localhost:8000
Parts of the Python surface — operation constants, chart-type and shape-type enums, the slide
builder — are generated from the Go declarations. Edit the Go source and run task generate;
never hand-edit the generated files. task check:generated fails the build if they drift.
See CONTRIBUTING.md for the full setup, code standards and PR checklist.
License
Apache License 2.0 — see LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gopptx-0.2.0a5-py3-none-win_amd64.whl.
File metadata
- Download URL: gopptx-0.2.0a5-py3-none-win_amd64.whl
- Upload date:
- Size: 8.4 MB
- Tags: Python 3, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
16a0c0162cc60b559c28ebc9c3d1e24c3b8140450185a21eb5e91835e556723d
|
|
| MD5 |
38ee81871809ab1827cb63d1cf860a6d
|
|
| BLAKE2b-256 |
a89b86fe06f985c3d9e61590647a7f96649c62bf69ef27aaebbddb92cf685162
|
File details
Details for the file gopptx-0.2.0a5-py3-none-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl.
File metadata
- Download URL: gopptx-0.2.0a5-py3-none-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl
- Upload date:
- Size: 8.8 MB
- Tags: Python 3, manylinux: glibc 2.17+ x86-64, manylinux: glibc 2.5+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
54f27668e308916e9ab636ee288448d8500ca3e448e741fb50e6208570e27d70
|
|
| MD5 |
c16966af549bb4aaca9468470b191bf2
|
|
| BLAKE2b-256 |
ae2c0a15a017ef03dbe28fa31ceb0c17533892d415b1fc95d86641fe3731ca23
|
File details
Details for the file gopptx-0.2.0a5-py3-none-macosx_10_13_universal2.whl.
File metadata
- Download URL: gopptx-0.2.0a5-py3-none-macosx_10_13_universal2.whl
- Upload date:
- Size: 7.7 MB
- Tags: Python 3, macOS 10.13+ universal2 (ARM64, x86-64)
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0061bf9269341dbcc3d535fd2e331b61267682975779851ff6a47a3c22105d72
|
|
| MD5 |
b863aa17a038ad21f8e578a04b3d7cd1
|
|
| BLAKE2b-256 |
d7a9487dc8a22fee3d47bb812bf3d7b00e72f16eddfaffa0befc4fe7b8166bc8
|