Golang使用gofpdf库和barcode库创建PDF原材料二维码标签【GBK中文或UTF8】及预览和打印
在现代制造业和仓储管理系统中,二维码标签在物料追踪和管理方面发挥着重要作用。本文将详细介绍如何使用Golang结合第三方库gofpdf和barcode来创建包含原材料信息的PDF二维码标签,支持GBK和UTF-8两种中文编码格式,并调用系统中安装的Argox标签打印机进行预览和打印。
目录
准备工作
在开始之前,我们需要安装必要的第三方库:
bash
# 安装gofpdf库,用于创建PDF文档
go get github.com/jung-kurt/gofpdf
# 安装barcode库,用于生成条形码和二维码
go get github.com/boombuler/barcode
# 安装OLE库,用于与Windows系统交互控制打印机
go get github.com/go-ole/go-ole
# 安装中文编码支持库
go get golang.org/x/text/encoding/simplifiedchinese
另外,我们需要准备中文字体文件,例如本例中的Alibaba-PuHuiTi-Medium.ttf
,以便在PDF中正确显示中文。
项目结构
bash
project/
├── pdf_label_gbk_utf8_print_tutorial.go # 主程序文件
├── Alibaba-PuHuiTi-Medium.ttf # 中文字体文件
└── go.mod # Go模块文件
核心代码解析
1. 导入必要的包
go
import (
"fmt"
"image"
"image/color"
"image/png"
"log"
"os"
"os/exec"
"strconv"
"strings"
// 引入gofpdf库,用于创建PDF文档
"github.com/jung-kurt/gofpdf"
// 引入barcode库,用于生成条形码和二维码
"github.com/boombuler/barcode"
"github.com/boombuler/barcode/qr"
// 引入OLE库,用于与Windows系统交互,控制打印机
"github.com/go-ole/go-ole"
"github.com/go-ole/go-ole/oleutil"
// 引入字符编码库,用于处理中文字符
"golang.org/x/text/encoding/simplifiedchinese"
)
2. 定义原材料结构体
go
// 定义原材料结构体,包含标签所需的所有信息
type Material struct {
Code string // 材料编码
Name string // 材料名称
Spec string // 规格型号
Date string // 生产日期
Batch string // 批次号
Qty string // 数量
Manufacturer string // 生产厂家
}
详细实现步骤
步骤1:创建原材料数据
go
// 创建原材料数据列表
func createMaterials() []Material {
// 初始化原材料数组
materials := []Material{
// 添加第一个原材料记录
{
Code: "020112423092510600001", // 材料编码
Name: "橡胶件1", // 材料名称
Spec: "45452-1254", // 规格型号
Date: "2023-09-25", // 生产日期
Batch: "1", // 批次号
Qty: "60000", // 数量
Manufacturer: "JZ", // 生产厂家
},
// 可以继续添加更多原材料...
}
// 返回原材料数据列表
return materials
}
步骤2:生成PDF标签文件(支持不同编码)
go
// 生成PDF标签文件
func createLabelsPDF(materials []Material, encoding string) {
// 创建一个新的PDF文档实例,使用自定义尺寸(82mm x 48mm),纵向布局,毫米为单位
pdf := gofpdf.New("P", "mm", "A4", "")
// 设置页面边距
pdf.SetTopMargin(0)
pdf.SetLeftMargin(0)
pdf.SetRightMargin(0)
pdf.SetMargins(0, 0, 0)
pdf.SetAutoPageBreak(false, 0)
// 添加字体,注意路径和字体文件名称
pdf.AddUTF8Font("Alibaba", "", "Alibaba-PuHuiTi-Medium.ttf") // 注意这里
pdf.SetFont("Alibaba", "", 12)
// 设置文本颜色
pdf.SetTextColor(0, 0, 0)
// 标签设置
labelWidth := 82.0
labelHeight := 48.0
qrSize := 20.0
//获取数据集
// 遍历所有原材料,为每个原材料生成一个标签
for i, material := range materials {
// 为每个标签添加一个新的页面,页面大小设置为标签尺寸
pdf.AddPageFormat("82*48", gofpdf.SizeType{labelHeight, labelWidth})
x := float64(0%2) * labelWidth
y := float64(0/2) * labelHeight
x1 := float64(0%2) * labelWidth
y1 := float64(0/2) * labelHeight
fmt.Printf("i: %v\n", i)
// 绘制边框
pdf.SetDrawColor(0, 0, 0) // 黑色边框
pdf.Rect(x1+0.5, y1+0.5, labelWidth-1, labelHeight-1, "D")
// 根据指定编码生成当前原材料的二维码并保存为PNG文件
qrCodeFileName := "qr_" + encoding + "_" + strconv.Itoa(i) + ".png"
if encoding == "gbk" {
createQRCodeGBK(qrCodeFileName, material.Code, 100, 100)
} else {
createQRCodeUTF8(qrCodeFileName, material.Code, 100, 100)
}
// 绘制标签背景
pdf.SetFillColor(255, 255, 255) // 白色背景
// 添加文本信息
// pdf.SetFont("Arial", "", 10)
x = x + 2
y = y + 2
pdf.SetY(y)
pdf.SetX(x)
pdf.Cell(0, 6, "材料名称: "+material.Name)
y = y + 6
pdf.SetY(y)
pdf.SetX(x)
pdf.Cell(0, 6, "材料规格: "+material.Spec)
y = y + 6
pdf.SetY(y)
pdf.SetX(x)
pdf.Cell(0, 6, "生产日期: "+material.Date+" 批次: "+material.Batch)
y = y + 6
pdf.SetY(y)
pdf.SetX(x)
pdf.Cell(0, 6, "包装数量: "+material.Qty)
y = y + 6
pdf.SetY(y)
pdf.SetX(x)
pdf.Cell(0, 6, "厂家: ")
y = y + 6
pdf.SetY(y)
pdf.SetX(x)
pdf.Cell(0, 6, material.Manufacturer)
// 添加二维码
pdf.Image(qrCodeFileName, x+labelWidth-qrSize-18, y-12, qrSize, qrSize, false, "", 0, "")
y = y + 8
pdf.SetY(y)
pdf.SetX(x + labelWidth - 60)
pdf.Cell(0, 6, material.Code)
}
// 根据编码类型确定PDF文件名
pdfFileName := "materials_labels_utf8.pdf"
if encoding == "gbk" {
pdfFileName = "materials_labels_gbk.pdf"
}
// 将生成的PDF内容保存到文件中
err := pdf.OutputFileAndClose(pdfFileName)
if err != nil {
log.Fatal("保存PDF文件失败:", err)
}
fmt.Printf("标签PDF文件已保存为 %s\n", pdfFileName)
}
步骤3:创建GBK格式二维码
go
// 创建GBK格式QR二维码
func createQRCodeGBK(fileName, codeData string, qrWidth, qrHeight int) {
// 打印原始数据
log.Println("Original data:", codeData)
// 将UTF8格式的码文转换为GBK,保持与VFP生成的二维码格式相同
gbkData, _ := simplifiedchinese.GB18030.NewEncoder().Bytes([]byte(codeData)) //使用官方库将utf-8转换为gbk
// 使用GBK编码生成二维码
code, err := qr.Encode(string(gbkData), qr.L, qr.Unicode)
if err != nil {
log.Fatal(err)
}
// 打印编码后的数据
log.Println("Encoded data: ", code.Content())
// 获取生成的码文的UTF格式是否与接收的码文一致
b, _ := simplifiedchinese.GB18030.NewDecoder().Bytes([]byte(code.Content())) //将gbk再转换为utf-8
if codeData != string(b) {
log.Fatal("data differs")
}
// 定义条码的大小
code, err = barcode.Scale(code, qrWidth, qrHeight)
if err != nil {
log.Fatal(err)
}
// 由于gofpdf写入图片需要8-bit格式,需要转换
// Convert image to RGBA with 8-bit depth
rgba := image.NewRGBA(code.Bounds())
ImageConvertRgba(code, rgba)
// 生成二维码
createPng(fileName, rgba)
}
步骤4:创建UTF-8格式二维码
go
// 创建UTF8格式QR二维码
func createQRCodeUTF8(fileName, codeData string, qrWidth, qrHeight int) {
// 打印原始数据
log.Println("Original data:", codeData)
// 使用UTF-8编码生成二维码
code, err := qr.Encode(codeData, qr.L, qr.Unicode)
if err != nil {
log.Fatal(err)
}
// 打印编码后的数据
log.Println("Encoded data: ", code.Content())
// 检查编码后的数据是否与原始数据一致
if codeData != code.Content() {
log.Fatal("data differs")
}
// 调整二维码大小
code, err = barcode.Scale(code, qrWidth, qrHeight)
if err != nil {
log.Fatal(err)
}
// 由于gofpdf写入图片需要8-bit格式,需要转换
// Convert image to RGBA with 8-bit depth
rgba := image.NewRGBA(code.Bounds())
ImageConvertRgba(code, rgba)
// 生成二维码
createPng(fileName, rgba)
}
步骤5:图像格式转换和保存
go
// 将图像转换为RGBA格式
func ImageConvertRgba(code barcode.Barcode, rgba *image.RGBA) *image.RGBA {
// 遍历二维码图像的每一个像素点
for x := 0; x < code.Bounds().Max.X; x++ {
for y := 0; y < code.Bounds().Max.Y; y++ {
// 获取当前位置的颜色值
c := code.At(x, y)
// 处理黑白像素
r, g, b, a := c.RGBA()
if a == 0 { // 如果是透明
rgba.Set(x, y, color.Transparent)
} else {
// 转换到 RGBA 8 位色
rgba.Set(x, y, color.RGBA{
R: uint8(r >> 8),
G: uint8(g >> 8),
B: uint8(b >> 8),
A: 255, // 设置为不透明
})
}
}
}
return rgba
}
// 生成png图片
func createPng(filename string, img image.Image) {
// 创建文件用于写入PNG图像
file, err := os.Create(filename)
if err != nil {
log.Fatal(err)
}
// 确保函数结束时关闭文件
defer file.Close()
// 将图像编码为PNG格式并写入文件
err = png.Encode(file, img)
if err != nil {
log.Fatal(err)
}
// 打印文件名
log.Println(file.Name())
}
步骤6:获取系统打印机列表
go
// 获取系统中安装的标签打印机列表
func getPrinterList() (string, string, error) {
// 使用PowerShell命令获取系统中所有打印机列表
cmd := exec.Command("powershell", "-Command", "Get-Printer")
output, err := cmd.Output()
if err != nil {
return "", "", err
}
fmt.Println("系统打印机列表:")
// 初始化返回结果
str_printer := ""
msg := "标签打印机检测失败,请检查系统是否安装标签打印机?"
// 按行分割输出结果
printers := strings.Split(string(output), "\n")
// 查找包含"Argox"关键字的打印机
for _, printer := range printers {
if printer != "" && strings.Contains(printer, "Argox") {
str_printer = strings.TrimSpace(printer)
msg = ""
break
}
}
return str_printer, msg, nil
}
步骤7:设置默认打印机
go
// 设置指定名称的打印机为系统默认打印机
func setDefaultPrinter(printerName string) error {
// 初始化COM库,用于与Windows系统交互
ole.CoInitialize(0)
// 程序结束时释放COM库资源
defer ole.CoUninitialize()
// 创建WbemScripting.SWbemLocator COM对象
unknown, err := oleutil.CreateObject("WbemScripting.SWbemLocator")
if err != nil {
return err
}
// 释放COM对象资源
defer unknown.Release()
// 获取IDispatch接口
wmi, err := unknown.QueryInterface(ole.IID_IDispatch)
if err != nil {
return err
}
// 释放接口资源
defer wmi.Release()
// 连接到WMI服务
serviceRaw, err := oleutil.CallMethod(wmi, "ConnectServer")
if err != nil {
return err
}
service := serviceRaw.ToIDispatch()
// 释放服务资源
defer service.Release()
// 执行WMI查询,查找指定名称的打印机
resultRaw, err := oleutil.CallMethod(service, "ExecQuery", "SELECT * FROM Win32_Printer WHERE Name = '"+printerName+"'")
if err != nil {
return err
}
result := resultRaw.ToIDispatch()
// 释放查询结果资源
defer result.Release()
// 获取查询结果的数量
countVar, err := oleutil.GetProperty(result, "Count")
if err != nil {
return err
}
count := int(countVar.Val)
// 如果没有找到指定名称的打印机,返回错误
if count == 0 {
return fmt.Errorf("未找到名为 '%s' 的打印机", printerName)
}
// 获取第一个查询结果(应该只有一个)
itemRaw, err := oleutil.CallMethod(result, "ItemIndex", 0)
if err != nil {
return err
}
item := itemRaw.ToIDispatch()
// 释放项目资源
defer item.Release()
// 调用SetDefaultPrinter方法将该打印机设为默认打印机
_, err = oleutil.CallMethod(item, "SetDefaultPrinter")
if err != nil {
return err
}
return nil
}
步骤8:打印PDF文件
go
// 使用系统默认应用程序打开并打印PDF文件
func printPDF(pdfFile string) error {
// 检查PDF文件是否存在
if _, err := os.Stat(pdfFile); os.IsNotExist(err) {
return fmt.Errorf("PDF文件 '%s' 不存在", pdfFile)
}
// 使用Windows的start命令打开PDF文件,这将使用系统默认的PDF阅读器打开文件
// 用户可以在打开的阅读器中选择打印选项
cmd := exec.Command("cmd", "/C", "start", "", pdfFile)
err := cmd.Run()
if err != nil {
return fmt.Errorf("打开PDF文件失败: %v", err)
}
fmt.Printf("已使用系统默认应用程序打开PDF文件 '%s',请在应用程序中选择打印选项。\n", pdfFile)
return nil
}
步骤9:主函数执行流程
go
// 主函数,程序入口点
func main() {
// 创建原材料数据列表
materials := createMaterials()
// 生成包含所有标签的PDF文件(使用UTF-8编码)
createLabelsPDF(materials, "utf8")
// 生成包含所有标签的PDF文件(使用GBK编码)
createLabelsPDF(materials, "gbk")
fmt.Println("PDF标签生成完成!")
// 获取系统中安装的标签打印机列表
printer, msg, err := getPrinterList()
if err != nil {
fmt.Printf("获取打印机列表失败: %v\n", err)
return
}
if len(msg) != 0 {
fmt.Printf("警告信息: %v\n", msg)
return
}
fmt.Printf("检测到标签打印机: %v\n", printer)
// 设置指定打印机为系统默认打印机
printerName := "Argox CP-3140EX PPLB"
err = setDefaultPrinter(printerName)
if err != nil {
log.Fatalf("设置默认打印机失败: %v", err)
}
fmt.Printf("成功将 '%s' 设置为默认打印机。\n", printerName)
// 使用系统默认应用程序打开并打印PDF文件(UTF-8版本)
err = printPDF("materials_labels_utf8.pdf")
if err != nil {
fmt.Printf("打印UTF-8版本PDF文件失败: %v\n", err)
}
// 使用系统默认应用程序打开并打印PDF文件(GBK版本)
err = printPDF("materials_labels_gbk.pdf")
if err != nil {
fmt.Printf("打印GBK版本PDF文件失败: %v\n", err)
}
}
运行程序
要运行这个程序,请执行以下步骤:
- 确保已安装所有依赖库
- 将中文字体文件
Alibaba-PuHuiTi-Medium.ttf
放在程序同级目录 - 确保系统中已安装Argox标签打印机
- 运行以下命令:
bash
go run pdf_label_gbk_utf8_print_tutorial.go
运行成功后,您将看到以下输出:
arduino
标签PDF文件已保存为 materials_labels_utf8.pdf
标签PDF文件已保存为 materials_labels_gbk.pdf
PDF标签生成完成!
系统打印机列表:
检测到标签打印机: Argox CP-3140EX PPLB
成功将 'Argox CP-3140EX PPLB' 设置为默认打印机。
已使用系统默认应用程序打开PDF文件 'materials_labels_utf8.pdf',请在应用程序中选择打印选项。
已使用系统默认应用程序打开PDF文件 'materials_labels_gbk.pdf',请在应用程序中选择打印选项。
总结
通过本教程,我们学习了如何使用Golang结合gofpdf和barcode库创建专业的原材料二维码标签,支持GBK和UTF-8两种中文编码格式,并通过OLE技术与Windows系统交互来设置默认打印机。主要知识点包括:
- 使用gofpdf库创建PDF文档并设置中文字体支持
- 使用barcode库生成二维码并调整尺寸
- 在PDF中添加文本和图像元素
- 支持GBK和UTF-8两种中文编码格式
- 使用PowerShell命令获取系统打印机列表
- 使用OLE技术与Windows WMI服务交互设置默认打印机
- 调用系统默认应用程序打开并打印PDF文件
这个示例可以轻松扩展以支持更多功能,例如:
- 支持不同尺寸的标签
- 添加公司Logo
- 支持批量打印
- 从数据库加载原材料数据
- 支持更多类型的条码
希望这个教程对您有所帮助!