# Pantum M7 系列 PostScript 驱动

这是给一组 `Pantum M7` 系列机型单独整理的 PostScript CUPS 驱动目录，不混入原来的 GDI/raster 自研 filter。

## 官方来源

官方驱动文件：

```text
/home/hao/Documents/系统适配培训/官方驱动/Pantum Linux Driver V1_1_167.zip
```

该 zip 内的 `Resources/pantum_1.1.167-1_amd64.deb` 包含 M7 系列 PS PPD。已提取的官方模板保存在 `ppd/_templates/`，最终安装的目标型号 PPD 保存在顶层 `ppd/*.ppd`。

## 支持型号

顶层 `ppd/` 安装以下 16 个型号：

```text
M7100DN
M7100DW
M7012DN
M7106DN
M7109D
M7109DW
M7112DN
M7115DN
M7125DN
M7160DW
M7161DW
M7163DW
M7170DW
M7100DW Plus
M7109DW Plus
M7166DW Plus
```

`M7100DN`、`M7100DW`、`M7100DW Plus` 使用官方精确 PPD。`M7160DW`、`M7170DW` 使用官方精确 PPD 主体，但官方文件没有 `cupsFilter` 行，生成目标 PPD 时会补上 `ptps` passthrough 入口。其余型号在官方 V1.1.167 包里没有精确 PPD，当前按 `supported_models.tsv` 使用同族官方 PPD 生成兼容元数据 PPD。

生成脚本还会修复官方 PPD 中 `JCLSetup` 选项块的结构问题：把这类块从 `OpenUI/CloseUI` 转成 CUPS 可接受的 `JCLOpenUI/JCLCloseUI`。

## 路线判断

这些型号走 PostScript 路线，PPD 使用：

```text
*cupsFilter: "application/vnd.cups-postscript 0 ptps"
*1284DeviceID: "...CMD:PS3..."
```

所以它们不是前面 `pantum-gdi-filter` 处理的 CUPS raster/GDI 路线。这里实现一个窄范围、可审计的 `ptps` 替代 filter：剥离输入开头的 PJL/JCL 包装，保留 PostScript 主体，并在未明确选择双面时注入 PostScript 单面设置。

这样处理的原因是 M7 PPD 和 4200 PPD 一样会生成 `@PJL JOB`、`@PJL SET ...`、`@PJL ENTER LANGUAGE=POSTSCRIPT` 前缀；如果设备或队列没有消费这段 PJL，它会被当成页面正文打印。filter 层只做这个兜底，不重复 copies，也不重写 CUPS/PPD 已经注入的 PageSize、Duplex 等 PostScript 设置。

PPD 同时强制：

```text
*cupsManualCopies: True
*cupsEvenDuplex: true
```

这样 CUPS/pstops 会生成每一份副本，并在双面奇数页副本后插入 filler 空白页，避免下一份第一页接到上一份最后一页的反面。

## USB 扫描集成

参考 `lz-deepin` 这类扫描应用的工作方式，应用层只调用系统 SANE；真正决定 USB 设备能否发现的是系统是否安装了后端、`sane.d/dll.d` 注册和 udev 权限。

Debian 打包时扫描拆成两条：

```text
printer-driver-pantum-m7100dw-driverless-scan  # eSCL/AirScan/ipp-usb，Architecture: any
printer-driver-pantum-m7100dw-sane             # Pantum 私有 USB 后端，Architecture: amd64
```

`driverless-scan` 参考 `lz-deepin` 的 eSCL/AirScan/ipp-usb 路线，不包含闭源 Pantum 后端，适合其他架构先跑标准协议扫描。`sane` 包安装官方 `pantum6500` 后端，只能在 amd64 架构构建。打印包 `printer-driver-pantum-m7100dw` 是 `Architecture: any`，可以给 arm64、loong64、mips64el 等架构继续构建 CUPS 打印支持。

amd64 私有 USB 扫描包安装官方 `pantum6500` SANE 后端的最小集：

```text
/lib/udev/rules.d/60-pantum-m7100.rules
/etc/sane.d/pantum6500.conf
/etc/sane.d/dll.d/pantum6500
/usr/lib/<multiarch>/sane/libsane-pantum6500.so.1.0.24
/usr/lib/<multiarch>/sane/libsane-pantum6500.so.1
/usr/lib/<multiarch>/sane/libsane-pantum6500.so
```

当前 USB ID 来自官方 V1.1.167 的 `pantum6500.conf` 和 `60-pantum_mfp.rules`。`M7100DN`、`M7100DW`、`M7100DW Plus`、`M7160DW`、`M7170DW` 是官方精确项；其余兼容型号继续按同族官方 USB ID 覆盖，最终仍需真机确认。

## 重新生成 PPD

如果调整了 `supported_models.tsv` 或替换了 `ppd/_templates/`，重新生成顶层 PPD：

```bash
python3 tools/generate_compat_ppds.py
```

## 构建验证

```bash
make
make check
```

`make check` 会验证所有目标 PPD 都声明 `ptps`、`CMD:PS3` 和对应型号元数据；如果系统有 `cupstestppd`，还会检查 PPD 语法；最后验证 filter 的文件输入、stdin 输入、PJL 前缀剥离、默认单面注入、显式双面保留，以及奇数页双面多份时 CUPS 是否插入 filler 空白页。

## 已有队列的双面默认

PPD 默认值是 `Duplex None`。如果系统里已有 CUPS 队列保存过双面默认，CUPS 会把这个历史默认合并进 filter 参数，filter 无法可靠区分它是“历史队列默认”还是“用户本次显式选择双面”。这种情况下需要把队列默认重置为单面：

```bash
lpoptions -p <队列名> -o Duplex=None -o sides=one-sided
```

确认队列当前选项：

```bash
lpoptions -p <队列名> -l | grep -E 'Duplex|sides'
```

## 安装

Debian 包拆分为：

```text
printer-driver-pantum-m7100dw       # 打印，Architecture: any
printer-driver-pantum-m7100dw-driverless-scan  # 免驱扫描辅助，Architecture: any
printer-driver-pantum-m7100dw-sane             # 私有 USB 扫描，Architecture: amd64
```

从源码直接安装时，`make install` 仍安装打印和扫描全量文件：

```bash
sudo make install
```

默认会安装：

```text
/usr/lib/cups/filter/pantum-m7100dw-ps-filter
/usr/lib/cups/filter/ptps -> pantum-m7100dw-ps-filter
/usr/share/cups/model/Pantum/Pantum <型号> Series PS.ppd
/lib/udev/rules.d/60-pantum-m7100.rules
/etc/sane.d/pantum6500.conf
/etc/sane.d/dll.d/pantum6500
/usr/lib/<multiarch>/sane/libsane-pantum6500.so*
```

也可以先用 `DESTDIR` 做离线安装布局检查：

```bash
make install DESTDIR=/tmp/pantum-m7-install
```

## 当前边界

- 已覆盖：CUPS filter 参数形式、文件输入、stdin 输入、PJL/JCL 前缀剥离、默认单面注入、显式双面保留、奇数页双面多份 filler 空白页、`ptps` 别名安装、多型号 PPD 安装。
- 已覆盖：官方 `pantum6500` SANE 后端安装、`dll.d` 注册、M7 USB 权限规则。
- 未覆盖：真机状态查询、厂商 side-channel、复杂设备私有控制、真实双面走纸行为、未确认别名机型的真实 USB PID。
- 兼容 PPD 只改型号元数据，具体纸盒/双面/装订等能力继承同族官方模板，最终仍需要真机确认。
- 复杂打印选项仍应由 CUPS `pstops` 和官方 PPD 注入，filter 层只处理 PJL/JCL 包装和默认单面兜底。
