package libgofunc import ( "strconv" "strings" "github.com/fogleman/gg" "golang.org/x/image/font" "golang.org/x/net/html" ) // -------------------- STYLE -------------------- type Style struct { PaddingLeft float64 PaddingRight float64 PaddingTop float64 PaddingBottom float64 FontSize float64 Width float64 Height float64 TextAlign string VerticalAlign string Border float64 } func parseStyle(styleStr string) Style { style := Style{ FontSize: 16, TextAlign: "left", VerticalAlign: "top", } parts := strings.Split(styleStr, ";") for _, p := range parts { kv := strings.SplitN(strings.TrimSpace(p), ":", 2) if len(kv) != 2 { continue } key := strings.TrimSpace(kv[0]) val := strings.TrimSpace(kv[1]) switch key { case "padding": v := parsePx(val) style.PaddingLeft, style.PaddingRight, style.PaddingTop, style.PaddingBottom = v, v, v, v case "padding-left": v := parsePx(val) style.PaddingLeft = v case "padding-right": v := parsePx(val) style.PaddingRight = v case "padding-top": v := parsePx(val) style.PaddingTop = v case "padding-bottom": v := parsePx(val) style.PaddingBottom = v case "font-size": style.FontSize = parsePx(val) case "width": style.Width = parsePx(val) case "height": style.Height = parsePx(val) case "text-align": style.TextAlign = val case "vertical-align": style.VerticalAlign = val case "border": style.Border = parsePx(val) } } return style } func parsePx(v string) float64 { v = strings.ReplaceAll(v, "px", "") f, _ := strconv.ParseFloat(v, 64) return f } // -------------------- NODE -------------------- type Node struct { Tag string Text string Attr map[string]string Style Style Children []*Node } func (n Node) getSrc() string { for k, v := range n.Attr { if k == "src" { return v } } return "" } func (n Node) getHeight() int { return int(n.Style.Height) } func BuildTree(n *html.Node, canvasWidth int, dc *gg.Context, face *font.Face) (*Node, int) { if n.Type != html.ElementNode { return nil, 0 } text := "" if n.Data == "h1" || n.Data == "h2" || n.Data == "h3" || n.Data == "p" || n.Data == "td" || n.Data == "th" || n.Type == html.TextNode { text = getText(n) } node := &Node{ Tag: n.Data, Text: text, Attr: map[string]string{}, } for _, a := range n.Attr { node.Attr[a.Key] = a.Val } if s, ok := node.Attr["style"]; ok { node.Style = parseStyle(s) } xPadding := node.Style.PaddingLeft + node.Style.PaddingRight yPadding := node.Style.PaddingTop + node.Style.PaddingBottom fontSize := node.Style.FontSize h := nodeHeight(n, dc, canvasWidth, int(xPadding), int(yPadding), face, fontSize, node.getHeight()) for c := n.FirstChild; c != nil; c = c.NextSibling { child, ch := BuildTree(c, canvasWidth, dc, face) if child != nil { node.Children = append(node.Children, child) } h += ch } return node, h }