...
1 package d2latex
2
3 import (
4 _ "embed"
5 "fmt"
6 "math"
7 "regexp"
8 "strconv"
9
10 "github.com/dop251/goja"
11
12 "oss.terrastruct.com/util-go/xdefer"
13 )
14
15 var pxPerEx = 8
16
17
18 var polyfillsJS string
19
20
21 var setupJS string
22
23
24 var mathjaxJS string
25
26
27
28 var svgRe = regexp.MustCompile(`<svg[^>]+width="([0-9\.]+)ex" height="([0-9\.]+)ex"[^>]+>`)
29
30 func Render(s string) (_ string, err error) {
31 defer xdefer.Errorf(&err, "latex failed to parse")
32 vm := goja.New()
33
34 if _, err := vm.RunString(polyfillsJS); err != nil {
35 return "", err
36 }
37
38 if _, err := vm.RunString(mathjaxJS); err != nil {
39 return "", err
40 }
41
42 if _, err := vm.RunString(setupJS); err != nil {
43 return "", err
44 }
45
46 val, err := vm.RunString(fmt.Sprintf(`adaptor.innerHTML(html.convert(`+"`"+"%s`"+`, {
47 em: %d,
48 ex: %d,
49 }))`, s, pxPerEx*2, pxPerEx))
50 if err != nil {
51 return "", err
52 }
53
54 return val.String(), nil
55 }
56
57 func Measure(s string) (width, height int, err error) {
58 defer xdefer.Errorf(&err, "latex failed to parse")
59 svg, err := Render(s)
60 if err != nil {
61 return 0, 0, err
62 }
63
64 dims := svgRe.FindAllStringSubmatch(svg, -1)
65 if len(dims) != 1 || len(dims[0]) != 3 {
66 return 0, 0, fmt.Errorf("svg parsing failed for latex: %v", svg)
67 }
68
69 wEx := dims[0][1]
70 hEx := dims[0][2]
71
72 wf, err := strconv.ParseFloat(wEx, 64)
73 if err != nil {
74 return 0, 0, fmt.Errorf("svg parsing failed for latex: %v", svg)
75 }
76 hf, err := strconv.ParseFloat(hEx, 64)
77 if err != nil {
78 return 0, 0, fmt.Errorf("svg parsing failed for latex: %v", svg)
79 }
80
81 return int(math.Ceil(wf * float64(pxPerEx))), int(math.Ceil(hf * float64(pxPerEx))), nil
82 }
83
View as plain text