Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f9c96971a7 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -28,5 +28,3 @@ go.work.sum
|
||||
build
|
||||
assets
|
||||
libgofunc
|
||||
libgo
|
||||
cmd/out.png
|
||||
|
||||
12
build_lib.sh
12
build_lib.sh
@@ -1,9 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
APP_NAME="libgofunc"
|
||||
VERSION="${1:-v0.1.7}"
|
||||
OUTPUT_DIR="../assets"
|
||||
BUILD_DIR="../build"
|
||||
VERSION="${1:-v0.1.3}"
|
||||
OUTPUT_DIR="assets"
|
||||
BUILD_DIR="build"
|
||||
|
||||
# need Android NDK
|
||||
NDK_HOME="$HOME/Android/Sdk/ndk/28.2.13676358" # <--- CHECK YOUR VERSION
|
||||
@@ -11,7 +11,7 @@ API=21
|
||||
|
||||
TOOLCHAIN="$NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin"
|
||||
OS="$(uname -s)"
|
||||
cd cmd
|
||||
|
||||
if [ "$OS" = "Darwin" ]; then
|
||||
export IOS_SDK=$(xcrun --sdk iphoneos --show-sdk-path)
|
||||
export IOS_SIM_SDK=$(xcrun --sdk iphonesimulator --show-sdk-path)
|
||||
@@ -27,7 +27,7 @@ if [ "$OS" = "Darwin" ]; then
|
||||
CC="$(xcrun --sdk iphonesimulator --find clang)" \
|
||||
CGO_CFLAGS="-isysroot $IOS_SIM_SDK -arch x86_64" \
|
||||
CGO_LDFLAGS="-isysroot $IOS_SIM_SDK -arch x86_64" \
|
||||
go build ./cmd -buildmode=c-archive -o build/ios/sim/libgofunc_arm64_sim.a .
|
||||
go build -buildmode=c-archive -o build/ios/sim/libgofunc_arm64_sim.a .
|
||||
|
||||
# xcodebuild -create-xcframework \
|
||||
# -library build/ios/device/libgofunc_arm64.a -headers build/ios/device/ \
|
||||
@@ -74,7 +74,7 @@ elif [ "$OS" = "Linux" ]; then
|
||||
tar -czf "${OUTPUT_DIR}/${VERSION}/${ARCHIVE_NAME}" -C "${BUILD_DIR}" ./${VERSION}/${ARCH}
|
||||
|
||||
export HTTPS_PROXY="socks5://localhost:8080"
|
||||
rclone copy ../assets/${VERSION} s3:mokkon/libs/libgofunc/${VERSION}
|
||||
rclone copy ./assets/${VERSION} s3:mokkon/libs/libgofunc/${VERSION}
|
||||
else
|
||||
echo "Unsupported OS: $OS"
|
||||
exit 1
|
||||
|
||||
94
cmd/main.go
94
cmd/main.go
File diff suppressed because one or more lines are too long
@@ -91,8 +91,7 @@ func toMonochrome(img image.Image) *image.Gray {
|
||||
for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
|
||||
for x := bounds.Min.X; x < bounds.Max.X; x++ {
|
||||
r, g, b, _ := img.At(x, y).RGBA()
|
||||
// grayValue := uint8((r + g + b) / 3 >> 8)
|
||||
grayValue := uint8((0.299*float64(r) + 0.587*float64(g) + 0.114*float64(b)) / 256.0)
|
||||
grayValue := uint8((r + g + b) / 3 >> 8)
|
||||
if grayValue > 128 {
|
||||
gray.Set(x, y, color.White)
|
||||
} else {
|
||||
@@ -139,6 +138,7 @@ func escposRaster(img *image.Gray) []byte {
|
||||
data = append(data, b)
|
||||
}
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
|
||||
3
go.mod
3
go.mod
@@ -1,6 +1,6 @@
|
||||
module gt.mokkon.com/sainw/libgofunc
|
||||
|
||||
go 1.26.0
|
||||
go 1.25.0
|
||||
|
||||
require (
|
||||
github.com/dlclark/regexp2 v1.11.5
|
||||
@@ -12,5 +12,6 @@ require (
|
||||
|
||||
require (
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||
github.com/google/gousb v1.1.3
|
||||
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/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/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/go.mod h1:M+GIBmg2MqaSWIJrXCZS+/wRFbr9fOguRz3SHn8DRPE=
|
||||
golang.org/x/image v0.38.0 h1:5l+q+Y9JDC7mBOMjo4/aPhMDcxEptsX+Tt3GgRQRPuE=
|
||||
|
||||
149
img.go
149
img.go
@@ -24,14 +24,7 @@ import (
|
||||
|
||||
"github.com/kenshaw/escpos"
|
||||
)
|
||||
import (
|
||||
"log"
|
||||
"path"
|
||||
"strconv"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
"golang.org/x/text/message"
|
||||
)
|
||||
import "log"
|
||||
|
||||
const (
|
||||
defalutFontSize = 18.0
|
||||
@@ -47,12 +40,11 @@ const (
|
||||
var fontFs embed.FS
|
||||
|
||||
//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, outputPath *C.char, payload *C.char, tmpl *C.char) *C.char {
|
||||
canvasWidth := int(width)
|
||||
goPath := C.GoString(outputPath)
|
||||
goPayload := C.GoString(payload)
|
||||
goTmpl := C.GoString(tmpl)
|
||||
workingDir := C.GoString(workingDirC)
|
||||
|
||||
data := make(map[string]interface{})
|
||||
err := json.Unmarshal([]byte(goPayload), &data)
|
||||
@@ -93,10 +85,7 @@ func GenPNG(width C.int, outputPath *C.char, payload *C.char, tmpl *C.char, work
|
||||
dc.SetFontFace(*face)
|
||||
|
||||
y := 0
|
||||
err = renderNode(dc, canvasWidth, body, &y, *face, workingDir)
|
||||
if err != nil {
|
||||
return NewErr(err)
|
||||
}
|
||||
renderNode(dc, canvasWidth, body, &y, *face)
|
||||
|
||||
err = dc.SavePNG(goPath)
|
||||
if err != nil {
|
||||
@@ -107,22 +96,14 @@ func GenPNG(width C.int, outputPath *C.char, payload *C.char, tmpl *C.char, work
|
||||
return NewOk(nil)
|
||||
}
|
||||
|
||||
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))
|
||||
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
|
||||
}
|
||||
|
||||
var funcMap = template.FuncMap{
|
||||
"formatNumber": FormatNumber,
|
||||
"div": Div,
|
||||
}
|
||||
|
||||
func renderTemplate(tmp string, data map[string]interface{}) (string, error) {
|
||||
tmpl, err := template.New("mytemplate").Funcs(funcMap).Parse(tmp)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
tmpl := template.Must(template.New("mytemplate").Parse(tmp))
|
||||
var buf bytes.Buffer
|
||||
if err := tmpl.Execute(&buf, data); err != nil {
|
||||
return "", err
|
||||
@@ -130,7 +111,7 @@ func renderTemplate(tmp string, data map[string]interface{}) (string, error) {
|
||||
return buf.String(), nil
|
||||
}
|
||||
|
||||
func renderNode(dc *gg.Context, canvasWidth int, n *Node, y *int, face font.Face, workingDir string) error {
|
||||
func renderNode(dc *gg.Context, canvasWidth int, n *Node, y *int, face font.Face) {
|
||||
before := *y
|
||||
if n.Style.PaddingTop > 0 {
|
||||
*y += int(n.Style.PaddingTop)
|
||||
@@ -143,17 +124,11 @@ func renderNode(dc *gg.Context, canvasWidth int, n *Node, y *int, face font.Face
|
||||
case "h3":
|
||||
drawTextBlock(dc, n, canvasWidth, eleH3Size, y, face)
|
||||
case "p":
|
||||
size := float64(elePSize)
|
||||
if n.Style.FontSize > 0 {
|
||||
size = n.Style.FontSize
|
||||
}
|
||||
drawTextBlock(dc, n, canvasWidth, size, y, face)
|
||||
drawTextBlock(dc, n, canvasWidth, elePSize, y, face)
|
||||
case "hr":
|
||||
renderLine(dc, n, canvasWidth, y)
|
||||
case "img":
|
||||
if err := drawImage(dc, n, y, workingDir); err != nil {
|
||||
return err
|
||||
}
|
||||
drawImage(dc, n, y)
|
||||
case "table":
|
||||
renderTable(dc, canvasWidth, n, y, face)
|
||||
}
|
||||
@@ -163,9 +138,8 @@ func renderNode(dc *gg.Context, canvasWidth int, n *Node, y *int, face font.Face
|
||||
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, workingDir)
|
||||
renderNode(dc, canvasWidth, c, y, face)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func drawTextBlock(dc *gg.Context, n *Node, canvasWidth int, size float64, y *int, face font.Face) {
|
||||
@@ -202,18 +176,14 @@ func wordWrap(dc *gg.Context, text string, maxWidth int) []string {
|
||||
return lines
|
||||
}
|
||||
|
||||
func drawImage(dc *gg.Context, n *Node, y *int, workingDir string) error {
|
||||
func drawImage(dc *gg.Context, n *Node, y *int) {
|
||||
src := n.getSrc()
|
||||
s := path.Join(workingDir, src)
|
||||
file, err := os.Open(s)
|
||||
file, err := os.Open(src)
|
||||
if err != nil {
|
||||
return fmt.Errorf("open file src: '%s', working directory: '%s', error : %s", src, workingDir, err.Error())
|
||||
return
|
||||
}
|
||||
defer file.Close()
|
||||
img, _, err := image.Decode(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
img, _, _ := image.Decode(file)
|
||||
padding := n.Style.PaddingLeft
|
||||
h := n.Style.Height
|
||||
if n.Style.Width > 0 {
|
||||
@@ -236,11 +206,10 @@ func drawImage(dc *gg.Context, n *Node, y *int, workingDir string) error {
|
||||
dc.DrawImage(img, int(padding), *y)
|
||||
*y += img.Bounds().Dy()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func renderTable(dc *gg.Context, canvasWidth int, table *Node, y *int, face font.Face) {
|
||||
headers, rows := extractRows(table)
|
||||
rows := extractRows(table)
|
||||
if len(rows) == 0 {
|
||||
return
|
||||
}
|
||||
@@ -254,11 +223,9 @@ func renderTable(dc *gg.Context, canvasWidth int, table *Node, y *int, face font
|
||||
colCount := len(rows[0])
|
||||
cellWidth := (canvasWidth - padding) / colCount
|
||||
border := table.Style.Border
|
||||
|
||||
for _, row := range rows {
|
||||
x := padding
|
||||
for i, cell := range row {
|
||||
header := headers[i]
|
||||
for _, cell := range row {
|
||||
if border > 0 {
|
||||
dc.SetLineWidth(border)
|
||||
dc.DrawRectangle(float64(x), float64(*y), float64(cellWidth), fontSize+defalutTableBorder)
|
||||
@@ -266,11 +233,7 @@ func renderTable(dc *gg.Context, canvasWidth int, table *Node, y *int, face font
|
||||
dc.Stroke()
|
||||
dc.SetRGB(0, 0, 0)
|
||||
dc.DrawStringAnchored(cell, float64(x+8), float64(*y+20), 0, 0)
|
||||
if w := header.Style.Width; w > 0 {
|
||||
x += int(w)
|
||||
} else {
|
||||
x += cellWidth
|
||||
}
|
||||
x += cellWidth
|
||||
}
|
||||
*y += int(fontSize) + defalutTableBorder
|
||||
}
|
||||
@@ -284,9 +247,8 @@ func renderLine(dc *gg.Context, line *Node, canvasWidth int, y *int) {
|
||||
*y += int(height)
|
||||
}
|
||||
|
||||
func extractRows(table *Node) ([]*Node, [][]string) {
|
||||
func extractRows(table *Node) [][]string {
|
||||
var rows [][]string
|
||||
var headers []*Node
|
||||
var traverse func(*Node)
|
||||
traverse = func(n *Node) {
|
||||
if n.Tag == "tr" {
|
||||
@@ -295,9 +257,6 @@ func extractRows(table *Node) ([]*Node, [][]string) {
|
||||
if td.Tag == "td" || td.Tag == "th" {
|
||||
row = append(row, td.Text)
|
||||
}
|
||||
if td.Tag == "th" {
|
||||
headers = append(headers, td)
|
||||
}
|
||||
}
|
||||
if len(row) > 0 {
|
||||
rows = append(rows, row)
|
||||
@@ -308,7 +267,7 @@ func extractRows(table *Node) ([]*Node, [][]string) {
|
||||
}
|
||||
}
|
||||
traverse(table)
|
||||
return headers, rows
|
||||
return rows
|
||||
}
|
||||
|
||||
func extractNodeRows(table *html.Node) [][]string {
|
||||
@@ -373,14 +332,9 @@ func printImg(prt *escpos.Escpos, imgPath string) error {
|
||||
fmt.Println(err)
|
||||
return err
|
||||
}
|
||||
data := []byte{0x1D, 0x4C, 0x00, 0x00}
|
||||
_, err = prt.WriteRaw(data)
|
||||
if err != nil {
|
||||
fmt.Println("error 0x1D, 0x4C:", err.Error())
|
||||
}
|
||||
|
||||
gray := toMonochrome(img)
|
||||
data = escposRaster(gray)
|
||||
data := escposRaster(gray)
|
||||
|
||||
_, err = prt.WriteRaw(data)
|
||||
return err
|
||||
@@ -455,66 +409,3 @@ func nodeHeight(n *html.Node, dc *gg.Context, canvasWidth int, xPadding, yPaddin
|
||||
}
|
||||
return y
|
||||
}
|
||||
|
||||
type RealNumber interface {
|
||||
~int | ~int8 | ~int16 | ~int32 | ~int64 |
|
||||
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 |
|
||||
~float32 | ~float64
|
||||
}
|
||||
|
||||
func FormatNumber(precision int, b any) string {
|
||||
return GenericFormatNumber(precision, convertToFloat64(b))
|
||||
}
|
||||
|
||||
func GenericFormatNumber[T RealNumber](precision int, v T) string {
|
||||
pEnglish := message.NewPrinter(language.English)
|
||||
|
||||
n := float64(v)
|
||||
s := fmt.Sprintf("%.*f", precision, n)
|
||||
|
||||
parts := strings.Split(s, ".")
|
||||
intPart := parts[0]
|
||||
i, err := strconv.Atoi(intPart)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
out := pEnglish.Sprintf("%d", i)
|
||||
|
||||
if len(parts) > 1 {
|
||||
return out + "." + parts[1]
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func Div(a, b any) float64 {
|
||||
return GenericDiv(convertToFloat64(a), convertToFloat64(b))
|
||||
}
|
||||
|
||||
func GenericDiv[T RealNumber](a, b T) float64 {
|
||||
floatB := float64(b)
|
||||
if floatB == 0 {
|
||||
return 0
|
||||
}
|
||||
return float64(a) / floatB
|
||||
}
|
||||
|
||||
func convertToFloat64(v any) float64 {
|
||||
switch t := v.(type) {
|
||||
case float64:
|
||||
return t
|
||||
case float32:
|
||||
return float64(t)
|
||||
case int:
|
||||
return float64(t)
|
||||
case int64:
|
||||
return float64(t)
|
||||
case int32:
|
||||
return float64(t)
|
||||
case uint:
|
||||
return float64(t)
|
||||
case uint64:
|
||||
return float64(t)
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
60
img_test.go
60
img_test.go
@@ -1,60 +0,0 @@
|
||||
package libgofunc
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDiv(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
a any
|
||||
b any
|
||||
want float64
|
||||
}{
|
||||
{"Float division", 10.5, 2.0, 5.25},
|
||||
{"Float division", 4975, 1000, 4.975},
|
||||
{"Integer division", 10, 4, 2.5},
|
||||
{"Mixed types", int64(100), float64(4.0), 25.0},
|
||||
{"Division by zero (float)", 10.0, 0.0, 0.0},
|
||||
{"Division by zero (int)", 5, 0, 0.0},
|
||||
{"Unsupported type defaults to zero", "string", 2, 0.0},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := Div(tt.a, tt.b)
|
||||
if got != tt.want {
|
||||
t.Errorf("TemplateDiv() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormatNumber(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
precision int
|
||||
val any
|
||||
want string
|
||||
}{
|
||||
{"Standard float with commas", 2, 1234567.891, "1,234,567.89"},
|
||||
{"Standard float with commas", 3, 4.975, "4.975"},
|
||||
{"Integer input with commas", 0, 5000000, "5,000,000"},
|
||||
{"Integer input forced decimals", 2, 5000, "5,000.00"},
|
||||
{"Negative float commas", 2, -9876543.21, "-9,876,543.21"},
|
||||
{"Small float rounding up", 2, 0.128, "0.13"},
|
||||
{"Small float rounding down", 2, 0.123, "0.12"},
|
||||
{"Handling NaN", 2, math.NaN(), ""},
|
||||
{"Handling Inf", 2, math.Inf(1), ""},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := FormatNumber(tt.precision, tt.val)
|
||||
if got != tt.want {
|
||||
t.Errorf("TemplateFloat() = %q, want %q", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
94
printer.go
94
printer.go
@@ -17,12 +17,33 @@ import (
|
||||
|
||||
"github.com/kenshaw/escpos"
|
||||
)
|
||||
import "errors"
|
||||
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
|
||||
func PrintImg(printer *C.char, imagePath *C.char) *C.char {
|
||||
goPrinter := C.GoString(printer)
|
||||
goImagePath := C.GoString(imagePath)
|
||||
var out *gousb.OutEndpoint
|
||||
// printer := "tcp:192.168.100.151:9100"
|
||||
// printer := "usb:/dev/usb/lp1"
|
||||
var w *bufio.ReadWriter
|
||||
@@ -44,58 +65,53 @@ func PrintImg(printer *C.char, imagePath *C.char) *C.char {
|
||||
}
|
||||
defer f.Close()
|
||||
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)
|
||||
} 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()
|
||||
// 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)
|
||||
} else {
|
||||
return NewErr(errors.New("invalid printer"))
|
||||
// 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.Init()
|
||||
prt.SetSmooth(1)
|
||||
prt.SetAlign("left")
|
||||
|
||||
err := printImg(prt, goImagePath)
|
||||
if err != nil {
|
||||
return NewErr(err)
|
||||
}
|
||||
prt.WriteRaw([]byte{0x1B, 0x64, 0x03})
|
||||
prt.Cut()
|
||||
prt.End()
|
||||
w.Flush()
|
||||
time.Sleep(1 * time.Second)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
return NewOk(nil)
|
||||
}
|
||||
|
||||
|
||||
6
vo.go
6
vo.go
@@ -10,13 +10,13 @@ import (
|
||||
)
|
||||
|
||||
type Reply struct {
|
||||
Status string `json:"status"` // "ok", "error"
|
||||
Status int `json:"status"`
|
||||
Err string `json:"err"`
|
||||
Result interface{} `json:"result"`
|
||||
}
|
||||
|
||||
func NewErr(err error) *C.char {
|
||||
e := Reply{Status: "error", Err: err.Error()}
|
||||
e := Reply{Status: 1, Err: err.Error()}
|
||||
b, err := json.Marshal(e)
|
||||
if err != nil {
|
||||
log.Println("Error json.Marshal:", err.Error())
|
||||
@@ -25,7 +25,7 @@ func NewErr(err error) *C.char {
|
||||
}
|
||||
|
||||
func NewOk(data interface{}) *C.char {
|
||||
e := Reply{Status: "ok", Result: data}
|
||||
e := Reply{Status: 0, Result: data}
|
||||
b, err := json.Marshal(e)
|
||||
if err != nil {
|
||||
log.Println("Error json.Marshal:", err.Error())
|
||||
|
||||
Reference in New Issue
Block a user