commit 9ef734816eefafe905ccd7f3c0c55ce1fd0b31e6 Author: dtapps Date: Fri Dec 22 13:13:11 2023 +0800 init diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..c56c479 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,17 @@ +kind: pipeline +type: docker +name: clone + +steps: + - name: Test + image: golang:1.18 + commands: + - go env -w GO111MODULE=on + - go env -w GOPROXY=https://goproxy.cn,direct + - go test -v ./... + - name: Benchmark + image: golang:1.18 + commands: + - go env -w GO111MODULE=on + - go env -w GOPROXY=https://goproxy.cn,direct + - go test -bench=. -benchmem \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..760d251 --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ +.env +.git +.svn +.idea +.vscode +*.log +gomod.sh +*_test.go +/vendor/ \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..ff84bbf --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 李光春 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..7becdbd --- /dev/null +++ b/README.md @@ -0,0 +1,17 @@ +

+Golang goqc +

+ +📦 Golang goqc + +[comment]: <> (go) +[![godoc](https://pkg.go.dev/badge/go.dtapp.net/goqc?status.svg)](https://pkg.go.dev/go.dtapp.net/goqc) +[![goproxy.cn](https://goproxy.cn/stats/go.dtapp.net/goqc/badges/download-count.svg)](https://goproxy.cn/stats/go.dtapp.net/goqc) +[![goreportcard.com](https://goreportcard.com/badge/go.dtapp.net/goqc)](https://goreportcard.com/report/go.dtapp.net/goqc) +[![deps.dev](https://img.shields.io/badge/deps-go-red.svg)](https://deps.dev/go/go.dtapp.net%2Fgoqc) + +#### 安装 + +```shell +go get -v -u go.dtapp.net/goqc@v1.0.0 +``` diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..3b60f3d --- /dev/null +++ b/go.mod @@ -0,0 +1,12 @@ +module go.dtapp.net/goqc + +go 1.21 + +require ( + github.com/fogleman/gg v1.3.0 + github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 + github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 + github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e +) + +require golang.org/x/image v0.14.0 // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..999d1d7 --- /dev/null +++ b/go.sum @@ -0,0 +1,10 @@ +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/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= +github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= +github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= +golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4= +golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= diff --git a/goqc_text.go b/goqc_text.go new file mode 100644 index 0000000..a9e5c77 --- /dev/null +++ b/goqc_text.go @@ -0,0 +1,129 @@ +package goqc + +import ( + "bytes" + "context" + "embed" + _ "embed" + "github.com/fogleman/gg" + "github.com/golang/freetype/truetype" + "github.com/nfnt/resize" + "github.com/skip2/go-qrcode" + "image/png" + "io" + "path/filepath" +) + +//go:embed simhei.ttf +var fontContent embed.FS +var fontPath = "simhei.ttf" +var fontSize = 16.0 + +func loadFontPath(dc *gg.Context) error { + // 设置字体和文本属性 + err := dc.LoadFontFace(fontPath, fontSize) + if err != nil { + return err + } + return nil +} + +func loadFontEmbed(dc *gg.Context) error { + // 读取嵌入的字体文件 + fontBytes, err := fontContent.ReadFile(fontPath) + if err != nil { + return err + } + // 设置字体 + f, err := truetype.Parse(fontBytes) + if err != nil { + return err + } + // 文本属性 + face := truetype.NewFace(f, &truetype.Options{ + Size: fontSize, + }) + dc.SetFontFace(face) + return nil +} + +// QrCodeOperation 二维码操作 +type QrCodeOperation struct { + ctx context.Context + dc *gg.Context +} + +// QrCodeText 生成二维码带文本 +func QrCodeText(ctx context.Context, textContent string, qcContent string, qcLevel qrcode.RecoveryLevel) (*QrCodeOperation, error) { + + // 生成二维码 + qr, err := qrcode.New(qcContent, qcLevel) + if err != nil { + return nil, err + } + + // 设置二维码图片的大小 + qrSize := 256 + + // 生成二维码图片 + qrImage := qr.Image(qrSize) + + // 调整二维码图片大小 + qrImage = resize.Resize(uint(qrSize), uint(qrSize), qrImage, resize.Lanczos3) + + // 使用 github.com/fogleman/gg 绘制文本 + dc := gg.NewContext(qrSize, qrSize) + dc.DrawImage(qrImage, 0, 0) + + // 设置字体和文本属性 + err = loadFontEmbed(dc) + if err != nil { + return nil, err + } + + // 设置文本颜色 + dc.SetRGB(0, 0, 0) + + // 计算文本尺寸 + textWidth, textHeight := dc.MeasureString(textContent) + + // 计算文本位置 + x := (float64(qrSize) - textWidth) / 2 + y := (float64(qrSize+qrSize) + textHeight - textHeight) / 2 + + // 绘制文本 + dc.DrawStringAnchored(textContent, x, y-6, 0, 0) + + return &QrCodeOperation{ctx: ctx, dc: dc}, err +} + +// SavePNG 保存图片 +func (o *QrCodeOperation) SavePNG(filePath, fileName string) error { + if fileName == "" { + return o.dc.SavePNG(filePath) + } else { + path := filepath.Join(filePath, "/", fileName) + return o.dc.SavePNG(path) + } +} + +// Encode 返回图片字节 +func (o *QrCodeOperation) Encode() ([]byte, error) { + img := o.dc.Image() + + encoder := png.Encoder{CompressionLevel: png.BestCompression} + + var b bytes.Buffer + err := encoder.Encode(&b, img) + + if err != nil { + return nil, err + } + + return b.Bytes(), nil +} + +// EncodePNG 返回图片编码 +func (o *QrCodeOperation) EncodePNG(w io.Writer) error { + return o.dc.EncodePNG(w) +} diff --git a/simhei.ttf b/simhei.ttf new file mode 100644 index 0000000..5bd4687 Binary files /dev/null and b/simhei.ttf differ diff --git a/version.go b/version.go new file mode 100644 index 0000000..732860f --- /dev/null +++ b/version.go @@ -0,0 +1,5 @@ +package goqc + +const ( + Version = "1.0.0" +)