diff --git a/.gitignore b/.gitignore index 0b542e8..54405ac 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,4 @@ build assets libgofunc libgo +cmd/out.png diff --git a/build_lib.sh b/build_lib.sh index bf73fba..fc737d8 100755 --- a/build_lib.sh +++ b/build_lib.sh @@ -1,9 +1,9 @@ #!/bin/bash APP_NAME="libgofunc" -VERSION="${1:-v0.1.3}" -OUTPUT_DIR="assets" -BUILD_DIR="build" +VERSION="${1:-v0.1.5}" +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 -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 \ # -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 diff --git a/go.sum b/go.sum index c646e8a..2e20190 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,6 @@ 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= diff --git a/img.go b/img.go index 880decd..d366bb5 100644 --- a/img.go +++ b/img.go @@ -24,7 +24,13 @@ import ( "github.com/kenshaw/escpos" ) -import "log" +import ( + "log" + "strconv" + + "golang.org/x/text/language" + "golang.org/x/text/message" +) const ( defalutFontSize = 18.0 @@ -102,8 +108,13 @@ func GenImg(width int, outputPath, payload, tmpl string) string { 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").Parse(tmp) + tmpl, err := template.New("mytemplate").Funcs(funcMap).Parse(tmp) if err != nil { return "", err } @@ -431,3 +442,66 @@ 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 + } +} diff --git a/img_test.go b/img_test.go new file mode 100644 index 0000000..a06f548 --- /dev/null +++ b/img_test.go @@ -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) + } + }) + } +} diff --git a/printer.go b/printer.go index 5a774bf..20b093c 100644 --- a/printer.go +++ b/printer.go @@ -17,6 +17,7 @@ import ( "github.com/kenshaw/escpos" ) +import "errors" //export PrintImg func PrintImg(printer *C.char, imagePath *C.char) *C.char { @@ -77,6 +78,8 @@ func PrintImg(printer *C.char, imagePath *C.char) *C.char { // reader := bufio.NewReader(rw) // writer := bufio.NewWriter(rw) // w = bufio.NewReadWriter(reader, writer) + } else { + return NewErr(errors.New("invalid printer")) } prt := escpos.New(w)