Golang使用gofpdf库和barcode库创建PDF原材料二维码标签【GBK中文或UTF8】及预览和打印

Golang使用gofpdf库和barcode库创建PDF原材料二维码标签【GBK中文或UTF8】及预览和打印

在现代制造业和仓储管理系统中,二维码标签在物料追踪和管理方面发挥着重要作用。本文将详细介绍如何使用Golang结合第三方库gofpdf和barcode来创建包含原材料信息的PDF二维码标签,支持GBK和UTF-8两种中文编码格式,并调用系统中安装的Argox标签打印机进行预览和打印。

目录

  1. 准备工作
  2. 项目结构
  3. 核心代码解析
  4. 详细实现步骤
  5. 运行程序
  6. 总结

准备工作

在开始之前,我们需要安装必要的第三方库:

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)
    }
}

运行程序

要运行这个程序,请执行以下步骤:

  1. 确保已安装所有依赖库
  2. 将中文字体文件Alibaba-PuHuiTi-Medium.ttf放在程序同级目录
  3. 确保系统中已安装Argox标签打印机
  4. 运行以下命令:
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系统交互来设置默认打印机。主要知识点包括:

  1. 使用gofpdf库创建PDF文档并设置中文字体支持
  2. 使用barcode库生成二维码并调整尺寸
  3. 在PDF中添加文本和图像元素
  4. 支持GBK和UTF-8两种中文编码格式
  5. 使用PowerShell命令获取系统打印机列表
  6. 使用OLE技术与Windows WMI服务交互设置默认打印机
  7. 调用系统默认应用程序打开并打印PDF文件

这个示例可以轻松扩展以支持更多功能,例如:

  • 支持不同尺寸的标签
  • 添加公司Logo
  • 支持批量打印
  • 从数据库加载原材料数据
  • 支持更多类型的条码

希望这个教程对您有所帮助!

相关推荐
梦想很大很大3 分钟前
使用 Go + Gin + Fx 构建工程化后端服务模板(gin-app 实践)
前端·后端·go
lekami_兰5 小时前
MySQL 长事务:藏在业务里的性能 “隐形杀手”
数据库·mysql·go·长事务
却尘9 小时前
一篇小白也能看懂的 Go 字符串拼接 & Builder & cap 全家桶
后端·go
ん贤9 小时前
一次批量删除引发的死锁,最终我选择不加锁
数据库·安全·go·死锁
mtngt111 天前
AI DDD重构实践
go
Grassto2 天前
12 go.sum 是如何保证依赖安全的?校验机制源码解析
安全·golang·go·哈希算法·go module
Grassto4 天前
11 Go Module 缓存机制详解
开发语言·缓存·golang·go·go module
程序设计实验室5 天前
2025年的最后一天,分享我使用go语言开发的电子书转换工具网站
go
我的golang之路果然有问题5 天前
使用 Hugo + GitHub Pages + PaperMod 主题 + Obsidian 搭建开发博客
golang·go·github·博客·个人开发·个人博客·hugo
啊汉7 天前
古文观芷App搜索方案深度解析:打造极致性能的古文搜索引擎
go·软件随想