Skip to content

Commit

Permalink
pptx
Browse files Browse the repository at this point in the history
  • Loading branch information
alixander committed Dec 10, 2023
1 parent 2713eb2 commit 86714d8
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 17 deletions.
4 changes: 2 additions & 2 deletions d2cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -566,10 +566,10 @@ func compile(ctx context.Context, ms *xmain.State, plugins []d2plugin.Plugin, fs
if user, err := user.Current(); err == nil {
username = user.Username
}
description := "Presentation generated with D2 - https://d2lang.com/"
description := "Presentation generated with D2 - https://d2lang.com"
rootName := getFileName(outputPath)
// version must be only numbers to avoid issues with PowerPoint
p := pptx.NewPresentation(rootName, description, rootName, username, version.OnlyNumbers())
p := pptx.NewPresentation(rootName, description, rootName, username, version.OnlyNumbers(), diagram.Root.Label != "")

boardIdToIndex := buildBoardIDToIndex(diagram, nil, nil)
path := []pptx.BoardTitle{
Expand Down
29 changes: 28 additions & 1 deletion e2etests-cli/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,7 @@ layers: {
},
},
{
name: "no-nav-board",
name: "no-nav-pdf",
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
writeFile(t, dir, "in.d2", `cat: how does the cat go? {
link: layers.cat
Expand All @@ -637,6 +637,33 @@ layers: {
testdataIgnoreDiff(t, ".pdf", pdf)
},
},
{
name: "no-nav-pptx",
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
writeFile(t, dir, "in.d2", `cat: how does the cat go? {
link: layers.cat
}
a.link: "https://www.google.com/maps/place/Smoked+Out+BBQ/@37.3848007,-121.9513887,17z/data=!3m1!4b1!4m6!3m5!1s0x808fc9182ad4d38d:0x8e2f39c3e927b296!8m2!3d37.3848007!4d-121.9492!16s%2Fg%2F11gjt85zvf"
label: ""
layers: {
cat: {
label: dog
home: {
link: _
}
the cat -> meow: goes
}
}
`)
err := runTestMain(t, ctx, dir, env, "in.d2", "out.pptx")
assert.Success(t, err)

file := readFile(t, dir, "out.pptx")
// err = pptx.Validate(file, 2)
assert.Success(t, err)
testdataIgnoreDiff(t, ".pptx", file)
},
},
{
name: "basic-fmt",
run: func(t *testing.T, ctx context.Context, dir string, env *xos.Env) {
Expand Down
Binary file not shown.
44 changes: 30 additions & 14 deletions lib/pptx/pptx.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ type Presentation struct {
Creator string
// D2Version can't have letters, only numbers (`[0-9]`) and `.`
// Otherwise, it may fail to open in PowerPoint
D2Version string
D2Version string
includeNav bool

Slides []*Slide
}
Expand Down Expand Up @@ -73,16 +74,32 @@ type Link struct {
Tooltip string
}

func NewPresentation(title, description, subject, creator, d2Version string) *Presentation {
func NewPresentation(title, description, subject, creator, d2Version string, includeNav bool) *Presentation {
return &Presentation{
Title: title,
Description: description,
Subject: subject,
Creator: creator,
D2Version: d2Version,
includeNav: includeNav,
}
}

func (p *Presentation) headerHeight() int {
if p.includeNav {
return HEADER_HEIGHT
}
return 0
}

func (p *Presentation) height() int {
return SLIDE_HEIGHT - p.headerHeight()
}

func (p *Presentation) aspectRatio() float64 {
return float64(IMAGE_WIDTH) / float64(p.height())
}

func (p *Presentation) AddSlide(pngContent []byte, titlePath []BoardTitle) (*Slide, error) {
src, err := png.Decode(bytes.NewReader(pngContent))
if err != nil {
Expand Down Expand Up @@ -111,26 +128,26 @@ func (p *Presentation) AddSlide(pngContent []byte, titlePath []BoardTitle) (*Sli
// └──┴────────────────────────────────────────────┴──┘ ─┴─ ─┴─
// ├────────────────────SLIDE WIDTH───────────────────┤
// ├─────────────────IMAGE WIDTH────────────────┤
if srcWidth/srcHeight >= IMAGE_ASPECT_RATIO {
if srcWidth/srcHeight >= p.aspectRatio() {
// here, the image aspect ratio is, at least, equal to the slide aspect ratio
// so, it makes sense to expand the image horizontally to use as much as space as possible
width = SLIDE_WIDTH
height = int(float64(width) * (srcHeight / srcWidth))
// first, try to make the image as wide as the slide
// but, if this results in a tall image, use only the
// image adjusted width to avoid overlapping with the header
if height > IMAGE_HEIGHT {
if height > p.height() {
width = IMAGE_WIDTH
height = int(float64(width) * (srcHeight / srcWidth))
}
} else {
// here, the aspect ratio could be 4x3, in which the image is still wider than taller,
// but expanding horizontally would result in an overflow
// so, we expand to make it fit the available vertical space
height = IMAGE_HEIGHT
height = p.height()
width = int(float64(height) * (srcWidth / srcHeight))
}
top := HEADER_HEIGHT + ((IMAGE_HEIGHT - height) / 2)
top := p.headerHeight() + ((p.height() - height) / 2)
left := (SLIDE_WIDTH - width) / 2

slide := &Slide{
Expand Down Expand Up @@ -186,7 +203,7 @@ func (p *Presentation) SaveTo(filePath string) error {
return err
}

err = addFileFromTemplate(zipWriter, fmt.Sprintf("ppt/slides/%s.xml", slideFileName), SLIDE_XML, getSlideXmlContent(imageID, slide))
err = addFileFromTemplate(zipWriter, fmt.Sprintf("ppt/slides/%s.xml", slideFileName), SLIDE_XML, p.getSlideXmlContent(imageID, slide))
if err != nil {
return err
}
Expand Down Expand Up @@ -248,11 +265,8 @@ 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)

//go:embed template.pptx
var PPTX_TEMPLATE []byte
Expand Down Expand Up @@ -344,7 +358,7 @@ type SlideXmlContent struct {
Links []SlideLinkXmlContent
}

func getSlideXmlContent(imageID string, slide *Slide) SlideXmlContent {
func (p *Presentation) getSlideXmlContent(imageID string, slide *Slide) SlideXmlContent {
title := make([]SlideXmlTitlePathContent, len(slide.BoardTitle)-1)
for i := 0; i < len(slide.BoardTitle)-1; i++ {
t := slide.BoardTitle[i]
Expand All @@ -354,16 +368,18 @@ func getSlideXmlContent(imageID string, slide *Slide) SlideXmlContent {
}
}
content := SlideXmlContent{
Title: slide.BoardTitle[len(slide.BoardTitle)-1].Name,
TitlePrefix: title,
Description: slide.BoardTitle[len(slide.BoardTitle)-1].BoardID,
HeaderHeight: HEADER_HEIGHT,
HeaderHeight: p.headerHeight(),
ImageID: imageID,
ImageLeft: slide.ImageLeft,
ImageTop: slide.ImageTop,
ImageWidth: slide.ImageWidth,
ImageHeight: slide.ImageHeight,
}
if p.includeNav {
content.Title = slide.BoardTitle[len(slide.BoardTitle)-1].Name
content.TitlePrefix = title
}

for _, link := range slide.Links {
var action string
Expand Down

0 comments on commit 86714d8

Please sign in to comment.