在非 Windows 平台上使用 Canon MF3200 Series 打印机

咕了三个月,总算写完了。
手里有一台年代略有些久远的 Canon ImageClass MF3222 打印机,但其打印质量还十分不错,因此打算将其利用起来。但是非常令人难过的是 MF3200 系列使用的都是 CARPS 而不是 CUPS,因此无法在非 Windows 平台直接使用。
一种折中的方法是,每次连接打印机时启动 Windows 虚拟机,但这并不是一种优雅的方法。而且,我还希望实现远程打印。
鉴于家中有一台 24 小时开机的 Linux 服务器,我决定通过 Windows 虚拟机构建一个打印服务器。

虚拟机准备

因为手里有 Windows Server 2008 的正版,而且 Windows Server 2008 有内建的 IPP 服务器,因此最终选择使用 Windows Server 2008 64-bit。CPU 建议分配 2 核,内存分配 1024 MB 即可。
如果你的服务器没有太多历史包袱,可以重装为 VMware ESXi 或 Proxmox VE 等虚拟机平台,但我的服务器已经部署了很多服务并且资源也有限,因此最终选择使用 VirtualBox + KVM 加速。
建议虚拟机网卡模式设置为桥接,这样方便在内网中部署 Bonjour 打印机以及 AirPrint,而不需要每次部署服务都进行端口映射。

安装基本服务

我们需要通过 IIS 和 nginx+PHP 配合,来使用 Windows 用户帐户验证、IPP over HTTP 服务器,以及与 PHP 的整合。
IIS 和 Wnmp 的安装过程不再赘述。值得注意的是,你需要安装 IIS URL Rewrite Module 2,以便使用高级的 URL 重写。
然后,你需要在服务器管理器中添加 IPP 服务器功能,以及桌面体验来打开扫描仪功能。
然后下载我的项目 qwqVictor/PDFPrinter-WinPHP,例如你可以解压到 IIS 的 webroot 下,路径为 C:\inetpub\wwwroot
如果你希望在其它操作系统上通过 CUPS 原生使用打印功能,请先安装 PdfScribe
如果你也希望使用 AirPrint,请提前下载 AirPrint Daemon。而且必须设置好虚拟 CUPS 打印机。

这里假设 PDFPrinter-WinPHP 的临时目录为 C:\Tempbin 目录被拷贝到 C:\bin

配置 Web 服务器

配置 nginx

nginx.conf 中设置 root C:/inetpub/wwwroot;,以及配置基本的 PHP 功能,设置 listen 的地址为 127.0.0.1:8081
完整配置文件如下:

server {
    listen 127.0.0.1:8081; # IPv4
#    server_name localhost;

    ## Parametrization using hostname of access and log filenames.
    access_log logs/localhost_access.log;
    error_log logs/localhost_error.log;

    ## Root and index files.
    root C:/inetpub/wwwroot;
    index  index.php index.html index.htm;
    ## Try the requested URI as files before handling it to PHP.
    location / {
        ## Regular PHP processing.
        location ~ \.php$ {
            try_files  $uri =404;
            fastcgi_pass   php_processes;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME    $document_root$fastcgi_script_name;
            include        fastcgi_params;
        }
    } # / location
    client_max_body_size 110M; 

} 

其中 110M 是允许的最大的文档上传大小,可以自行设置。

配置 IIS

此时 IIS 的默认站点下应当已经有一个 Printers 的虚拟目录,不要动它!也许是我太菜如果删了它我不知道怎么恢复。
在 URL 重写中添加三条规则如下:
Rule 1
规则 1

Rule 2
规则 2

Rule 3
规则 3

这里我希望使用 Windows 的账户体系进行验证,但如果我们使用 Windows 身份验证,它会使用 NTLM,而 NTLM 是基本无法反代的。所以我们要使用基本身份验证。
IIS Auth

配置 PDFPrinter-WinPHP 的 PHP 部分

变量 描述 我的配置值
printerBinFile PDFPrinter.exe 路径 “C:\bin\PDFtoPrinter.exe”
scannerBinFile wia-cmd-scanner.exe 路径 “C:\bin\wia-cmd-scanner.exe”
tmpDir 临时目录路径 “C:\Temp”
hostName 最终访问域名 “printer.imvictor.tech”
printerName 打印机名称 “Canon MF3200 Series”
vprinterName 虚拟 CUPS 打印机名称 “Canon MF3200 Series (Virtual CUPS)”
scannerMaxDPI 扫描仪最大 DPI 300
defaultScanWidth 默认扫描宽度(cm) 210
defaultScanHeight 默认扫描高度 296
additionalInfo 打印机页面显示给用户的额外信息
additionalInfoScanner 扫描仪页面显示给用户的额外信息

其它反向代理等等就不再赘述了,最终完成类似这样:
WebUI

配置打印机

虚拟 CUPS 打印配置

安装 PdfScribe 之后,记得重命名它的虚拟设备为上文中 vprinterName 的值。
我们需要配置 PdfScribe 使得它能够在输出 PDF 后直接打开 PDF,然后修改打开方式为我们的 wrapper,这样也方便我们对 PDF 文件立即改名以防止阻塞。
wrapper 的代码我使用 C++ 编写,由于是自用也没有做多少边界处理,仅供参考:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <string>
#include <ctime>
char cmd1[50000], cmd2[50000];
int rd;
int main(int argc, char const *argv[]) {
    if (argc <= 1) return 1;
    srand(time(NULL));
    rd = rand();
    sprintf(cmd1, "cmd.exe /c \"move %s %s.%d.pdf\"", argv[1], argv[1], rd);
    system(cmd1);
    if (argc >= 3) {
        sprintf(cmd2, "C:\\bin\\PDFtoPrinter.exe %s.%d.pdf \"%s\"", argv[1], rd, argv[2]);
    }
    else {
        sprintf(cmd2, "C:\\bin\\PDFtoPrinter.exe %s.%d.pdf", argv[1], rd);
    }
    system(cmd2);
    return 0;
} 

在这里我写死了路径,您也可以根据自己的情况进行修改。
然后我们需要配置注册表来修改 PDF 的默认打开方式为我们的 wrapper,假设我们的 wrapper 路径为 C:\bin\printer_wrapper.exe
打开注册表,首先删除 HKEY_CLASSES_ROOT\.pdf,以防止干扰。
HKEY_LOCAL_MACHINE\SOFTWARE\Classes 下找到 .pdf,将其默认值项修改为一个不会重复的名字,例如 PDF_auto_File
然后在 HKEY_LOCAL_MACHINE\SOFTWARE\Classes 下建立一个和刚刚取的名字相同的项,在其下建立三层项 shell\open\command,将 command 的默认值项修改为 wrapper 路径加上 "%1"。如果您直接使用以上例子中的 wrapper,还需要在 "%1" 后面用括号括起来您的打印机名字。例如我的值为 "C:\bin\printer_wrapper.exe" "%1" "Canon MF3200 Series"
如果您的所有配置都与我的一致,那么您可以直接用以下 reg 文件:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\.pdf]
@="PDF_auto_File"

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\.pdf\OpenWithProgids]

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\PDF_auto_File]

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\PDF_auto_File\shell]

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\PDF_auto_File\shell\open]

[HKEY_LOCAL_MACHINE\SOFTWARE\Classes\PDF_auto_File\shell\open\command]
@="\"C:\\bin\\printer_wrapper.exe\" \"%1\" \"Canon MF3200 Series\""


在这里将打印机共享之后,就可以通过 IPP 打印了。

配置 AirPrint

假设现在你已经把 AirPrint Daemon 解压到 C:\AirPrint 下,且已经安装 nssm。
在管理员的 cmd 中输入 nssm.exe install,此时会弹出 GUI,可以参照下图设置。
NSSM Page
启动参数为 -R _ipp._tcp,_universal
注意在 Log on 选项卡里面可以最好让 AirPrint 使用对打印机有权限但不是 SYSTEM 帐户启动。
配置好之后在 iOS 设备上选择虚拟 CUPS 设备即可。
iOS AirPrint

配置扫描仪

安装桌面体验之后,扫描仪应当可以使用。请先查看设备管理器中图像设备中的 Canon MF3200 Series 是否正常启动,并且请通过控制面板测试一下。
如果前面的操作你都成功完成,扫描功能应当已经可以使用。

插曲: 解决在线扫描无彩色问题

在使用 wia-cmd-scanner 的过程中,我发现它似乎不能正常进行彩色扫描。
查阅官方文档([1], [2], [3])后我们发现,与扫描色彩有关的有两个项,分别为 ID 6146 的 WIA_IPS_CUR_INTENT 和 ID 4104 的 WIA_IPA_DEPTH。前者决定了色彩模式,后者决定了色彩位深度。而该程序的作者仅设置了 WIA_IPS_CUR_INTENT 而没有设置 WIA_IPA_DEPTH,使得 WIA_IPA_DEPTH 恒为 1。
我已经解决了问题,并发出了 Pull Request 请求合并到上游,在这期间你仍可以直接使用 PDFPrinter-WinPHP 中的修改版本。
如今作者已经修复了问题,最新的 PDFPrinter-WinPHP 已经包含最新版本。

发表评论

电子邮件地址不会被公开。 必填项已用*标注


由于移动端输入法兼容性问题,Markdown 编辑器已停用,但您仍可以使用 Markdown 语法。