Compare commits
2 Commits
99189e4b51
...
8a23c7037f
| Author | SHA1 | Date | |
|---|---|---|---|
| 8a23c7037f | |||
| 29ec943d13 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -30,3 +30,4 @@ assets
|
|||||||
libgofunc
|
libgofunc
|
||||||
libgo
|
libgo
|
||||||
cmd/out.png
|
cmd/out.png
|
||||||
|
cmd/*.png
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
APP_NAME="libgofunc"
|
APP_NAME="libgofunc"
|
||||||
VERSION="${1:-v0.1.7}"
|
VERSION="${1:-v0.1.9}"
|
||||||
OUTPUT_DIR="../assets"
|
OUTPUT_DIR="../assets"
|
||||||
BUILD_DIR="../build"
|
BUILD_DIR="../build"
|
||||||
|
|
||||||
|
|||||||
45
cmd/main.go
45
cmd/main.go
@@ -22,11 +22,12 @@ func main() {
|
|||||||
const temp = `
|
const temp = `
|
||||||
<img src="../assets/logo.png" style="width:230;height:200;padding-left:130px;padding-top:30px"/>
|
<img src="../assets/logo.png" style="width:230;height:200;padding-left:130px;padding-top:30px"/>
|
||||||
<h1 style="padding-left:150px">{{.station.name}}</h1>
|
<h1 style="padding-left:150px">{{.station.name}}</h1>
|
||||||
|
<p style="padding-left:0px;font-size:18">စက်သုံးဆီဆိုင်လိပ်စာ စက်သုံးဆီဆိုင်လိပ်စာ စက်သုံးဆီဆိုင်လိပ်စာ စက်သုံးဆီဆိုင်လိပ်စာ စက်သုံးဆီဆိုင်လိပ်စာ စက်သုံးဆီဆိုင်လိပ်စာ စက်သုံးဆီဆိုင်လိပ်စာ</p>
|
||||||
|
|
||||||
<p style="padding-left:0px;font-size:18">Address: မင်္ဂလာပါ {{(index .sales 0).salePerson}}</p>
|
<p style="padding-left:0px;font-size:18">Address: မင်္ဂလာပါ {{(index .sales 0).salePerson}}</p>
|
||||||
<p style="padding-left:0px">Receipt: RCPT001</p>
|
<p style="padding-left:0px">Receipt: RCPT001</p>
|
||||||
<p style="padding-left:0px">Phone: 0977777777</p>
|
<p style="padding-left:0px">Phone: 0977777777</p>
|
||||||
<p style="padding-left:0px">Date: 4 Jan 2026 15:38:38</p>
|
<p style="padding-left:0px">Date: {{formatDateFromSec (index .sales 0).timeSec "2006-01-02 15:04:05"}}</p>
|
||||||
<p style="padding-left:0px">Car No.: 3J/3883</p>
|
<p style="padding-left:0px">Car No.: 3J/3883</p>
|
||||||
<p style="padding-left:0px">Casher: မနှင်းနှင်း</p>
|
<p style="padding-left:0px">Casher: မနှင်းနှင်း</p>
|
||||||
<p style="padding-left:0px">MOP: B2B</p>
|
<p style="padding-left:0px">MOP: B2B</p>
|
||||||
@@ -57,8 +58,48 @@ func main() {
|
|||||||
|
|
||||||
<p style="padding-left:0px;padding-top:50px;">
|
<p style="padding-left:0px;padding-top:50px;">
|
||||||
စက်သုံးဆီ အရေအတွက် နှင့် အရည်အသွေးစျေးနှုန်းများ အားသံသယရှိပါက ph 09450539099, 09765421033, 09765421029 သို့တိုင်ကြား နိုင်ပါသည်။</p>
|
စက်သုံးဆီ အရေအတွက် နှင့် အရည်အသွေးစျေးနှုန်းများ အားသံသယရှိပါက ph 09450539099, 09765421033, 09765421029 သို့တိုင်ကြား နိုင်ပါသည်။</p>
|
||||||
|
<cut>
|
||||||
|
<img src="../assets/logo.png" style="width:230;height:200;padding-left:130px;padding-top:30px"/>
|
||||||
|
<h1 style="padding-left:150px">{{.station.name}}</h1>
|
||||||
|
<p style="padding-left:0px;font-size:18">စက်သုံးဆီဆိုင်လိပ်စာ စက်သုံးဆီဆိုင်လိပ်စာ စက်သုံးဆီဆိုင်လိပ်စာ စက်သုံးဆီဆိုင်လိပ်စာ စက်သုံးဆီဆိုင်လိပ်စာ စက်သုံးဆီဆိုင်လိပ်စာ စက်သုံးဆီဆိုင်လိပ်စာ</p>
|
||||||
|
|
||||||
|
<p style="padding-left:0px;font-size:18">Address: မင်္ဂလာပါ {{(index .sales 0).salePerson}}</p>
|
||||||
|
<p style="padding-left:0px">Receipt: RCPT001</p>
|
||||||
|
<p style="padding-left:0px">Phone: 0977777777</p>
|
||||||
|
<p style="padding-left:0px">Date: {{formatDateFromSec (index .sales 0).timeSec "2006-01-02 15:04:05"}}</p>
|
||||||
|
<p style="padding-left:0px">Car No.: 3J/3883</p>
|
||||||
|
<p style="padding-left:0px">Casher: မနှင်းနှင်း</p>
|
||||||
|
<p style="padding-left:0px">MOP: B2B</p>
|
||||||
|
<p style="padding-left:0px">Tier: 1</p>
|
||||||
|
<p style="padding-left:0px">Deal No.: RR</p>
|
||||||
|
<hr style="height:1px;padding-left:0px;padding-right:10px;padding-bottom:10px"/>
|
||||||
|
|
||||||
|
<table style="padding-left:0px;padding-bottom:10px;border:0px;font-size:16px;border:0px;">
|
||||||
|
<tr>
|
||||||
|
<th style="width:120">Item</th>
|
||||||
|
<th style="width:50">Pump</th>
|
||||||
|
<th>Price</th>
|
||||||
|
<th>Liter</th>
|
||||||
|
<th>Gallon</th>
|
||||||
|
<th>Amount</th>
|
||||||
|
</tr>
|
||||||
|
{{range .sales}}
|
||||||
|
<tr>
|
||||||
|
<td>{{.product}}</td>
|
||||||
|
<td>{{.fpId}}</td>
|
||||||
|
<td>{{.price}}</td>
|
||||||
|
<td>{{.volume}}</td>
|
||||||
|
<td>{{.volume}}</td>
|
||||||
|
<td>{{.amount}}</td>
|
||||||
|
</tr>
|
||||||
|
{{end}}
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p style="padding-left:0px;padding-top:50px;">
|
||||||
|
စက်သုံးဆီ အရေအတွက် နှင့် အရည်အသွေးစျေးနှုန်းများ အားသံသယရှိပါက ph 09450539099, 09765421033, 09765421029 သို့တိုင်ကြား နိုင်ပါသည်။</p>
|
||||||
|
|
||||||
`
|
`
|
||||||
result := libgofunc.GenImg(550, "./out.png", payload, temp, "./")
|
result := libgofunc.GenImg(550, "./", payload, temp, "./")
|
||||||
fmt.Println("Result:", result)
|
fmt.Println("Result:", result)
|
||||||
// PrintImg(C.CString("usb:/dev/usb/lp1"), C.CString("build/out.png"))
|
// PrintImg(C.CString("usb:/dev/usb/lp1"), C.CString("build/out.png"))
|
||||||
// libgofunc.Print("int:/dev/bus/usb/001/046", "./out.png")
|
// libgofunc.Print("int:/dev/bus/usb/001/046", "./out.png")
|
||||||
|
|||||||
1
go.mod
1
go.mod
@@ -12,5 +12,6 @@ require (
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||||
|
github.com/google/uuid v1.6.0
|
||||||
golang.org/x/text v0.35.0 // indirect
|
golang.org/x/text v0.35.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
2
go.sum
2
go.sum
@@ -4,6 +4,8 @@ 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/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/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
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=
|
||||||
golang.org/x/image v0.38.0 h1:5l+q+Y9JDC7mBOMjo4/aPhMDcxEptsX+Tt3GgRQRPuE=
|
golang.org/x/image v0.38.0 h1:5l+q+Y9JDC7mBOMjo4/aPhMDcxEptsX+Tt3GgRQRPuE=
|
||||||
|
|||||||
75
img.go
75
img.go
@@ -28,7 +28,9 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
"golang.org/x/text/language"
|
"golang.org/x/text/language"
|
||||||
"golang.org/x/text/message"
|
"golang.org/x/text/message"
|
||||||
)
|
)
|
||||||
@@ -47,9 +49,9 @@ const (
|
|||||||
var fontFs embed.FS
|
var fontFs embed.FS
|
||||||
|
|
||||||
//export GenPNG
|
//export GenPNG
|
||||||
func GenPNG(width C.int, outputPath *C.char, payload *C.char, tmpl *C.char, workingDirC *C.char) *C.char {
|
func GenPNG(width C.int, outDir *C.char, payload *C.char, tmpl *C.char, workingDirC *C.char) *C.char {
|
||||||
canvasWidth := int(width)
|
canvasWidth := int(width)
|
||||||
goPath := C.GoString(outputPath)
|
goOutDir := C.GoString(outDir)
|
||||||
goPayload := C.GoString(payload)
|
goPayload := C.GoString(payload)
|
||||||
goTmpl := C.GoString(tmpl)
|
goTmpl := C.GoString(tmpl)
|
||||||
workingDir := C.GoString(workingDirC)
|
workingDir := C.GoString(workingDirC)
|
||||||
@@ -66,14 +68,27 @@ func GenPNG(width C.int, outputPath *C.char, payload *C.char, tmpl *C.char, work
|
|||||||
}
|
}
|
||||||
|
|
||||||
htmlStr = uni2zg(htmlStr)
|
htmlStr = uni2zg(htmlStr)
|
||||||
root, err := html.Parse(strings.NewReader(htmlStr))
|
htmls := strings.Split(htmlStr, "<cut>")
|
||||||
|
result := make([]string, 0)
|
||||||
|
for _, html := range htmls {
|
||||||
|
out, err := GenPng(canvasWidth, goOutDir, html, workingDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return NewErr(err)
|
return NewErr(err)
|
||||||
}
|
}
|
||||||
|
result = append(result, out)
|
||||||
|
}
|
||||||
|
return NewOk(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
func GenPng(canvasWidth int, outDir string, htmlStr string, workingDir string) (string, error) {
|
||||||
|
root, err := html.Parse(strings.NewReader(htmlStr))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
face, err := LoadFont(defalutFontSize)
|
face, err := LoadFont(defalutFontSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return NewErr(err)
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
// First pass: compute required height
|
// First pass: compute required height
|
||||||
@@ -95,20 +110,19 @@ func GenPNG(width C.int, outputPath *C.char, payload *C.char, tmpl *C.char, work
|
|||||||
y := 0
|
y := 0
|
||||||
err = renderNode(dc, canvasWidth, body, &y, *face, workingDir)
|
err = renderNode(dc, canvasWidth, body, &y, *face, workingDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return NewErr(err)
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = dc.SavePNG(goPath)
|
outPath := path.Join(outDir, uuid.NewString()+".png")
|
||||||
|
err = dc.SavePNG(outPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return NewErr(err)
|
return "", err
|
||||||
|
}
|
||||||
|
return outPath, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// PrintReceipt(goPath)
|
func GenImg(width int, outputDir, payload, tmpl, workingDir string) string {
|
||||||
return NewOk(nil)
|
result := GenPNG(C.int(width), C.CString(outputDir), C.CString(payload), C.CString(tmpl), C.CString(workingDir))
|
||||||
}
|
|
||||||
|
|
||||||
func GenImg(width int, outputPath, payload, tmpl, workingDir string) string {
|
|
||||||
result := GenPNG(C.int(width), C.CString(outputPath), C.CString(payload), C.CString(tmpl), C.CString(workingDir))
|
|
||||||
r := C.GoString(result)
|
r := C.GoString(result)
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
@@ -116,6 +130,7 @@ func GenImg(width int, outputPath, payload, tmpl, workingDir string) string {
|
|||||||
var funcMap = template.FuncMap{
|
var funcMap = template.FuncMap{
|
||||||
"formatNumber": FormatNumber,
|
"formatNumber": FormatNumber,
|
||||||
"div": Div,
|
"div": Div,
|
||||||
|
"formatDateFromSec": formatDateFromSec,
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderTemplate(tmp string, data map[string]interface{}) (string, error) {
|
func renderTemplate(tmp string, data map[string]interface{}) (string, error) {
|
||||||
@@ -160,7 +175,8 @@ func renderNode(dc *gg.Context, canvasWidth int, n *Node, y *int, face font.Face
|
|||||||
if n.Style.PaddingBottom > 0 {
|
if n.Style.PaddingBottom > 0 {
|
||||||
*y += int(n.Style.PaddingBottom)
|
*y += int(n.Style.PaddingBottom)
|
||||||
}
|
}
|
||||||
log.Printf("render %s y, y', height: %d, %d, %d\n", n.Tag, before, *y, *y-before)
|
_ = before
|
||||||
|
// log.Printf("render %s y, y', height: %d, %d, %d\n", n.Tag, before, *y, *y-before)
|
||||||
|
|
||||||
for _, c := range n.Children {
|
for _, c := range n.Children {
|
||||||
renderNode(dc, canvasWidth, c, y, face, workingDir)
|
renderNode(dc, canvasWidth, c, y, face, workingDir)
|
||||||
@@ -451,7 +467,7 @@ func nodeHeight(n *html.Node, dc *gg.Context, canvasWidth int, xPadding, yPaddin
|
|||||||
h = implicit
|
h = implicit
|
||||||
}
|
}
|
||||||
y += h
|
y += h
|
||||||
log.Printf("nodeHeight %s height: %d, \n", n.Data, y)
|
// log.Printf("nodeHeight %s height: %d, \n", n.Data, y)
|
||||||
}
|
}
|
||||||
return y
|
return y
|
||||||
}
|
}
|
||||||
@@ -518,3 +534,32 @@ func convertToFloat64(v any) float64 {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func formatDateFromSec(input any, layout string) string {
|
||||||
|
var sec int64
|
||||||
|
switch v := input.(type) {
|
||||||
|
case int64:
|
||||||
|
sec = v
|
||||||
|
case int:
|
||||||
|
sec = int64(v)
|
||||||
|
case float64:
|
||||||
|
sec = int64(v)
|
||||||
|
case float32:
|
||||||
|
sec = int64(v)
|
||||||
|
case string:
|
||||||
|
parsed, err := strconv.ParseInt(v, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
if parsedFloat, errFloat := strconv.ParseFloat(v, 64); errFloat == nil {
|
||||||
|
sec = int64(parsedFloat)
|
||||||
|
} else {
|
||||||
|
return fmt.Sprintf("[Error: invalid time string %q]", v)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sec = parsed
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return "[Error: unsupported time type]"
|
||||||
|
}
|
||||||
|
t := time.UnixMilli(sec * 1000)
|
||||||
|
return t.Format(layout)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user