Golang实现PDF文件打印到Windows打印机

Golang实现PDF文件打印到Windows打印机 大家好

我使用gofpdf创建了一个包含一些简单格式的简单PDF文件,并希望在Windows机器上使用标签打印机打印此PDF。使用纯文本可以正常工作,但PDF不行。有人能给我一个示例吗?那将非常有帮助。

我将gofpdf的输出作为字节切片传递给这个函数。但我遇到了打印机错误:

var buf bytes.Buffer
pdf.Output(&buf)
print2(buf.Bytes())

func print2(content []byte) {
	fmt.Println(string(content))
	name, err := prt.Default() // 以字符串形式返回默认打印机的名称
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println(name)
	p, err := prt.Open(name) // 打开指定名称的打印机并返回一个*Printer
	if err != nil {
		fmt.Println(err)
	}

	//err = p.StartDocument("test", "text") // test: 文档名称, text: 文档类型
	err = p.StartDocument("test", "RAW")
	if err != nil {
		fmt.Println(err)
	}
	err = p.StartPage() // 开始新页面
	if err != nil {
		fmt.Println(err)
	}
	//n, err := p.Write([]byte("Hello, Printer!")) // 向打印机发送一些文本
	n, err := p.Write(content) // 向打印机发送一些文本
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println("写入打印机的字节数:", n)
	err = p.EndPage() // 页面结束
	if err != nil {
		fmt.Println(err)
	}
	err = p.EndDocument() // 文档结束
	if err != nil {
		fmt.Println(err)
	}
	err = p.Close() // 关闭资源
	if err != nil {
		fmt.Println(err)
	}
}

或者,是否可以将gofpdf生成的文件直接发送到打印机?我已经没有头绪了……

感谢您的帮助!


更多关于Golang实现PDF文件打印到Windows打印机的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

你好,@Dino

你提供的示例代码不完整,无法编译源代码供我自己测试。你是否在 GitHub 或其他地方有完整的代码?

更多关于Golang实现PDF文件打印到Windows打印机的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我不知道打印机上具体的错误信息是什么。PDF文件被正确发送,从代码中没有产生任何错误信息。如果我将PDF保存到磁盘并用PDF阅读器打开,它看起来完全正常。错误应该出现在发送给打印机的消息格式中的某个地方。你可以测试一下,如果你从磁盘上随便拿一个其他PDF文件,并通过代码发送到你的打印机。

在Windows上打印PDF文件需要使用专门的打印处理器,不能直接将PDF原始数据作为RAW数据发送。以下是几种解决方案:

方案1:使用Windows打印处理器(推荐)

package main

import (
    "bytes"
    "fmt"
    "os"
    "os/exec"
    "path/filepath"
    "runtime"
    
    "github.com/jung-kurt/gofpdf"
    "github.com/danicat/simplego/printer"
)

func createPDF() []byte {
    pdf := gofpdf.New("P", "mm", "A4", "")
    pdf.AddPage()
    pdf.SetFont("Arial", "B", 16)
    pdf.Cell(40, 10, "Hello, Printer!")
    pdf.Ln(12)
    pdf.SetFont("Arial", "", 12)
    pdf.Cell(40, 10, "This is a test PDF document.")
    
    var buf bytes.Buffer
    pdf.Output(&buf)
    return buf.Bytes()
}

func printPDFWithWindows(pdfData []byte) error {
    // 创建临时文件
    tmpFile, err := os.CreateTemp("", "print_*.pdf")
    if err != nil {
        return err
    }
    defer os.Remove(tmpFile.Name())
    
    // 写入PDF数据
    if _, err := tmpFile.Write(pdfData); err != nil {
        return err
    }
    tmpFile.Close()
    
    // 使用Windows命令打印
    cmd := exec.Command("cmd", "/C", "start", "/min", "", tmpFile.Name())
    return cmd.Run()
}

func main() {
    pdfData := createPDF()
    
    if runtime.GOOS == "windows" {
        if err := printPDFWithWindows(pdfData); err != nil {
            fmt.Printf("打印失败: %v\n", err)
        } else {
            fmt.Println("PDF已发送到默认打印机")
        }
    }
}

方案2:使用第三方库(如go-ole)

package main

import (
    "bytes"
    "fmt"
    "os"
    "path/filepath"
    
    "github.com/go-ole/go-ole"
    "github.com/go-ole/go-ole/oleutil"
    "github.com/jung-kurt/gofpdf"
)

func printPDFViaCOM(pdfData []byte) error {
    ole.CoInitialize(0)
    defer ole.CoUninitialize()
    
    // 创建临时PDF文件
    tmpDir := os.TempDir()
    pdfPath := filepath.Join(tmpDir, "print_temp.pdf")
    
    if err := os.WriteFile(pdfPath, pdfData, 0644); err != nil {
        return err
    }
    defer os.Remove(pdfPath)
    
    // 使用Shell执行打印
    unknown, err := oleutil.CreateObject("Shell.Application")
    if err != nil {
        return err
    }
    defer unknown.Release()
    
    shell, err := unknown.QueryInterface(ole.IID_IDispatch)
    if err != nil {
        return err
    }
    defer shell.Release()
    
    // 调用ShellExecute方法打印
    oleutil.CallMethod(shell, "ShellExecute", pdfPath, "Print", "", "open")
    
    return nil
}

func main() {
    pdf := gofpdf.New("P", "mm", "A4", "")
    pdf.AddPage()
    pdf.SetFont("Arial", "B", 16)
    pdf.Cell(40, 10, "Test Print")
    
    var buf bytes.Buffer
    pdf.Output(&buf)
    
    if err := printPDFViaCOM(buf.Bytes()); err != nil {
        fmt.Printf("打印错误: %v\n", err)
    }
}

方案3:使用外部工具(如SumatraPDF)

package main

import (
    "bytes"
    "fmt"
    "os"
    "os/exec"
    "path/filepath"
    
    "github.com/jung-kurt/gofpdf"
)

func printWithSumatraPDF(pdfData []byte) error {
    // 创建临时文件
    tmpFile, err := os.CreateTemp("", "print_*.pdf")
    if err != nil {
        return err
    }
    defer os.Remove(tmpFile.Name())
    
    // 写入PDF数据
    if _, err := tmpFile.Write(pdfData); err != nil {
        return err
    }
    tmpFile.Close()
    
    // SumatraPDF命令行打印
    // 需要先安装SumatraPDF: https://www.sumatrapdfreader.org/download-free-pdf-viewer
    cmd := exec.Command("SumatraPDF.exe", "-print-to-default", tmpFile.Name())
    cmd.Stdout = os.Stdout
    cmd.Stderr = os.Stderr
    
    return cmd.Run()
}

func main() {
    pdf := gofpdf.New("P", "mm", "A4", "")
    pdf.AddPage()
    pdf.SetFont("Arial", "B", 16)
    pdf.Cell(40, 10, "Print Test")
    
    var buf bytes.Buffer
    pdf.Output(&buf)
    
    if err := printWithSumatraPDF(buf.Bytes()); err != nil {
        fmt.Printf("打印错误: %v\n", err)
    }
}

方案4:使用RAW打印但转换为打印机语言(针对标签打印机)

如果您的标签打印机支持PCL、PostScript或ZPL等页面描述语言:

package main

import (
    "bytes"
    "fmt"
    
    "github.com/jung-kurt/gofpdf"
    "github.com/danicat/simplego/printer"
)

func convertPDFToPCL(pdfData []byte) ([]byte, error) {
    // 这里需要PDF到PCL的转换库
    // 可以使用外部工具如Ghostscript或pdftopcl
    // 这是一个示例框架
    return pdfData, nil
}

func printToLabelPrinter(pdfData []byte) error {
    prtName, err := printer.Default()
    if err != nil {
        return err
    }
    
    p, err := printer.Open(prtName)
    if err != nil {
        return err
    }
    defer p.Close()
    
    // 转换为打印机可接受的格式
    printerData, err := convertPDFToPCL(pdfData)
    if err != nil {
        return err
    }
    
    err = p.StartDocument("label", "RAW")
    if err != nil {
        return err
    }
    
    _, err = p.Write(printerData)
    if err != nil {
        return err
    }
    
    return p.EndDocument()
}

func main() {
    pdf := gofpdf.New("P", "mm", "A4", "")
    pdf.AddPage()
    pdf.SetFont("Arial", "B", 16)
    pdf.Cell(40, 10, "Label Content")
    
    var buf bytes.Buffer
    pdf.Output(&buf)
    
    if err := printToLabelPrinter(buf.Bytes()); err != nil {
        fmt.Printf("打印错误: %v\n", err)
    }
}

关键点:

  1. PDF是页面描述格式,不能直接作为RAW数据发送到打印机
  2. Windows需要打印处理器来解析PDF并转换为打印机语言
  3. 对于标签打印机,可能需要先将PDF转换为打印机支持的语言(如ZPL、EPL等)
  4. 最简单的方法是使用Windows内置的打印功能或外部工具
回到顶部