golang生成二维码图片,支持图片下方增加多行居中文本

golang生成二维码图片,支持图片下方增加多行居中文本

效果
image

工具类代码

package Utils

import (
	"bytes"
	"fmt"
	"github.com/golang/freetype/truetype"
	"github.com/skip2/go-qrcode"
	"golang.org/x/image/font"
	"golang.org/x/image/math/fixed"
	"image"
	"image/color"
	"image/draw"
	"image/png"
	"os"
	"regexp"
)

// GenQRCodeImg 生成二维码图片 用法:err := Utils.GenQRCodeImg("https://www.example.com", []string{"设备名称1122室行", "建筑物1-3教室行文字室行室行"}, 300, 20, "D:\\simhei.ttf", "output1.png")
func GenQRCodeImg(url string, textLines []string, qrSize, fontSize int, fontPath, savePath string) error {
	img, err := genQRCode(url, textLines, qrSize, fontSize, fontPath)
	if err != nil {
		return err
	}
	// 保存图片
	outFile, err := os.Create(savePath)
	if err != nil {
		fmt.Println("Error creating output file:", err)
		return err
	}
	defer outFile.Close()
	err = png.Encode(outFile, img)
	return err
}

// GenQRCodeBuffer 生成二维码图片的字节数组 用法:buffer, err := Utils.GenQRCodeBuffer("https://www.example.com", []string{"设备名称1112室行", "建筑物2-3教室行文字室行室行"}, 300, 20, "D:\\simhei.ttf")
func GenQRCodeBuffer(url string, textLines []string, qrSize, fontSize int, fontPath string) (*bytes.Buffer, error) {
	img, err := genQRCode(url, textLines, qrSize, fontSize, fontPath)
	if err != nil {
		return nil, err
	}
	// 将图片编码为字节数组
	var buf bytes.Buffer
	err = png.Encode(&buf, img)
	if err != nil {
		fmt.Println("Error encoding image:", err)
		return nil, err
	}
	return &buf, nil
}

func genQRCode(url string, textLines []string, qrSize, fontSize int, fontPath string) (*image.RGBA, error) {
	// 生成二维码
	qr, err := qrcode.Encode(url, qrcode.Medium, qrSize)
	if err != nil {
		fmt.Println("Error generating QR code:", err)
		return nil, err
	}

	// 解码二维码图片
	qrImg, _, err := image.Decode(bytes.NewReader(qr))
	if err != nil {
		fmt.Println("Error decoding QR code:", err)
		return nil, err
	}

	// 创建新图片,并将二维码绘制在图片上
	img := image.NewRGBA(image.Rect(0, 0, qrSize, qrSize+len(textLines)*(fontSize+10)))
	draw.Draw(img, img.Bounds(), &image.Uniform{color.White}, image.Point{}, draw.Src) // 设置白色背景
	draw.Draw(img, img.Bounds(), qrImg, image.Point{}, draw.Over)

	// 加载字体文件
	fontBytes, err := os.ReadFile(fmt.Sprintf(fontPath))
	if err != nil {
		fmt.Println("Error reading font file:", err)
		return nil, err
	}
	font, err := truetype.Parse(fontBytes)
	if err != nil {
		fmt.Println("Error parsing font:", err)
		return nil, err
	}
	face := truetype.NewFace(font, &truetype.Options{Size: float64(fontSize)})

	// 计算文字的位置
	textY := qrSize - 10 + (len(textLines)-1)*fontSize

	// 绘制文字
	for i, line := range textLines {
		textWidth := countChineseCharacters(line)*fontSize + countNonChineseCharacters(line)*fontSize/2
		textX := (qrSize - textWidth) / 2                                    // 计算每行文字的水平居中位置
		drawText(img, line, textX, textY+i*(fontSize+10), color.Black, face) // 将文字颜色黑色
	}

	return img, nil
}

// 绘制文字
func drawText(img draw.Image, text string, x, y int, c color.Color, face font.Face) {
	d := &font.Drawer{
		Dst:  img,
		Src:  image.NewUniform(c),
		Face: face,
		Dot:  fixed.Point26_6{X: fixed.Int26_6(x * 64), Y: fixed.Int26_6(y * 64)},
	}
	d.DrawString(text)
}

// 计算中文个数
func countChineseCharacters(input string) int {
	// 正则表达式,用于匹配所有中文字符
	chinesePattern := regexp.MustCompile(`[\p{Han}]`)
	// 找到所有匹配的中文字符
	matches := chinesePattern.FindAllString(input, -1)
	// 返回匹配的中文字符数量
	return len(matches)
}

// 计算非中文个数
func countNonChineseCharacters(input string) int {
	// 正则表达式,用于匹配非中文字符
	nonChinesePattern := regexp.MustCompile(`[^\p{Han}]`)
	// 找到所有匹配的非中文字符
	matches := nonChinesePattern.FindAllString(input, -1)
	// 返回匹配的非中文字符数量
	return len(matches)
}

调用

  • 注意将D:\simhei.ttf替换成自己想要的字体文件的路径
package main

import (
    "Utils"
)

func main() {
	Utils.GenQRCodeImg("https://www.example.com", []string{"设备名称1122室行", "建筑物1-3教室行文字室行室行"}, 300, 20, "D:\\simhei.ttf", "output1.png")
}

posted @ 2024-05-07 14:53  jomz  阅读(152)  评论(0编辑  收藏  举报