mirror of
https://github.com/kovetskiy/mark.git
synced 2026-05-02 05:12:35 +00:00
Add support for d2lang
This commit is contained in:
107
d2/d2.go
Normal file
107
d2/d2.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package d2
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/base64"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/chromedp/cdproto/dom"
|
||||
"github.com/chromedp/chromedp"
|
||||
|
||||
"github.com/kovetskiy/mark/attachment"
|
||||
"github.com/reconquest/pkg/log"
|
||||
|
||||
"oss.terrastruct.com/d2/d2graph"
|
||||
"oss.terrastruct.com/d2/d2layouts/d2dagrelayout"
|
||||
"oss.terrastruct.com/d2/d2lib"
|
||||
"oss.terrastruct.com/d2/d2renderers/d2svg"
|
||||
"oss.terrastruct.com/d2/d2themes/d2themescatalog"
|
||||
d2log "oss.terrastruct.com/d2/lib/log"
|
||||
"oss.terrastruct.com/d2/lib/textmeasure"
|
||||
"oss.terrastruct.com/util-go/go2"
|
||||
)
|
||||
|
||||
var renderTimeout = 120 * time.Second
|
||||
|
||||
func ProcessD2(title string, d2Diagram []byte, scale float64) (attachment.Attachment, error) {
|
||||
ctx, cancel := context.WithTimeout(context.TODO(), renderTimeout)
|
||||
ctx = d2log.WithDefault(ctx)
|
||||
defer cancel()
|
||||
|
||||
ruler, err := textmeasure.NewRuler()
|
||||
if err != nil {
|
||||
return attachment.Attachment{}, err
|
||||
}
|
||||
layoutResolver := func(engine string) (d2graph.LayoutGraph, error) {
|
||||
return d2dagrelayout.DefaultLayout, nil
|
||||
}
|
||||
renderOpts := &d2svg.RenderOpts{
|
||||
Pad: go2.Pointer(int64(5)),
|
||||
ThemeID: &d2themescatalog.GrapeSoda.ID,
|
||||
}
|
||||
compileOpts := &d2lib.CompileOptions{
|
||||
LayoutResolver: layoutResolver,
|
||||
Ruler: ruler,
|
||||
}
|
||||
|
||||
diagram, _, err := d2lib.Compile(ctx, string(d2Diagram), compileOpts, renderOpts)
|
||||
if err != nil {
|
||||
return attachment.Attachment{}, err
|
||||
}
|
||||
|
||||
out, err := d2svg.Render(diagram, renderOpts)
|
||||
if err != nil {
|
||||
return attachment.Attachment{}, err
|
||||
}
|
||||
|
||||
log.Debugf(nil, "Rendering: %q", title)
|
||||
pngBytes, boxModel, err := convertSVGtoPNG(ctx, out, scale)
|
||||
if err != nil {
|
||||
return attachment.Attachment{}, err
|
||||
}
|
||||
|
||||
checkSum, err := attachment.GetChecksum(bytes.NewReader(d2Diagram))
|
||||
log.Debugf(nil, "Checksum: %q -> %s", title, checkSum)
|
||||
|
||||
if err != nil {
|
||||
return attachment.Attachment{}, err
|
||||
}
|
||||
if title == "" {
|
||||
title = checkSum
|
||||
}
|
||||
|
||||
fileName := title + ".png"
|
||||
|
||||
return attachment.Attachment{
|
||||
ID: "",
|
||||
Name: title,
|
||||
Filename: fileName,
|
||||
FileBytes: pngBytes,
|
||||
Checksum: checkSum,
|
||||
Replace: title,
|
||||
Width: strconv.FormatInt(boxModel.Width, 10),
|
||||
Height: strconv.FormatInt(boxModel.Height, 10),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func convertSVGtoPNG(ctx context.Context, svg []byte, scale float64) (png []byte, m *dom.BoxModel, err error) {
|
||||
var (
|
||||
result []byte
|
||||
model *dom.BoxModel
|
||||
)
|
||||
ctx, cancel := chromedp.NewContext(ctx)
|
||||
defer cancel()
|
||||
|
||||
err = chromedp.Run(ctx,
|
||||
chromedp.Navigate(fmt.Sprintf("data:image/svg+xml;base64,%s", base64.StdEncoding.EncodeToString(svg))),
|
||||
chromedp.ScreenshotScale(`document.querySelector("svg > svg")`, scale, &result, chromedp.ByJSPath),
|
||||
chromedp.Dimensions(`document.querySelector("svg > svg")`, &model, chromedp.ByJSPath),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return result, model, err
|
||||
}
|
||||
Reference in New Issue
Block a user