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
  • 支持批量打印
  • 从数据库加载原材料数据
  • 支持更多类型的条码

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

相关推荐
光头闪亮亮6 小时前
go-fitz库-PDF文件所有页转换到HTML及从HTML中提取图片的示例教程
go
用户855651414467 小时前
环信http请求失败排查
go
_码力全开_1 天前
P1005 [NOIP 2007 提高组] 矩阵取数游戏
java·c语言·c++·python·算法·矩阵·go
程序员爱钓鱼1 天前
Python编程实战 · 基础入门篇 | Python程序的运行方式
后端·go
光头闪亮亮2 天前
gozxing库-对图片中多个二维码进行识别的完整示例教程
go
召摇2 天前
在浏览器中无缝运行Go工具:WebAssembly实战指南
后端·面试·go
王中阳Go3 天前
我发现不管是Java还是Golang,懂AI之后,是真吃香!
后端·go·ai编程
半枫荷3 天前
二、Go语法基础(基本语法)
go
struggle20254 天前
AxonHub 开源程序是一个现代 AI 网关系统,提供统一的 OpenAI、Anthropic 和 AI SDK 兼容 API
css·人工智能·typescript·go·shell·powershell