diff --git a/lib/pptx/pptx.go b/lib/pptx/pptx.go index 349d09393..897720e75 100644 --- a/lib/pptx/pptx.go +++ b/lib/pptx/pptx.go @@ -6,7 +6,7 @@ import ( _ "embed" "fmt" "strings" - "time" + "text/template" ) // Measurements in OOXML are made in English Metric Units (EMUs) where 1 inch = 914,400 EMUs @@ -41,111 +41,142 @@ func copyPptxTemplateTo(w *zip.Writer) error { return nil } -func addFile(zipFile *zip.Writer, filePath, content string) error { - w, err := zipFile.Create(filePath) - if err != nil { - return err - } - w.Write([]byte(content)) - return nil -} - //go:embed templates/slide.xml.rels var RELS_SLIDE_XML string -func getRelsSlideXml(imageID string) string { - return fmt.Sprintf(RELS_SLIDE_XML, imageID, imageID) +type RelsSlideXmlContent struct { + FileName string + RelationshipID string } //go:embed templates/slide.xml var SLIDE_XML string -func getSlideXml(boardPath []string, imageID string, top, left, width, height int) string { - var slideTitle string +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 boardName := boardPath[len(boardPath)-1] prefixPath := boardPath[:len(boardPath)-1] + var prefix string if len(prefixPath) > 0 { - prefix := strings.Join(prefixPath, " / ") + " / " - slideTitle = fmt.Sprintf(`%s%s`, prefix, boardName) - } else { - slideTitle = fmt.Sprintf(`%s`, boardName) + 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, } - slideDescription := strings.Join(boardPath, " / ") - top += HEADER_HEIGHT - return fmt.Sprintf(SLIDE_XML, slideDescription, slideDescription, imageID, left, top, width, height, slideDescription, HEADER_HEIGHT, slideTitle) } //go:embed templates/rels_presentation.xml var RELS_PRESENTATION_XML string -func getPresentationXmlRels(slideFileNames []string) string { - var builder strings.Builder +type RelsPresentationSlideXmlContent struct { + RelationshipID string + FileName string +} + +type RelsPresentationXmlContent struct { + Slides []RelsPresentationSlideXmlContent +} + +func getRelsPresentationXmlContent(slideFileNames []string) RelsPresentationXmlContent { + var content RelsPresentationXmlContent for _, name := range slideFileNames { - builder.WriteString(fmt.Sprintf( - ``, name, name, - )) + content.Slides = append(content.Slides, RelsPresentationSlideXmlContent{ + RelationshipID: name, + FileName: name, + }) } - return fmt.Sprintf(RELS_PRESENTATION_XML, builder.String()) + return content } //go:embed templates/content_types.xml var CONTENT_TYPES_XML string -func getContentTypesXml(slideFileNames []string) string { - var builder strings.Builder - for _, name := range slideFileNames { - builder.WriteString(fmt.Sprintf( - ``, name, - )) - } - - return fmt.Sprintf(CONTENT_TYPES_XML, builder.String()) +type ContentTypesXmlContent struct { + FileNames []string } //go:embed templates/presentation.xml var PRESENTATION_XML string -func getPresentationXml(slideFileNames []string) string { - var builder strings.Builder - for i, name := range slideFileNames { - // in the exported presentation, the first slide ID was 256, so keeping it here for compatibility - builder.WriteString(fmt.Sprintf(``, 256+i, name)) +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, } - return fmt.Sprintf(PRESENTATION_XML, builder.String(), SLIDE_WIDTH, SLIDE_HEIGHT) + for i, name := range slideFileNames { + 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, + }) + } + return content } //go:embed templates/core.xml var CORE_XML string -func getCoreXml(title, subject, description, creator string) string { - dateTime := time.Now().Format(time.RFC3339) - return fmt.Sprintf( - CORE_XML, - title, - subject, - creator, - description, - creator, - dateTime, - dateTime, - ) +type CoreXmlContent struct { + Title string + Subject string + Creator string + Description string + LastModifiedBy string + Created string + Modified string } //go:embed templates/app.xml var APP_XML string -func getAppXml(slides []*Slide, d2version string) string { - var builder strings.Builder - for _, slide := range slides { - builder.WriteString(fmt.Sprintf(`%s`, strings.Join(slide.BoardPath, "/"))) - } - return fmt.Sprintf( - APP_XML, - len(slides), - len(slides), - len(slides)+3, // number of entries, len(slides) + Office Theme + 2 Fonts - builder.String(), - d2version, - ) +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 + } + return tmpl.Execute(w, templateData) } diff --git a/lib/pptx/presentation.go b/lib/pptx/presentation.go index fea845fd5..43f3522da 100644 --- a/lib/pptx/presentation.go +++ b/lib/pptx/presentation.go @@ -16,6 +16,8 @@ import ( "fmt" "image/png" "os" + "strings" + "time" ) type Presentation struct { @@ -142,42 +144,61 @@ func (p *Presentation) SaveTo(filePath string) error { return err } - err = addFile(zipWriter, fmt.Sprintf("ppt/slides/_rels/%s.xml.rels", slideFileName), getRelsSlideXml(imageID)) + err = addFileFromTemplate(zipWriter, fmt.Sprintf("ppt/slides/_rels/%s.xml.rels", slideFileName), RELS_SLIDE_XML, RelsSlideXmlContent{ + FileName: imageID, + RelationshipID: imageID, + }) if err != nil { return err } - err = addFile( - zipWriter, - fmt.Sprintf("ppt/slides/%s.xml", slideFileName), - getSlideXml(slide.BoardPath, imageID, slide.ImageTop, slide.ImageLeft, slide.ImageWidth, slide.ImageHeight), - ) + err = addFileFromTemplate(zipWriter, fmt.Sprintf("ppt/slides/%s.xml", slideFileName), SLIDE_XML, getSlideXmlContent(imageID, slide)) if err != nil { return err } } - err = addFile(zipWriter, "[Content_Types].xml", getContentTypesXml(slideFileNames)) + err = addFileFromTemplate(zipWriter, "[Content_Types].xml", CONTENT_TYPES_XML, ContentTypesXmlContent{ + FileNames: slideFileNames, + }) if err != nil { return err } - err = addFile(zipWriter, "ppt/_rels/presentation.xml.rels", getPresentationXmlRels(slideFileNames)) + err = addFileFromTemplate(zipWriter, "ppt/_rels/presentation.xml.rels", RELS_PRESENTATION_XML, getRelsPresentationXmlContent(slideFileNames)) if err != nil { return err } - err = addFile(zipWriter, "ppt/presentation.xml", getPresentationXml(slideFileNames)) + err = addFileFromTemplate(zipWriter, "ppt/presentation.xml", PRESENTATION_XML, getPresentationXmlContent(slideFileNames)) if err != nil { return err } - err = addFile(zipWriter, "docProps/core.xml", getCoreXml(p.Title, p.Subject, p.Description, p.Creator)) + dateTime := time.Now().Format(time.RFC3339) + err = addFileFromTemplate(zipWriter, "docProps/core.xml", CORE_XML, CoreXmlContent{ + Creator: p.Creator, + Subject: p.Subject, + Description: p.Description, + LastModifiedBy: p.Creator, + Title: p.Title, + Created: dateTime, + Modified: dateTime, + }) if err != nil { return err } - err = addFile(zipWriter, "docProps/app.xml", getAppXml(p.Slides, p.D2Version)) + titles := make([]string, 0, len(p.Slides)) + for _, slide := range p.Slides { + titles = append(titles, strings.Join(slide.BoardPath, "/")) + } + err = addFileFromTemplate(zipWriter, "docProps/app.xml", APP_XML, AppXmlContent{ + SlideCount: len(p.Slides), + TitlesOfPartsCount: len(p.Slides) + 3, + D2Version: p.D2Version, + Titles: titles, + }) if err != nil { return err } diff --git a/lib/pptx/templates/app.xml b/lib/pptx/templates/app.xml index 0400cf42f..ada0cf3db 100644 --- a/lib/pptx/templates/app.xml +++ b/lib/pptx/templates/app.xml @@ -4,9 +4,9 @@ 1 0 D2 - On-screen Show (4:3) + On-screen Show (16:9) 0 - %d + {{.SlideCount}} 0 0 0 @@ -29,23 +29,23 @@ Slide Titles - %d + {{.SlideCount}} - + Arial Calibri Office Theme - %s + {{range .Titles}} + {{.}} + {{end}} - - false false false - %s + {{.D2Version}} \ No newline at end of file diff --git a/lib/pptx/templates/content_types.xml b/lib/pptx/templates/content_types.xml index 2a1b29ed7..6d6106c76 100644 --- a/lib/pptx/templates/content_types.xml +++ b/lib/pptx/templates/content_types.xml @@ -54,7 +54,9 @@ - %s + {{range .FileNames}} + + {{end}} - %s - %s - %s + {{.Title}} + {{.Subject}} + {{.Creator}} - %s - %s + {{.Description}} + {{.LastModifiedBy}} 1 - %s - %s + {{.Created}} + {{.Modified}} \ No newline at end of file diff --git a/lib/pptx/templates/presentation.xml b/lib/pptx/templates/presentation.xml index edd06d463..4f3b0e744 100644 --- a/lib/pptx/templates/presentation.xml +++ b/lib/pptx/templates/presentation.xml @@ -6,8 +6,12 @@ - %s - + + {{range .Slides}} + + {{end}} + + diff --git a/lib/pptx/templates/rels_presentation.xml b/lib/pptx/templates/rels_presentation.xml index 6f85deb57..f7010c2c5 100644 --- a/lib/pptx/templates/rels_presentation.xml +++ b/lib/pptx/templates/rels_presentation.xml @@ -15,5 +15,7 @@ - %s + {{range .Slides}} + + {{end}} \ No newline at end of file diff --git a/lib/pptx/templates/slide.xml b/lib/pptx/templates/slide.xml index 6bdaa177c..2721068a1 100644 --- a/lib/pptx/templates/slide.xml +++ b/lib/pptx/templates/slide.xml @@ -19,22 +19,22 @@ - + - + - - + + @@ -43,14 +43,14 @@ - + - + @@ -75,7 +75,17 @@ - %s + + {{if .TitlePrefix}} + + {{.TitlePrefix}} + + {{end}} + + + {{.Title}} + + diff --git a/lib/pptx/templates/slide.xml.rels b/lib/pptx/templates/slide.xml.rels index f7ea83ea6..92475c305 100644 --- a/lib/pptx/templates/slide.xml.rels +++ b/lib/pptx/templates/slide.xml.rels @@ -3,7 +3,7 @@ - + Target="../media/{{.FileName}}.png" /> \ No newline at end of file