Skip to content

Commit

Permalink
Merge pull request #940 from berniexie/pdf-link-overlay
Browse files Browse the repository at this point in the history
exports: pdf exports link overlay
  • Loading branch information
berniexie authored Feb 28, 2023
2 parents f545183 + c0d5bd9 commit 2ddea93
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 10 deletions.
2 changes: 2 additions & 0 deletions ci/release/changelogs/next.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

#### Improvements 🧹

- PDF exports now support external links on shapes [#891](https://github.com/terrastruct/d2/issues/891)

#### Bugfixes ⛑️

- Fixes a regression where PNG backgrounds could be cut off in the appendix. [#941](https://github.com/terrastruct/d2/pull/941)
12 changes: 11 additions & 1 deletion d2cli/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"os"
"os/exec"
"path/filepath"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -488,7 +489,16 @@ func renderPDF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, ske
return svg, err
}

err = pdf.AddPDFPage(pngImg, currBoardPath, themeID, rootFill)
viewboxSlice := appendix.FindViewboxSlice(svg)
viewboxX, err := strconv.ParseFloat(viewboxSlice[0], 64)
if err != nil {
return svg, err
}
viewboxY, err := strconv.ParseFloat(viewboxSlice[1], 64)
if err != nil {
return svg, err
}
err = pdf.AddPDFPage(pngImg, currBoardPath, themeID, rootFill, diagram.Shapes, pad, viewboxX, viewboxY)
if err != nil {
return svg, err
}
Expand Down
7 changes: 7 additions & 0 deletions d2renderers/d2svg/appendix/appendix.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,13 @@ var widthRegex = regexp.MustCompile(`width=\"([.0-9]+)\"`)
var heightRegex = regexp.MustCompile(`height=\"([.0-9]+)\"`)
var svgRegex = regexp.MustCompile(`<svg(.*?)>`)

func FindViewboxSlice(svg []byte) []string {
viewboxMatches := viewboxRegex.FindAllStringSubmatch(string(svg), 2)
viewboxMatch := viewboxMatches[1]
viewboxRaw := viewboxMatch[1]
return strings.Split(viewboxRaw, " ")
}

func Append(diagram *d2target.Diagram, ruler *textmeasure.Ruler, in []byte) []byte {
svg := string(in)

Expand Down
32 changes: 23 additions & 9 deletions lib/pdf/pdf.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/jung-kurt/gofpdf"

"oss.terrastruct.com/d2/d2renderers/d2fonts"
"oss.terrastruct.com/d2/d2target"
"oss.terrastruct.com/d2/d2themes"
"oss.terrastruct.com/d2/d2themes/d2themescatalog"
"oss.terrastruct.com/d2/lib/color"
Expand All @@ -19,13 +20,13 @@ type GoFPDF struct {

func Init() *GoFPDF {
newGofPDF := gofpdf.NewCustom(&gofpdf.InitType{
UnitStr: "in",
UnitStr: "pt",
})

newGofPDF.AddUTF8FontFromBytes("source", "", d2fonts.FontFaces[d2fonts.SourceSansPro.Font(0, d2fonts.FONT_STYLE_REGULAR)])
newGofPDF.AddUTF8FontFromBytes("source", "B", d2fonts.FontFaces[d2fonts.SourceSansPro.Font(0, d2fonts.FONT_STYLE_BOLD)])
newGofPDF.SetAutoPageBreak(false, 0)
newGofPDF.SetLineWidth(0.05)
newGofPDF.SetLineWidth(2)
newGofPDF.SetMargins(0, 0, 0)

fpdf := GoFPDF{
Expand Down Expand Up @@ -57,7 +58,7 @@ func (g *GoFPDF) GetFillRGB(themeID int64, fill string) (color.RGB, error) {
return color.Hex2RGB(fill)
}

func (g *GoFPDF) AddPDFPage(png []byte, boardPath []string, themeID int64, fill string) error {
func (g *GoFPDF) AddPDFPage(png []byte, boardPath []string, themeID int64, fill string, shapes []d2target.Shape, pad int64, viewboxX, viewboxY float64) error {
var opt gofpdf.ImageOptions
opt.ImageType = "png"
imageInfo := g.pdf.RegisterImageOptionsReader(strings.Join(boardPath, "/"), opt, bytes.NewReader(png))
Expand All @@ -73,10 +74,10 @@ func (g *GoFPDF) AddPDFPage(png []byte, boardPath []string, themeID int64, fill

g.pdf.SetFont("source", "B", 14)
pathString := strings.Join(boardPath, " / ")
headerMargin := 0.3
headerMargin := 28.0
headerWidth := g.pdf.GetStringWidth(pathString) + 2*headerMargin

minPageDimension := 6.0
minPageDimension := 576.0
pageWidth = math.Max(math.Max(minPageDimension, imageWidth), headerWidth)
pageHeight = math.Max(minPageDimension, imageHeight)

Expand All @@ -86,7 +87,7 @@ func (g *GoFPDF) AddPDFPage(png []byte, boardPath []string, themeID int64, fill
}

// Add page
headerHeight := 0.75
headerHeight := 72.0
g.pdf.AddPageFormat("", gofpdf.SizeType{Wd: pageWidth, Ht: pageHeight + headerHeight})

// Draw header
Expand Down Expand Up @@ -117,17 +118,30 @@ func (g *GoFPDF) AddPDFPage(png []byte, boardPath []string, themeID int64, fill
g.pdf.CellFormat(pageWidth-prefixWidth-headerMargin, headerHeight, boardName, "", 0, "", false, 0, "")

// Draw image
g.pdf.ImageOptions(strings.Join(boardPath, "/"), (pageWidth-imageWidth)/2, headerHeight+(pageHeight-imageHeight)/2, imageWidth, imageHeight, false, opt, 0, "")
imageX := (pageWidth - imageWidth) / 2
imageY := headerHeight + (pageHeight-imageHeight)/2
g.pdf.ImageOptions(strings.Join(boardPath, "/"), imageX, imageY, imageWidth, imageHeight, false, opt, 0, "")

// Draw external links
for _, shape := range shapes {
if shape.Link != "" {
linkX := imageX + float64(shape.Pos.X) - viewboxX - float64(shape.StrokeWidth)
linkY := imageY + float64(shape.Pos.Y) - viewboxY - float64(shape.StrokeWidth)
linkWidth := float64(shape.Width) + float64(shape.StrokeWidth*2)
linkHeight := float64(shape.Height) + float64(shape.StrokeWidth*2)
g.pdf.LinkString(linkX, linkY, linkWidth, linkHeight, shape.Link)
}
}

// Draw header/img seperator
g.pdf.SetXY(headerMargin, headerHeight)
g.pdf.SetLineWidth(0.01)
g.pdf.SetLineWidth(1)
if fillRGB.IsLight() {
g.pdf.SetDrawColor(10, 15, 37) // steel-900
} else {
g.pdf.SetDrawColor(255, 255, 255)
}
g.pdf.CellFormat(pageWidth-(headerMargin*2), 0.01, "", "T", 0, "", false, 0, "")
g.pdf.CellFormat(pageWidth-(headerMargin*2), 1, "", "T", 0, "", false, 0, "")

return nil
}
Expand Down

0 comments on commit 2ddea93

Please sign in to comment.