3 Commits
main ... no-usb

Author SHA1 Message Date
99189e4b51 add working dir 2026-06-04 00:10:32 +06:30
d8781c3981 add template functions 2026-06-03 00:23:08 +06:30
d7ffc17d71 update to latest 2026-06-02 10:08:24 +06:30
10 changed files with 269 additions and 318 deletions

2
.gitignore vendored
View File

@@ -28,3 +28,5 @@ go.work.sum
build build
assets assets
libgofunc libgofunc
libgo
cmd/out.png

View File

@@ -1,9 +1,9 @@
#!/bin/bash #!/bin/bash
APP_NAME="libgofunc" APP_NAME="libgofunc"
VERSION="${1:-v0.1.3}" VERSION="${1:-v0.1.7}"
OUTPUT_DIR="assets" OUTPUT_DIR="../assets"
BUILD_DIR="build" BUILD_DIR="../build"
# need Android NDK # need Android NDK
NDK_HOME="$HOME/Android/Sdk/ndk/28.2.13676358" # <--- CHECK YOUR VERSION 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" TOOLCHAIN="$NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin"
OS="$(uname -s)" OS="$(uname -s)"
cd cmd
if [ "$OS" = "Darwin" ]; then if [ "$OS" = "Darwin" ]; then
export IOS_SDK=$(xcrun --sdk iphoneos --show-sdk-path) export IOS_SDK=$(xcrun --sdk iphoneos --show-sdk-path)
export IOS_SIM_SDK=$(xcrun --sdk iphonesimulator --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)" \ CC="$(xcrun --sdk iphonesimulator --find clang)" \
CGO_CFLAGS="-isysroot $IOS_SIM_SDK -arch x86_64" \ CGO_CFLAGS="-isysroot $IOS_SIM_SDK -arch x86_64" \
CGO_LDFLAGS="-isysroot $IOS_SIM_SDK -arch x86_64" \ CGO_LDFLAGS="-isysroot $IOS_SIM_SDK -arch x86_64" \
go build -buildmode=c-archive -o build/ios/sim/libgofunc_arm64_sim.a . go build ./cmd -buildmode=c-archive -o build/ios/sim/libgofunc_arm64_sim.a .
# xcodebuild -create-xcframework \ # xcodebuild -create-xcframework \
# -library build/ios/device/libgofunc_arm64.a -headers build/ios/device/ \ # -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} tar -czf "${OUTPUT_DIR}/${VERSION}/${ARCHIVE_NAME}" -C "${BUILD_DIR}" ./${VERSION}/${ARCH}
export HTTPS_PROXY="socks5://localhost:8080" 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 else
echo "Unsupported OS: $OS" echo "Unsupported OS: $OS"
exit 1 exit 1

File diff suppressed because one or more lines are too long

View File

@@ -91,7 +91,8 @@ func toMonochrome(img image.Image) *image.Gray {
for y := bounds.Min.Y; y < bounds.Max.Y; y++ { for y := bounds.Min.Y; y < bounds.Max.Y; y++ {
for x := bounds.Min.X; x < bounds.Max.X; x++ { for x := bounds.Min.X; x < bounds.Max.X; x++ {
r, g, b, _ := img.At(x, y).RGBA() r, g, b, _ := img.At(x, y).RGBA()
grayValue := uint8((r + g + b) / 3 >> 8) // grayValue := uint8((r + g + b) / 3 >> 8)
grayValue := uint8((0.299*float64(r) + 0.587*float64(g) + 0.114*float64(b)) / 256.0)
if grayValue > 128 { if grayValue > 128 {
gray.Set(x, y, color.White) gray.Set(x, y, color.White)
} else { } else {
@@ -138,7 +139,6 @@ func escposRaster(img *image.Gray) []byte {
data = append(data, b) data = append(data, b)
} }
} }
return data return data
} }

32
go.mod
View File

@@ -1,6 +1,6 @@
module gt.mokkon.com/sainw/libgofunc module gt.mokkon.com/sainw/libgofunc
go 1.25.0 go 1.26.0
require ( require (
github.com/dlclark/regexp2 v1.11.5 github.com/dlclark/regexp2 v1.11.5
@@ -10,37 +10,7 @@ require (
golang.org/x/net v0.52.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
github.com/google/gousb v1.1.3
github.com/tdewolff/canvas v0.0.0-20260406091912-5d4f7059846e
golang.org/x/text v0.35.0 // indirect golang.org/x/text v0.35.0 // indirect
) )

134
go.sum
View File

@@ -1,148 +1,14 @@
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/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 h1:5l+q+Y9JDC7mBOMjo4/aPhMDcxEptsX+Tt3GgRQRPuE=
golang.org/x/image v0.38.0/go.mod h1:/3f6vaXC+6CEanU4KJxbcUZyEePbyKbaLoDOe4ehFYY= 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/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
golang.org/x/net v0.52.0 h1:He/TN1l0e4mmR3QqHMT2Xab3Aj3L9qjbhRm78/6jrW0= 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/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/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
golang.org/x/text v0.35.0 h1:JOVx6vVDFokkpaq1AEptVzLTpDe9KGpj5tR4/X+ybL8= 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/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=

149
img.go
View File

@@ -24,7 +24,14 @@ import (
"github.com/kenshaw/escpos" "github.com/kenshaw/escpos"
) )
import "log" import (
"log"
"path"
"strconv"
"golang.org/x/text/language"
"golang.org/x/text/message"
)
const ( const (
defalutFontSize = 18.0 defalutFontSize = 18.0
@@ -40,11 +47,12 @@ 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) *C.char { func GenPNG(width C.int, outputPath *C.char, payload *C.char, tmpl *C.char, workingDirC *C.char) *C.char {
canvasWidth := int(width) 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)
workingDir := C.GoString(workingDirC)
data := make(map[string]interface{}) data := make(map[string]interface{})
err := json.Unmarshal([]byte(goPayload), &data) err := json.Unmarshal([]byte(goPayload), &data)
@@ -85,7 +93,10 @@ func GenPNG(width C.int, outputPath *C.char, payload *C.char, tmpl *C.char) *C.c
dc.SetFontFace(*face) dc.SetFontFace(*face)
y := 0 y := 0
renderNode(dc, canvasWidth, body, &y, *face) err = renderNode(dc, canvasWidth, body, &y, *face, workingDir)
if err != nil {
return NewErr(err)
}
err = dc.SavePNG(goPath) err = dc.SavePNG(goPath)
if err != nil { if err != nil {
@@ -96,14 +107,22 @@ func GenPNG(width C.int, outputPath *C.char, payload *C.char, tmpl *C.char) *C.c
return NewOk(nil) return NewOk(nil)
} }
func GenImg(width int, outputPath, payload, tmpl string) string { func GenImg(width int, outputPath, payload, tmpl, workingDir string) string {
result := GenPNG(C.int(width), C.CString(outputPath), C.CString(payload), C.CString(tmpl)) 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
} }
var funcMap = template.FuncMap{
"formatNumber": FormatNumber,
"div": Div,
}
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, err := template.New("mytemplate").Funcs(funcMap).Parse(tmp)
if err != nil {
return "", err
}
var buf bytes.Buffer var buf bytes.Buffer
if err := tmpl.Execute(&buf, data); err != nil { if err := tmpl.Execute(&buf, data); err != nil {
return "", err return "", err
@@ -111,7 +130,7 @@ func renderTemplate(tmp string, data map[string]interface{}) (string, error) {
return buf.String(), nil return buf.String(), nil
} }
func renderNode(dc *gg.Context, canvasWidth int, n *Node, y *int, face font.Face) { func renderNode(dc *gg.Context, canvasWidth int, n *Node, y *int, face font.Face, workingDir string) error {
before := *y before := *y
if n.Style.PaddingTop > 0 { if n.Style.PaddingTop > 0 {
*y += int(n.Style.PaddingTop) *y += int(n.Style.PaddingTop)
@@ -124,11 +143,17 @@ func renderNode(dc *gg.Context, canvasWidth int, n *Node, y *int, face font.Face
case "h3": case "h3":
drawTextBlock(dc, n, canvasWidth, eleH3Size, y, face) drawTextBlock(dc, n, canvasWidth, eleH3Size, y, face)
case "p": case "p":
drawTextBlock(dc, n, canvasWidth, elePSize, y, face) size := float64(elePSize)
if n.Style.FontSize > 0 {
size = n.Style.FontSize
}
drawTextBlock(dc, n, canvasWidth, size, y, face)
case "hr": case "hr":
renderLine(dc, n, canvasWidth, y) renderLine(dc, n, canvasWidth, y)
case "img": case "img":
drawImage(dc, n, y) if err := drawImage(dc, n, y, workingDir); err != nil {
return err
}
case "table": case "table":
renderTable(dc, canvasWidth, n, y, face) renderTable(dc, canvasWidth, n, y, face)
} }
@@ -138,8 +163,9 @@ 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) 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) renderNode(dc, canvasWidth, c, y, face, workingDir)
} }
return nil
} }
func drawTextBlock(dc *gg.Context, n *Node, canvasWidth int, size float64, y *int, face font.Face) { func drawTextBlock(dc *gg.Context, n *Node, canvasWidth int, size float64, y *int, face font.Face) {
@@ -176,14 +202,18 @@ func wordWrap(dc *gg.Context, text string, maxWidth int) []string {
return lines return lines
} }
func drawImage(dc *gg.Context, n *Node, y *int) { func drawImage(dc *gg.Context, n *Node, y *int, workingDir string) error {
src := n.getSrc() src := n.getSrc()
file, err := os.Open(src) s := path.Join(workingDir, src)
file, err := os.Open(s)
if err != nil { if err != nil {
return return fmt.Errorf("open file src: '%s', working directory: '%s', error : %s", src, workingDir, err.Error())
} }
defer file.Close() defer file.Close()
img, _, _ := image.Decode(file) img, _, err := image.Decode(file)
if err != nil {
return err
}
padding := n.Style.PaddingLeft padding := n.Style.PaddingLeft
h := n.Style.Height h := n.Style.Height
if n.Style.Width > 0 { if n.Style.Width > 0 {
@@ -206,10 +236,11 @@ func drawImage(dc *gg.Context, n *Node, y *int) {
dc.DrawImage(img, int(padding), *y) dc.DrawImage(img, int(padding), *y)
*y += img.Bounds().Dy() *y += img.Bounds().Dy()
} }
return nil
} }
func renderTable(dc *gg.Context, canvasWidth int, table *Node, y *int, face font.Face) { func renderTable(dc *gg.Context, canvasWidth int, table *Node, y *int, face font.Face) {
rows := extractRows(table) headers, rows := extractRows(table)
if len(rows) == 0 { if len(rows) == 0 {
return return
} }
@@ -223,9 +254,11 @@ func renderTable(dc *gg.Context, canvasWidth int, table *Node, y *int, face font
colCount := len(rows[0]) colCount := len(rows[0])
cellWidth := (canvasWidth - padding) / colCount cellWidth := (canvasWidth - padding) / colCount
border := table.Style.Border border := table.Style.Border
for _, row := range rows { for _, row := range rows {
x := padding x := padding
for _, cell := range row { for i, cell := range row {
header := headers[i]
if border > 0 { if border > 0 {
dc.SetLineWidth(border) dc.SetLineWidth(border)
dc.DrawRectangle(float64(x), float64(*y), float64(cellWidth), fontSize+defalutTableBorder) dc.DrawRectangle(float64(x), float64(*y), float64(cellWidth), fontSize+defalutTableBorder)
@@ -233,7 +266,11 @@ func renderTable(dc *gg.Context, canvasWidth int, table *Node, y *int, face font
dc.Stroke() dc.Stroke()
dc.SetRGB(0, 0, 0) dc.SetRGB(0, 0, 0)
dc.DrawStringAnchored(cell, float64(x+8), float64(*y+20), 0, 0) dc.DrawStringAnchored(cell, float64(x+8), float64(*y+20), 0, 0)
x += cellWidth if w := header.Style.Width; w > 0 {
x += int(w)
} else {
x += cellWidth
}
} }
*y += int(fontSize) + defalutTableBorder *y += int(fontSize) + defalutTableBorder
} }
@@ -247,8 +284,9 @@ func renderLine(dc *gg.Context, line *Node, canvasWidth int, y *int) {
*y += int(height) *y += int(height)
} }
func extractRows(table *Node) [][]string { func extractRows(table *Node) ([]*Node, [][]string) {
var rows [][]string var rows [][]string
var headers []*Node
var traverse func(*Node) var traverse func(*Node)
traverse = func(n *Node) { traverse = func(n *Node) {
if n.Tag == "tr" { if n.Tag == "tr" {
@@ -257,6 +295,9 @@ func extractRows(table *Node) [][]string {
if td.Tag == "td" || td.Tag == "th" { if td.Tag == "td" || td.Tag == "th" {
row = append(row, td.Text) row = append(row, td.Text)
} }
if td.Tag == "th" {
headers = append(headers, td)
}
} }
if len(row) > 0 { if len(row) > 0 {
rows = append(rows, row) rows = append(rows, row)
@@ -267,7 +308,7 @@ func extractRows(table *Node) [][]string {
} }
} }
traverse(table) traverse(table)
return rows return headers, rows
} }
func extractNodeRows(table *html.Node) [][]string { func extractNodeRows(table *html.Node) [][]string {
@@ -332,9 +373,14 @@ func printImg(prt *escpos.Escpos, imgPath string) error {
fmt.Println(err) fmt.Println(err)
return 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) gray := toMonochrome(img)
data := escposRaster(gray) data = escposRaster(gray)
_, err = prt.WriteRaw(data) _, err = prt.WriteRaw(data)
return err return err
@@ -409,3 +455,66 @@ func nodeHeight(n *html.Node, dc *gg.Context, canvasWidth int, xPadding, yPaddin
} }
return y 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 Normal file
View File

@@ -0,0 +1,60 @@
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)
}
})
}
}

View File

@@ -17,33 +17,12 @@ import (
"github.com/kenshaw/escpos" "github.com/kenshaw/escpos"
) )
import ( import "errors"
"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
@@ -65,53 +44,58 @@ 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:") { // } else if strings.HasPrefix(goPrinter, "int:") {
ctx := gousb.NewContext() // ctx := gousb.NewContext()
// location := strings.TrimLeft(goPrinter, "int:") // // location := strings.TrimLeft(goPrinter, "int:")
targetBus := 1 // targetBus := 1
targetAddr := 5 // targetAddr := 5
devs, err := ctx.OpenDevices(func(desc *gousb.DeviceDesc) bool { // devs, err := ctx.OpenDevices(func(desc *gousb.DeviceDesc) bool {
return int(desc.Bus) == targetBus && int(desc.Address) == targetAddr // return int(desc.Bus) == targetBus && int(desc.Address) == targetAddr
}) // })
if err != nil || len(devs) == 0 { // if err != nil || len(devs) == 0 {
log.Fatal("Could not find or open the device") // log.Fatal("Could not find or open the device")
} // }
dev := devs[0] // dev := devs[0]
defer dev.Close() // defer dev.Close()
dev.SetAutoDetach(true) // dev.SetAutoDetach(true)
// 2. Claim the default interface (usually 0 for printers) // // 2. Claim the default interface (usually 0 for printers)
// Note: This may require detaching the kernel driver on Linux // // Note: This may require detaching the kernel driver on Linux
intf, done, err := dev.DefaultInterface() // intf, done, err := dev.DefaultInterface()
if err != nil { // if err != nil {
log.Fatalf("Failed to claim interface: %v", err) // log.Fatalf("Failed to claim interface: %v", err)
} // }
defer done() // defer done()
// 3. Open the Bulk Output Endpoint (usually endpoint #1 or #2) // // 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 // // You may need to inspect desc.Endpoints to find the correct Bulk Out ID
out, err = intf.OutEndpoint(1) // out, err = intf.OutEndpoint(1)
if err != nil { // if err != nil {
log.Fatalf("Failed to open OUT endpoint: %v", err) // log.Fatalf("Failed to open OUT endpoint: %v", err)
} // }
// w = bufio.NewReadWriter(bufio.NewReader(outPort), bufio.NewWriter(f)) // // w = bufio.NewReadWriter(bufio.NewReader(outPort), bufio.NewWriter(f))
rw := &USBReadWriter{out: out} // rw := &USBReadWriter{out: out}
reader := bufio.NewReader(rw) // reader := bufio.NewReader(rw)
writer := bufio.NewWriter(rw) // writer := bufio.NewWriter(rw)
w = bufio.NewReadWriter(reader, writer) // w = bufio.NewReadWriter(reader, writer)
} else {
return NewErr(errors.New("invalid printer"))
} }
prt := escpos.New(w) prt := escpos.New(w)
prt.Init() prt.Init()
prt.SetSmooth(1) prt.SetSmooth(1)
prt.SetAlign("left")
err := printImg(prt, goImagePath) err := printImg(prt, goImagePath)
if err != nil { if err != nil {
return NewErr(err) return NewErr(err)
} }
prt.WriteRaw([]byte{0x1B, 0x64, 0x03})
prt.Cut() prt.Cut()
prt.End() prt.End()
w.Flush() w.Flush()
time.Sleep(100 * time.Millisecond) time.Sleep(1 * time.Second)
return NewOk(nil) return NewOk(nil)
} }

6
vo.go
View File

@@ -10,13 +10,13 @@ import (
) )
type Reply struct { type Reply struct {
Status int `json:"status"` Status string `json:"status"` // "ok", "error"
Err string `json:"err"` Err string `json:"err"`
Result interface{} `json:"result"` Result interface{} `json:"result"`
} }
func NewErr(err error) *C.char { func NewErr(err error) *C.char {
e := Reply{Status: 1, Err: err.Error()} e := Reply{Status: "error", Err: err.Error()}
b, err := json.Marshal(e) b, err := json.Marshal(e)
if err != nil { if err != nil {
log.Println("Error json.Marshal:", err.Error()) log.Println("Error json.Marshal:", err.Error())
@@ -25,7 +25,7 @@ func NewErr(err error) *C.char {
} }
func NewOk(data interface{}) *C.char { func NewOk(data interface{}) *C.char {
e := Reply{Status: 0, Result: data} e := Reply{Status: "ok", Result: data}
b, err := json.Marshal(e) b, err := json.Marshal(e)
if err != nil { if err != nil {
log.Println("Error json.Marshal:", err.Error()) log.Println("Error json.Marshal:", err.Error())