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.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

gopptx-0.2.0a5-py3-none-win_amd64.whl (8.4 MB view details)

Uploaded Python 3Windows x86-64

gopptx-0.2.0a5-py3-none-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl (8.8 MB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64manylinux: glibc 2.5+ x86-64

gopptx-0.2.0a5-py3-none-macosx_10_13_universal2.whl (7.7 MB view details)

Uploaded Python 3macOS 10.13+ universal2 (ARM64, x86-64)

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

Hashes for gopptx-0.2.0a5-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 16a0c0162cc60b559c28ebc9c3d1e24c3b8140450185a21eb5e91835e556723d
MD5 38ee81871809ab1827cb63d1cf860a6d
BLAKE2b-256 a89b86fe06f985c3d9e61590647a7f96649c62bf69ef27aaebbddb92cf685162

See more details on using hashes here.

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

File hashes

Hashes for gopptx-0.2.0a5-py3-none-manylinux1_x86_64.manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_5_x86_64.whl
Algorithm Hash digest
SHA256 54f27668e308916e9ab636ee288448d8500ca3e448e741fb50e6208570e27d70
MD5 c16966af549bb4aaca9468470b191bf2
BLAKE2b-256 ae2c0a15a017ef03dbe28fa31ceb0c17533892d415b1fc95d86641fe3731ca23

See more details on using hashes here.

File details

Details for the file gopptx-0.2.0a5-py3-none-macosx_10_13_universal2.whl.

File metadata

File hashes

Hashes for gopptx-0.2.0a5-py3-none-macosx_10_13_universal2.whl
Algorithm Hash digest
SHA256 0061bf9269341dbcc3d535fd2e331b61267682975779851ff6a47a3c22105d72
MD5 b863aa17a038ad21f8e578a04b3d7cd1
BLAKE2b-256 d7a9487dc8a22fee3d47bb812bf3d7b00e72f16eddfaffa0befc4fe7b8166bc8

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