A Go library for reading and writing Microsoft Office documents (PPTX, DOCX, XLSX) using the Open Packaging Conventions (OPC) standard.
- OPC Package Support: Low-level API for working with Open Packaging Convention packages
- Round-Trip Preservation: Byte-identical round-trip fidelity for unmodified parts across all formats
- PowerPoint (PPTX): Create and modify PowerPoint presentations
- Create presentations from scratch or from templates
- Add, remove, and reorder slides
- Work with slide masters and layouts
- Add shapes, text, tables, and images
- Auto shapes with solid/gradient fills, lines, and shadows
- Slide transitions (fade, push, wipe, and more)
- Support for placeholders and themes
- Word (DOCX): Create and modify Word documents
- Create documents from scratch
- Add headings, paragraphs, and tables
- Rich text formatting (bold, italic, color, font, size)
- Paragraph alignment, spacing, and indentation
- Bullet and numbered lists
- Headers and footers
- Inline images
- Page setup (size, margins)
- Excel (XLSX): Create and modify Excel workbooks
- Create workbooks with multiple sheets
- Read and write cell values (strings, numbers, booleans)
- Formula support
- Cell styling (fonts, fills, borders, number formats, alignment)
- Freeze panes, auto-filter, and data validation
- Merged cells and named ranges
- Column widths and row heights
go get github.com/mgilbir/spinepackage main
import (
"github.com/mgilbir/spine/common/dml"
"github.com/mgilbir/spine/pptx"
)
func main() {
// Create a new presentation
p := pptx.Create()
p.Properties.Title = "My Presentation"
p.Properties.Creator = "Author Name"
// Add a slide
slide := p.AddSlide()
slide.SetName("Introduction")
// Add a text box
textBox := slide.AddTextBox()
textBox.SetPosition(dml.Inches(1), dml.Inches(1))
textBox.SetSize(dml.Inches(8), dml.Inches(1))
textBox.SetText("Hello, World!")
// Save the presentation
if err := p.Save("presentation.pptx"); err != nil {
panic(err)
}
}package main
import (
"github.com/mgilbir/spine/docx"
)
func main() {
// Create a new document
doc := docx.Create()
doc.Properties.Title = "My Document"
// Add a heading
doc.AddHeading("Welcome", 1)
// Add a paragraph
doc.AddParagraphWithText("This is a simple document created with Spine.")
// Add formatted text
p := doc.AddParagraph()
bold := p.AddRun()
bold.SetText("Bold text")
bold.SetBold(true)
// Save the document
if err := doc.Save("document.docx"); err != nil {
panic(err)
}
}package main
import (
"fmt"
"github.com/mgilbir/spine/xlsx"
)
func main() {
// Create a new workbook
wb := xlsx.Create()
// Add a sheet
sheet := wb.AddSheet("Sales")
// Set cell values
sheet.SetCellValue("A1", "Product")
sheet.SetCellValue("B1", "Revenue")
sheet.SetCellValue("A2", "Widgets")
sheet.SetCellValue("B2", 1500.0)
sheet.SetCellValue("A3", "Gadgets")
sheet.SetCellValue("B3", 3200.0)
// Add a formula
cell, _ := sheet.Cell("B4")
cell.SetFormula("SUM(B2:B3)")
// Save the workbook
if err := wb.Save("spreadsheet.xlsx"); err != nil {
panic(err)
}
fmt.Printf("Sheets: %d\n", wb.SheetCount())
}package main
import (
"github.com/mgilbir/spine/pptx"
)
func main() {
// Open an existing presentation
p, err := pptx.Open("existing.pptx")
if err != nil {
panic(err)
}
defer p.Close()
// Modify properties
p.Properties.Title = "Updated Title"
// Add a new slide
p.AddSlide()
// Save to a new file
if err := p.SaveAs("modified.pptx"); err != nil {
panic(err)
}
}package main
import (
"github.com/mgilbir/spine/pptx"
)
func main() {
// Create a new presentation based on a template
// This preserves the template's masters, layouts, and themes
p, err := pptx.CreateFromTemplate("template.pptx")
if err != nil {
panic(err)
}
defer p.Close()
// Add slides using template layouts
layout := p.GetLayoutByType(pptx.LayoutTitleAndContent)
_ = p.AddSlideFromLayout(layout)
// Save the new presentation
if err := p.Save("from_template.pptx"); err != nil {
panic(err)
}
}opc/- Open Packaging Conventions implementationcommon/- Shared types and utilitiesdml/- DrawingML types (colors, geometry, fills, lines)chart/- Chart typesdiagram/- Diagram types
docprops/- Document properties (core and extended)enum/- Common enumerationsomml/- Office Math Markup Language typesoxml/- Shared Office XML typesvml/- Vector Markup Language typesxml/- XML namespace handling and Builder-based serialization
pptx/- PowerPoint document supportdocx/- Word document supportxlsx/- Excel document support
The library uses EMUs (English Metric Units) internally, which is the standard unit in Office Open XML. Helper functions are provided for common conversions:
import "github.com/mgilbir/spine/common/dml"
// Convert from inches to EMUs
width := dml.Inches(10.5)
// Convert from centimeters to EMUs
height := dml.Centimeters(5.0)
// Convert from points to EMUs
fontSize := dml.Points(12)The following standard slide layout types are supported:
| Type | Description |
|---|---|
LayoutTitle |
Title slide |
LayoutTitleAndContent |
Title and content |
LayoutSectionHeader |
Section header |
LayoutTwoContent |
Two content areas |
LayoutComparison |
Comparison layout |
LayoutTitleOnly |
Title only |
LayoutBlank |
Blank slide |
LayoutContentWithCaption |
Content with caption |
LayoutPictureWithCaption |
Picture with caption |
LayoutTitleAndVerticalText |
Title and vertical text |
LayoutVerticalTitleAndText |
Vertical title and text |
Unit tests run against both small synthetic fixtures (committed to git) and a set of real-world Office files sourced from the internet. The external files are used for round-trip compatibility testing: each file is parsed, serialized back, and compared byte-for-byte against the original.
External fixtures are not checked into the repository. To download them:
make fetchThis reads testdata/external.txt (a list of destination paths and URLs) and downloads any missing files. Use bash testdata/fetch.sh --force to re-download all of them.
To run the full test suite (fetches external files first):
make testTo lint:
make lint- Go 1.25 or later
MIT License - see LICENSE file for details.
Contributions are welcome! Please feel free to submit issues and pull requests.