ADR-0006:组件与 PDF 交互
2026-10-14 更新:本文保留初始决策背景。富文本、字体组缺字策略、分页控制、分节、合并表格与中文表单的扩展边界见 ADR-0007。
- 日期:2026-10-14
- 状态:已采纳
- 范围:核心组件 SPI、页面合成、目录及 PDF 交互首版
背景
段落与表格分页已经具备可复用的测量及来源映射。新的需求包括页眉页脚、图像、形状、线条、水印、不同定位方式,以及能跳转的目录/书签、评论批注和真实可填写字段。继续在示例末尾追加命令无法保证页区预留和目录加入后的最终页目标正确。
首版以 PDF 为交付对象:评论作为批注,表单作为可编辑字段,目录与书签关联最终页面。
决策
- 核心拥有
ComponentSPI、上下文、定位和页面区域;新增export4j-components提供标准实现与文档编排。核心不反向依赖实现模块,模型保持 JDK-only。 ComponentLayout返回本地平衡指令、尺寸和诊断;ComponentBlock作为不可拆分正文适配器。保留原语义段落/表格的跨页算法,不把所有内容强制变成固定盒子。- 先预留页眉页脚,再分页正文。最终统一按背景、正文、页区、前景合成,页字段获得真实总页数。
- 定位支持页面绝对坐标、父区域九锚点与比例视口。视口必须在父区域内;自定义绘制需要自行裁剪。
- 目录作为独立前置页,固定 48 pt 页码列,使条目换行和目录页数独立于最终数字。正文块首片段是锚点,目录页偏移确定后一次性解析目标。
- 将书签、链接、评论与字段保存为绘制 API 的
DocumentExtras,保持后端中立。PDF 后端转换为 outline、annotation、AcroForm;不参与分页或重新测量。 - 表单首版仅提供 ASCII 单/多行文字和复选框,保留当前值、默认值及外观流,默认可编辑、不扁平化、不执行脚本。中文初始值明确拒绝,后续独立设计字段字体契约。
Block开放为接口以允许核心适配器实现;未知块明确失败。提供构造器兼容入口,记录 record、sealed 及枚举扩展带来的调用方检查要求。
考虑的替代方案
| 方案 | 评估 |
|---|---|
| 示例直接绘制全部组件 | 能快速输出,但不能统一区域预留、来源、诊断与最终页码 |
| 模型直接持有字体、绘制或 PDFBox 类型 | 破坏基础层独立和多后端边界 |
| 立即重写为通用嵌套约束树 | 超出首版需求,增加已有分页回归风险 |
| 根据真实页数字反复迭代目录分页 | 可能产生页数反馈;固定列宽可避免该循环 |
| 将表单绘制成普通文字或扁平化 | 无法满足可填写和保存要求 |
影响
新增一个实际模块,无新外部依赖或原生组件。基础组件可复用,正文仍支持段落与表格拆分。自定义组件属于可信 Java 代码,结构预算不是执行沙箱;无最终页数的正文组件不能读取页索引改变布局。
首版使用统一页面设置和重复模板,目录只能前置;不支持章节页码重启、图文绕排或任意嵌套流。评论与字段的可见层由 PDF 阅读器负责,通常显示在页面内容之上。
本记录扩展 ADR-0004 与 ADR-0005,保留它们的段落和表格规则。两份记录中的早期页眉页脚/组件边界由本记录更新,历史验证结论保持原时间范围。
验证方式
定位、页区预留、图层、分页推进、预算、目录跨页与目标错误通过单元测试验证。PDF 集成测试检查坐标转换、层级、字段树、widget、值和外观流。综合示例使用 pypdf 独立解析并填写保存,再由 Poppler 渲染全部页面,检查内容及填写外观。证据见阶段三组件验收。