You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用win32print打印PDF仅发声无输出,求排查与替代方案

Win32print打印PDF无输出及ShellExecute报错问题排查与替代方案

问题描述

我正在使用win32print API向打印机发送文档,相关代码如下:

import win32print
import win32api
import os
import time
def list_printers():
    printers = win32print.EnumPrinters(win32print.PRINTER_ENUM_LOCAL            |win32print.PRINTER_ENUM_CONNECTIONS)
    printer_list=[printer[2] for printer in printers]
    return printer_list

def choose_printer(printers):
    print("Available Printers:")
    for i, printer in enumerate(printers):
        print(f"{i + 1}. {printer}")  
    while True:
        try:
            choice = int(input("Select a printer by number: "))
            if 1 <= choice <= len(printers):
                return printers[choice - 1]
            else:
                print("Invalid choice. Please select a valid printer number.")
        except ValueError:
            print("Invalid input. Please enter a number.")
def print_pdf(pdf_path, printer_name):
    if not os.path.exists(pdf_path):
        raise FileNotFoundError(f"No such file: '{pdf_path}'")
    print(f"Printing '{pdf_path}' to '{printer_name}'")
    printer_handle = win32print.OpenPrinter(printer_name)
    job_id = win32print.StartDocPrinter(printer_handle, 1, ("PDF Document",None,"RAW"))
    try:
        win32print.StartPagePrinter(printer_handle)
        
        with open(pdf_path, 'rb') as pdf_file:
            pdf_content = pdf_file.read()
            # print(pdf_content)        
        # Write the PDF content to the printer
        # time.sleep(4)
        bytesPrinted=win32print.WritePrinter(printer_handle, pdf_content)
        print(bytesPrinted)
        win32print.EndPagePrinter(printer_handle)
    finally:
        win32print.EndDocPrinter(printer_handle)
        win32print.ClosePrinter(printer_handle)
if __name__ == "__main__":
    pdf_file_path = "C:/Users/DELL/Downloads/test.pdf"

    printers = list_printers()
    if not printers:
        print("No printers found.")
    else:
        selected_printer=choose_printer(printers)
        print_pdf(pdf_file_path,selected_printer)

我还尝试了该方法:win32api.ShellExecute(0, "printto",pdf_file_path,f'"{printername}"', ".", 0),但出现错误:device attached to the system is not functioning。第一种方法运行无报错,但打印机仅发出声音却没有打印输出,请问我哪里操作有误?有没有其他替代方法可以使用?

问题原因与修复

1. Win32print直接发送PDF内容的问题

用RAW模式直接把PDF字节流发给打印机,绝大多数普通打印机不支持直接解析PDF格式——打印机只识别自家打印语言(如PCL、PostScript)或通用ESC/POS指令。打印机发声是因为接收到数据但无法解析,直接丢弃了。

修复方向:

  • 若打印机支持PostScript,可将PDF转成PostScript后发送(需结合GhostScript工具);
  • 通用方案是先将PDF转成打印机可识别的位图/增强元文件(EMF),再发送打印。

2. ShellExecute "printto"报错的问题

printto参数要求打印机名称为原始设备名/共享名,不能加多余引号或格式错误。此外该方法依赖系统默认PDF阅读器,若阅读器异常(如Acrobat Reader故障)也会触发设备错误。

修复方向:

  • 确保打印机名称是list_printers()返回的原始字符串,不要手动添加引号;
  • 检查系统默认PDF阅读器能否手动正常打印该PDF,异常则修复或更换阅读器。

替代方案

方案1:PyMuPDF转图片打印

PyMuPDF可将PDF每页转成图片,再通过win32print输出,兼容性极强:

import fitz
import win32print
import win32ui
import win32con

def print_pdf_as_image(pdf_path, printer_name):
    doc = fitz.open(pdf_path)
    printer_handle = win32print.OpenPrinter(printer_name)
    try:
        printer_info = win32print.GetPrinter(printer_handle, 2)
        dc = win32ui.CreateDC()
        dc.CreatePrinterDC(printer_name)
        dc.StartDoc("PDF Print Job")
        
        for page_num in range(len(doc)):
            page = doc.load_page(page_num)
            pix = page.get_pixmap()
            # 创建位图并绘制
            bmp = win32ui.CreateBitmap()
            bmp.CreateCompatibleBitmap(dc, pix.width, pix.height)
            hdc = win32ui.CreateDCFromHandle(dc.GetSafeHdc())
            hdc.SelectObject(bmp)
            hdc.DrawBitmap((0,0), bmp, (0,0,pix.width,pix.height))
            
            # 发送到打印机
            dc.StartPage()
            dc.StretchBlt((0,0), printer_info['pDevMode'].dmPaperWidth, printer_info['pDevMode'].dmPaperHeight, hdc, (0,0), pix.width, pix.height, win32con.SRCCOPY)
            dc.EndPage()
        
        dc.EndDoc()
    finally:
        win32print.ClosePrinter(printer_handle)

方案2:ShellExecute普通打印命令

放弃printto,直接用print命令让系统默认阅读器处理打印,稳定性更高:

import win32api

def print_with_shell(pdf_path):
    # 0为后台执行,1为前台显示阅读器窗口
    win32api.ShellExecute(0, "print", pdf_path, None, ".", 0)

该方法使用系统默认打印机;若需指定打印机,确保printto参数格式正确(无需额外引号):

win32api.ShellExecute(0, "printto", pdf_path, printer_name, ".", 0)

方案3:GhostScript转PostScript打印

若打印机支持PostScript,可先用GhostScript将PDF转成PS,再用RAW模式发送:

import subprocess
import win32print

def pdf_to_ps(pdf_path, ps_path):
    # 需提前安装GhostScript,并将gswin64c.exe加入系统环境变量
    subprocess.run(["gswin64c", "-sDEVICE=ps2write", "-o", ps_path, pdf_path], check=True)

def print_ps(ps_path, printer_name):
    printer_handle = win32print.OpenPrinter(printer_name)
    job_id = win32print.StartDocPrinter(printer_handle, 1, ("PS Document", None, "RAW"))
    try:
        win32print.StartPagePrinter(printer_handle)
        with open(ps_path, 'rb') as f:
            win32print.WritePrinter(printer_handle, f.read())
        win32print.EndPagePrinter(printer_handle)
    finally:
        win32print.EndDocPrinter(printer_handle)
        win32print.ClosePrinter(printer_handle)

内容的提问来源于stack exchange,提问作者dhrummil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 23:44:53