d2/lib/pptx/pptx.go

183 lines
4.4 KiB
Go
Raw Normal View History

2023-04-05 18:34:50 +00:00
package pptx
2023-04-04 14:13:47 +00:00
import (
"archive/zip"
"bytes"
_ "embed"
"fmt"
"strings"
2023-04-10 18:45:10 +00:00
"text/template"
2023-04-04 14:13:47 +00:00
)
2023-04-10 14:45:04 +00:00
// Measurements in OOXML are made in English Metric Units (EMUs) where 1 inch = 914,400 EMUs
// The intent is to have a measurement unit that doesn't require floating points when dealing with centimeters, inches, points (DPI).
2023-04-04 14:13:47 +00:00
// Office Open XML (OOXML) http://officeopenxml.com/prPresentation.php
2023-04-10 14:45:04 +00:00
// https://startbigthinksmall.wordpress.com/2010/01/04/points-inches-and-emus-measuring-units-in-office-open-xml/
const SLIDE_WIDTH = 9_144_000
const SLIDE_HEIGHT = 5_143_500
const HEADER_HEIGHT = 392_471
const IMAGE_HEIGHT = SLIDE_HEIGHT - HEADER_HEIGHT
// keep the right aspect ratio: SLIDE_WIDTH / SLIDE_HEIGHT = IMAGE_WIDTH / IMAGE_HEIGHT
const IMAGE_WIDTH = 8_446_273
const IMAGE_ASPECT_RATIO = float64(IMAGE_WIDTH) / float64(IMAGE_HEIGHT)
2023-04-04 14:13:47 +00:00
//go:embed template.pptx
2023-04-10 16:49:30 +00:00
var PPTX_TEMPLATE []byte
2023-04-04 14:13:47 +00:00
func copyPptxTemplateTo(w *zip.Writer) error {
2023-04-10 16:49:30 +00:00
reader := bytes.NewReader(PPTX_TEMPLATE)
2023-04-04 14:13:47 +00:00
zipReader, err := zip.NewReader(reader, reader.Size())
if err != nil {
2023-04-06 18:16:32 +00:00
fmt.Printf("error creating zip reader: %v", err)
2023-04-04 14:13:47 +00:00
}
for _, f := range zipReader.File {
2023-04-06 18:16:32 +00:00
if err := w.Copy(f); err != nil {
return fmt.Errorf("error copying %s: %v", f.Name, err)
2023-04-04 14:13:47 +00:00
}
}
return nil
}
2023-04-10 16:49:30 +00:00
//go:embed templates/slide.xml.rels
var RELS_SLIDE_XML string
2023-04-04 14:13:47 +00:00
2023-04-10 18:45:10 +00:00
type RelsSlideXmlContent struct {
FileName string
RelationshipID string
2023-04-04 14:13:47 +00:00
}
2023-04-10 16:49:30 +00:00
//go:embed templates/slide.xml
var SLIDE_XML string
2023-04-04 14:13:47 +00:00
2023-04-10 18:45:10 +00:00
type SlideXmlContent struct {
Title string
TitlePrefix string
Description string
HeaderHeight int
ImageID string
ImageLeft int
ImageTop int
ImageWidth int
ImageHeight int
}
func getSlideXmlContent(imageID string, slide *Slide) SlideXmlContent {
boardPath := slide.BoardPath
2023-04-05 14:40:21 +00:00
boardName := boardPath[len(boardPath)-1]
prefixPath := boardPath[:len(boardPath)-1]
2023-04-10 18:45:10 +00:00
var prefix string
2023-04-05 14:40:21 +00:00
if len(prefixPath) > 0 {
2023-04-10 18:45:10 +00:00
prefix = strings.Join(prefixPath, " / ") + " / "
}
return SlideXmlContent{
Title: boardName,
TitlePrefix: prefix,
Description: strings.Join(boardPath, " / "),
HeaderHeight: HEADER_HEIGHT,
ImageID: imageID,
ImageLeft: slide.ImageLeft,
ImageTop: slide.ImageTop + HEADER_HEIGHT,
ImageWidth: slide.ImageWidth,
ImageHeight: slide.ImageHeight,
2023-04-05 14:40:21 +00:00
}
2023-04-04 14:13:47 +00:00
}
2023-04-10 16:49:30 +00:00
//go:embed templates/rels_presentation.xml
var RELS_PRESENTATION_XML string
2023-04-10 18:45:10 +00:00
type RelsPresentationSlideXmlContent struct {
RelationshipID string
FileName string
}
type RelsPresentationXmlContent struct {
Slides []RelsPresentationSlideXmlContent
}
func getRelsPresentationXmlContent(slideFileNames []string) RelsPresentationXmlContent {
var content RelsPresentationXmlContent
2023-04-04 14:13:47 +00:00
for _, name := range slideFileNames {
2023-04-10 18:45:10 +00:00
content.Slides = append(content.Slides, RelsPresentationSlideXmlContent{
RelationshipID: name,
FileName: name,
})
2023-04-04 14:13:47 +00:00
}
2023-04-10 18:45:10 +00:00
return content
2023-04-04 14:13:47 +00:00
}
2023-04-10 16:49:30 +00:00
//go:embed templates/content_types.xml
var CONTENT_TYPES_XML string
2023-04-10 18:45:10 +00:00
type ContentTypesXmlContent struct {
FileNames []string
2023-04-04 14:13:47 +00:00
}
2023-04-10 16:49:30 +00:00
//go:embed templates/presentation.xml
var PRESENTATION_XML string
2023-04-10 18:45:10 +00:00
type PresentationSlideXmlContent struct {
ID int
RelationshipID string
}
type PresentationXmlContent struct {
SlideWidth int
SlideHeight int
Slides []PresentationSlideXmlContent
}
func getPresentationXmlContent(slideFileNames []string) PresentationXmlContent {
content := PresentationXmlContent{
SlideWidth: SLIDE_WIDTH,
SlideHeight: SLIDE_HEIGHT,
}
2023-04-04 14:13:47 +00:00
for i, name := range slideFileNames {
2023-04-10 18:45:10 +00:00
content.Slides = append(content.Slides, PresentationSlideXmlContent{
// in the exported presentation, the first slide ID was 256, so keeping it here for compatibility
ID: 256 + i,
RelationshipID: name,
})
2023-04-04 14:13:47 +00:00
}
2023-04-10 18:45:10 +00:00
return content
2023-04-04 14:13:47 +00:00
}
2023-04-05 18:22:12 +00:00
2023-04-10 16:49:30 +00:00
//go:embed templates/core.xml
var CORE_XML string
2023-04-05 18:22:12 +00:00
2023-04-10 18:45:10 +00:00
type CoreXmlContent struct {
Title string
Subject string
Creator string
Description string
LastModifiedBy string
Created string
Modified string
2023-04-05 18:22:12 +00:00
}
2023-04-10 16:49:30 +00:00
//go:embed templates/app.xml
var APP_XML string
2023-04-10 18:45:10 +00:00
type AppXmlContent struct {
SlideCount int
TitlesOfPartsCount int
Titles []string
D2Version string
}
func addFileFromTemplate(zipFile *zip.Writer, filePath, templateContent string, templateData interface{}) error {
w, err := zipFile.Create(filePath)
if err != nil {
return err
}
tmpl, err := template.New(filePath).Parse(templateContent)
if err != nil {
return err
2023-04-06 14:01:44 +00:00
}
2023-04-10 18:45:10 +00:00
return tmpl.Execute(w, templateData)
2023-04-05 18:22:12 +00:00
}