HP LaserJet 1020 是一款相当老的黑白激光打印机。打印机本身依然能正常工作,但到了 Apple Silicon 时代,一个新的问题出现了: 打印机没坏,驱动也装了,macOS 甚至能够识别打印机,但一打印就报错。 这次在 Apple Silicon Mac 上配置 HP LaserJet 1020 时,就遇到了这样的问题。最终发现,真正的问题并不是 USB、CUPS 配置或者重复驱动,而是一个隐藏得更深的架构兼容问题: HP LaserJet 1020 使用的旧 ZJS 打印 Filter 仍然是 x86_64 程序,而现在的 M 系列 Mac 已经是 ARM64。 这篇文章把整个排查过程记录下来,作为以后重装系统或再次遇到类似问题时的备忘。
一、问题现象
环境大致如下:
设备:Apple Silicon Mac
架构:arm64
系统:macOS
打印机:HP LaserJet 1020
连接方式:USB
打印系统:CUPSHP LaserJet 1020 的驱动已经安装,系统也能够正常识别打印机。 但是发送打印任务后,打印队列提示:
The printer software is not compatible with this device.同时打印任务中的 Data 阶段失败。第一反应很容易怀疑:
驱动没装好?
USB 有问题?
CUPS 队列坏了?
驱动版本冲突?但实际原因并不是这些。
二、先检查 CUPS 是否识别打印机
首先检查打印队列:
lpstat -p -d系统能够找到:
HP_LaserJet_1020而且已经被设置为默认打印机。继续查看设备 URI:
lpstat -v可以看到类似:
usb://Hewlett-Packard/HP%20LaserJet%201020?serial=...这说明几个基础环节都是正常的:
macOS
↓
CUPS
↓
USB
↓
HP LaserJet 1020系统不是“找不到打印机”。
三、检查 PPD 是否存在
接下来检查 CUPS 的 PPD:
ls -lah /etc/cups/ppd/本机存在:
HP_LaserJet_1020.ppd继续查看打印机支持的参数:
lpoptions -p HP_LaserJet_1020 -l能够正常列出:
PageSize
MediaType
HPResolution
REt
EconoMode
InputSlot
JamRecovery
PrintDensity
...这一步非常重要。因为它说明: PPD 本身能够被 CUPS 正常读取。 问题开始从“打印机配置”缩小到“真正负责处理打印数据的 Filter”。
四、找到真正的打印 Filter
检查 PPD 中定义的 CUPS Filter:
grep -E '^\*cupsFilter|^\*cupsFilter2' \
"/etc/cups/ppd/HP_LaserJet_1020.ppd"得到:
*cupsFilter: "application/vnd.cups-raster 100 /Library/Printers/hp/laserjet/hplaserjetzjs.bundle/Contents/MacOS/rasterToHPZJS"
*cupsFilter: "application/vnd.cups-command 100 /Library/Printers/hp/laserjet/hplaserjetzjs.bundle/Contents/MacOS/commandToHPZJS"到这里基本已经找到关键位置。当前打印链路实际上是:
应用程序
↓
macOS 打印系统
↓
CUPS
↓
Raster
↓
rasterToHPZJS
↓
HP ZJS
↓
LaserJet 1020也就是说,真正负责把 CUPS 数据转换成打印机能够理解的数据的是:
rasterToHPZJS五、真正的问题:Filter 竟然还是 x86_64
接下来检查这两个程序的 CPU 架构:
file \
"/Library/Printers/hp/laserjet/hplaserjetzjs.bundle/Contents/MacOS/rasterToHPZJS"
# 以及:
file \
"/Library/Printers/hp/laserjet/hplaserjetzjs.bundle/Contents/MacOS/commandToHPZJS"结果非常关键:
Mach-O 64-bit executable x86_64两个都是:
x86_64而当前 Mac 是:
arm64问题终于明确了。
六、为什么打印机能识别,却不能打印?
这是这次问题最容易让人困惑的地方。系统能够识别:
HP LaserJet 1020PPD 也能读取。USB 连接也是正常的。但是:
识别打印机
≠
能够执行打印 Filter真正打印时需要执行:
rasterToHPZJS但这个程序是 Intel x86_64 二进制。所以整个链路实际上变成了:
Apple Silicon Mac
ARM64
↓
CUPS
↓
尝试执行 rasterToHPZJS
↓
x86_64
↓
架构兼容问题
↓
Data failed这就是为什么表面上“一切正常”,真正发送打印任务时才失败。
七、解决方案:安装 Rosetta 2
先检查 Rosetta:
pkgutil --pkg-info com.apple.pkg.RosettaUpdateAuto如果没有安装,会出现类似:
No receipt for 'com.apple.pkg.RosettaUpdateAuto' found安装 Rosetta 2:
sudo softwareupdate --install-rosetta --agree-to-license安装完成后再次检查:
pkgutil --pkg-info com.apple.pkg.RosettaUpdateAuto如果能够看到:
package-id: com.apple.pkg.RosettaUpdateAuto
version: ...
volume: /
location: /
install-time: ...说明 Rosetta 已经安装。
八、直接测试 HP Filter
还可以手动验证这个 x86_64 Filter 能不能通过 Rosetta 启动:
arch -x86_64 \
"/Library/Printers/hp/laserjet/hplaserjetzjs.bundle/Contents/MacOS/rasterToHPZJS"执行后出现:
ERROR: Usage: rasterToHPZJS job-id user title copies options [file]注意:这个 ERROR 在这里反而是好消息。它不是架构错误。 因为我们直接运行 rasterToHPZJS 时没有传入 CUPS 所要求的:
job-id
user
title
copies
options
file所以程序正常启动以后,才打印 Usage。也就是说:
ARM64 macOS
↓
Rosetta 2
↓
x86_64 rasterToHPZJS
↓
程序成功启动 ✓架构兼容问题已经解决。
九、清理失败任务并重新启用打印机
之前失败的任务可能已经让 CUPS 暂停打印队列。因此可以执行:
cancel -a HP_LaserJet_1020
# 然后:
cupsenable HP_LaserJet_1020
cupsaccept HP_LaserJet_1020
# 检查:
lpstat -p -d确认打印机处于 Idle/启用状态。重新发送一个简单 PDF 测试。打印恢复正常。
十、检查是不是安装了多个驱动
问题解决以后,我又进一步排查了一次:
会不会实际上装了好几套 HP 驱动,只是其中一套碰巧工作了?
可以执行:
lpstat -p -d
lpstat -v
# 再检查
ls -lah /etc/cups/ppd/本机最终只有:
HP_LaserJet_1020.ppd继续检查 HP 驱动:
find /Library/Printers/hp -maxdepth 4 -type d 2>/dev/null | sort实际核心目录只有:
/Library/Printers/hp/laserjet/hplaserjetzjs.bundleFilter 也只有:
commandToHPZJS
rasterToHPZJS检查安装包:
pkgutil --pkgs | grep -Ei 'hp|hewlett|printer|laserjet'得到:
com.apple.pkg.HP_LaserjetZJS十一、当前正常工作的完整环境
最终通过:
system_profiler SPPrintersDataType可以确认当前环境。关键数据如下:
Printer: HP LaserJet 1020
Status: Idle
Print Server: Local
Driver Version: 1.6.1
Default: Yes
CUPS Version:
CUPS/2.3.4
macOS arm64
CUPS filters:
rasterToHPZJS
commandToHPZJS
Bundle:
hplaserjetzjs.bundle
Version:
1.6.1值得注意的是,系统信息中 PPD 显示为:
HP LaserJet 1022, 1.6.1但实际连接的是:
HP LaserJet 1020由于当前 ZJS 驱动链已经实际完成打印验证,因此没有必要为了这个型号显示差异去修改已经工作的 PPD。
十二、最终打印链路
现在这台老 LaserJet 1020 在 Apple Silicon Mac 上实际工作的方式,可以概括为:
┌───────────────────────────┐
│ Apple Silicon Mac │
│ ARM64 │
└─────────────┬─────────────┘
↓
macOS CUPS
↓
HP ZJS Driver 1.6.1
↓
┌───────────────────────────┐
│ rasterToHPZJS │
│ x86_64 │
└─────────────┬─────────────┘
↓
Rosetta 2
↓
HP ZJS
↓
USB
↓
┌───────────────────────────┐
│ HP LaserJet 1020 │
└───────────────────────────┘所以 Rosetta 2 在这里不是打印机驱动。
十三、为什么不直接用 Generic PCL?
这里还有一个容易踩的坑。看到老打印机无法工作,很容易想到: 那直接换 Generic PCL Driver 不就行了吗? 对于 LaserJet 1020,并不建议这样处理。 因为当前已经确认它工作的链路是:
CUPS Raster
↓
HP ZJS Filter
↓
ZJS
↓
LaserJet 1020这类 host-based/ZJS 打印机和普通支持标准 PCL 的网络/办公打印机不是完全相同的情况。 所以不要因为看到“LaserJet”就默认 Generic PCL 一定能够替代原来的 ZJS 驱动。
十四、这算彻底解决了吗?
从“正常使用”的角度:已经解决。 目前:
打印机识别 ✓
USB ✓
CUPS ✓
PPD ✓
ZJS Filter ✓
Rosetta ✓
实际打印 ✓但是从技术架构上,它仍然存在一个历史包袱:
ARM64 macOS
↓
x86_64 HP Driver
↓
Rosetta 2所以这不是“纯 ARM64 原生打印”。如果未来真的希望彻底去掉 Rosetta,需要寻找或者自行构建 ARM64 原生的 ZJS 打印链,例如:
macOS
ARM64
↓
CUPS
↓
ARM64 Native Filter
↓
foo2zjs / ZjStream
↓
HP LaserJet 1020但对于一台已经服役很多年的 LaserJet 1020 来说,如果现有方案稳定工作,为了去掉 Rosetta 而重新折腾整个打印链,实际收益并不高。
十五、以后重装 macOS,记住这几个检查项
这也是写这篇文章最主要的目的。如果以后重装系统,又遇到:
The printer software is not compatible with this device.不要第一时间反复删除打印机或者重装驱动。按照下面的顺序检查即可:
① CUPS 是否识别打印机
↓
② USB URI 是否正常
↓
③ PPD 是否存在
↓
④ PPD 使用哪个 cupsFilter
↓
⑤ file 检查 Filter 架构
↓
⑥ x86_64 → 检查 Rosetta 2
↓
⑦ arch -x86_64 手工验证 Filter
↓
⑧ 清除失败任务并重新启用队列
↓
⑨ 实际打印 PDF其中最关键的三个命令可以直接留作备忘:
# 检查打印机
lpstat -p -d
# 检查 HP Filter 架构
file "/Library/Printers/hp/laserjet/hplaserjetzjs.bundle/Contents/MacOS/rasterToHPZJS"
# 检查 Rosetta 2
pkgutil --pkg-info com.apple.pkg.RosettaUpdateAutoRosetta 不存在时:
sudo softwareupdate --install-rosetta --agree-to-license