From f327a23cc5396be91900b0e5e52be89c24c7bd51 Mon Sep 17 00:00:00 2001 From: Bernard Xie Date: Mon, 27 Feb 2023 20:02:33 -0800 Subject: [PATCH 1/7] wip --- d2cli/main.go | 7 ++++--- lib/pdf/pdf.go | 29 +++++++++++++++++++++++------ 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/d2cli/main.go b/d2cli/main.go index 794f2a0711..72d3c5efcf 100644 --- a/d2cli/main.go +++ b/d2cli/main.go @@ -284,7 +284,8 @@ func compile(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, sketc var svg []byte if filepath.Ext(outputPath) == ".pdf" { - svg, err = renderPDF(ctx, ms, plugin, sketch, pad, themeID, outputPath, page, ruler, diagram, nil, nil) + // svg, err = renderPDF(ctx, ms, plugin, sketch, pad, themeID, outputPath, page, ruler, diagram, nil, nil) + svg, err = renderPDF(ctx, ms, plugin, sketch, 0, themeID, outputPath, page, ruler, diagram, nil, nil) } else { compileDur := time.Since(start) svg, err = render(ctx, ms, compileDur, plugin, sketch, pad, themeID, darkThemeID, inputPath, outputPath, bundle, forceAppendix, page, ruler, diagram) @@ -459,7 +460,7 @@ func renderPDF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, ske rootFill := diagram.Root.Fill // gofpdf will print the png img with a slight filter // make the bg fill within the png transparent so that the pdf bg fill is the only bg color present - diagram.Root.Fill = "transparent" + // diagram.Root.Fill = "transparent" svg, err = d2svg.Render(diagram, &d2svg.RenderOpts{ Pad: int(pad), @@ -487,7 +488,7 @@ func renderPDF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, ske return svg, err } - err = pdf.AddPDFPage(pngImg, currBoardPath, themeID, rootFill) + err = pdf.AddPDFPage(pngImg, currBoardPath, themeID, rootFill, diagram.Shapes, pad) if err != nil { return svg, err } diff --git a/lib/pdf/pdf.go b/lib/pdf/pdf.go index 7cfc9b0b1f..4285f01005 100644 --- a/lib/pdf/pdf.go +++ b/lib/pdf/pdf.go @@ -5,9 +5,12 @@ import ( "math" "strings" + "github.com/davecgh/go-spew/spew" "github.com/jung-kurt/gofpdf" "oss.terrastruct.com/d2/d2renderers/d2fonts" + "oss.terrastruct.com/d2/d2renderers/d2svg/appendix" + "oss.terrastruct.com/d2/d2target" "oss.terrastruct.com/d2/d2themes" "oss.terrastruct.com/d2/d2themes/d2themescatalog" "oss.terrastruct.com/d2/lib/color" @@ -19,13 +22,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{ @@ -57,7 +60,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) error { var opt gofpdf.ImageOptions opt.ImageType = "png" imageInfo := g.pdf.RegisterImageOptionsReader(strings.Join(boardPath, "/"), opt, bytes.NewReader(png)) @@ -73,10 +76,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) @@ -86,7 +89,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 @@ -119,6 +122,20 @@ func (g *GoFPDF) AddPDFPage(png []byte, boardPath []string, themeID int64, fill // Draw image g.pdf.ImageOptions(strings.Join(boardPath, "/"), (pageWidth-imageWidth)/2, headerHeight+(pageHeight-imageHeight)/2, imageWidth, imageHeight, false, opt, 0, "") + // Draw external links + for _, shape := range shapes { + if shape.Link != "" { + linkX := (pageWidth-imageWidth)/2 + float64(pad/2) + float64(shape.Pos.X) + linkY := (pageHeight-imageHeight)/2 + float64(pad/2) + float64(shape.Pos.Y) + appendix.ICON_RADIUS/2 + headerHeight + linkWidth := float64(shape.Width) + linkHeight := float64(shape.Height) + spew.Dump("X", linkX, "Y", linkY) + spew.Dump("w", linkWidth, "h", linkHeight) + spew.Dump("pw", pageWidth, "pwh", pageHeight) + g.pdf.LinkString(linkX, linkY, linkWidth, linkHeight, shape.Link) + } + } + // Draw header/img seperator g.pdf.SetXY(headerMargin, headerHeight) g.pdf.SetLineWidth(0.01) From e8a473f0fd80fa8ac4de8a47e2a07230b7328faf Mon Sep 17 00:00:00 2001 From: Bernard Xie Date: Tue, 28 Feb 2023 12:40:07 -0800 Subject: [PATCH 2/7] working --- d2cli/main.go | 17 +++++++------ d2renderers/d2svg/appendix/appendix.go | 7 ++++++ lib/pdf/pdf.go | 35 +++++++++++++++----------- 3 files changed, 37 insertions(+), 22 deletions(-) diff --git a/d2cli/main.go b/d2cli/main.go index ca5f347eb4..76596cdd3b 100644 --- a/d2cli/main.go +++ b/d2cli/main.go @@ -284,8 +284,7 @@ func compile(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, sketc var svg []byte if filepath.Ext(outputPath) == ".pdf" { - // svg, err = renderPDF(ctx, ms, plugin, sketch, pad, themeID, outputPath, page, ruler, diagram, nil, nil) - svg, err = renderPDF(ctx, ms, plugin, sketch, 0, themeID, outputPath, page, ruler, diagram, nil, nil) + svg, err = renderPDF(ctx, ms, plugin, sketch, pad, themeID, outputPath, page, ruler, diagram, nil, nil) } else { compileDur := time.Since(start) svg, err = render(ctx, ms, compileDur, plugin, sketch, pad, themeID, darkThemeID, inputPath, outputPath, bundle, forceAppendix, page, ruler, diagram) @@ -378,11 +377,12 @@ func render(ctx context.Context, ms *xmain.State, compileDur time.Duration, plug func _render(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, sketch bool, pad int64, themeID int64, darkThemeID *int64, outputPath string, bundle, forceAppendix bool, page playwright.Page, ruler *textmeasure.Ruler, diagram *d2target.Diagram) ([]byte, error) { toPNG := filepath.Ext(outputPath) == ".png" svg, err := d2svg.Render(diagram, &d2svg.RenderOpts{ - Pad: int(pad), - Sketch: sketch, - ThemeID: themeID, - DarkThemeID: darkThemeID, - SetDimensions: toPNG, + Pad: int(pad), + Sketch: sketch, + ThemeID: themeID, + DarkThemeID: darkThemeID, + // SetDimensions: toPNG, + SetDimensions: true, }) if err != nil { return nil, err @@ -489,7 +489,8 @@ func renderPDF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, ske return svg, err } - err = pdf.AddPDFPage(pngImg, currBoardPath, themeID, rootFill, diagram.Shapes, pad) + viewboxSlice := appendix.FindViewboxSlice(svg) + err = pdf.AddPDFPage(pngImg, currBoardPath, themeID, rootFill, diagram.Shapes, pad, viewboxSlice) if err != nil { return svg, err } diff --git a/d2renderers/d2svg/appendix/appendix.go b/d2renderers/d2svg/appendix/appendix.go index 3cb6a48a13..ede8a0f2eb 100644 --- a/d2renderers/d2svg/appendix/appendix.go +++ b/d2renderers/d2svg/appendix/appendix.go @@ -53,6 +53,13 @@ var viewboxRegex = regexp.MustCompile(`viewBox=\"([0-9\- ]+)\"`) var widthRegex = regexp.MustCompile(`width=\"([.0-9]+)\"`) var heightRegex = regexp.MustCompile(`height=\"([.0-9]+)\"`) +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) diff --git a/lib/pdf/pdf.go b/lib/pdf/pdf.go index 4285f01005..6ad5cd1e92 100644 --- a/lib/pdf/pdf.go +++ b/lib/pdf/pdf.go @@ -3,13 +3,12 @@ package pdf import ( "bytes" "math" + "strconv" "strings" - "github.com/davecgh/go-spew/spew" "github.com/jung-kurt/gofpdf" "oss.terrastruct.com/d2/d2renderers/d2fonts" - "oss.terrastruct.com/d2/d2renderers/d2svg/appendix" "oss.terrastruct.com/d2/d2target" "oss.terrastruct.com/d2/d2themes" "oss.terrastruct.com/d2/d2themes/d2themescatalog" @@ -60,7 +59,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, shapes []d2target.Shape, pad int64) error { +func (g *GoFPDF) AddPDFPage(png []byte, boardPath []string, themeID int64, fill string, shapes []d2target.Shape, pad int64, viewboxSlice []string) error { var opt gofpdf.ImageOptions opt.ImageType = "png" imageInfo := g.pdf.RegisterImageOptionsReader(strings.Join(boardPath, "/"), opt, bytes.NewReader(png)) @@ -79,7 +78,8 @@ func (g *GoFPDF) AddPDFPage(png []byte, boardPath []string, themeID int64, fill headerMargin := 28.0 headerWidth := g.pdf.GetStringWidth(pathString) + 2*headerMargin - minPageDimension := 576.0 + // minPageDimension := 576.0 + minPageDimension := 0.0 pageWidth = math.Max(math.Max(minPageDimension, imageWidth), headerWidth) pageHeight = math.Max(minPageDimension, imageHeight) @@ -120,31 +120,38 @@ 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 := (pageWidth-imageWidth)/2 + float64(pad/2) + float64(shape.Pos.X) - linkY := (pageHeight-imageHeight)/2 + float64(pad/2) + float64(shape.Pos.Y) + appendix.ICON_RADIUS/2 + headerHeight - linkWidth := float64(shape.Width) - linkHeight := float64(shape.Height) - spew.Dump("X", linkX, "Y", linkY) - spew.Dump("w", linkWidth, "h", linkHeight) - spew.Dump("pw", pageWidth, "pwh", pageHeight) + viewboxX, err := strconv.ParseFloat(viewboxSlice[0], 64) + if err != nil { + return err + } + viewboxY, err := strconv.ParseFloat(viewboxSlice[1], 64) + if err != nil { + return err + } + 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 } From a85a225c73d05728359631814ba670d9373eba04 Mon Sep 17 00:00:00 2001 From: Bernard Xie Date: Tue, 28 Feb 2023 12:45:00 -0800 Subject: [PATCH 3/7] reverts --- d2cli/main.go | 13 ++++++------- lib/pdf/pdf.go | 3 +-- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/d2cli/main.go b/d2cli/main.go index 76596cdd3b..4c405f0cf8 100644 --- a/d2cli/main.go +++ b/d2cli/main.go @@ -377,12 +377,11 @@ func render(ctx context.Context, ms *xmain.State, compileDur time.Duration, plug func _render(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, sketch bool, pad int64, themeID int64, darkThemeID *int64, outputPath string, bundle, forceAppendix bool, page playwright.Page, ruler *textmeasure.Ruler, diagram *d2target.Diagram) ([]byte, error) { toPNG := filepath.Ext(outputPath) == ".png" svg, err := d2svg.Render(diagram, &d2svg.RenderOpts{ - Pad: int(pad), - Sketch: sketch, - ThemeID: themeID, - DarkThemeID: darkThemeID, - // SetDimensions: toPNG, - SetDimensions: true, + Pad: int(pad), + Sketch: sketch, + ThemeID: themeID, + DarkThemeID: darkThemeID, + SetDimensions: toPNG, }) if err != nil { return nil, err @@ -460,7 +459,7 @@ func renderPDF(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, ske rootFill := diagram.Root.Fill // gofpdf will print the png img with a slight filter // make the bg fill within the png transparent so that the pdf bg fill is the only bg color present - // diagram.Root.Fill = "transparent" + diagram.Root.Fill = "transparent" svg, err = d2svg.Render(diagram, &d2svg.RenderOpts{ Pad: int(pad), diff --git a/lib/pdf/pdf.go b/lib/pdf/pdf.go index 6ad5cd1e92..731024f71b 100644 --- a/lib/pdf/pdf.go +++ b/lib/pdf/pdf.go @@ -78,8 +78,7 @@ func (g *GoFPDF) AddPDFPage(png []byte, boardPath []string, themeID int64, fill headerMargin := 28.0 headerWidth := g.pdf.GetStringWidth(pathString) + 2*headerMargin - // minPageDimension := 576.0 - minPageDimension := 0.0 + minPageDimension := 576.0 pageWidth = math.Max(math.Max(minPageDimension, imageWidth), headerWidth) pageHeight = math.Max(minPageDimension, imageHeight) From f8512a95a709cabf0d61f619ca2bb17399fa2a2c Mon Sep 17 00:00:00 2001 From: Bernard Xie Date: Tue, 28 Feb 2023 13:46:02 -0800 Subject: [PATCH 4/7] test --- d2renderers/d2svg/appendix/appendix.go | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/d2renderers/d2svg/appendix/appendix.go b/d2renderers/d2svg/appendix/appendix.go index ede8a0f2eb..e343808ff9 100644 --- a/d2renderers/d2svg/appendix/appendix.go +++ b/d2renderers/d2svg/appendix/appendix.go @@ -111,6 +111,13 @@ func Append(diagram *d2target.Diagram, ruler *textmeasure.Ruler, in []byte) []by } if !strings.Contains(svg, `font-family: "font-regular"`) { + + // if fillRGB.IsLight() { + // g.pdf.SetTextColor(10, 15, 37) // steel-900 + // } else { + // g.pdf.SetTextColor(255, 255, 255) + // } + appendix += fmt.Sprintf(`