内容来源
PDF、图片、模板文档、网页四种内容怎么打、该选哪种,以及数据绑定与远程素材。
最后更新
一条打印任务里的内容写成 source.items:一个有序数组,数组顺序就是页序。
一份 PDF 也是长度为 1 的数组。
source: {
items: [
{ type: 'pdf', asset }, // 一份 PDF
{ type: 'image', asset, pageLayout: { mode: 'custom', scalePercent: 80 } },
{ type: 'document', document: doc, data: { orderNo: 'A-1024' } },
],
}平时不用手写这个结构——compose() 的 addPdf / addImage / addDocument
会替你生成。
该选哪种
| 场景 | 选 | 原因 |
|---|---|---|
| 服务端已生成 PDF(发票、报表、合同) | 版式由服务端决定,矢量直通,清晰 | |
| 照片、扫描件、已渲染好的图 | 图片 | 一张 = 一页,完整适配到纸张,不拉伸 |
| 面单、小票、价签等模板化内容 | 模板文档 | 毫米精度、{{占位符}} 绑定数据,可用在线设计器做 |
| 已有 vue-plugin-hiprint 模板 | Hiprint | 经适配器转换,见 Hiprint 模板 |
| 已有网页版式 | 网页 | 消毒后快照成页 |
上传内容
PDF、图片、网页需要先把字节交给 PrintLink:
const asset = await client.uploadAsset(pdfBytes, 'application/pdf');返回的 AssetRef 可以在后续调用里反复使用:同一份 PDF 先预览再打印,或者打到
多台打印机,都不需要重新上传。compose() 内部会自动处理上传并按 SHA-256
去重。
await client.compose({ queueId })
.paper('A4')
.addPdf(pdfBytes) // File / Blob / Uint8Array / 已上传的 AssetRef 都行
.printAndWait();.pageRange('2-4') 可以选择只打某几页:
- 它的作用是过滤,不是重排。
'3,1'打出来仍然是第 1、3 页的顺序。 - 想重排页序,就把同一个 asset 作为多个项放进去:
addPdf(a).pageRange('3').addPdf(a).pageRange('1')(asset 只会上传一次)。 - 语法错或倒序(
'3-1')→INVALID_REQUEST;部分越界会截断并给PAGE_RANGE_CLAMPED;一页都选不到 →INVALID_REQUEST。
单份 PDF 保持原样
只有一份 PDF 时,PrintLink 会把文件原样送进打印队列,不做重新编码,产物哈希 与文件本身一致。
图片
图片没有自己的纸张尺寸——纸张由任务级的 paper 决定,图片适配到纸的可打印区。
await client.compose({ queueId })
.paper('6in')
.addImage(photoBlob)
.printAndWait();需要精细摆放时用 .imageLayout(...),只影响这一张图,详见
打印参数 · 图片位置与大小。
若页面整页只有一张满幅图片,PrintLink 会把它当作照片页处理:直接嵌入 原始像素(JPEG 不重新编码),并按照片横竖方向选择纸面方向——这是照片打印 最清晰的一条路径。
模板文档
用结构化元素描述页面,不经过 HTML 排版。{{占位符}} 在打印前用数据替换:
const doc = PrintLink.documentBuilder()
.page('100x150', (page) =>
page
.text({ x: 5, y: 6, width: 90, height: 10, text: '订单号:{{orderNo}}' })
.qrcode({ x: 60, y: 20, width: 30, height: 30, value: '{{orderNo}}' }),
)
.build();
await client.compose({ queueId })
.paper('100x150')
.addDocument(doc).data({ orderNo: 'SO-2026-0001' })
.printAndWait();数据跟着内容项走:同一份模板加上 N 次、各绑一份数据,就是一条任务里的 N 页, 互不干扰:
const job = client.compose({ queueId }).paper('100x150');
for (const order of orders) job.addDocument(template).data(order);
await job.printAndWait();支持的占位符只有纯路径插值({{order.customer.name}}),不做表达式求值。
数据里没有这个路径时,会保留原样并给 BINDING_MISSING 警告。
模板文档还支持 table(表格)与 repeat(重复区块)两种数据驱动元素,
它们在渲染前展开成基础元素,超出区域高度时自动分页续排:
{ id: 'lines', type: 'table', x: 8, y: 30, width: 84, height: 40,
rowHeight: 7, dataPath: 'lines',
columns: [
{ key: 'sku', title: 'SKU' },
{ key: 'qty', title: '数量', width: 0.6, align: 'right' },
],
header: { repeat: true } } // 续页时重复表头模板里的图片不能直接写远程 URL:只能用已登记的资产或 data:image/* 内联
数据。想绑定数据里的图片路径,用 Image 元素的 sourceBinding 字段指向该路径,
取值同样必须落在上面两种形式里;不合法时给 BINDING_VALUE_INVALID 并回退到
静态图片,不会静默失败。
网页(HTML)
把一段 HTML 交给 PrintLink,它会消毒后快照成页:
await client.compose({ queueId })
.paper('A4')
.addHtml(htmlBytes) // 已上传的 text/html asset
.printAndWait();限制:
- 单个 HTML 资产 ≤ 1 MiB,每次请求最多 10 个 HTML 项,单项最多 50 页。
- 脚本、外链、
file:引用全部被剥离,渲染过程零网络请求。 - 无内置浏览器的环境(无头服务)会返回
HTML_SNAPSHOT_UNAVAILABLE, 不会退化成纯文本。
远程素材
图片与网页可以不先上传,直接给一个公网地址,由 PrintLink 去取:
await client.compose({ queueId })
.paper('A4')
.add(item) // { type: 'image', remote: { url: 'https://cdn.example.com/a.png' } }
.printAndWait();只允许公网地址
出于安全考虑,远程抓取只接受公网目标:必须是 http(s) 默认端口、不带凭据,
且主机不能是回环、内网、链路本地或多播地址。指向内网的地址会被拒绝
(REMOTE_FETCH_DENIED),不会「过滤掉内网再连其余」。
取回的字节与上传走同样的检查:白名单校验、体积上限、按内容判定类型。 PDF 必须上传——远程 PDF 没有用户能事先看到的形态。