如何打造一个牛逼的打印机

Lobsters Hottest 工具

摘要

Nishant Joshi 详细介绍了如何将 Xteink X3 电子墨水显示屏改造为功能打印机,通过实现 Internet Printing Protocol 并优化 ESP32-C3 微控制器上的内存限制。

<p><a href="https://lobste.rs/s/pxreik/how_build_f_king_printer">评论</a></p>
查看原文
查看缓存全文

缓存时间: 2026/09/08 23:09

# 如何打造一台**了不起的打印机** · 尼尚特·乔希 来源:https://nishantjosh.dev/blogs/how-to-build-a-fking-printer/ 我本打算组装一台电子墨水屏设备,偶然在网上发现了 Xteink X3。仔细阅读产品说明后,发现它竟然支持完全编程控制。 我立马心动了。 设备到手后,我很喜欢它纤薄的外观,握在手里也很有质感。我开始在 CrossPoint 固件里添加各种功能:定制开机动画、摇晃阅读器就能掷出的骰子、为旧金山技术交流会准备的 LinkedIn 二维码。 但向设备传输内容的过程很繁琐——必须连接它的热点,然后在浏览器里打开专用上传页面。 真够难受的。 在寻找更便捷传输方式时,我突然想到:既然它长得像纸,就应该像纸一样使用。 我应该能直接在上面打印东西。 **Xteink X3 正在显示一幅打印机的黑白素描** ## 什么是真正的打印机? 我希望能从 MacBook 上打开文件,点击“打印”,然后选择 Xteink 设备。这意味着我需要弄清楚计算机在打印端期望获得什么。 最终我研究了 **Internet 打印协议**(https://www.pwg.org/ipp/ippguide.html),简称 IPP。该协议允许计算机向打印机查询支持的功能、提交文档,并跟踪任务状态。所有通信都基于 HTTP 协议进行。例如`Get\-Printer\-Attributes`用于查询设备能力;`Print\-Job`则负责发送打印任务。 我声明了单色输出、300 dpi 分辨率、单份打印和单面打印。对于文档格式,支持 Apple 光栅和 PWG 光栅格式,这意味着 Mac 需要先将文档转换为像素数据再发送。`penguin`程序会负责将结果缩放至适合屏幕显示。 我声明了 A5 和 Letter 两种纸张尺寸,媒体类型设为`stationery`(信纸),并定义了名为`face\-up`(正面朝上)的输出纸盒。 我给它取名`penguin`——这个颜色搭配很合适。 使用 Bonjour 服务广播了一个名为`\_ipp\.\_tcp`的服务。广播信息中包含了我支持的文档格式以及打印任务应发送的地址。 为了在 macOS 上实现免驱动发现,我还必须添加`\_universal`子类型(https://github.com/NishantJoshi00/crosspoint-reader/blob/f137b35327db4f685ed2803558d74216975031c8/src/activities/printer/PrinterActivity.cpp#L228)。这意味着需要直接调用 ESP\-IDF 的 mDNS API,因为 Arduino 封装层并未暴露该接口。 让计算机能够发送页面内容只是完成了一半工作,我还需要在这个小设备上接收并处理这些数据。 ## 页面内容该往哪放? 一张 300 dpi 的 Letter 尺寸页面包含 2550×3300 像素。按每灰度像素 1 字节计算,未压缩数据约 8.4 MB。 而 X3 只有 400 KB 内存,其中 16 KB 被预留为缓存(https://documentation.espressif.com/esp32-c3_datasheet_en.html)。我需要同时运行 Wi\-Fi、打印服务器,并想办法接收整个该死的页面数据。 在 Wi\-Fi 运行并分配打印机页面图像内存后,堆空间仅剩 6.8 KB。 我想起 Linux 的`mmap`机制(https://man7.org/linux/man-pages/man2/mmap.2.html)。能否在 SD 卡上实现类似功能来扩展可用内存?但 C3 的内存映射仅支持闪存,不支持 SD 卡文件。 不过等等……我能否将显示屏作为存储介质? 如果我将传入的页面通过转换管道处理,并直接将结果写入显示屏会怎样?解码像素数据,缩放至合适尺寸,抖动处理为黑白二值图像。每处理完一行就立即写入显示屏对应位置并重用工作区,如此循环直到整个页面完成。 显示屏本身已有保留用于屏幕图像的内存区域,我可以在页面传入时直接在该区域构建图像。在此之前,我曾为了复制图像而额外创建一整套第二图像。 我的解码器原本就按行处理数据,于是我调整了缩放器使其也能输出完整行数据(https://github.com/NishantJoshi00/crosspoint-reader/commit/cbefbd6d9596a5bbe831e32742e88172b7a63e0b),并将这些行直接写入显示屏的图像内存区域。最初我让页面像打印机出纸一样逐条显示,但由于每次中间刷新都需要约半秒,我最终改为一次性呈现完整页面。 完成的页面会被保存为 BMP 格式存储在 SD 卡上,使用现有的截图保存功能(https://github.com/NishantJoshi00/crosspoint-reader/blob/f137b35327db4f685ed2803558d74216975031c8/src/util/ScreenshotUtil.cpp#L151)。 **图像缓冲区内存变化** - 芯片总内存 400 KB - 改造前占用 ~113 KB - 改造后占用 ~62 KB 这样就为网络栈的 socket 缓冲区腾出了空间。 ## 预览窗口里出现的企鹅 不知为何,我的 MacBook 上存着一张《无职转生》的漫画示例图片。我用预览程序打开它,准备打印。 在打印机列表里,我看到了`penguin`! 我靠! 选择它并打印。漫画页面在 Xteink 上显示效果极佳。我记得画面大约 1 秒就完整呈现,现在它还显示在设备上。 **印刷在 Xteink X3 上的漫画页面,设备搁在一台闭合的 MacBook 上** 我花了一整个晚上才完成首次成功打印。 打印服务器直接运行在阅读器本身。它既可以连接现有 Wi\-Fi 网络,也能创建名为`literate\-penguin`(识字企鹅)的热点。 我的企鹅现在能“阅读”了。 所有代码都在我的 CrossPoint 仓库分支(https://github.com/NishantJoshi00/crosspoint-reader)中,包括完整的**打印机实现模块**(https://github.com/NishantJoshi00/crosspoint-reader/tree/f137b35327db4f685ed2803558d74216975031c8/src/network/ipp)。 已打印的文件会保存在 SD 卡中,我可以随时在阅读器上浏览它们——毕竟我的打印机也需要“纸盒”,而那正是一个文件夹。

相似文章

用3D打印机写明信片

Hacker News Top

作者描述了如何将笔固定在3D打印机上用于书写明信片,包括在OpenSCAD中设计笔适配器,以及使用Inkscape和svg2gcode生成G代码。该项目通过自定义控制软件解决了归零安全问题。