slastra/printrow

GitHub: slastra/printrow

一款无需驱动和服务器的浏览器端热敏标签设计器,通过 Web Bluetooth 连接 KNAON Y50P 打印机并将 CSV 数据批量打印为标签。

Stars: 0 | Forks: 0

# 打印 row **[printrow.lastra.us](https://printrow.lastra.us)** 是一款通过 Web Bluetooth 针对 CSV 数据进行打印的标签设计器。无需驱动、无需安装、无需打印服务器:在浏览器中设计标签,将 `{{variables}}` 绑定到 CSV 列,然后直接从页面批量打印到 KNAON Y50P 热敏打印机。 ![printrow 编辑器:一个带有包裹图标的黄色标签,包含产品名称和 Code 128 条形码,其中的 SKU、价格和条形码数据会从导入的 CSV 中实时解析并显示在侧边的列面板中](https://static.pigsec.cn/wp-content/uploads/repos/cas/6c/6c0521bfbda7096603e802932b6710f29bccc74b6e20373691c1d26519a5c613.jpg) ## 功能介绍 - **画布编辑器**:多选、框选、对齐与分布、分组、拖拽重排图层、自由旋转、撤销/重做,以及中键拖拽平移。 - **元素**:文本(内置 9 种字体)、条形码和二维码(通过 bwip-js 支持 7 种码制)、图像、方框,以及通过可搜索选择器使用 lucide 的约 1,750 个图标。 - **CSV 绑定**:`{{column}}` 直接解析到对应的 CSV 列;无需映射步骤。支持针对文本、数字、货币(8 种代码)和日期(7 种格式)进行逐列格式化设置,该配置保存在模板中,因此下周重新导入文件时设置依然有效。 - **批量打印**:可以打印单行或所有行,并配有进度条、取消功能,以及在标签打印之间进行打印机状态检查,这样出现卡纸或盖子未盖好的情况时会停止打印任务,而不会将数据发送到无响应的设备中。 ## 工作原理 Y50P 使用一种专有的带帧二进制协议,该协议是通过硬件抓包逆向工程得出的。打印机本身没有内置字体,也没有条形码码制。它只接受 400×240 的 1-bit 位图。所有内容都在主机端进行渲染,这也是预览结果能够完全可信的原因: - **zod 模型是唯一的真实数据源**;Konva 只是它的一个视图。相同的节点构建器同时为编辑器画布和打印栅格化器提供数据,因此它们之间不会产生偏差。 - **预览以打印机的真实分辨率渲染**:203 dpi,强制的 1-bit 阈值处理,针对照片使用 Atkinson 抖动。屏幕上的点阵网格_就是_标签的真实样子,包括所有的像素锯齿。 - **条形码的模块网格在任何元素尺寸下都会对齐到完整的打印机点**。分数模块是导致缩放后的条形码既模糊又难以被扫描仪识别的原因。 - **纸张颜色和模切形状仅用于预览。** 打印头会在任何装入的纸张上烧灼出黑色;如果彩色背景进入阈值处理阶段,将会把整个标签打印成纯黑色。 - **传输方式**:BLE GATT 写入操作以 20 字节为单位分块并进行节奏控制,同时在标签之间轮询双向状态(就绪 / 盖子打开 / 缺纸)。 底层传输格式非常严苛,如果你 fork 本项目,有一点特别值得注意:光栅行不带长度字段,因此如果某一行的宽度与介质宽度不完全一致,就会移动后续所有行的标记,并可能导致固件挂起。`buildStream` 会拒绝编码此类数据,并且在 `protocol.spec.ts` 中,前导码是针对硬件抓包逐字节严格固定的。 ## 技术栈 SvelteKit 2 · Svelte 5 runes · Tailwind 4 · shadcn-svelte · Konva · zod · bwip-js · lucide · bun ## 开发 ``` bun install bun run dev # http://localhost:5173 bun test src # protocol vectors, CSV parsing, geometry, formatting, icon search bun run check # svelte-check ``` ## 部署 `nixpacks.toml` 使用 Bun 进行构建并启动 adapter-node 服务器,因此 Coolify 无需额外配置: ``` bun install --frozen-lockfile → bun run build → node build ``` 没有数据库,服务器端也不需要持久化任何内容(模板保存在浏览器的 localStorage 中,并且直接从浏览器访问打印机),因此服务器仅用于提供静态资源和 SSR 外壳。它监听 `PORT`(适配器在 0.0.0.0 上默认为 3000)。推送到 `main` 分支会自动重新部署。 **请通过 HTTPS 提供服务。** Web Bluetooth 只能在安全上下文中运行,因此在普通的 http 源下,“连接”按钮将完全不起作用。 ## 浏览器支持 Web Bluetooth 仅支持 Chromium 内核浏览器。**Linux** 上的 Chrome 还需要启用 `chrome://flags/#enable-web-bluetooth` 并重启浏览器;`#enable-web-bluetooth-new-permissions-backend` 是可选的,但它允许已知打印机免扫描直接重连。ChromeOS 默认启用此功能。除了打印之外,其他所有功能都可以在任何现代浏览器中正常使用。 设备发现特意按设备名称而不是 service UUID 进行过滤:如果使用 service UUID 过滤,会导致 Chrome 将 `SetDiscoveryFilter` UUID 列表推送给 BlueZ,这会引发桌面版 Linux 上 `bluetoothd` 5.87 版本的段错误。 ## 硬件

A KNAON Y50P thermal printer, lid closed, presenting a freshly printed label that reads PRINTROW above a barcode

已在 **KNAON Y50P** 上验证,使用 50 × 30 mm 纸张,精度为 8 dots/mm。其他介质高度也是安全的,因为协议从不传输高度:打印机只会不断接收数据行,直到光栅数据结束。除了 50 mm 之外的宽度遵循已抓包的帧格式,但尚未在真实纸张上进行过测试。 该硬件是贴牌生产的,因此你桌面上的打印机可能会标有不同的名称。此处的 KNAON 设备及其兄弟产品 **FlashToy U8** 使用相同的协议,并且驱动它们的供应商 Android 应用都封装了同一个 `com.j0data.sdk` 库。品牌并不是区分标准,USB 供应商 ID 也不是:`0x5958` 是未注册的,并与使用 TSPL 协议的打印机共享。真正起决定性作用的是底层传输格式。只要帧以 `1a 01` 开头、以 `a1` 结尾,并且使用初始值 `0xCA896ADE` 进行 CRC-32 校验,无论外壳上的标签写的是什么,都属于此协议。 ## 许可证 MIT
标签:CSV数据绑定, Web蓝牙, 批量打印, 标签设计器, 热敏打印机, 硬件控制