接入开发

内容来源

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(发票、报表、合同)PDF版式由服务端决定,矢量直通,清晰
照片、扫描件、已渲染好的图图片一张 = 一页,完整适配到纸张,不拉伸
面单、小票、价签等模板化内容模板文档毫米精度、{{占位符}} 绑定数据,可用在线设计器做
已有 vue-plugin-hiprint 模板Hiprint经适配器转换,见 Hiprint 模板
已有网页版式网页消毒后快照成页

上传内容

PDF、图片、网页需要先把字节交给 PrintLink:

const asset = await client.uploadAsset(pdfBytes, 'application/pdf');

返回的 AssetRef 可以在后续调用里反复使用:同一份 PDF 先预览再打印,或者打到 多台打印机,都不需要重新上传。compose() 内部会自动处理上传并按 SHA-256 去重。

PDF

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 没有用户能事先看到的形态。

相关页面

本页目录