gozxing库介绍及使用gozxing识别图片中的多个二维码
gozxing库 是 Java ZXing(Zebra Crossing)库的 Go 语言端口,核心用于条形码与二维码的解码(识别) 和编码(生成),完全基于纯 Go 实现(无 CGO 依赖),可跨平台使用,是 Go 生态中处理条码/二维码的主流工具之一。
一、核心功能
gozxing 继承了 ZXing 的核心能力,覆盖条码处理的主要场景,具体包括:
1. 解码能力(识别现有条码/二维码)
- 支持的码制:覆盖主流一维码和二维码,常见包括:
- 二维码:QR Code、Data Matrix、Aztec Code;
- 一维码(条形码):Code 128、Code 39、EAN-13、EAN-8、UPC-A、UPC-E、ITF 等。
- 输入兼容性:可处理
image.Image类型的图像(支持 PNG、JPG 等常见格式),无需额外转换。 - 参数控制:通过
Hints(解码参数)优化识别效果,如指定目标码制、开启“强力解码”、设置字符集等(解决模糊、变形条码识别问题)。
2. 编码能力(生成新的条码/二维码)
- 支持的码制:主要覆盖 QR Code、Code 128、Code 39 等常用类型(部分冷门码制仅支持解码)。
- 输出灵活性:生成的条码/二维码以
image.Image类型返回,可直接保存为 PNG/JPG 文件,或用于网络传输。 - 生成参数:可配置二维码容错级别(L/M/Q/H)、条码宽度/高度、边距等,满足不同场景需求(如高容错用于印刷场景)。
二、关键特性
-
纯 Go 实现,无依赖
不依赖 CGO 或第三方原生库,仅依赖 Go 标准库(如image包),编译后可直接在 Linux、Windows、macOS 等平台运行,跨平台部署便捷。 -
API 设计贴近 ZXing,降低学习成本
接口命名、参数逻辑(如DecodeHintType、BarcodeFormat)与 Java ZXing 保持一致,熟悉 ZXing 的开发者可快速上手。 -
轻量高效,适合嵌入式/后台场景
库体积小,解码/编码性能满足中小规模需求(如后台批量处理条码、嵌入式设备扫码),若需超高性能(如实时视频流扫码),可搭配图像预处理(如缩放、降噪)优化。 -
完善的错误处理
解码/编码失败时会返回具体错误(如“未找到条码”“格式不支持”“参数无效”),便于问题定位。
三、典型使用场景
- 客户端工具:桌面扫码工具、命令行条码识别/生成工具;
- 后台服务:批量处理用户上传的条码图片(如物流单号识别、商品条码录入);
- 嵌入式设备:树莓派等设备结合摄像头实现扫码功能;
- 业务系统:生成带参数的二维码(如支付码、分享码),或识别用户上传的二维码(如登录验证、内容跳转)。
四、快速使用示例
1. 解码示例(识别图片中的 QR 码)
package main
import (
"image"
_ "image/jpeg"
_ "image/png"
"os"
"github.com/makiuchi-d/gozxing"
"github.com/makiuchi-d/gozxing/qrcode"
)
func main() {
// 1. 读取图片文件
file, err := os.Open("qrcode.png") // 替换为你的条码图片路径
if err != nil {
panic("打开图片失败: " + err.Error())
}
defer file.Close()
// 2. 解码图片为 image.Image
img, _, err := image.Decode(file)
if err != nil {
panic("解码图片失败: " + err.Error())
}
// 3. 转换为 gozxing 所需的 BinaryBitmap
source := gozxing.NewLuminanceSourceFromImage(img)
bmp := gozxing.NewBinaryBitmap(gozxing.NewHybridBinarizer(source))
// 4. 配置解码参数(Hints)
hints := map[gozxing.DecodeHintType]interface{}{
gozxing.DecodeHintType_POSSIBLE_FORMATS: []gozxing.BarcodeFormat{gozxing.BarcodeFormat_QR_CODE}, // 指定目标码制
gozxing.DecodeHintType_TRY_HARDER: true, // 开启强力解码(解决模糊条码)
}
// 5. 初始化解码器并执行解码
reader := qrcode.NewQRCodeReader() // QR 码专用解码器
result, err := reader.Decode(bmp, hints)
if err != nil {
panic("解码失败: " + err.Error())
}
// 输出结果
println("条码内容:", result.GetText())
println("码制:", result.GetBarcodeFormat().String())
}
2. 使用gozxing识别图片中的多个二维码
由于gozxing只能识别图片中第一个码,要识别图片中多个二维码,需要循环识别和标记遮盖区域,直到没有新的二维码被识别出来。
package main
import (
"fmt"
"image"
"image/color"
"image/draw"
"image/jpeg"
"log"
"math"
"os"
"github.com/makiuchi-d/gozxing"
"github.com/makiuchi-d/gozxing/qrcode"
)
// ReadMultipleQRCodes 从图片中识别多个二维码
// 参数:
// - inputImagePath: 输入图片路径
// - outputImagePath: 输出标记了识别区域的图片路径(可选)
// 返回值:
// - []string: 识别到的二维码内容列表
// - error: 错误信息
func ReadMultipleQRCodes(inputImagePath, outputImagePath string) ([]string, error) {
// 打开输入图片文件
inputFile, err := os.Open(inputImagePath)
if err != nil {
return nil, fmt.Errorf("无法打开输入图片: %v", err)
}
// 函数结束时关闭文件
defer inputFile.Close()
// 解码图片
img, _, err := image.Decode(inputFile)
if err != nil {
return nil, fmt.Errorf("无法解码图片: %v", err)
}
// 存储识别到的二维码内容
var results []string
// 循环识别,直到没有新的二维码被识别出来
for {
// 创建BinaryBitmap用于解码
bmp, err := gozxing.NewBinaryBitmapFromImage(img)
if err != nil {
return nil, fmt.Errorf("无法创建BinaryBitmap: %v", err)
}
// 创建二维码读取器
qrReader := qrcode.NewQRCodeReader()
// 设置解码参数
hints := make(map[gozxing.DecodeHintType]interface{})
// 指定预期的二维码格式
hints[gozxing.DecodeHintType_POSSIBLE_FORMATS] = []gozxing.BarcodeFormat{
gozxing.BarcodeFormat_QR_CODE,
}
// 开启TRY_HARDER模式提升识别率
hints[gozxing.DecodeHintType_TRY_HARDER] = true
// 设置字符集
hints[gozxing.DecodeHintType_CHARACTER_SET] = "UTF-8"
// 尝试解码
result, err := qrReader.Decode(bmp, hints)
if err != nil {
// 没有更多可识别的二维码
if _, ok := err.(gozxing.NotFoundException); ok {
fmt.Println("没有更多二维码可识别")
break
}
log.Printf("解码出错: %v", err)
return results, err
}
// 获取二维码内容
text := result.GetText()
fmt.Printf("识别到二维码内容: %s\n", text)
results = append(results, text)
// 获取二维码位置信息
points := result.GetResultPoints()
if len(points) == 0 {
log.Println("警告:未获取到二维码位置信息")
continue
}
// 计算需要遮盖的矩形区域
minX, minY := math.MaxFloat64, math.MaxFloat64
maxX, maxY := -math.MaxFloat64, -math.MaxFloat64
for _, p := range points {
if p.GetX() < minX {
minX = p.GetX()
}
if p.GetY() < minY {
minY = p.GetY()
}
if p.GetX() > maxX {
maxX = p.GetX()
}
if p.GetY() > maxY {
maxY = p.GetY()
}
}
// 构造一个稍微大一点的矩形,确保完全覆盖二维码
rect := image.Rect(
int(minX)-2, // 向左扩展2个像素
int(minY)-2, // 向上扩展2个像素
int(maxX)+2, // 向右扩展2个像素
int(maxY)+2, // 向下扩展2个像素
)
// 确保矩形在图像边界内
imgBounds := img.Bounds()
rect = rect.Intersect(imgBounds)
// 在原图上进行"遮盖"操作
rgba := image.NewRGBA(imgBounds)
draw.Draw(rgba, imgBounds, img, imgBounds.Min, draw.Src)
// 使用白色遮盖已识别的二维码
maskColor := color.RGBA{255, 255, 255, 255}
mask := image.NewUniform(maskColor)
draw.Draw(rgba, rect, mask, image.Point{}, draw.Src)
// 更新图像,为下一次循环做准备
img = rgba
}
// 如果指定了输出路径,则保存标记了识别区域的图片
if outputImagePath != "" {
outFile, err := os.Create(outputImagePath)
if err != nil {
log.Printf("无法创建输出文件: %v", err)
} else {
err = jpeg.Encode(outFile, img, &jpeg.Options{Quality: 90})
if err != nil {
log.Printf("无法保存标记后的图像: %v", err)
}
outFile.Close()
fmt.Printf("标记后的图像已保存为%s\n", outputImagePath)
}
}
return results, nil
}
func main() {
// 示例使用
inputImage := "./output/page_001_150dpi.png" // 输入图片路径
outputImage := "./output/page_001_marked.jpg" // 输出标记图片路径
// 识别二维码
results, err := ReadMultipleQRCodes(inputImage, outputImage)
if err != nil {
log.Fatal("识别失败:", err)
}
// 打印识别结果
fmt.Println("\n=== 所有识别到的二维码内容 ===")
for i, res := range results {
fmt.Printf("%d: %s\n", i+1, res)
}
}
这段代码展示了如何使用gozxing库识别图片中的多个二维码。关键点包括:
- 使用[gozxing.NewBinaryBitmapFromImage]
- 使用[qrcode.NewQRCodeReader()]创建二维码读取器
- 设置解码参数提升识别率
- 循环识别并遮盖已识别的二维码,避免重复识别
- 获取二维码位置信息并可视化标记
3. 编码示例(生成 QR 码)
package main
import (
"image/png"
"os"
"github.com/makiuchi-d/gozxing"
"github.com/makiuchi-d/gozxing/qrcode"
)
func main() {
// 1. 配置编码参数
contents := "https://example.com" // 二维码内容
width := 300 // 二维码宽度
height := 300 // 二维码高度
hints := map[gozxing.EncodeHintType]interface{}{
gozxing.EncodeHintType_CHARACTER_SET: "UTF-8", // 字符集
gozxing.EncodeHintType_ERROR_CORRECTION: qrcode.ErrorCorrectionLevel_H, // 高容错(H级,可恢复30%损坏内容)
gozxing.EncodeHintType_MARGIN: 1, // 边距(单位:像素)
}
// 2. 生成二维码图像
writer := qrcode.NewQRCodeWriter()
img, err := writer.Write(contents, gozxing.BarcodeFormat_QR_CODE, width, height, hints)
if err != nil {
panic("生成二维码失败: " + err.Error())
}
// 3. 保存为 PNG 文件
file, err := os.Create("generated_qrcode.png")
if err != nil {
panic("创建文件失败: " + err.Error())
}
defer file.Close()
if err := png.Encode(file, img); err != nil {
panic("保存图片失败: " + err.Error())
}
println("二维码生成成功,已保存为 generated_qrcode.png")
}
五、依赖与安装
- Go 版本要求:建议 Go 1.15+(兼容主流新版本)。
- 安装方式:通过
go get直接下载:go get -u github.com/makiuchi-d/gozxing
六、常见问题与解决方案
-
解码失败(提示“not found”)
- 检查图片中条码是否清晰(避免模糊、变形、反光);
- 开启
DecodeHintType_TRY_HARDER参数,增强解码容错; - 确认
POSSIBLE_FORMATS指定的码制与实际条码一致(如误将条形码指定为 QR_CODE)。
-
“BarcodeFormat_QR_CODE undefined” 错误
- 该常量定义在
gozxing根包下,需用gozxing.BarcodeFormat_QR_CODE引用(而非子包如qrcode.BarcodeFormat_QR_CODE)。
- 该常量定义在
-
编码时提示“unsupported format”
- 部分码制仅支持解码(如 Aztec Code),确认目标码制在
writer.Write中支持(如 QR Code、Code 128 均支持编码)。
- 部分码制仅支持解码(如 Aztec Code),确认目标码制在
七、使用场景
gozxing 是一个用于二维码/条码识别与生成库,提供了丰富的功能和 API,适用于各种场景。以下是一些常见的使用场景:
- 扫码应用:在移动端或桌面应用中集成扫码功能,识别用户扫描的二维码/条码内容。
- 数据传输:在移动设备上进行二维码数据传输,如二维码登录、二维码支付等。
- 数据共享:在移动设备之间进行数据传输,如二维码分享、二维码登录等。
- 商品管理:在库存管理、商品追踪等场景中使用条码/二维码进行商品识别和管理。
- 数据验证:在数据传输中,对数据进行验证,如二维码数据是否正确、数据是否被篡改等。
- 数据安全:在数据传输中,对数据进行加密,如二维码数据加密传输、二维码数据签名等。
- 数据统计:在数据传输中,对数据进行统计,如二维码数据使用情况、数据传输量等。
- 图像处理:结合图像处理库,对二维码/条码图像进行预处理,如图像增强、图像裁剪等,提高识别率。
- 二维码/条码识别与生成:在移动设备上进行二维码/条码识别和生成,如二维码登录、二维码支付等。
- 批量处理:在后台服务中批量处理二维码/条码图片,如批量识别、批量生成等。