Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

gopptx

License: Apache 2.0 Go 1.25+ Python 3.10+

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

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 in Inches(), Point() or Emu().
  • Presentation is a context manager. Leaving the with block releases the native handle; save() writes the file. Both are explicit — nothing is written implicitly.
  • Presentation.new(title) already contains a title slide at index 0. Your first add_slide() becomes slide 1.
  • Pass a ChartType member, 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.

Metadata

Release files for gopptx 0.2.0a5

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

Built distributions (wheels)

Table of built distributions (wheels) for gopptx 0.2.0a5
File Interpreter ABI Platform
gopptx-0.2.0a5-py3-none-win_amd64.whl Python 3 none Windows x86-64 Details
gopptx-0.2.0a5-py3-none-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl Python 3 none Linux glibc 2.17+ x86-64, Linux glibc 2.5+ x86-64 Details
gopptx-0.2.0a5-py3-none-macosx_10_13_universal2.whl Python 3 none macOS 10.13+ universal2 (ARM64, x86-64) Details

Total release size: 25.0 MB

Release files / gopptx-0.2.0a5-py3-none-win_amd64.whl

Download URL gopptx-0.2.0a5-py3-none-win_amd64.whl
Size 8.4 MB
Tags Python 3 Windows x86-64
SHA-256 checksum
How to use checksums
16a0c0162cc60b559c28ebc9c3d1e24c3b8140450185a21eb5e91835e556723d
BLAKE2b-256 checksum
How to use checksums
a89b86fe06f985c3d9e61590647a7f96649c62bf69ef27aaebbddb92cf685162
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.14

Release files / gopptx-0.2.0a5-py3-none-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl

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
Size 8.8 MB
Tags Linux glibc 2.17+ x86-64 Linux glibc 2.5+ x86-64 Python 3
SHA-256 checksum
How to use checksums
54f27668e308916e9ab636ee288448d8500ca3e448e741fb50e6208570e27d70
BLAKE2b-256 checksum
How to use checksums
ae2c0a15a017ef03dbe28fa31ceb0c17533892d415b1fc95d86641fe3731ca23
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.14

Release files / gopptx-0.2.0a5-py3-none-macosx_10_13_universal2.whl

Download URL gopptx-0.2.0a5-py3-none-macosx_10_13_universal2.whl
Size 7.7 MB
Tags Python 3 macOS 10.13+ universal2 (ARM64, x86-64)
SHA-256 checksum
How to use checksums
0061bf9269341dbcc3d535fd2e331b61267682975779851ff6a47a3c22105d72
BLAKE2b-256 checksum
How to use checksums
d7a9487dc8a22fee3d47bb812bf3d7b00e72f16eddfaffa0befc4fe7b8166bc8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.1.0 CPython/3.13.14
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