Skip to content

xPdf API 接口规范

版本: Unified API / V2 Engine 更新: 2026-03-10

说明: 本文描述当前正式公开 schema。唯一 canonical 路由为 POST /api/v1/labelprod/test 仅通过环境与 token 区分。


1. 接口概览

路由鉴权方式用途
POST /api/v1/labelAuthorization: Bearer <token>唯一公开请求入口
  • Content-Type: application/json
  • 响应: application/pdf (二进制流)
  • 默认输出模式: binary
  • settings.output.mode = "file" 时,响应会带 Content-Disposition

2. 请求结构

json
{
  "settings": {
    "defaults": {
      "text": {
        "font_family": "NotoSans-Regular",
        "font_size": 11,
        "color": "#111111"
      },
      "stroke": {
        "color": "#000000",
        "width": 0.4
      },
      "fill": {
        "color": "#FFFFFF",
        "opacity": 1.0
      },
      "shape": {
        "corner_radius": 0
      }
    },
    "metadata": {
      "title": "xPdf Document",
      "author": "xPdf"
    },
    "output": {
      "mode": "file",
      "file_name": "invoice-20260310.pdf"
    },
    "profile": "pdfa-2b"
  },
  "header": {
    "height": 12,
    "elements": []
  },
  "footer": {
    "height": 10,
    "elements": []
  },
  "pages": [
    {
      "size": "label_100_150",
      "elements": []
    }
  ]
}

3. 顶层对象

3.1 DocumentRequest

字段类型必填说明
settingsSettings全局设置
pagesPage[]页面数组
headerSection全局页眉
footerSection全局页脚

3.1.1 Page 尺寸

每个页面必须显式指定尺寸,支持两种写法,二选一:

  • size
  • width + height

规则:

  • sizewidth/height 不能同时出现
  • 不写 size 时,必须同时提供 widthheight
  • size 不区分大小写

支持的 size 预设:

  • a4 = 210 x 297 mm
  • a6 = 105 x 148 mm
  • letter = 215.9 x 279.4 mm
  • legal = 215.9 x 355.6 mm
  • label_100_100 = 100 x 100 mm
  • label_100_150 = 100 x 150 mm
  • label_4_6_in = 101.6 x 152.4 mm

示例:

json
{
  "pages": [
    { "size": "A4", "elements": [] },
    { "width": 100, "height": 150, "elements": [] }
  ]
}

3.1.2 Page Margin / Content Box

可选配置:

  • settings.page_margin
  • pages[].margin

示例:

json
{
  "settings": {
    "page_margin": { "top": 10, "right": 12, "bottom": 10, "left": 12 }
  },
  "pages": [
    {
      "size": "letter",
      "margin": { "top": 8, "right": 10, "bottom": 12, "left": 10 },
      "elements": []
    }
  ]
}

规则:

  • 未配置 page_margin 时,正文元素维持当前页面绝对坐标语义。
  • 一旦配置 page_marginpages[].elementsx/y 改为相对 content box 左上角。
  • pages[].elements 超出 content box 会直接校验报错,不做自动裁剪或纠偏。
  • header/footer 仍按页面坐标工作,不受 page_margin 约束。
  • 正文自动分页到后续页时,会从下一页 content box 顶部继续排版。

headerfooter 共用同一个结构:

json
{
  "height": 12,
  "elements": [
    { "type": "text", "x": 5, "y": 8, "content": "Page Header" }
  ]
}
字段类型必填说明
heightnumber区域高度,单位 mm
elementsElement[]该区域内渲染的元素列表

语义说明:

  • header全局页眉,会应用到每一页。
  • footer全局页脚,会应用到每一页。
  • elements 为空时,该区域本身仍然存在;不要依赖"空数组自动忽略区域"。

坐标与定位:

  • header.elements页面绝对坐标渲染,通常约定写在 y = 0 .. header.height 区间内。
  • footer.elements 会自动整体下移到页面底部,偏移量为 page.height - footer.height。 也就是说,footer 内部元素通常写成相对页脚区域的坐标,例如 y = 0 .. footer.height

与正文的关系:

  • header 不会自动把正文元素整体下移。正文元素仍按页面绝对坐标渲染。
  • 因此如果你使用页眉,建议正文元素自己避开页眉区域,例如从 y >= header.height 开始排布。
  • footer.height 会参与正文可用高度计算,正文分页/溢出时会避开页脚底部区域。
  • 配置 page_margin 后,正文自动分页到后续页会从下一页 content box 顶部开始。

实践建议:

  • header.height / footer.height 应与内部元素实际占用高度大体一致,不要随意写过大。
  • 如果只是普通固定区域装饰,推荐把页眉内容放在 header,页脚内容放在 footer,不要手工复制到每页。
  • 如果需要每页不同的顶部/底部内容,仍应放在 pages[].elements 中单独控制,而不是使用全局 header/footer

3.3 Settings

字段类型必填说明
defaultsDefaults全局默认样式
metadataMetadataPDF 元数据
outputOutputSettings响应输出模式与文件名
profilestringPDF/A 配置
page_marginPageMargin正文内容区页边距

profile 支持: pdfa-1b, pdfa-2b, pdfa-3b, pdfa-4, pdfa-2u, pdfa-3u, pdfa-ua1 等。

3.3.1 OutputSettings

字段类型必填说明
modebinary | file输出方式,默认 binary
file_namestring自定义文件名,仅 mode = "file" 时生效

规则:

  • binary 或不传:只返回 PDF 二进制。
  • file:返回 Content-Disposition,用于按文件下载。
  • file_name 不传:回退到默认文件名 gPdf-MMDDHHmmssSSS.pdf
  • file_name 会经过安全清洗,并自动补 .pdf 后缀。

3.4 Defaults

字段类型说明
textTextStyle文本默认样式
strokeStrokeStyle线条/描边默认样式
fillFillStyle填充默认样式
shapeShapeDefaults形状默认样式

ShapeDefaults:

字段类型说明
corner_radiusnumber矩形默认圆角半径(mm)

说明:

  • settings.defaults 只接受结构化写法:text / stroke / fill / shape

3.5 Metadata

字段类型说明
titlestring标题
authorstring作者
subjectstring主题
creatorstring创建工具
producerstring生成器
languagestring语言代码

4. 元素类型

elements[] 中每项都必须带 type:

  • text
  • barcode
  • line
  • rect
  • circle
  • ellipse
  • polygon
  • link
  • image
  • table
  • stack

通用字段:

  • 大多数元素支持 z_index (默认 0)
  • 大多数元素支持 comment (仅备注,不渲染)
  • 支持旋转的元素: text, barcode, rect, ellipse, image (0/90/180/270)
  • 超链接支持两种模式:
    • 元素挂载 link 字段(text/barcode/line/rect/circle/ellipse/polygon/image
    • 独立热点元素 type: "link"

4.1 x_anchor(横向锚定定位)

x_anchor 用于按参考边界自动计算元素的最终 x

当前支持的元素:

  • text
  • barcode
  • rect
  • image
  • link

不支持:

  • line / circle / ellipse / polygon / table / stack / block

规则:

  • xx_anchor 互斥,同时传入会直接报错
  • 不使用 x_anchor 时,仍按原有 x 绝对定位
  • text 使用 x_anchor 时,style.width 必填
  • barcode / rect / image / link 使用 x_anchor 时,使用元素自身 width
  • table_left / table_right 只允许在 stack -> block 内使用

参考值:

  • page_left
  • page_right
  • content_left
  • content_right
  • table_left
  • table_right

计算规则:

  • 左侧参考:resolved_x = reference + offset
  • 右侧参考:resolved_x = reference - offset - width

示例:

json
{
  "type": "text",
  "x_anchor": { "reference": "content_right", "offset": 8 },
  "y": 12,
  "content": "$1,235.85",
  "style": {
    "width": 24,
    "text_align": "right"
  }
}

5. 样式对象

5.1 StrokeStyle

json
{
  "color": "#111111",
  "width": 0.5,
  "opacity": 1.0,
  "cap": "butt",
  "join": "miter",
  "miter_limit": 10,
  "dash": {
    "preset": "dashed",
    "pattern": [3, 2],
    "phase": 0
  },
  "compound": {
    "kind": "double",
    "gap": 0.3
  }
}

字段说明:

  • cap: butt / round / square
  • join: miter / round / bevel
  • dash.preset: solid / dashed / dotted / custom
  • dash.pattern 仅在 preset=custom 时建议提供
  • compound.kind: 当前仅支持 double
  • compound.gap: 双线两根线之间的净距(mm)

说明:

  • 未设置 compound 时按单线处理。
  • compoundlinetable.gridtable.cell.borders 统一复用。
  • double + dash 为非法组合。
  • double + marker 为非法组合。
  • rect/circle/ellipse/polygon 若传入 compound 会报不支持。

5.2 FillStyle

json
{
  "color": "#F5F5F5",
  "opacity": 1.0,
  "rule": "nonzero"
}

rule: nonzero / even_odd

5.3 MarkerStyle (Line)

json
{
  "start": "none",
  "end": "arrow",
  "size": 2.5
}

start/end: none / arrow / open_arrow / circle / bar

5.4 LinkSpec (超链接)

json
{
  "target": { "type": "url", "url": "https://example.com" },
  "alt": "open official site",
  "padding": 1.0,
  "border": { "color": "#1A202C", "width": 0.3 }
}

LinkTarget:

  • URL: { "type": "url", "url": "https://..." }
  • 页内跳转: { "type": "page", "page": 2, "x": 10, "y": 20 }

LinkBorderStyle:

  • color: hex 颜色
  • width: 线宽(mm),0 视为不绘制

约束:

  • URL 仅支持 http://https://mailto:tel:
  • URL 前后空白会被裁剪(trim)后再写入
  • page1 开始,且不能超过请求中显式 pages
  • padding 必须为有限数且 >= 0
  • border.width 必须为有限数且 >= 0
  • border.color(若提供)必须是合法 hex 颜色
  • 任一 link 字段不合法会直接返回 ValidationError(不会静默跳过)

6. Shape 元素

line/rect/circle/ellipse/polygon 均可选挂载 link: LinkSpec

6.1 Line

json
{
  "type": "line",
  "x1": 4,
  "y1": 99,
  "x2": 96,
  "y2": 99,
  "stroke": {
    "color": "#000000",
    "width": 0.4,
    "dash": { "preset": "solid" }
  },
  "link": {
    "target": { "type": "url", "url": "https://example.com/spec" }
  }
}

stroke 省略时会走默认链路(见第 9 节)。

6.2 Rect

json
{
  "type": "rect",
  "x_anchor": { "reference": "content_right", "offset": 6 },
  "y": 20,
  "width": 60,
  "height": 20,
  "fill": { "color": "#FFFFFF" },
  "stroke": { "color": "#222222", "width": 0.6 },
  "corner_radius": 2
}

6.3 Circle

json
{
  "type": "circle",
  "cx": 40,
  "cy": 40,
  "r": 12,
  "fill": { "color": "#E6F4FF" },
  "stroke": { "color": "#2B6CB0", "width": 0.5 }
}

6.4 Ellipse

json
{
  "type": "ellipse",
  "cx": 70,
  "cy": 40,
  "rx": 16,
  "ry": 10,
  "rotation": 0,
  "fill": { "color": "#FFF7E6" },
  "stroke": { "color": "#C05621", "width": 0.5 }
}

6.5 Polygon

json
{
  "type": "polygon",
  "points": [
    { "x": 20, "y": 80 },
    { "x": 35, "y": 60 },
    { "x": 50, "y": 80 },
    { "x": 40, "y": 95 }
  ],
  "fill": { "color": "#F0FFF4" },
  "stroke": { "color": "#2F855A", "width": 0.5 }
}
json
{
  "type": "link",
  "x_anchor": { "reference": "content_left", "offset": 10 },
  "y": 10,
  "width": 40,
  "height": 8,
  "target": { "type": "url", "url": "https://example.com" },
  "alt": "Open website"
}

7. 其他元素

7.1 Text

必填字段: y, content,并且必须二选一提供:

  • x
  • x_anchor

style 复用 TextStyle:

  • font_family, font_size, font_weight, color
  • text_align, vertical_align, line_height
  • width, height, text_overflow
  • shrink_to_fit, min_font_size
  • 可选 link: LinkSpec

支持变量: {page}, {total_pages}

7.2 Barcode

必填字段: y, format, content, width, height,并且必须二选一提供:

  • x
  • x_anchor

可选: options, hrt, rotation, z_index, comment, link

7.3 Image

必填字段: y, width, height, data,并且必须二选一提供:

  • x
  • x_anchor

可选: format, rotation, z_index, comment, link

data 支持:

  • 文件名(从资源层读取)
  • Base64 数据

7.4 Table

说明:

  • 当前公开 table schema 仅支持本节定义的结构。

顶层结构:

json
{
  "type": "table",
  "x": 12,
  "y": 24,
  "width": 180,
  "columns": [],
  "rows": [],
  "cell": {},
  "header": {},
  "row_header": {},
  "body": {},
  "grid": {},
  "pagination": {}
}

顶层字段:

字段类型必填说明
xnumber左上角 X(mm)
ynumber左上角 Y(mm)
z_indexinteger层级
commentstring备注
widthnumber表格总宽度
columnsTableColumn[]列定义
rowsTableRow[]行数据
cellTableCellStyle全表默认单元格样式
headerTableHeaderConfig列表头配置
row_headerTableZoneConfig行表头区配置
bodyTableBodyConfig正文区配置
gridTableGridConfig网格线配置
paginationTablePaginationConfig分页配置

7.4.1 Column

json
{
  "key": "amount",
  "header": "Amount",
  "width": { "mode": "fixed", "value": 30 },
  "role": "data",
  "cell": {
    "text": { "text_align": "right" }
  },
  "header_cell": {
    "text": { "font_weight": "bold" }
  }
}
字段类型必填说明
keystring列 key,必须唯一
headerstring叶子列表头文本,默认空字符串
widthTableColumnWidth列宽模型
rolestringdata / row_header,默认 data
cellTableCellStyle该列正文单元格样式
header_cellTableCellStyle该列列表头单元格样式

规则:

  • columns[].key 必须唯一。
  • role = "row_header" 的列必须连续放在最左侧。
  • 支持多个行表头列。

TableColumnWidth:

json
{ "mode": "fixed", "value": 30 }
{ "mode": "percent", "value": 25 }
{ "mode": "auto" }

7.4.2 Row / Cell

rows 为对象数组,key 对应 columns[].key

简写单元格:

json
{ "name": "Apple", "qty": 2, "enabled": true, "note": null }

复杂单元格:

json
{
  "group": {
    "value": "Fruit",
    "row_span": 2,
    "col_span": 1,
    "style": {
      "text": { "font_weight": "bold" }
    },
    "link": {
      "target": { "type": "url", "url": "https://example.com" }
    }
  }
}

复杂单元格字段:

字段类型必填说明
valuestring | number | boolean | null单元格值
row_spaninteger向下合并行数
col_spaninteger向右合并列数
styleTableCellStyle单元格样式覆盖
linkLinkSpec单元格超链接

规则:

  • row_span >= 1
  • col_span >= 1
  • span 不能越界,也不能和其他 span 重叠
  • null 渲染为空字符串
  • boolean 渲染为 "true" / "false"
  • link 仅能出现在复杂单元格对象中

7.4.3 TableCellStyle

json
{
  "padding": { "x": 1, "y": 1 },
  "text": { "font_size": 9, "color": "#111111" },
  "fill": { "color": "#FFFFFF" },
  "content_offset_x": 1.5,
  "content_offset_y": 0.5,
  "borders": {
    "top": false,
    "right": { "color": "#111111", "width": 0.2 },
    "bottom": { "color": "#111111", "width": 0.2 },
    "left": false
  }
}
字段类型说明
paddingTablePadding单元格内边距
textTextStyle文本样式
fillFillStyle填充样式
content_offset_xnumber单元格内容横向微调(mm)
content_offset_ynumber单元格内容纵向微调(mm)
bordersTableBorders单元格单边边框

TablePadding:

字段类型说明
xnumber水平内边距(mm)
ynumber垂直内边距(mm)

TableBorders:

  • top?: false | StrokeStyle
  • right?: false | StrokeStyle
  • bottom?: false | StrokeStyle
  • left?: false | StrokeStyle

7.4.4 Header / Row Header / Body

header:

json
{
  "show": true,
  "repeat_on_page_break": true,
  "rows": [
    {
      "cells": [
        { "content": "Product", "col_span": 2 },
        { "content": "Stock", "row_span": 2 }
      ]
    }
  ],
  "cell": {
    "fill": { "color": "#F3F4F6" },
    "text": { "font_weight": "bold" }
  }
}

字段:

  • show?: boolean,默认 true
  • repeat_on_page_break?: boolean,默认 true
  • rows?: TableHeaderRow[],分组表头行;叶子表头仍来自 columns[].header
  • cell?: TableCellStyle

row_header:

json
{
  "cell": {
    "fill": { "color": "#F8F8F8" },
    "text": { "font_weight": "bold" }
  }
}

字段:

  • cell?: TableCellStyle

body:

json
{
  "cell": {},
  "alternate_fill": { "color": "#FAFAFA" }
}

字段:

  • cell?: TableCellStyle
  • alternate_fill?: FillStyle

表达规则:

  • 分组表头使用 header.rows
  • 叶子列表头使用 columns[].header
  • 行表头使用 columns[].role = "row_header"

7.4.5 Grid

json
{
  "frame": {
    "color": "#111111",
    "width": 0.3,
    "compound": { "kind": "double", "gap": 0.3 }
  },
  "horizontal": { "color": "#D1D5DB", "width": 0.2 },
  "vertical": false
}

字段:

  • frame?: false | StrokeStyle
  • horizontal?: false | StrokeStyle
  • vertical?: false | StrokeStyle

说明:

  • grid.framegrid.horizontalgrid.vertical 统一使用 StrokeStyle

7.4.6 Pagination

json
{
  "keep_spans_together": true,
  "row_min_height": 10,
  "header_min_height": 12
}

字段:

  • keep_spans_together?: boolean,默认 true
  • row_min_height?: number
  • header_min_height?: number

说明:

  • 当存在 row_span 时,要求 keep_spans_together = true

7.4.7 宽度与样式规则

宽度规则:

  • columns.length >= 1
  • columns[].width 统一使用 fixed / percent / auto
  • 若提供 table.width:
    • fixed 先按 mm 占用
    • percenttable.width 百分比分配
    • auto 吃剩余空间,并基于表头/正文内容测量分配
    • 若不存在 auto,列宽求解结果必须精确填满 table.width
  • 若未提供 table.width:
    • 所有列都必须使用 fixed
  • percent 总和不得超过 100
  • rows 中出现未在 columns[].key 定义的字段会报错
  • header.show = false 时,header.rowscolumns[].headerheader_cell 视为忽略
  • 当使用 row_span 时,不支持 keep_spans_together = false

样式优先级:

  1. settings.defaults
  2. table.cell
  3. header.cell / row_header.cell / body.cell
  4. columns[].cell / columns[].header_cell
  5. cell.style

边框优先级:

  1. grid
  2. table.cell.borders
  3. 区域级 cell.borders
  4. 列级 cell/header_cell.borders
  5. cell.style.borders

7.5 Stack / Block

用途:

  • stack 用于"表格结束后再跟随一组内容"的发票/对账单场景。
  • 它不接管 table 的原有定位;table.x/y/width 仍按当前语义工作。
  • stack 只解决 table 与后续内容块之间的顺序排版和分页问题。

结构:

json
{
  "type": "stack",
  "gap": 6,
  "children": [
    {
      "type": "table",
      "x": 18,
      "y": 123,
      "width": 180,
      "columns": [],
      "rows": []
    },
    {
      "type": "block",
      "elements": [
        { "type": "text", "x": 128, "y": 0, "content": "Subtotal" },
        { "type": "text", "x": 168, "y": 0, "content": "$1,343.65" },
        { "type": "line", "x1": 128, "y1": 7, "x2": 178, "y2": 7 }
      ]
    }
  ]
}

顶层字段:

字段类型必填说明
gapnumber前后 child 之间的垂直间距(mm),默认 0
childrenStackChild[]顺序排版的子项

规则:

  • stack 仅允许出现在 pages[].elements
  • stack.children[0] 必须是 table
  • stack.children[1..] 只能是 block
  • children.length >= 2

block:

json
{
  "type": "block",
  "elements": [
    { "type": "text", "x": 128, "y": 0, "content": "Subtotal" },
    { "type": "text", "x": 168, "y": 0, "content": "$1,343.65" }
  ]
}

规则:

  • block 不提供自己的 x/y/width/height
  • block.elements[].x 继续使用现有 body 元素语义
  • block.elements[].y 为相对 block 起点的偏移
  • block 内不允许再嵌套 table / stack / block
  • block 高度由系统根据内部元素自动测量

分页语义:

  • table 先按现有逻辑分页
  • 只有在 table 真正结束后,后续 block 才开始排版
  • 若某个 block 当前页放不下,则整块移到下一页
  • 若某个 block 自身高度已超过一页可用高度,则直接报错
  • gap 表示前一个 child 最终结束位置到下一个 child 起始位置的垂直距离
  • block 被整体移到下一页时,不保留上一页的 gap

8. 坐标与单位

  • 坐标单位: mm
  • 原点: 左上角 (0, 0)
  • X 轴向右, Y 轴向下

9. 默认值优先级

9.1 样式优先级

  1. 元素本身字段(例如 line.stroke.width
  2. settings.defaults 对应字段(如 defaults.stroke.width
  3. 系统默认配置

table 的优先级为:

  1. settings.defaults
  2. table.cell
  3. header.cell / row_header.cell / body.cell
  4. columns[].cell / columns[].header_cell
  5. cell.style

9.2 线条/形状默认行为

  • line.stroke 全省略时:
    • color 默认 #000000
    • width 默认 0.4
  • rect/circle/ellipse/polygon.stroke 全省略时:
    • color 默认 #000000
    • width 默认 1.0
  • fill 全省略时默认不填充(透明)
  • rect.corner_radius 默认链路:
    • element.corner_radius
    • settings.defaults.shape.corner_radius
    • 系统默认值 0

10. 错误码

错误码触发条件
API-001JSON 非法
API-002请求校验失败
API-101Authorization 缺失或格式错误
API-102鉴权失败
API-500系统内部错误
API-501PDF 渲染失败

常见 ValidationError 触发:

  • link 非法(不支持的 URL scheme、页码越界、非法 padding/border
  • table 非法(未知列 key、table.width 无法为未声明列分配正宽度、非法 span)
  • profile 非法
  • xx_anchor 同时出现