navbar on pdfs

This commit is contained in:
Júlio César Batista 2023-04-14 16:58:55 -03:00
parent 00ed4ca75b
commit 6f18b232b9
No known key found for this signature in database
GPG key ID: 10C4B861BF314878
2 changed files with 46 additions and 17 deletions

View file

@ -33,6 +33,7 @@ import (
"oss.terrastruct.com/d2/lib/background" "oss.terrastruct.com/d2/lib/background"
"oss.terrastruct.com/d2/lib/imgbundler" "oss.terrastruct.com/d2/lib/imgbundler"
ctxlog "oss.terrastruct.com/d2/lib/log" ctxlog "oss.terrastruct.com/d2/lib/log"
"oss.terrastruct.com/d2/lib/pdf"
pdflib "oss.terrastruct.com/d2/lib/pdf" pdflib "oss.terrastruct.com/d2/lib/pdf"
"oss.terrastruct.com/d2/lib/png" "oss.terrastruct.com/d2/lib/png"
"oss.terrastruct.com/d2/lib/pptx" "oss.terrastruct.com/d2/lib/pptx"
@ -353,7 +354,7 @@ func compile(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, rende
switch filepath.Ext(outputPath) { switch filepath.Ext(outputPath) {
case ".pdf": case ".pdf":
pageMap := buildBoardIDToIndex(diagram, nil, nil) pageMap := buildBoardIDToIndex(diagram, nil, nil)
pdf, err := renderPDF(ctx, ms, plugin, renderOpts, outputPath, page, ruler, diagram, nil, nil, pageMap) pdf, err := renderPDF(ctx, ms, plugin, renderOpts, outputPath, page, ruler, diagram, nil, nil, "", pageMap)
if err != nil { if err != nil {
return pdf, false, err return pdf, false, err
} }
@ -684,19 +685,26 @@ func _render(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opts
return svg, nil return svg, nil
} }
func renderPDF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opts d2svg.RenderOpts, outputPath string, page playwright.Page, ruler *textmeasure.Ruler, diagram *d2target.Diagram, pdf *pdflib.GoFPDF, boardPath []string, pageMap map[string]int) (svg []byte, err error) { func renderPDF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opts d2svg.RenderOpts, outputPath string, page playwright.Page, ruler *textmeasure.Ruler, diagram *d2target.Diagram, pdf *pdflib.GoFPDF, boardPath []pdf.BoardTitle, boardType string, pageMap map[string]int) (svg []byte, err error) {
var isRoot bool var isRoot bool
if pdf == nil { if pdf == nil {
pdf = pdflib.Init() pdf = pdflib.Init()
isRoot = true isRoot = true
} }
var currBoardPath []string var currBoardPath []pdflib.BoardTitle
// Root board doesn't have a name, so we use the output filename // Root board doesn't have a name, so we use the output filename
if diagram.Name == "" { if diagram.Name == "" {
currBoardPath = append(boardPath, "root") currBoardPath = append(boardPath, pdflib.BoardTitle{
Name: "root",
BoardID: "root",
})
} else { } else {
currBoardPath = append(boardPath, diagram.Name) prev := boardPath[len(boardPath)-1]
currBoardPath = append(boardPath, pdflib.BoardTitle{
Name: diagram.Name,
BoardID: strings.Join([]string{prev.BoardID, boardType, diagram.Name}, "."),
})
} }
if !diagram.IsFolderOnly { if !diagram.IsFolderOnly {
@ -749,19 +757,19 @@ func renderPDF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, opt
} }
for _, dl := range diagram.Layers { for _, dl := range diagram.Layers {
_, err := renderPDF(ctx, ms, plugin, opts, "", page, ruler, dl, pdf, currBoardPath, pageMap) _, err := renderPDF(ctx, ms, plugin, opts, "", page, ruler, dl, pdf, currBoardPath, "layers", pageMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
for _, dl := range diagram.Scenarios { for _, dl := range diagram.Scenarios {
_, err := renderPDF(ctx, ms, plugin, opts, "", page, ruler, dl, pdf, currBoardPath, pageMap) _, err := renderPDF(ctx, ms, plugin, opts, "", page, ruler, dl, pdf, currBoardPath, "scenarios", pageMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
for _, dl := range diagram.Steps { for _, dl := range diagram.Steps {
_, err := renderPDF(ctx, ms, plugin, opts, "", page, ruler, dl, pdf, currBoardPath, pageMap) _, err := renderPDF(ctx, ms, plugin, opts, "", page, ruler, dl, pdf, currBoardPath, "steps", pageMap)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -15,10 +15,17 @@ import (
"oss.terrastruct.com/d2/lib/color" "oss.terrastruct.com/d2/lib/color"
) )
const TITLE_SEP = " / "
type GoFPDF struct { type GoFPDF struct {
pdf *gofpdf.Fpdf pdf *gofpdf.Fpdf
} }
type BoardTitle struct {
Name string
BoardID string
}
func Init() *GoFPDF { func Init() *GoFPDF {
newGofPDF := gofpdf.NewCustom(&gofpdf.InitType{ newGofPDF := gofpdf.NewCustom(&gofpdf.InitType{
UnitStr: "pt", UnitStr: "pt",
@ -59,9 +66,13 @@ func (g *GoFPDF) GetFillRGB(themeID int64, fill string) (color.RGB, error) {
return color.Hex2RGB(fill) return color.Hex2RGB(fill)
} }
func (g *GoFPDF) AddPDFPage(png []byte, boardPath []string, themeID int64, fill string, shapes []d2target.Shape, pad int64, viewboxX, viewboxY float64, pageMap map[string]int) error { func (g *GoFPDF) AddPDFPage(png []byte, titlePath []BoardTitle, themeID int64, fill string, shapes []d2target.Shape, pad int64, viewboxX, viewboxY float64, pageMap map[string]int) error {
var opt gofpdf.ImageOptions var opt gofpdf.ImageOptions
opt.ImageType = "png" opt.ImageType = "png"
boardPath := make([]string, len(titlePath))
for i, t := range titlePath {
boardPath[i] = t.Name
}
imageInfo := g.pdf.RegisterImageOptionsReader(strings.Join(boardPath, "/"), opt, bytes.NewReader(png)) imageInfo := g.pdf.RegisterImageOptionsReader(strings.Join(boardPath, "/"), opt, bytes.NewReader(png))
if g.pdf.Err() { if g.pdf.Err() {
return g.pdf.Error() return g.pdf.Error()
@ -102,20 +113,30 @@ func (g *GoFPDF) AddPDFPage(png []byte, boardPath []string, themeID int64, fill
g.pdf.SetFont("source", "", 14) g.pdf.SetFont("source", "", 14)
// Draw board path prefix // Draw board path prefix
var prefixWidth float64 prefixWidth := headerMargin
prefixPath := boardPath[:len(boardPath)-1] if len(titlePath) > 1 {
if len(prefixPath) > 0 { for _, t := range titlePath[:len(titlePath)-1] {
prefix := strings.Join(boardPath[:len(boardPath)-1], " / ") + " / " g.pdf.SetXY(prefixWidth, 0)
prefixWidth = g.pdf.GetStringWidth(prefix) w := g.pdf.GetStringWidth(t.Name)
var linkID int
if pageNum, ok := pageMap[t.BoardID]; ok {
linkID = g.pdf.AddLink()
g.pdf.SetLink(linkID, 0, pageNum+1)
}
g.pdf.CellFormat(w, headerHeight, t.Name, "", 0, "", false, linkID, "")
prefixWidth += w
g.pdf.SetXY(headerMargin, 0) g.pdf.SetXY(prefixWidth, 0)
g.pdf.CellFormat(prefixWidth, headerHeight, prefix, "", 0, "", false, 0, "") w = g.pdf.GetStringWidth(TITLE_SEP)
g.pdf.CellFormat(prefixWidth, headerHeight, TITLE_SEP, "", 0, "", false, 0, "")
prefixWidth += w
}
} }
// Draw board name // Draw board name
boardName := boardPath[len(boardPath)-1] boardName := boardPath[len(boardPath)-1]
g.pdf.SetFont("source", "B", 14) g.pdf.SetFont("source", "B", 14)
g.pdf.SetXY(prefixWidth+headerMargin, 0) g.pdf.SetXY(prefixWidth, 0)
g.pdf.CellFormat(pageWidth-prefixWidth-headerMargin, headerHeight, boardName, "", 0, "", false, 0, "") g.pdf.CellFormat(pageWidth-prefixWidth-headerMargin, headerHeight, boardName, "", 0, "", false, 0, "")
// Draw image // Draw image