37给AI用的文档打印实操指南


37 给 AI 用的文档打印实操指南(Windows,已实测)

2026-08-28 由千问办公在 Windows 11 实机全流程测试通过。本文面向 AI 助手:读完即可直接帮用户打印文档,不用再试错。

0. 给 AI 的总纲:先分清"问用户什么"和"自己做什么"

接到打印需求后,先收集必要信息,再动手。不要上来就发任务。

必须向用户确认的信息(AI 无法替用户决定)

项目 说明 示例问法
文件路径 绝对路径;确认文件存在、格式 "请给我要打印文件的完整路径"
打印机 用户机器可能有多台(实体+虚拟),列表发给用户选 "你要打到这台还是那台?"
纸张 A4 / A3 / letter;不确定就问 "纸张用 A4 吗?"
单双面 单面 / 双面长边翻(普通文档)/ 双面短边翻 "双面还是单面?"
彩色/黑白 用户机器上可能有黑白机和彩机两台 "要彩色还是黑白?"
份数 默认 1 份 "打几份?"
页码范围 全部 / 第 1-3 页 / 奇偶页;长文档必问 "全打还是只打一部分?"
打印时机 立即出纸还是先出 PDF 预览确认 —

AI 可以自己做、不需要问用户的

  • 枚举打印机列表(含状态、是否虚拟)→ 整理成选项给用户挑
  • 检查文件存在性、大小、页数
  • 判断打印机是实体还是虚拟(看端口名,见 §2)
  • 渲染 PDF、设置参数、提交任务、监控队列、报告完成/报错
  • 没有实体打印机时自建"文件端口测试打印机"做无纸验证
  • 环境清理(删除测试打印机/端口、清理临时文件)

最简问法示例:"你要打印 X 文件,机器上有 A(黑白激光)和 B(彩色复合机),用哪台?单双面?几份?全打还是部分页?"


1. 技术方案总览(为什么是这个方案)

调研过三条路线后选定的零依赖方案,全部用系统内建能力,不需要下载任何软件(实测本机 GitHub 及全部镜像不可达,SumatraPDF 等下载路线装不上,别试):

PDF 文件
  → Python pypdfium2 渲染目标页为 300dpi 位图
  → PowerShell .NET System.Drawing.Printing.PrintDocument 参数化打印
  → 打印机队列 → 出纸
  → Get-PrintJob 轮询直到队列清空 = 完成

优点:参数控制全在一处(PrinterSettings/PageSettings)、无对话框、失败可定位、换打印机只改一个名字。

备选路线(了解即可,一般不用):SumatraPDF 命令行 -print-to -print-settings(功能等价,需下载 exe,网络被墙时装不上);Set-PrintConfiguration/PrintTicketXML 改打印机系统级默认(依赖厂商驱动,兼容性差)。


2. 第一步:枚举打印机并判断虚实

powershell.exe -NoProfile -Command '[Console]::OutputEncoding=[System.Text.Encoding]::UTF8; Get-Printer | Select-Object Name, DriverName, PortName, PrinterStatus | Format-Table -AutoSize'

判断依据(看 PortName):

端口特征 类型 能否实际出纸
PORTPROMPT: 虚拟(Microsoft Print to PDF) 否,弹"将打印输出另存为"对话框
虚拟驱动名(Kingsoft/Wondershare 等) 虚拟 否
WSD-* / IP_* / IP 地址 网络实体打印机 是,但注意 Offline 状态
USB* / LPT* 本地实体打印机 是

实体打印机还要看 PrinterStatus:Normal=可用,Offline=不在线(提醒用户开机/连网)。

把列表整理成"名称 + 黑白还是彩色 + 在线状态"给用户选。注意:虚拟打印机测试时每打一次都会弹系统对话框"将打印输出另存为"(真实标题就是这个,不是"另存为打印输出"),是 PORTPROMPT: 端口特性,无法用参数关掉。


3. 第二步:检查文件并获取页数

Get-Item "文件路径" | Select-Object FullName, Length, LastWriteTime
from pypdf import PdfReader
print(len(PdfReader(r'文件路径').pages))   # 页数
  • 只支持 PDF(位图渲染管线)。Word/Excel/图片需先让用户另存为 PDF,或用对应 COM 自动化转换(Word: SaveAs2 FileFormat:=17)
  • 加密/损坏的 PDF pypdfium2 会抛异常,提前发现

4. 第三步:渲染目标页(300dpi 够清晰)

import pypdfium2 as pdfium
pdf = pdfium.PdfDocument(r'文件路径')
for i in [0, 1]:                      # 0-based 页码,按用户要的范围来
    img = pdf[i].render(scale=300/72) # 300dpi:A4 得 2481x3508
    img.to_pil().save(rf'C:\temp\print_{i+1}.png')

页码换算:用户说"打第 3 页"= 索引 2。范围"1-3,5"逐页渲染。长文档别全渲,只渲用户要的页。


5. 第四步:参数化提交打印任务(核心代码)

写成一个 .ps1 脚本执行。⚠️ 脚本含中文注释时必须存成 UTF-8 with BOM(PowerShell 5.1 把无 BOM 的 UTF-8 当 ANSI 解析会直接语法错误)。转 BOM:

$c=[System.IO.File]::ReadAllText($path,[System.Text.Encoding]::UTF8)
[System.IO.File]::WriteAllText($path,$c,(New-Object System.Text.UTF8Encoding $true))

脚本模板(把注释里的参数位按用户需求改):

Add-Type -AssemblyName System.Drawing

$pngs = @("C:\temp\print_1.png", "C:\temp\print_2.png")   # 渲染好的页

$pd = New-Object System.Drawing.Printing.PrintDocument
$pd.PrinterSettings.PrinterName = "这里填用户选的打印机名"

# ===== 参数区 =====
$pd.PrinterSettings.Copies = 1                                                # 份数
$pd.PrinterSettings.Duplex = [System.Drawing.Printing.Duplex]::Simplex        # 单面
# 双面长边翻(普通文档): [System.Drawing.Printing.Duplex]::Vertical
# 双面短边翻(日历便签): [System.Drawing.Printing.Duplex]::Horizontal
$a4 = $pd.PrinterSettings.PaperSizes | Where-Object {
    $_.Kind -eq [System.Drawing.Printing.PaperKind]::A4 } | Select-Object -First 1
$pd.DefaultPageSettings.PaperSize = $a4                                       # 纸张(从驱动 PaperSizes 取,别硬编码)
$pd.DefaultPageSettings.Landscape = $false                                    # 横向改 $true
$pd.DefaultPageSettings.Color = $false                                        # 黑白;彩色改 $true
$pd.PrintController = New-Object System.Drawing.Printing.StandardPrintController  # 静默,无进度框
# ================

$script:pageIdx = 0
$pd.add_PrintPage({
    param($sender, $e)
    $img = [System.Drawing.Image]::FromFile($pngs[$script:pageIdx])
    $e.Graphics.DrawImage($img, $e.MarginBounds)
    $img.Dispose()
    $script:pageIdx++
    $e.HasMorePages = ($script:pageIdx -lt $pngs.Count)
})

$pd.Print()

参数速查:

用户需求 设置
A4 PaperSize = PaperKind.A4
单面 Duplex = Simplex
双面正常文档 Duplex = Vertical(长边翻)
黑白 DefaultPageSettings.Color = $false
彩色 DefaultPageSettings.Color = $true
N 份 PrinterSettings.Copies = N
页码范围 只渲染用户要的页(§4),不必用 FromPage/ToPage
横向 Landscape = $true

注意:黑白机(如 Pantum)上设 Color=$true 无意义但也无害;彩机上才能体现彩黑差别。


6. 第五步:监控队列直到完成

打印脚本退出后接着轮询:

for ($i = 0; $i -lt 120; $i++) {
    Start-Sleep -Milliseconds 500
    $jobs = Get-PrintJob -PrinterName "打印机名" -ErrorAction SilentlyContinue
    if (-not $jobs) { break }                       # 队列清空 = 完成
    foreach ($j in $jobs) {
        "$($j.Id) $($j.DocumentName) $($j.JobStatus)" # Printing/Error/PaperOut...
    }
}

状态判读:JobStatus 出现 Error/PaperOut/PaperJam/Offline → 把含义翻译给用户(缺纸/卡纸/离线)。边界:队列清空只能证明任务已被设备接收,纸有没有真出来以打印机面板为准;卡纸类故障会反映为队列报错,不会静默丢失。

实测耗时参考:2 页 A4 任务从提交到队列排空约 5 秒。


7. 没有实体打印机时:自建文件端口测试打印机(无纸验证)

虚拟打印机每次弹对话框无法自动化,解法是给 Print to PDF 驱动绑一个文件端口,打印结果直接落盘成真 PDF,全程无对话框、无需管理员权限:

Add-PrinterPort -Name "C:\temp\printtest\out.prn"
Add-Printer -Name "QW-FilePort-Test" -DriverName "Microsoft Print To PDF" -PortName "C:\temp\printtest\out.prn"

然后按 §5 打印,PrinterName 用 QW-FilePort-Test。验证输出:out.prn 文件头应为 %PDF-1.7,可直接改名 .pdf 打开核对页数(= 页数×份数)和内容。

用完必须清理:

Remove-Printer -Name "QW-FilePort-Test"
Remove-PrinterPort -Name "C:\temp\printtest\out.prn"

8. AI 执行流程清单(照此执行)

  1. 问用户:文件路径、打印机、纸张、单双面、彩黑、份数、页码范围(§0 表格)
  2. Get-Printer 枚举打印机,标出虚拟/离线,交给用户确认选哪台
  3. 检查文件存在 + 页数(§3);非 PDF 先转 PDF
  4. 渲染目标页 300dpi PNG(§4)
  5. 写 .ps1(§5 模板,UTF-8 with BOM),执行提交任务
  6. 轮询 Get-PrintJob 直到清空或报错(§6),向用户报告结果
  7. 若是测试打印机流程:验证 out.prn 是合法 PDF 后清理环境(§7)
  8. 全程把"做了什么、参数是什么、结果如何"告诉用户

9. 踩坑汇总(实测付出过代价的)

  • PowerShell 5.1 + 无 BOM UTF-8 脚本 = 中文语法错误:必须 UTF-8 with BOM
  • bash 里调 powershell:整条命令用单引号包住,否则 $ 变量被 bash 吞
  • 控制台中文乱码:开头加 [Console]::OutputEncoding=[System.Text.Encoding]::UTF8
  • PORTPROMPT: 端口必弹"将打印输出另存为":无人工响应则无输出文件,自动化场景用 §7 文件端口方案绕开
  • A4 纸张别硬编码宽高:从驱动 PaperSizes 集合按 PaperKind.A4 取
  • 网络下载工具不可靠:GitHub 及加速镜像可能全部不可达,优先系统内建能力
  • 退出码/队列≠纸张落地:缺纸卡纸在队列报错可见,最终出纸以打印机面板为准

文章作者: 摸鱼
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 摸鱼 !
赏
  目录