Rescuing old printers with an in-browser Linux VM bridged to WebUSB over USB/IP | 海外技术热榜

4 阅读10分钟

Rescuing old printers with an in-browser Linux VM bridged to WebUSB over USB/IP

原文链接

🔗 Rescuing old printers with an in-browser Linux VM bridged to WebUSB over USB/IP

翻译说明

本文翻译自Hacker News最新热门技术文章,内容仅供学习参考,版权归原作者所有。

完整翻译内容

<< 首页

印刷发明:背景故事

我有一台旧照片打印机

我们的故事始于我意外地购买了一台佳能 SELPHY 照片打印机。我买了一台新的 3D 打印机,并问我的朋友马克是否想要旧的。他答应了,并问我是否想要这台照片打印机作为回报。他在 eBay 上买了一张备用的,里面有纸张和墨水,价格还低于纸张和墨水本身的价值!

我也答应了,因为全家人都会喜欢的新玩意让我很兴奋。然后我发现为什么这些旧打印机的价格这么低。 Mac 已经有一段时间不支持它们了,Windows 也不支持。 Mark 使用 Linux:他没有遇到过这个问题。

令人高兴的是,我的办公桌上已经有了一个 Manjaro 盒子。这是一个小型 Lenovo ThinkCenter,我主要用它来测试。碰巧的是,这些也适用于 eBay 上的一首歌。

Linux 可以通过 AirPrint 共享

我在我的 Manjaro 机器上安装了 CUPS 和 Gutenprint,它在 SELPHY 上打印得很漂亮。我设置 Avahi 通过 AirPrint 共享它,全家人都可以从他们的 Mac 和 iPhone 进行打印。

我们打印的照片就像 1999 年一样:您可以触摸的真实照片!除了——与 1999 年不同——它很简单、即时,你只能打印好的照片,而且你可以先裁剪和修复曝光。您还可以看到 CMY 打印的魔力就在您面前展开,因为这些打印机将纸张经过三次,首先打印黄色,然后打印洋红色,最后打印青色平面。

美好的结局!但这只是故事的中间部分。因为那时我想:我的父母会喜欢其中一件。他们可以打印孙子孙女的照片。也许我可以将他们设置为 Raspberry Pi 作为打印服务器?但这样一来,它的价格就不那么便宜了。不管怎样,我不相信他们会购买额外的插头和电线。

并不是每个人都运行 Linux

当然——我想——肯定有可能单独使用软件来解决这个问题。那不是很好吗?让我们从垃圾填埋场中拯救一百万台打印机。

于是我花了 18 英镑购买了一个月的 Claude Code,然后开始编码。 (现代法学硕士简直令人难以置信:按照史蒂夫·乔布斯的说法,如果计算机是思维的自行车,那么克劳德·科德就是一架私人飞机。)

克劳德和我开始开发一个原生 Mac 应用程序,该应用程序可以谨慎地运行一个简单的 Linux 虚拟机。它将使用 Virtualization.framework、转发 USB 流量并通过 mDNS 通告打印机。但它可能不会被 App Store 允许。即使是这样,也只有 Mac 用户会看到任何好处。

但几乎每个人都可以使用网络应用程序

然后我想起了(多亏了 micro:bit 系列,它目前是蓝牙控制的 Meccano 总线的大脑),Chrome 具有 WebUSB。如果我可以把它变成一个网络应用程序怎么办?然后它就可以在任何地方工作——无需安装。另外,它可以用 JavaScript 做很酷的事情,我一直很喜欢这一点。 :)

所以我将 Xcode 换成了 VS Code 并重新开始。不久之后,很明显这会起作用,我注册了printerface.app和printervention.app(克劳德更喜欢前者;我的妻子更喜欢后者;我的妻子赢了)。

它是如何运作的?

网络应用程序如何工作

这个应用程序的核心是令人惊叹的 v86,它在浏览器中模拟 x86 CPU 以及围绕它的整个机器。它在运行时将机器代码编译为 WebAssembly 模块,这使得整个安排变得极其缓慢。我这样做是为了让这台 v86 机器运行带有 CUPS、Gutenprint 和支持包的 Alpine Linux。

浏览器通过 WebUSB 连接到您的打印机,检索其品牌和型号。它使用 trigrams 查找最接近的匹配的 Gutenprint 驱动程序名称,并通过模拟键盘发送 lpadmin 命令来安装它。

然后,要打印文件,请将其上传到模拟计算机并发送 lp 打印命令。而且,就像变魔术一样,模拟机器中生成的原始二进制打印数据最终会到达您的打印机。

当然,最后一步才是有趣的。它经历了几个我迭代。

桥接 CUPS 和 WebUSB

首先,我使用了自定义 CUPS 后端。这其实是双子座的主意。后端是一个简单的 shell 脚本,接收原始打印数据并通过 v86 TTY 将其逐字节发送回浏览器。在那里,字节被重新组装并通过批量 USB 传输调用传递到打印机。

这样做的美妙之处在于:它有效!我最初有点怀疑,但打印确实可以通过在设备上推送单向、即发即忘的二进制数据流来实现。这是我用 Chrome 从 SELPHY 打印的第一张照片:纸板箱里的一只家猫。

[一只猫,但不是我们所知道的]

当然,这都是错误的,但 CMY 平面的位移使其成为色彩缤纷的抽象艺术。事实证明,当您将分离的 Y-M-C 打印数据推送到需要文本的 TTY 上时,就会发生这种情况,从而使用换行符和控制字符执行有趣的操作。当我向后端脚本添加 stty raw 命令后,效果就消失了。

第二次迭代是一种替代方案,可能更高效,CUPS 后端实现。这个使用 v86 的 9p 文件系统以更大的块传输数据。这一张还以有趣的方式(这次是条纹)破坏了它的第一张照片。这里的学习?在尝试从 JavaScript 读回文件之前,请始终在 Linux 端同步文件。

这两种方法的主要缺点是数据流都是单向的。 CP-400 没有显示屏,因此如果出现问题,您无法立即判断是卡纸、墨盒空还是其他原因,除非计算机可以将该消息转发给您。由于在此设置中计算机从未听到打印机发出的声音,因此它显然无法做到这一点。

使桥梁双向

我想要尝试将数据从浏览器流回模拟 Linux 机器的另一个原因是一台旧的佳能 USB 扫描仪,它在过去十年里一直放在我的书架上。我想尝试一个类似的奇怪技巧来复活旧扫描仪和旧打印机会很好。

无论如何,我给了 Claude 一杯新鲜的热茶,并询问它如何双向桥接模拟 Linux 机器的 USB 和 WebUSB。

在我看来,克劳德确实做到了这一点。它首先提出了两个我从未听说过的东西:USB/IP 和 tcpip.js。

  • USB/IP 在 Linux 机器上运行。它将传出的 USB 数据打包到 TCP 数据包中,并从传入的 TCP 数据包中解开 USB 数据。通过 USB/IP 工作,不再需要自定义 CUPS 后端:据 CUPS 所知,它只是通过普通 USB 连接到普通 USB 打印机。
  • tcpip.js 运行在 JavaScript 端,主要是通过将 lwIP 编译为 WebAssembly。你看,我们的 v86 机器有一个模拟网卡,但从它进入 JavaScript 环境的是原始以太网帧。当然,浏览器不会公开任何网络堆栈来将 L2 以太网流量转换回 L4 TCP/IP 流量。这就是 tcpip.js 为我们做的事情。

连接好这两件事后,Claude 漫不经心地开始一次性制作一个 400 线 USB/IP 到 WebUSB 桥接器。现在打印不仅可以工作,而且 CUPS 还清楚地知道每个阶段发生了什么。

此时,我使用 SANE 制作了一个扫描应用程序的原型,Claude 还对 tcpip.js 进行了一个小但关键的修复,以使其也能正常工作。 (我已经注册了 yes-we-scan.app:您可以期待它很快就可用)。

进一步调整

但回到 Printervention.app,我还有两个小问题。

首先,我似乎无法阻止 CUPS 压缩我的照片以适应 SELPHY 的 6 x 4 英寸明信片纸张尺寸(无论我要求什么适合或填充设置)。为了解决这个问题,我现在将任何 JPEG 嵌入到与打印机纸张尺寸相匹配的手卷 PDF 文件中。

我从一个古老的项目(打印 CD 封面)中找到了一些 CoffeeScript 来完成这项工作,但我从未抽出时间发布它。 Claude 帮助添加了一些代码来处理 EXIF 方向数据a,还将 ICC 配置文件从 JPEG 传递到 PDF 图像的元数据中,以实现更好的色彩再现。

其次,我的大部分照片都在 Apple Photos 中,或者通过 AirDrop 从我的 iPhone 中提取。这意味着它们中的大多数都存储为 HEIC。我要求 Claude 建立一个合理的转换管道——它永远不会尝试将所有未压缩的图像数据同时保存在内存中——它也有义务将 libheif-js 和 wasm-mozjpeg 粘合在一起,同时确保再次通过 ICC 配置文件。

最后,我添加了一些耗材的附属链接(知道某人现在正在使用特定打印机进行打印似乎是一个很好的线索!),以及一些非常基本的遥测,发送会话、打印机和打印作业的基本详细信息以保存到 Neon Postgres DB。

这就是我的打印机发明。我希望它对你有用。我购买了一批(非常少的)SELPHY 打印机库存,希望它的发布能让它们的价格一夜之间翻两番。 :)

接下来是什么

该应用程序仅在这几种照片打印机上进行了测试,但我希望它能够适用于一系列其他 Gutenprint 支持的型号,只要您不要尝试一次性打印太大的东西。如果您的打印机无法工作,请联系我们。毫无疑问,可以进行改进,包括添加额外的 PPD 软件包,例如 brlaser 和 splix。

我必须道歉,到目前为止我还没有开源任何我不需要的部分。主要是因为我认为对于打印机耗材公司来说,这将是一个非常具有粘性的网络资产,可以与其销售网站集成。我更希望他们付钱给我为他们贴上白标签,而不是仅仅分叉一个回购协议并免费获得所有内容。

乔治·麦凯伦 2026 年 4 月

<< 首页


翻译声明:本文由AI自动翻译,如有不准确之处欢迎指正


🙏 如果本文对你有帮助,欢迎打赏支持,你的鼓励是我持续输出优质内容的最大动力! 💴 打赏通道:点击文章末尾「赞赏」按钮即可,每一分支持都是我前进的动力~