fix html to png
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -27,3 +27,4 @@ go.work.sum
|
|||||||
|
|
||||||
build
|
build
|
||||||
assets
|
assets
|
||||||
|
libgofunc
|
||||||
|
|||||||
15
.vscode/launch.json
vendored
Normal file
15
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
// Use IntelliSense to learn about possible attributes.
|
||||||
|
// Hover to view descriptions of existing attributes.
|
||||||
|
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Dev",
|
||||||
|
"type": "go",
|
||||||
|
"request": "launch",
|
||||||
|
"mode": "auto",
|
||||||
|
"program": "${workspaceFolder}/cmd",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
141
canvas.go
Normal file
141
canvas.go
Normal file
@@ -0,0 +1,141 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
109
cmd/main.go
Normal file
109
cmd/main.go
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
/*
|
||||||
|
#include <stdint.h>
|
||||||
|
*/
|
||||||
|
"C"
|
||||||
|
"fmt"
|
||||||
|
_ "image/png"
|
||||||
|
|
||||||
|
"github.com/google/gousb"
|
||||||
|
)
|
||||||
|
import (
|
||||||
|
"github.com/google/gousb/usbid"
|
||||||
|
"gt.mokkon.com/sainw/libgofunc"
|
||||||
|
)
|
||||||
|
|
||||||
|
//export Sum
|
||||||
|
func Sum(a, b int) int {
|
||||||
|
return a + b
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
payload := `{"Name":"Ko Myo","Amount":3000}`
|
||||||
|
const temp = `
|
||||||
|
<img src="logo.png" style="width:230;height:200;padding-left:130px;padding-top:30px"/>
|
||||||
|
<h1 style="padding-left:150px">New Day Energy</h1>
|
||||||
|
|
||||||
|
<p style="padding-left:10px">Address: မင်္ဂလာပါ {{.Name}}</p>
|
||||||
|
<p style="padding-left:10px">Receipt: RCPT001</p>
|
||||||
|
<p style="padding-left:10px">Phone: 0977777777</p>
|
||||||
|
<p style="padding-left:10px">Date: 4 Jan 2026 15:38:38</p>
|
||||||
|
<p style="padding-left:10px">Car No.: 3J/3883</p>
|
||||||
|
<p style="padding-left:10px">Casher: မနှင်းနှင်း</p>
|
||||||
|
<p style="padding-left:10px">MOP: B2B</p>
|
||||||
|
<p style="padding-left:10px">Tier: 1</p>
|
||||||
|
<p style="padding-left:10px">Deal No.: RR</p>
|
||||||
|
<hr style="height:1px;padding-left:10px;padding-right:10px;padding-bottom:10px"/>
|
||||||
|
|
||||||
|
<table style="padding-left:10px;padding-bottom:10px;border:0px;font-size:16px;border:0px;">
|
||||||
|
<tr>
|
||||||
|
<th>Item</th>
|
||||||
|
<th>Pump</th>
|
||||||
|
<th>Price</th>
|
||||||
|
<th>Liter</th>
|
||||||
|
<th>Gallon</th>
|
||||||
|
<th>Amount</th>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>95 RON</td>
|
||||||
|
<td>P8</td>
|
||||||
|
<td>2,000</td>
|
||||||
|
<td>3.25</td>
|
||||||
|
<td>0.715</td>
|
||||||
|
<td>6,500</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p style="padding-left:0px;padding-top:50px;">
|
||||||
|
စက်သုံးဆီ အရေအတွက် နှင့် အရည်အသွေးစျေးနှုန်းများ အားသံသယရှိပါက ph 09450539099, 09765421033, 09765421029 သို့တိုင်ကြား နိုင်ပါသည်။</p>
|
||||||
|
`
|
||||||
|
result := libgofunc.GenImg(550, "./out.png", payload, temp)
|
||||||
|
fmt.Println("Result:", result)
|
||||||
|
// PrintImg(C.CString("usb:/dev/usb/lp1"), C.CString("build/out.png"))
|
||||||
|
// libgofunc.Print("int:/dev/bus/usb/001/046", "./out.png")
|
||||||
|
libgofunc.Print("tcp:192.168.100.151:9100", "./out.png")
|
||||||
|
// printer := "tcp:192.168.100.151:9100"
|
||||||
|
// ListUSB()
|
||||||
|
}
|
||||||
|
|
||||||
|
func ListUSB() {
|
||||||
|
ctx := gousb.NewContext()
|
||||||
|
defer ctx.Close()
|
||||||
|
|
||||||
|
// OpenDevices returns all devices that return 'true' in the filter
|
||||||
|
devices, _ := ctx.OpenDevices(func(desc *gousb.DeviceDesc) bool {
|
||||||
|
// fmt.Println(usbid.Describe(desc))
|
||||||
|
|
||||||
|
// path := fmt.Sprintf("/dev/bus/usb/%03d/%03d", desc.Bus, desc.Address)
|
||||||
|
// fmt.Printf("Device Path: %s\n", path)
|
||||||
|
|
||||||
|
// switch desc.Class {
|
||||||
|
// case 7:
|
||||||
|
// fmt.Println("Found a standard printer")
|
||||||
|
// case 0xFF:
|
||||||
|
// fmt.Println("Found a vendor-specific device (likely your printer)")
|
||||||
|
// }
|
||||||
|
|
||||||
|
return true // Open every device to read its name
|
||||||
|
})
|
||||||
|
defer func() {
|
||||||
|
for _, d := range devices {
|
||||||
|
|
||||||
|
d.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
for _, d := range devices {
|
||||||
|
fmt.Println(usbid.Describe(d.Desc))
|
||||||
|
fmt.Printf("Bus: %d, Address: %d\n", d.Desc.Bus, d.Desc.Address)
|
||||||
|
// Read human-readable names from the device strings
|
||||||
|
manufacturer, _ := d.Manufacturer()
|
||||||
|
product, _ := d.Product()
|
||||||
|
serial, _ := d.SerialNumber()
|
||||||
|
// d.Desc.Path
|
||||||
|
fmt.Printf("ID: %s:%s | Manufacturer: %s | Product: %s | Serial: %s\n",
|
||||||
|
d.Desc.Vendor, d.Desc.Product, manufacturer, product, serial)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package main
|
package libgofunc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"image"
|
"image"
|
||||||
|
|||||||
40
go.mod
40
go.mod
@@ -1,16 +1,46 @@
|
|||||||
module libgofunc
|
module gt.mokkon.com/sainw/libgofunc
|
||||||
|
|
||||||
go 1.22.0
|
go 1.25.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/dlclark/regexp2 v1.11.5
|
github.com/dlclark/regexp2 v1.11.5
|
||||||
github.com/fogleman/gg v1.3.0
|
github.com/fogleman/gg v1.3.0
|
||||||
github.com/kenshaw/escpos v0.0.0-20221114190919-df06b682a8fc
|
github.com/kenshaw/escpos v0.0.0-20221114190919-df06b682a8fc
|
||||||
golang.org/x/image v0.24.0
|
golang.org/x/image v0.38.0
|
||||||
golang.org/x/net v0.34.0
|
golang.org/x/net v0.52.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
codeberg.org/go-latex/latex v0.2.0 // indirect
|
||||||
|
codeberg.org/go-pdf/fpdf v0.11.1 // indirect
|
||||||
|
github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298 // indirect
|
||||||
|
github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966 // indirect
|
||||||
|
github.com/BurntSushi/xgb v0.0.0-20210121224620-deaf085860bc // indirect
|
||||||
|
github.com/BurntSushi/xgbutil v0.0.0-20190907113008-ad855c713046 // indirect
|
||||||
|
github.com/ByteArena/poly2tri-go v0.0.0-20170716161910-d102ad91854f // indirect
|
||||||
|
github.com/Kagami/go-avif v0.1.0 // indirect
|
||||||
|
github.com/andybalholm/brotli v1.2.1 // indirect
|
||||||
|
github.com/benoitkugler/textlayout v0.3.2 // indirect
|
||||||
|
github.com/benoitkugler/textprocessing v0.0.6 // indirect
|
||||||
|
github.com/go-fonts/latin-modern v0.3.3 // indirect
|
||||||
|
github.com/go-text/typesetting v0.3.4 // indirect
|
||||||
|
github.com/kolesa-team/go-webp v1.0.5 // indirect
|
||||||
|
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef // indirect
|
||||||
|
github.com/srwiley/scanx v0.0.0-20190309010443-e94503791388 // indirect
|
||||||
|
github.com/tdewolff/font v0.0.0-20260314002930-9f995dac393e // indirect
|
||||||
|
github.com/tdewolff/minify/v2 v2.24.11 // indirect
|
||||||
|
github.com/tdewolff/parse/v2 v2.8.11 // indirect
|
||||||
|
github.com/wcharczuk/go-chart/v2 v2.1.2 // indirect
|
||||||
|
github.com/yuin/goldmark v1.8.2 // indirect
|
||||||
|
gonum.org/v1/plot v0.16.0 // indirect
|
||||||
|
modernc.org/knuth v0.5.5 // indirect
|
||||||
|
modernc.org/token v1.1.0 // indirect
|
||||||
|
star-tex.org/x/tex v0.7.1 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||||
golang.org/x/text v0.22.0 // indirect
|
github.com/google/gousb v1.1.3
|
||||||
|
github.com/tdewolff/canvas v0.0.0-20260406091912-5d4f7059846e
|
||||||
|
golang.org/x/text v0.35.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
134
go.sum
134
go.sum
@@ -1,14 +1,148 @@
|
|||||||
|
codeberg.org/go-latex/latex v0.2.0 h1:Ol/a6VHY06N+5gPfewswymoRb5ZcKDXWVaVegcx4hbI=
|
||||||
|
codeberg.org/go-latex/latex v0.2.0/go.mod h1:VJAwQir7/T8LZxj7xAPivISKiVOwkMpQ8bTuPQ31X0Y=
|
||||||
|
codeberg.org/go-pdf/fpdf v0.11.1 h1:U8+coOTDVLxHIXZgGvkfQEi/q0hYHYvEHFuGNX2GzGs=
|
||||||
|
codeberg.org/go-pdf/fpdf v0.11.1/go.mod h1:Y0DGRAdZ0OmnZPvjbMp/1bYxmIPxm0ws4tfoPOc4LjU=
|
||||||
|
github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298 h1:1qlsVAQJXZHsaM8b6OLVo6muQUQd4CwkH/D3fnnbHXA=
|
||||||
|
github.com/BurntSushi/freetype-go v0.0.0-20160129220410-b763ddbfe298/go.mod h1:D+QujdIlUNfa0igpNMk6UIvlb6C252URs4yupRUV4lQ=
|
||||||
|
github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966 h1:lTG4HQym5oPKjL7nGs+csTgiDna685ZXjxijkne828g=
|
||||||
|
github.com/BurntSushi/graphics-go v0.0.0-20160129215708-b43f31a4a966/go.mod h1:Mid70uvE93zn9wgF92A/r5ixgnvX8Lh68fxp9KQBaI0=
|
||||||
|
github.com/BurntSushi/xgb v0.0.0-20210121224620-deaf085860bc h1:7D+Bh06CRPCJO3gr2F7h1sriovOZ8BMhca2Rg85c2nk=
|
||||||
|
github.com/BurntSushi/xgb v0.0.0-20210121224620-deaf085860bc/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
|
github.com/BurntSushi/xgbutil v0.0.0-20190907113008-ad855c713046 h1:O/r2Sj+8QcMF7V5IcmiE2sMFV2q3J47BEirxbXJAdzA=
|
||||||
|
github.com/BurntSushi/xgbutil v0.0.0-20190907113008-ad855c713046/go.mod h1:uw9h2sd4WWHOPdJ13MQpwK5qYWKYDumDqxWWIknEQ+k=
|
||||||
|
github.com/ByteArena/poly2tri-go v0.0.0-20170716161910-d102ad91854f h1:l7moT9o/v/9acCWA64Yz/HDLqjcRTvc0noQACi4MsJw=
|
||||||
|
github.com/ByteArena/poly2tri-go v0.0.0-20170716161910-d102ad91854f/go.mod h1:vIOkSdX3NDCPwgu8FIuTat2zDF0FPXXQ0RYFRy+oQic=
|
||||||
|
github.com/Kagami/go-avif v0.1.0 h1:8GHAGLxCdFfhpd4Zg8j1EqO7rtcQNenxIDerC/uu68w=
|
||||||
|
github.com/Kagami/go-avif v0.1.0/go.mod h1:OPmPqzNdQq3+sXm0HqaUJQ9W/4k+Elbc3RSfJUemDKA=
|
||||||
|
github.com/andybalholm/brotli v1.2.1 h1:R+f5xP285VArJDRgowrfb9DqL18yVK0gKAW/F+eTWro=
|
||||||
|
github.com/andybalholm/brotli v1.2.1/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
|
||||||
|
github.com/benoitkugler/pstokenizer v1.0.0/go.mod h1:l1G2Voirz0q/jj0TQfabNxVsa8HZXh/VMxFSRALWTiE=
|
||||||
|
github.com/benoitkugler/textlayout v0.3.2 h1:Y/LTkwpQ9G0Fia9yhPmZA9IR5AnE8Cq30j3C+Gx5/IE=
|
||||||
|
github.com/benoitkugler/textlayout v0.3.2/go.mod h1:o+1hFV+JSHBC9qNLIuwVoLedERU7sBPgEFcuSgfvi/w=
|
||||||
|
github.com/benoitkugler/textlayout-testdata v0.1.1/go.mod h1:i/qZl09BbUOtd7Bu/W1CAubRwTWrEXWq6JwMkw8wYxo=
|
||||||
|
github.com/benoitkugler/textprocessing v0.0.6 h1:obkMyj62GEPg3xUVYqROlCN22z1OleuZm6ULqX9Om1g=
|
||||||
|
github.com/benoitkugler/textprocessing v0.0.6/go.mod h1:Io0gN08/PXEzrSOWFa88xHx2Xv3VjvLMY7H76YoI23A=
|
||||||
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
|
github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ=
|
||||||
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||||
github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
|
github.com/fogleman/gg v1.3.0 h1:/7zJX8F6AaYQc57WQCyN9cAIz+4bCJGO9B+dyW29am8=
|
||||||
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||||
|
github.com/go-fonts/latin-modern v0.3.3 h1:g2xNgI8yzdNzIVm+qvbMryB6yGPe0pSMss8QT3QwlJ0=
|
||||||
|
github.com/go-fonts/latin-modern v0.3.3/go.mod h1:tHaiWDGze4EPB0Go4cLT5M3QzRY3peya09Z/8KSCrpY=
|
||||||
|
github.com/go-text/typesetting v0.3.4 h1:YYurUOtEb9kGSOz4uE3k4OpBGsp1dDL8+fjCeaFamAU=
|
||||||
|
github.com/go-text/typesetting v0.3.4/go.mod h1:4qZCQphq4KSgGTAeI0uMEkVbROgfah8BuyF5LRYr7XY=
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
|
||||||
|
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||||
|
github.com/google/gousb v1.1.3 h1:xt6M5TDsGSZ+rlomz5Si5Hmd/Fvbmo2YCJHN+yGaK4o=
|
||||||
|
github.com/google/gousb v1.1.3/go.mod h1:GGWUkK0gAXDzxhwrzetW592aOmkkqSGcj5KLEgmCVUg=
|
||||||
github.com/kenshaw/escpos v0.0.0-20221114190919-df06b682a8fc h1:4JwmN2Scz1vR+hfSxkdy2IE/DzxX2Cftm2lhWHyN0k0=
|
github.com/kenshaw/escpos v0.0.0-20221114190919-df06b682a8fc h1:4JwmN2Scz1vR+hfSxkdy2IE/DzxX2Cftm2lhWHyN0k0=
|
||||||
github.com/kenshaw/escpos v0.0.0-20221114190919-df06b682a8fc/go.mod h1:M+GIBmg2MqaSWIJrXCZS+/wRFbr9fOguRz3SHn8DRPE=
|
github.com/kenshaw/escpos v0.0.0-20221114190919-df06b682a8fc/go.mod h1:M+GIBmg2MqaSWIJrXCZS+/wRFbr9fOguRz3SHn8DRPE=
|
||||||
|
github.com/kolesa-team/go-webp v1.0.5 h1:GZQHJBaE8dsNKZltfwqsL0qVJ7vqHXsfA+4AHrQW3pE=
|
||||||
|
github.com/kolesa-team/go-webp v1.0.5/go.mod h1:QmJu0YHXT3ex+4SgUvs+a+1SFCDcCqyZg+LbIuNNTnE=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef h1:Ch6Q+AZUxDBCVqdkI8FSpFyZDtCVBc2VmejdNrm5rRQ=
|
||||||
|
github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef/go.mod h1:nXTWP6+gD5+LUJ8krVhhoeHjvHTutPxMYl5SvkcnJNE=
|
||||||
|
github.com/srwiley/scanx v0.0.0-20190309010443-e94503791388 h1:ZdkidVdpLW13BQ9a+/3uerT2ezy9J7KQWH18JCfhDmI=
|
||||||
|
github.com/srwiley/scanx v0.0.0-20190309010443-e94503791388/go.mod h1:C/WY5lmWfMtPFYYBTd3Lzdn4FTLr+RxlIeiBNye+/os=
|
||||||
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/tdewolff/canvas v0.0.0-20260406091912-5d4f7059846e h1:A8iHpv0I/IDv+i5YQ/km/UlqSmonRz4UNIrckFxYc+A=
|
||||||
|
github.com/tdewolff/canvas v0.0.0-20260406091912-5d4f7059846e/go.mod h1:xCHrGFuVb9eeblIAffMuLzKoRnYHQj8xZq8yZ7YQfEw=
|
||||||
|
github.com/tdewolff/font v0.0.0-20260314002930-9f995dac393e h1:20EEwnJWwKApfX5KttlWbIjgXrXa+HUvkiVUow1hdJ0=
|
||||||
|
github.com/tdewolff/font v0.0.0-20260314002930-9f995dac393e/go.mod h1:EFuulYdR5cCTF2zKMW6NxchFgd5xtEPSrjkD1MFWDpA=
|
||||||
|
github.com/tdewolff/minify/v2 v2.24.11 h1:JlANsiWaRBXedoYtsiZgY3YFkdr42oF32vp2SLgQKi4=
|
||||||
|
github.com/tdewolff/minify/v2 v2.24.11/go.mod h1:exq1pjdrh9uAICdfVKQwqz6MsJmWmQahZuTC6pTO6ro=
|
||||||
|
github.com/tdewolff/parse/v2 v2.8.11 h1:SGyjEy3xEqd+W9WVzTlTQ5GkP/en4a1AZNZVJ1cvgm0=
|
||||||
|
github.com/tdewolff/parse/v2 v2.8.11/go.mod h1:Hwlni2tiVNKyzR1o6nUs4FOF07URA+JLBLd6dlIXYqo=
|
||||||
|
github.com/tdewolff/test v1.0.11/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8=
|
||||||
|
github.com/wcharczuk/go-chart/v2 v2.1.2 h1:Y17/oYNuXwZg6TFag06qe8sBajwwsuvPiJJXcUcLL6E=
|
||||||
|
github.com/wcharczuk/go-chart/v2 v2.1.2/go.mod h1:Zi4hbaqlWpYajnXB2K22IUYVXRXaLfSGNNR7P4ukyyQ=
|
||||||
|
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||||
|
github.com/yuin/goldmark v1.8.2 h1:kEGpgqJXdgbkhcOgBxkC0X0PmoPG1ZyoZ117rDVp4zE=
|
||||||
|
github.com/yuin/goldmark v1.8.2/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg=
|
||||||
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
|
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||||
|
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||||
|
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
|
||||||
|
golang.org/x/image v0.0.0-20210504121937-7319ad40d33e/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
|
golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E=
|
||||||
golang.org/x/image v0.24.0 h1:AN7zRgVsbvmTfNyqIbbOraYL8mSwcKncEj8ofjgzcMQ=
|
golang.org/x/image v0.24.0 h1:AN7zRgVsbvmTfNyqIbbOraYL8mSwcKncEj8ofjgzcMQ=
|
||||||
golang.org/x/image v0.24.0/go.mod h1:4b/ITuLfqYq1hqZcjofwctIhi7sZh2WaCjvsBNjjya8=
|
golang.org/x/image v0.24.0/go.mod h1:4b/ITuLfqYq1hqZcjofwctIhi7sZh2WaCjvsBNjjya8=
|
||||||
|
golang.org/x/image v0.38.0 h1:5l+q+Y9JDC7mBOMjo4/aPhMDcxEptsX+Tt3GgRQRPuE=
|
||||||
|
golang.org/x/image v0.38.0/go.mod h1:/3f6vaXC+6CEanU4KJxbcUZyEePbyKbaLoDOe4ehFYY=
|
||||||
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||||
|
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||||
|
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
|
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||||
|
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||||
|
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||||
|
golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
|
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
|
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
|
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||||
|
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||||
|
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||||
|
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
|
||||||
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||||
|
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0=
|
||||||
|
golang.org/x/net v0.52.0/go.mod h1:R1MAz7uMZxVMualyPXb+VaqGSa3LIaUqk0eEt3w36Sw=
|
||||||
|
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
|
||||||
|
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
|
||||||
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
|
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||||
|
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||||
|
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||||
|
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||||
|
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
|
||||||
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||||
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
|
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||||
|
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||||
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
|
||||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||||
|
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8=
|
||||||
|
golang.org/x/text v0.35.0/go.mod h1:khi/HExzZJ2pGnjenulevKNX1W67CUy0AsXcNubPGCA=
|
||||||
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
|
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||||
|
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||||
|
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
|
||||||
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
gonum.org/v1/plot v0.16.0 h1:dK28Qx/Ky4VmPUN/2zeW0ELyM6ucDnBAj5yun7M9n1g=
|
||||||
|
gonum.org/v1/plot v0.16.0/go.mod h1:Xz6U1yDMi6Ni6aaXILqmVIb6Vro8E+K7Q/GeeH+Pn0c=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
modernc.org/knuth v0.5.5 h1:6lap2U/ISm8aC/4NU58ALFCRllNPaK0EZcIGY/oDgUg=
|
||||||
|
modernc.org/knuth v0.5.5/go.mod h1:e5SBb35HQBj2aFwbBO3ClPcViLY3Wi0LzaOd7c/3qMk=
|
||||||
|
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
|
||||||
|
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||||
|
star-tex.org/x/tex v0.7.1 h1:4qGAByRyY0WQsOjtcHlxz+FgrYxz8fzxIds2Gjepp5U=
|
||||||
|
star-tex.org/x/tex v0.7.1/go.mod h1:Y3y0U7sZTltTh/CDZIx0oAtMjG7eMaTuTtvDZGdyhJo=
|
||||||
|
|||||||
285
img.go
285
img.go
@@ -1,4 +1,4 @@
|
|||||||
package main
|
package libgofunc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
/*
|
/*
|
||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
"image"
|
"image"
|
||||||
_ "image/png"
|
_ "image/png"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"embed"
|
"embed"
|
||||||
@@ -25,18 +24,24 @@ import (
|
|||||||
|
|
||||||
"github.com/kenshaw/escpos"
|
"github.com/kenshaw/escpos"
|
||||||
)
|
)
|
||||||
|
import "log"
|
||||||
|
|
||||||
const (
|
const (
|
||||||
canvasWidth = 550
|
defalutFontSize = 18.0
|
||||||
padding = 5
|
defalutTableBorder = 5
|
||||||
lineGap = 12
|
lineGap = 12
|
||||||
|
elePSize = 18
|
||||||
|
eleH1Size = 32
|
||||||
|
eleH2Size = 24
|
||||||
|
eleH3Size = 19
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed static/*
|
//go:embed static/*
|
||||||
var fontFs embed.FS
|
var fontFs embed.FS
|
||||||
|
|
||||||
//export GenPNG
|
//export GenPNG
|
||||||
func GenPNG(outputPath *C.char, payload *C.char, tmpl *C.char) *C.char {
|
func GenPNG(width C.int, outputPath *C.char, payload *C.char, tmpl *C.char) *C.char {
|
||||||
|
canvasWidth := int(width)
|
||||||
goPath := C.GoString(outputPath)
|
goPath := C.GoString(outputPath)
|
||||||
goPayload := C.GoString(payload)
|
goPayload := C.GoString(payload)
|
||||||
goTmpl := C.GoString(tmpl)
|
goTmpl := C.GoString(tmpl)
|
||||||
@@ -58,42 +63,29 @@ func GenPNG(outputPath *C.char, payload *C.char, tmpl *C.char) *C.char {
|
|||||||
return NewErr(err)
|
return NewErr(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fontBytes, err := fontFs.ReadFile("static/Zawgyi-One.ttf")
|
face, err := LoadFont(defalutFontSize)
|
||||||
if err != nil {
|
|
||||||
return NewErr(err)
|
|
||||||
}
|
|
||||||
ttfFont, err := opentype.Parse(fontBytes)
|
|
||||||
if err != nil {
|
|
||||||
return NewErr(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
face, err := opentype.NewFace(ttfFont, &opentype.FaceOptions{
|
|
||||||
Size: 24,
|
|
||||||
DPI: 72,
|
|
||||||
Hinting: font.HintingFull,
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return NewErr(err)
|
return NewErr(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// First pass: compute required height
|
// First pass: compute required height
|
||||||
dummyDC := gg.NewContext(canvasWidth, 150)
|
dummyDC := gg.NewContext(canvasWidth, 150)
|
||||||
dummyDC.SetFontFace(face)
|
dummyDC.SetFontFace(*face)
|
||||||
bodyNode := findNode(root, "body")
|
bodyNode := findNode(root, "body")
|
||||||
if bodyNode == nil {
|
if bodyNode == nil {
|
||||||
bodyNode = root
|
bodyNode = root
|
||||||
}
|
}
|
||||||
|
|
||||||
computedHeight := computeHeight(bodyNode, padding, dummyDC, face)
|
body, height := BuildTree(bodyNode, canvasWidth, dummyDC, face)
|
||||||
|
|
||||||
// Second pass: actual rendering
|
// Second pass: actual rendering
|
||||||
dc := gg.NewContext(canvasWidth, computedHeight+50)
|
dc := gg.NewContext(canvasWidth, height)
|
||||||
dc.SetRGB(1, 1, 1)
|
dc.SetRGB(1, 1, 1)
|
||||||
dc.Clear()
|
dc.Clear()
|
||||||
dc.SetFontFace(face)
|
dc.SetFontFace(*face)
|
||||||
|
|
||||||
y := padding
|
y := 0
|
||||||
renderNode(dc, bodyNode, &y, face)
|
renderNode(dc, canvasWidth, body, &y, *face)
|
||||||
|
|
||||||
err = dc.SavePNG(goPath)
|
err = dc.SavePNG(goPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -104,6 +96,12 @@ func GenPNG(outputPath *C.char, payload *C.char, tmpl *C.char) *C.char {
|
|||||||
return NewOk(nil)
|
return NewOk(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GenImg(width int, outputPath, payload, tmpl string) string {
|
||||||
|
result := GenPNG(C.int(width), C.CString(outputPath), C.CString(payload), C.CString(tmpl))
|
||||||
|
r := C.GoString(result)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
func renderTemplate(tmp string, data map[string]interface{}) (string, error) {
|
func renderTemplate(tmp string, data map[string]interface{}) (string, error) {
|
||||||
tmpl := template.Must(template.New("mytemplate").Parse(tmp))
|
tmpl := template.Must(template.New("mytemplate").Parse(tmp))
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
@@ -113,34 +111,48 @@ func renderTemplate(tmp string, data map[string]interface{}) (string, error) {
|
|||||||
return buf.String(), nil
|
return buf.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderNode(dc *gg.Context, n *html.Node, y *int, face font.Face) {
|
func renderNode(dc *gg.Context, canvasWidth int, n *Node, y *int, face font.Face) {
|
||||||
if n.Type == html.ElementNode {
|
before := *y
|
||||||
switch n.Data {
|
if n.Style.PaddingTop > 0 {
|
||||||
|
*y += int(n.Style.PaddingTop)
|
||||||
|
}
|
||||||
|
switch n.Tag {
|
||||||
case "h1":
|
case "h1":
|
||||||
drawTextBlock(dc, getText(n), 28, y, face)
|
drawTextBlock(dc, n, canvasWidth, eleH1Size, y, face)
|
||||||
|
case "h2":
|
||||||
|
drawTextBlock(dc, n, canvasWidth, eleH2Size, y, face)
|
||||||
|
case "h3":
|
||||||
|
drawTextBlock(dc, n, canvasWidth, eleH3Size, y, face)
|
||||||
case "p":
|
case "p":
|
||||||
drawTextBlock(dc, getText(n), 24, y, face)
|
drawTextBlock(dc, n, canvasWidth, elePSize, y, face)
|
||||||
|
case "hr":
|
||||||
|
renderLine(dc, n, canvasWidth, y)
|
||||||
case "img":
|
case "img":
|
||||||
drawImage(dc, n, y)
|
drawImage(dc, n, y)
|
||||||
case "table":
|
case "table":
|
||||||
renderTable(dc, n, y, face)
|
renderTable(dc, canvasWidth, n, y, face)
|
||||||
|
}
|
||||||
|
if n.Style.PaddingBottom > 0 {
|
||||||
|
*y += int(n.Style.PaddingBottom)
|
||||||
|
}
|
||||||
|
log.Printf("render %s y, y', height: %d, %d, %d\n", n.Tag, before, *y, *y-before)
|
||||||
|
|
||||||
|
for _, c := range n.Children {
|
||||||
|
renderNode(dc, canvasWidth, c, y, face)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
func drawTextBlock(dc *gg.Context, n *Node, canvasWidth int, size float64, y *int, face font.Face) {
|
||||||
renderNode(dc, c, y, face)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func drawTextBlock(dc *gg.Context, text string, size float64, y *int, face font.Face) {
|
|
||||||
dc.SetFontFace(face)
|
dc.SetFontFace(face)
|
||||||
lines := wordWrap(dc, text, canvasWidth-padding*2)
|
padding := n.Style.PaddingLeft + n.Style.PaddingRight
|
||||||
|
lines := wordWrap(dc, n.Text, canvasWidth-int(padding))
|
||||||
|
SetFontSize(dc, size)
|
||||||
for _, line := range lines {
|
for _, line := range lines {
|
||||||
dc.SetRGB(0, 0, 0)
|
dc.SetRGB(0, 0, 0)
|
||||||
dc.DrawString(line, padding, float64(*y))
|
dc.DrawStringAnchored(line, padding, float64(*y), 0, 0.5)
|
||||||
|
// dc.DrawString(line, padding, float64(*y))
|
||||||
*y += int(size) + lineGap
|
*y += int(size) + lineGap
|
||||||
}
|
}
|
||||||
*y += 5
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func wordWrap(dc *gg.Context, text string, maxWidth int) []string {
|
func wordWrap(dc *gg.Context, text string, maxWidth int) []string {
|
||||||
@@ -164,53 +176,101 @@ func wordWrap(dc *gg.Context, text string, maxWidth int) []string {
|
|||||||
return lines
|
return lines
|
||||||
}
|
}
|
||||||
|
|
||||||
func drawImage(dc *gg.Context, n *html.Node, y *int) {
|
func drawImage(dc *gg.Context, n *Node, y *int) {
|
||||||
src := getAttr(n, "src")
|
src := n.getSrc()
|
||||||
file, err := os.Open(src)
|
file, err := os.Open(src)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
img, _, _ := image.Decode(file)
|
img, _, _ := image.Decode(file)
|
||||||
widthStr := getAttr(n, "width")
|
padding := n.Style.PaddingLeft
|
||||||
if widthStr != "" {
|
h := n.Style.Height
|
||||||
w, _ := strconv.Atoi(widthStr)
|
if n.Style.Width > 0 {
|
||||||
scale := float64(w) / float64(img.Bounds().Dx())
|
ix := padding
|
||||||
|
iy := float64(*y)
|
||||||
|
scale := n.Style.Width / float64(img.Bounds().Dx())
|
||||||
dc.Push()
|
dc.Push()
|
||||||
dc.Scale(scale, scale)
|
dc.Scale(scale, scale)
|
||||||
dc.DrawImage(img, padding, *y)
|
if scale > 0 {
|
||||||
|
ix = ix / scale
|
||||||
|
iy = iy / scale
|
||||||
|
}
|
||||||
|
dc.DrawImage(img, int(ix), int(iy))
|
||||||
dc.Pop()
|
dc.Pop()
|
||||||
*y += int(float64(img.Bounds().Dy()) * scale)
|
if float64(img.Bounds().Dy())*scale > h {
|
||||||
|
h = float64(img.Bounds().Dy()) * scale
|
||||||
|
}
|
||||||
|
*y += int(h)
|
||||||
} else {
|
} else {
|
||||||
dc.DrawImage(img, padding, *y)
|
dc.DrawImage(img, int(padding), *y)
|
||||||
*y += img.Bounds().Dy()
|
*y += img.Bounds().Dy()
|
||||||
}
|
}
|
||||||
*y += 10
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderTable(dc *gg.Context, table *html.Node, y *int, face font.Face) {
|
func renderTable(dc *gg.Context, canvasWidth int, table *Node, y *int, face font.Face) {
|
||||||
rows := extractRows(table)
|
rows := extractRows(table)
|
||||||
if len(rows) == 0 {
|
if len(rows) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
fontSize := defalutFontSize
|
||||||
|
|
||||||
|
if table.Style.FontSize > 0 {
|
||||||
|
fontSize = table.Style.FontSize
|
||||||
|
}
|
||||||
|
SetFontSize(dc, fontSize)
|
||||||
|
padding := int(table.Style.PaddingLeft + table.Style.PaddingRight)
|
||||||
colCount := len(rows[0])
|
colCount := len(rows[0])
|
||||||
cellWidth := (canvasWidth - padding*2) / colCount
|
cellWidth := (canvasWidth - padding) / colCount
|
||||||
dc.SetFontFace(face)
|
border := table.Style.Border
|
||||||
for _, row := range rows {
|
for _, row := range rows {
|
||||||
x := padding
|
x := padding
|
||||||
for _, cell := range row {
|
for _, cell := range row {
|
||||||
dc.DrawRectangle(float64(x), float64(*y), float64(cellWidth), 30)
|
if border > 0 {
|
||||||
|
dc.SetLineWidth(border)
|
||||||
|
dc.DrawRectangle(float64(x), float64(*y), float64(cellWidth), fontSize+defalutTableBorder)
|
||||||
|
}
|
||||||
dc.Stroke()
|
dc.Stroke()
|
||||||
dc.SetRGB(0, 0, 0)
|
dc.SetRGB(0, 0, 0)
|
||||||
dc.DrawString(cell, float64(x+8), float64(*y+20))
|
dc.DrawStringAnchored(cell, float64(x+8), float64(*y+20), 0, 0)
|
||||||
x += cellWidth
|
x += cellWidth
|
||||||
}
|
}
|
||||||
*y += 30
|
*y += int(fontSize) + defalutTableBorder
|
||||||
}
|
}
|
||||||
*y += 10
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func extractRows(table *html.Node) [][]string {
|
func renderLine(dc *gg.Context, line *Node, canvasWidth int, y *int) {
|
||||||
|
height := line.Style.Height
|
||||||
|
xPadding := line.Style.PaddingLeft + line.Style.PaddingRight
|
||||||
|
dc.SetLineWidth(height)
|
||||||
|
dc.DrawLine(line.Style.PaddingLeft, float64(*y), float64(canvasWidth)-xPadding, float64(*y))
|
||||||
|
*y += int(height)
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractRows(table *Node) [][]string {
|
||||||
|
var rows [][]string
|
||||||
|
var traverse func(*Node)
|
||||||
|
traverse = func(n *Node) {
|
||||||
|
if n.Tag == "tr" {
|
||||||
|
var row []string
|
||||||
|
for _, td := range n.Children {
|
||||||
|
if td.Tag == "td" || td.Tag == "th" {
|
||||||
|
row = append(row, td.Text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(row) > 0 {
|
||||||
|
rows = append(rows, row)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, c := range n.Children {
|
||||||
|
traverse(c)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
traverse(table)
|
||||||
|
return rows
|
||||||
|
}
|
||||||
|
|
||||||
|
func extractNodeRows(table *html.Node) [][]string {
|
||||||
var rows [][]string
|
var rows [][]string
|
||||||
var traverse func(*html.Node)
|
var traverse func(*html.Node)
|
||||||
traverse = func(n *html.Node) {
|
traverse = func(n *html.Node) {
|
||||||
@@ -247,15 +307,6 @@ func getText(n *html.Node) string {
|
|||||||
return buf.String()
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAttr(n *html.Node, key string) string {
|
|
||||||
for _, a := range n.Attr {
|
|
||||||
if a.Key == key {
|
|
||||||
return a.Val
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func findNode(n *html.Node, tag string) *html.Node {
|
func findNode(n *html.Node, tag string) *html.Node {
|
||||||
if n.Type == html.ElementNode && n.Data == tag {
|
if n.Type == html.ElementNode && n.Data == tag {
|
||||||
return n
|
return n
|
||||||
@@ -268,36 +319,6 @@ func findNode(n *html.Node, tag string) *html.Node {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func computeHeight(n *html.Node, currentY int, dc *gg.Context, face font.Face) int {
|
|
||||||
y := currentY
|
|
||||||
if n.Type == html.ElementNode {
|
|
||||||
switch n.Data {
|
|
||||||
case "h1":
|
|
||||||
dc.SetFontFace(face)
|
|
||||||
lines := wordWrap(dc, getText(n), canvasWidth-padding*2)
|
|
||||||
y += len(lines)*28 + len(lines)*lineGap + 5
|
|
||||||
case "p":
|
|
||||||
dc.SetFontFace(face)
|
|
||||||
lines := wordWrap(dc, getText(n), canvasWidth-padding*2)
|
|
||||||
y += len(lines)*18 + len(lines)*lineGap + 5
|
|
||||||
case "table":
|
|
||||||
rows := extractRows(n)
|
|
||||||
y += len(rows)*30 + 10
|
|
||||||
case "img":
|
|
||||||
widthStr := getAttr(n, "width")
|
|
||||||
h := 100
|
|
||||||
if widthStr != "" {
|
|
||||||
h = 100
|
|
||||||
}
|
|
||||||
y += h + 10
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for c := n.FirstChild; c != nil; c = c.NextSibling {
|
|
||||||
y = computeHeight(c, y, dc, face)
|
|
||||||
}
|
|
||||||
return y
|
|
||||||
}
|
|
||||||
|
|
||||||
func printImg(prt *escpos.Escpos, imgPath string) error {
|
func printImg(prt *escpos.Escpos, imgPath string) error {
|
||||||
imgFile, err := os.Open(imgPath)
|
imgFile, err := os.Open(imgPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -318,3 +339,73 @@ func printImg(prt *escpos.Escpos, imgPath string) error {
|
|||||||
_, err = prt.WriteRaw(data)
|
_, err = prt.WriteRaw(data)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func LoadFont(size float64) (*font.Face, error) {
|
||||||
|
fontBytes, err := fontFs.ReadFile("static/Zawgyi-One.ttf")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
ttfFont, err := opentype.Parse(fontBytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
face, err := opentype.NewFace(ttfFont, &opentype.FaceOptions{
|
||||||
|
Size: size,
|
||||||
|
DPI: 72,
|
||||||
|
Hinting: font.HintingFull,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &face, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetFontSize(dc *gg.Context, size float64) {
|
||||||
|
if size < 5 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
face, err := LoadFont(size)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("SetFontSize: ", err.Error())
|
||||||
|
}
|
||||||
|
dc.SetFontFace(*face)
|
||||||
|
}
|
||||||
|
|
||||||
|
func nodeHeight(n *html.Node, dc *gg.Context, canvasWidth int, xPadding, yPadding int, face *font.Face, fontSize float64, implicit int) int {
|
||||||
|
y := 0
|
||||||
|
if n.Type == html.ElementNode {
|
||||||
|
h := 0
|
||||||
|
switch n.Data {
|
||||||
|
case "h1":
|
||||||
|
dc.SetFontFace(*face)
|
||||||
|
lines := wordWrap(dc, getText(n), canvasWidth-xPadding)
|
||||||
|
h = (len(lines) * eleH1Size) + (len(lines) * lineGap) + yPadding
|
||||||
|
case "h2":
|
||||||
|
dc.SetFontFace(*face)
|
||||||
|
lines := wordWrap(dc, getText(n), canvasWidth-xPadding)
|
||||||
|
h = (len(lines) * eleH2Size) + (len(lines) * lineGap) + yPadding
|
||||||
|
case "h3":
|
||||||
|
dc.SetFontFace(*face)
|
||||||
|
lines := wordWrap(dc, getText(n), canvasWidth-xPadding)
|
||||||
|
h = (len(lines) * eleH3Size) + (len(lines) * lineGap) + yPadding
|
||||||
|
case "p":
|
||||||
|
dc.SetFontFace(*face)
|
||||||
|
lines := wordWrap(dc, getText(n), canvasWidth-xPadding)
|
||||||
|
h = (len(lines) * elePSize) + (len(lines) * lineGap) + yPadding
|
||||||
|
case "hr":
|
||||||
|
h = yPadding
|
||||||
|
case "table":
|
||||||
|
rows := extractNodeRows(n)
|
||||||
|
h = (len(rows) * int(fontSize+defalutTableBorder)) + yPadding
|
||||||
|
case "img":
|
||||||
|
h = implicit + yPadding
|
||||||
|
}
|
||||||
|
if implicit > h {
|
||||||
|
h = implicit
|
||||||
|
}
|
||||||
|
y += h
|
||||||
|
log.Printf("nodeHeight %s height: %d, \n", n.Data, y)
|
||||||
|
}
|
||||||
|
return y
|
||||||
|
}
|
||||||
|
|||||||
51
main.go
51
main.go
@@ -1,51 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
/*
|
|
||||||
#include <stdint.h>
|
|
||||||
*/
|
|
||||||
"C"
|
|
||||||
"fmt"
|
|
||||||
_ "image/png"
|
|
||||||
)
|
|
||||||
|
|
||||||
//export Sum
|
|
||||||
func Sum(a, b int) int {
|
|
||||||
return a + b
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
payload := `{"Name":"Ko Myo","Amount":3000}`
|
|
||||||
const temp = `
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<th><img src="static/logo.png" width="80"/></th>
|
|
||||||
<th><h1 style="font-size:28">မြန်မာစာသည်တို့စာ (Invoice)</h1></th>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<p>မင်္ဂလာပါ {{.Name}}, သင်၏ အိုင်ဗွိုင်းစိန်း အချက်အလက်များပါသည်။</p>
|
|
||||||
<p>အထက်ပါ အကွက်နှစ်ကွက်ကတော့ အချိန်နဲ့ တပြေးညီ ဖောင့်ပြောင်းပေးတဲ့ မြန်မာဖောင့် ကွန်ဗာတာပဲ ဖြစ်ပါတယ်။ စာရိုက်ထည့်တာနဲ့ဖြစ်ဖြစ် ဒါမှမဟုတ် ကူးထည့်တာနဲ့ဖြစ်ဖြစ် မြန်မာဖောင့် တစ်ခုကနေ တစ်ခုကို ပြောင်းပေးပါတယ်။ မြန်မာ ယူနီကုဒ်ကနေ ပြောင်းချင်တယ်ဆို မြန်မာ ယူနီကုဒ်ဘက်မှာ ရိုက်ထည့်၊ ကူးထည့်လိုက်တာနဲ့ ဇော်ဂျီဝမ်းဘက်မှာ ဇော်ဂျီဖောင့်ကိုပြောင်းပြီးသား တိုက်ရိုက်ထွက်လာပါမယ်။ အပြန်အလှန်ပါပဲ၊ ဇော်ဂျီကနေပြောင်းချင်တယ်ဆိုရင် ဇော်ဂျီဝမ်းဘက်မှာ ရိုက်ထည့်၊ ကူးထည့်တာနဲ့ မြန်မာ ယူနီကုဒ်ဖောင့်ကို ပြောင်းပြီးသားက မြန်မာ ယူနီကုဒ်အကွက်ထဲမှာ ပေါ်လာမှာဖြစ်ပါတယ်။</p>
|
|
||||||
|
|
||||||
<table border="1">
|
|
||||||
<tr>
|
|
||||||
<th>ပစ္စည်း</th>
|
|
||||||
<th>အရေအတွက်</th>
|
|
||||||
<th>ဈေးနှုန်း</th>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Hosting</td>
|
|
||||||
<td>1</td>
|
|
||||||
<td>{{.Amount}}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Domain registration</td>
|
|
||||||
<td>1</td>
|
|
||||||
<td>$15</td>
|
|
||||||
</tr>
|
|
||||||
</table>`
|
|
||||||
result := GenPNG(C.CString("build/out.png"), C.CString(payload), C.CString(temp))
|
|
||||||
goResult := C.GoString(result)
|
|
||||||
fmt.Println("Result:", goResult)
|
|
||||||
PrintImg(C.CString("usb:/dev/usb/lp1"), C.CString("build/out.png"))
|
|
||||||
}
|
|
||||||
65
printer.go
65
printer.go
@@ -1,4 +1,4 @@
|
|||||||
package main
|
package libgofunc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
/*
|
/*
|
||||||
@@ -17,12 +17,33 @@ import (
|
|||||||
|
|
||||||
"github.com/kenshaw/escpos"
|
"github.com/kenshaw/escpos"
|
||||||
)
|
)
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/google/gousb"
|
||||||
|
)
|
||||||
|
|
||||||
|
type USBReadWriter struct {
|
||||||
|
out *gousb.OutEndpoint
|
||||||
|
in *gousb.InEndpoint // Optional, can be nil if you only write
|
||||||
|
}
|
||||||
|
|
||||||
|
func (urw *USBReadWriter) Write(p []byte) (n int, err error) {
|
||||||
|
return urw.out.Write(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (urw *USBReadWriter) Read(p []byte) (n int, err error) {
|
||||||
|
if urw.in == nil {
|
||||||
|
return 0, fmt.Errorf("read not supported")
|
||||||
|
}
|
||||||
|
return urw.in.Read(p)
|
||||||
|
}
|
||||||
|
|
||||||
//export PrintImg
|
//export PrintImg
|
||||||
func PrintImg(printer *C.char, imagePath *C.char) *C.char {
|
func PrintImg(printer *C.char, imagePath *C.char) *C.char {
|
||||||
goPrinter := C.GoString(printer)
|
goPrinter := C.GoString(printer)
|
||||||
goImagePath := C.GoString(imagePath)
|
goImagePath := C.GoString(imagePath)
|
||||||
|
var out *gousb.OutEndpoint
|
||||||
// printer := "tcp:192.168.100.151:9100"
|
// printer := "tcp:192.168.100.151:9100"
|
||||||
// printer := "usb:/dev/usb/lp1"
|
// printer := "usb:/dev/usb/lp1"
|
||||||
var w *bufio.ReadWriter
|
var w *bufio.ReadWriter
|
||||||
@@ -44,6 +65,40 @@ func PrintImg(printer *C.char, imagePath *C.char) *C.char {
|
|||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
w = bufio.NewReadWriter(bufio.NewReader(f), bufio.NewWriter(f))
|
w = bufio.NewReadWriter(bufio.NewReader(f), bufio.NewWriter(f))
|
||||||
|
} else if strings.HasPrefix(goPrinter, "int:") {
|
||||||
|
ctx := gousb.NewContext()
|
||||||
|
// location := strings.TrimLeft(goPrinter, "int:")
|
||||||
|
targetBus := 1
|
||||||
|
targetAddr := 5
|
||||||
|
devs, err := ctx.OpenDevices(func(desc *gousb.DeviceDesc) bool {
|
||||||
|
return int(desc.Bus) == targetBus && int(desc.Address) == targetAddr
|
||||||
|
})
|
||||||
|
if err != nil || len(devs) == 0 {
|
||||||
|
log.Fatal("Could not find or open the device")
|
||||||
|
}
|
||||||
|
dev := devs[0]
|
||||||
|
defer dev.Close()
|
||||||
|
dev.SetAutoDetach(true)
|
||||||
|
|
||||||
|
// 2. Claim the default interface (usually 0 for printers)
|
||||||
|
// Note: This may require detaching the kernel driver on Linux
|
||||||
|
intf, done, err := dev.DefaultInterface()
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to claim interface: %v", err)
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
// 3. Open the Bulk Output Endpoint (usually endpoint #1 or #2)
|
||||||
|
// You may need to inspect desc.Endpoints to find the correct Bulk Out ID
|
||||||
|
out, err = intf.OutEndpoint(1)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to open OUT endpoint: %v", err)
|
||||||
|
}
|
||||||
|
// w = bufio.NewReadWriter(bufio.NewReader(outPort), bufio.NewWriter(f))
|
||||||
|
rw := &USBReadWriter{out: out}
|
||||||
|
reader := bufio.NewReader(rw)
|
||||||
|
writer := bufio.NewWriter(rw)
|
||||||
|
w = bufio.NewReadWriter(reader, writer)
|
||||||
}
|
}
|
||||||
prt := escpos.New(w)
|
prt := escpos.New(w)
|
||||||
|
|
||||||
@@ -59,3 +114,9 @@ func PrintImg(printer *C.char, imagePath *C.char) *C.char {
|
|||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
return NewOk(nil)
|
return NewOk(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Print(printer, imagePath string) string {
|
||||||
|
result := PrintImg(C.CString(printer), C.CString(imagePath))
|
||||||
|
r := C.GoString(result)
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
package main
|
package libgofunc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|||||||
Reference in New Issue
Block a user