我原计划做电子墨水屏(e-ink display),上网看到 Xteink X3设备(Xteink X3)称完全可编程便购入。到货后喜其扁平扎实,往 CrossPoint固件(CrossPoint firmware)加启动动画、摇掷骰子及领英(LinkedIn)旧金山社交二维码。但传文件需连热点开网页,甚烦。寻更优法时觉其如纸当可打印,遂想在苹果笔记本(MacBook)点打印选它,继而查互联网打印协议(Internet Printing Protocol,IPP)。
正文
我本来计划自己做一块电子墨水屏显示器,在网上闲逛时看到了 Xteink X3。某处细节说明里写着:这东西完全可编程。
我立刻心动了。
到货后,我很喜欢它扁平的形态,握在手里很扎实。我开始往 CrossPoint 固件里加东西:换一个开机动画、摇一摇阅读器就能掷骰子、给旧金山的社交活动放一个 LinkedIn 二维码。
但把内容传上去很繁琐。我得先连上它的热点,再在浏览器里打开一个上传小网页。
恶心。
找一种更舒服的传输方式时,我忽然想到:如果它看起来像纸,就应该表现得像纸。
我应该能往它上面打印。

什么让一台打印机成为打印机?
我想要的体验是:在 MacBook 上打开文件,按打印,然后选 Xteink。所以得先弄清楚我的电脑在另一端期待什么。
我找到了 Internet Printing Protocol(IPP)。它让电脑询问打印机支持什么、提交文档、再查询作业进展。消息走 HTTP。Get-Printer-Attributes 这类操作查询能力,Print-Job 提交要打印的内容。
我声明了黑白输出、300 dpi、单份、单面。文档格式只收 Apple raster 和 PWG raster,也就是说 Mac 得先把文档转成像素再发过来,penguin 再把图缩到刚好填满屏幕。我还声明了 A5 和 Letter 纸张、介质类型 stationery、一个叫 face-up 的出纸槽。
打印机叫 penguin,配色正好相衬。我用 Bonjour 以这个名字广播 _ipp._tcp 服务,通告里写明支持的格式和打印作业该送达的地址。
要让 macOS 免驱动发现设备,还得添加 _universal 子类型。这意味着要直接调 ESP-IDF 的 mDNS API,Arduino 封装没把这个接口暴露出来。
让电脑发出这一页只是完成了一半,我还得在这台设备上把它接住。
这一页放哪儿?
300 dpi 的 Letter 页面是 2,550 × 3,300 像素。按每个灰度像素 1 字节算,未压缩大概是 8.4 MB。
X3 只有 400 KB 内存,其中 16 KB 留给缓存。我还要同时跑 Wi-Fi、跑打印服务器,再设法收下整整一页该死的内容。
Wi-Fi 跑起来、页面图像也分配好之后,堆上只剩 6.8 KB。
我想起 Linux 里的 mmap:能不能拿 SD 卡做类似的事,假装自己有更多内存?不行,C3 的内存映射只覆盖 flash,不能映射 SD 卡上的文件。
等一下。能不能把显示屏本身当作存储?
如果让收到的页面数据经过一条变换流水线,把结果直接写进屏幕呢:解码像素、缩放到合适大小、抖动成黑白。每一行一准备好,就放到它在屏幕上的位置,然后复用这块工作区,直到拼出完整一页。
显示屏本来就有一块内存留给屏幕图像。我可以在数据到达时直接在那里拼页。而在这之前,我得先在内存里拼出完整第二张图像,再整体拷过去。
我的解码器本来就是逐行工作的。我改成让缩放器也把完成的行直接交出来,接进屏幕图像。一开始我让页面像打印机出纸那样一条条显现,可每刷新一次中间状态要花大约半秒,于是改成等整页完成后一次显示。
成品页我用现成的截图保存代码存成 BMP,写进 SD 卡。图像缓冲内存从芯片 400 KB 里的约 113 KB 降到了约 62 KB,给网络栈腾出了放 socket 缓冲区的空间。
Preview 里出现了一只企鹅
不知为何,我 MacBook 里有一张《无职转生》的漫画样图。我用 Preview 打开它,然后去打印。打印机列表里出现了 penguin。
我靠。
我选中它,打印。漫画页在 Xteink 上效果很好。凭记忆大概一秒就显示出来了,画面现在还留在那里。

这第一张打印花了我一个晚上。
打印服务器现在就运行在阅读器上。我既可以让它加入 Wi-Fi 网络,也可以让它自己开热点,热点名叫 literate-penguin。
我的企鹅现在会阅读了。
代码在我的 CrossPoint fork 里,包括打印服务的实现。打出来的东西存在 SD 卡上,可以直接在阅读器里翻看。说到底,我的打印机还是有个出纸托盘的——只不过它是一个文件夹。
评论
多数人被“把文件‘打印’到电子墨水屏上”这个点子点燃,觉得它又酷又顺理成章;少数人则直接发问:这和把 PDF 传进设备有什么本质区别?另有一部分人已经转向关心怎么复刻一台。
这就是《星际迷航》里的 PADD 成真了
- 较多人觉得这个用法“太正确了”:把墨水屏阅读器当作一张可反复写入的纸,而不是随身电脑,收发文档的体验终于有了实物感。
- 有人直接兴奋地感叹“我们终于有《星际迷航》里的 PADD 了”(@andyfilms1)。
直接加载 PDF 不就行了吗?
- 少数人对“打印到墨水屏”的目的表示困惑:如果内容最终只是显示在电子纸屏幕上,为什么还要模拟一套打印流程,而不是直接把 PDF 传给设备?
- 引用原话里的核心疑问:“作者说‘打印’到墨水屏上,为什么不直接加载 PDF?我到底漏掉了什么?”(@greazy)
更想学怎么造一台“打印机”
- 少数人对展示的软件实现更感兴趣,看完后想知道整套流程如何搭建,甚至已经有了可以去更新的 fork。
- “干得好,但我更想知道怎么做一个这样的打印机。”(@ks2048)
看完之后又犯了 eInk 瘾
- 有评论者承认自己一直在刷这类展示,说不清真正用途,但被激起了购买欲,甚至开始纠结该买 X3 还是 X4。
- 这种“先买了再说”的冲动消费情绪,恰好说明项目本身的视觉冲击力很强。