Files
libgofunc/canvas.go
2026-04-08 15:31:23 +06:30

142 lines
2.9 KiB
Go

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
}