4 Commits

Author SHA1 Message Date
016dad446f add CheckPrinter 2026-10-02 22:35:05 +06:30
06f38b707e v0.1.11 2026-09-09 22:43:57 +06:30
5f4a427f3b split big chunk of data to write to printer 2026-09-08 17:24:54 +06:30
7bb8778611 pump to 0.1.10 2026-09-03 09:23:58 +06:30
4 changed files with 140 additions and 84 deletions

View File

@@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
APP_NAME="libgofunc" APP_NAME="libgofunc"
VERSION="${1:-v0.1.9}" VERSION="${1:-v0.1.12}"
OUTPUT_DIR="../assets" OUTPUT_DIR="../assets"
BUILD_DIR="../build" BUILD_DIR="../build"

File diff suppressed because one or more lines are too long

19
img.go
View File

@@ -22,8 +22,6 @@ import (
"golang.org/x/net/html" "golang.org/x/net/html"
"encoding/json" "encoding/json"
"github.com/kenshaw/escpos"
) )
import ( import (
"log" "log"
@@ -377,30 +375,25 @@ func findNode(n *html.Node, tag string) *html.Node {
return nil return nil
} }
func printImg(prt *escpos.Escpos, imgPath string) error { func imgData(imgPath string) ([]byte, error) {
imgFile, err := os.Open(imgPath) imgFile, err := os.Open(imgPath)
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return err return nil, err
} }
img, _, err := image.Decode(imgFile) img, _, err := image.Decode(imgFile)
defer imgFile.Close() defer imgFile.Close()
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
return err return nil, err
} }
data := []byte{0x1D, 0x4C, 0x00, 0x00} data := []byte{0x1D, 0x4C, 0x00, 0x00}
_, err = prt.WriteRaw(data)
if err != nil {
fmt.Println("error 0x1D, 0x4C:", err.Error())
}
gray := toMonochrome(img) gray := toMonochrome(img)
data = escposRaster(gray) imgData := escposRaster(gray)
data = append(data, imgData...)
_, err = prt.WriteRaw(data) return data, err
return err
} }
func LoadFont(size float64) (*font.Face, error) { func LoadFont(size float64) (*font.Face, error) {

View File

@@ -15,92 +15,122 @@ import (
"time" "time"
"errors"
"github.com/kenshaw/escpos" "github.com/kenshaw/escpos"
) )
import "errors" import "io"
//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)
// printer := "tcp:192.168.100.151:9100" err := Print(goPrinter, goImagePath)
// printer := "usb:/dev/usb/lp1" if err != nil {
var w *bufio.ReadWriter return NewErr(err)
if strings.HasPrefix(goPrinter, "tcp:") {
location := strings.TrimLeft(goPrinter, "tcp:")
conn, err := net.Dial("tcp", location)
if err != nil {
log.Println("error dialing:", err.Error())
return NewErr(err)
}
defer conn.Close()
w = bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn))
} else if strings.HasPrefix(goPrinter, "usb:") {
location := strings.TrimLeft(goPrinter, "usb:")
f, err := os.OpenFile(location, os.O_RDWR, os.ModeDevice)
if err != nil {
log.Println("error OpenFile usb:", err.Error())
return NewErr(err)
}
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)
// // 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"))
} }
return NewOk(nil)
}
//export CheckPrinter
func CheckPrinter(printer *C.char) *C.char {
goPrinter := C.GoString(printer)
err := Check(goPrinter)
if err != nil {
return NewErr(err)
}
return NewOk(nil)
}
func Print(printer, imagePath string) error {
conn, err := connect(printer)
if err != nil {
return err
}
defer conn.Close()
w := bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn))
prt := escpos.New(w) prt := escpos.New(w)
prt.Init() prt.Init()
prt.SetSmooth(1) prt.SetSmooth(1)
prt.SetAlign("left") prt.SetAlign("left")
err := printImg(prt, goImagePath) imgBytes, err := imgData(imagePath)
if err != nil { if err != nil {
return NewErr(err) return err
} }
err = writeChunk(w, prt, imgBytes)
if err != nil {
return err
}
time.Sleep(500 * time.Millisecond)
w.Flush()
prt.WriteRaw([]byte{0x1B, 0x64, 0x03}) prt.WriteRaw([]byte{0x1B, 0x64, 0x03})
prt.Cut() prt.Cut()
prt.End() prt.End()
w.Flush() w.Flush()
time.Sleep(1 * time.Second) time.Sleep(1 * time.Second)
return NewOk(nil) return nil
} }
func Print(printer, imagePath string) string { func Check(printer string) error {
result := PrintImg(C.CString(printer), C.CString(imagePath)) conn, err := connect(printer)
r := C.GoString(result) if err != nil {
return r return err
}
defer conn.Close()
var w *bufio.ReadWriter
w = bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn))
prt := escpos.New(w)
prt.Init()
prt.SetSmooth(1)
prt.SetAlign("left")
time.Sleep(100 * time.Millisecond)
return w.Flush()
}
func connect(printer string) (io.ReadWriteCloser, error) {
if strings.HasPrefix(printer, "tcp:") {
location := strings.TrimLeft(printer, "tcp:")
conn, err := net.Dial("tcp", location)
if err != nil {
log.Println("error net.Dial tcp:", err.Error())
return nil, err
}
return conn, nil
} else if strings.HasPrefix(printer, "usb:") {
location := strings.TrimLeft(printer, "usb:")
f, err := os.OpenFile(location, os.O_RDWR, os.ModeDevice)
if err != nil {
log.Println("error os.OpenFile usb:", err.Error())
return nil, err
}
return f, nil
}
return nil, errors.New("invalid printer")
}
// writeChunk breaks the large byte array into smaller chunks
func writeChunk(w *bufio.ReadWriter, prt *escpos.Escpos, data []byte) error {
chunkSize := 1024 // 1 KB chunks work best for network printers
for i := 0; i < len(data); i += chunkSize {
end := min(i+chunkSize, len(data))
_, err := prt.WriteRaw(data[i:end])
if err != nil {
log.Println("Error writing image chunk:", err)
return err
}
if err := w.Flush(); err != nil {
log.Println("Error flushing buffer:", err)
return err
}
// Give the printer's network chip a microsecond to breathe
time.Sleep(5 * time.Millisecond)
}
return nil
} }