阶段三基础表格验收
- 日期:2026-10-14
- 对象:
0.1.0-SNAPSHOT的语义表格实现。 - 结论:混合段落/表格、自动行高、整行分页及重复表头通过本地验证;阶段三整体尚未完成。
- 关联:表格 API、ADR-0005、段落历史验收
实现范围
保留原 9 个模块,在语义模型加入有序混合块、矩形表格、固定/比例列宽、纯文本单元格及内边距。布局结果加入有序混合片段、表格行列来源和重复表头标记。字体、文本、绘制与 PDF 后端边界保持原职责,不新增第三方依赖或资源。
每个单元格只换行一次。行高取最高文字布局加上下内边距;分页仅移动完整行。表头组加任一正文行无法放入新页时明确失败,不生成表头独占的无限页面。预算覆盖块、原文、生成行、页面、每表行列与全文单元格;生成行预算包含重复表头。
环境与构建
使用 Windows / PowerShell、Microsoft OpenJDK 21.0.10+7-LTS、Gradle Wrapper 9.2.1、PDFBox / FontBox 3.0.8 和 JUnit 6.1.3。
.\gradlew.bat clean build :examples:run :examples:textPdf :examples:flowPdf :examples:tablePdf --console=plain最终清理构建结果为 BUILD SUCCESSFUL,81 个任务中 80 个执行、1 个无需执行。全部生产和测试代码使用 -Xlint:all -Werror 编译,Javadoc、源码包、JAR 和示例发行包构建通过。现有锁文件和校验元数据继续有效,无需重写。
CI 已配置 Windows / Linux 的 Java 21 构建和四个示例任务;远程托管执行尚未验证。
自动化验证
| 模块 | 通过用例数 | 内容 |
|---|---|---|
| model | 11 | 原模型测试及混合顺序、嵌套集合快照、矩形与表头校验 |
| font-core | 4 | 字体读取、所有权、许可及无效输入 |
| text-core | 12 | 字体回退、换行、Unicode、行框和预算 |
| graphics-api | 5 | 绘制数据与输入契约 |
| graphics-core | 2 | 指令构建与路径 |
| layout-core | 32 | 原段落 16 项,加表格列宽、行高、来源、表头、间距、推进、预算及绘制 16 项 |
| backend-pdf | 22 | 原输出 21 项,加三页中英文混合表格集成测试 |
| 合计 | 88 | 0 失败、0 错误、0 跳过 |
新增 20 项测试验证以下行为:
- 固定/比例列、极大比例权重、左右内边距和最高单元格决定行高。
- 多行表头与下一正文行共同移页、无表头续页、段落/表格/段落顺序及块索引。
- 原始行号、单元格文字范围、空文本、显式空行和对齐。
- 超高行及表头/正文组合及时失败,单项检查使用 2 s 超时防止无限重试。
- 结构、共享单元格、码点、生成行及页面预算,包含额外重复表头;补充字符按一个码点计数。
- 列宽耗尽、内边距耗尽、非有限总高度及文字失败的行列/UTF-16 上下文。
0.3 / 0.1舍入边界与低0.00000001 pt的真实不足高度,片段包含关系采用0.000000001 pt绝对误差。- 绘制消费原有字形和坐标,不改变混合顺序,结果可复现且不可变。
真实 PDF 集成测试使用两份固定字体,生成 3 页,检查 Row00 至 Row08 各出现一次、顺序一致、两列表头各出现 3 次,表前/表后段落顺序正确;同时验证元数据、页面尺寸、字体嵌入和 ToUnicode。
独立 PDF 检查
pdfinfo examples/build/export4j-table-example.pdf
pdftoppm -scale-to 1200 -png examples/build/export4j-table-example.pdf examples/build/export4j-table-example使用 Poppler 26.07.0、pypdf 6.10.0。输出为 3 页 A4,595.276 × 841.89 pt,PDF 1.6,52,036 字节,未加密。共 3 个表格片段,包含 32 条正文记录。
| 页面 | 正文行 | 表头 |
|---|---|---|
| 1 | ROW-01 至 ROW-11 | 原始表头 |
| 2 | ROW-12 至 ROW-23 | 重复表头 |
| 3 | ROW-24 至 ROW-32 | 重复表头 |
逐页查看长边 1,200 px 的 PNG。确认中文自动换行、较长单元格增加行高、网格与文字位于内容区,表头、正文及表后说明无缺字、重叠或裁切。
pypdf 普通提取仍会在中文字符间推断额外空格,独立语义核查先归一化空白。确认 32 个编号严格按顺序出现一次,“通过”共 32 次,两列表头各出现 3 次,标题位于首行之前,结束说明位于末行之后。原始提取结果保存在 examples/build/export4j-table-example.txt,不承诺所有阅读器原样复制空白。
各页字体均有 ToUnicode 与嵌入的 TrueType 字体流,同一文档复用两个子集:Liberation Sans 解压流 11,228 字节,霞鹜文楷 TC 解压流 38,428 字节。既有精确绘制、文本和段落示例继续运行;段落报告保持 3 页、6 个段落片段。
文档与分发检查
83 个源码文件的目录与包声明一致,自研 Java 均保留 Apache-2.0 SPDX 声明。125 个文档相对链接和标题结构检查通过;jdeps --api-only --ignore-missing-deps -verbose:class 检查 9 个 JAR,公共 API 未发现 Apache 实现类型泄漏。
核心 JAR 包含 LICENSE / NOTICE,不携带示例字体。示例 JAR 内字体和许可与资源原文件字节一致,发行包与启动主类使用新根包。锁定 Maven 坐标仍为已登记的 15 项。
限制与后续
当前表格只支持矩形纯文本,不支持合并单元格、嵌套表格、内容驱动列宽、固定行高、垂直居中、横向分页、单行拆页或富文本。空表格和纯表头表格不接受;不可容纳内容失败,不自动缩小或裁切。
孤行控制、与下段保持相邻、分节、正式页眉页脚组件、复杂塑形和多格式适配仍未实现。未进行大文档性能基准、跨 JDK 一致性、PDF/A、PDF/UA 或无障碍标签验证。结构预算不等于总内存或运行时间限制。
下一步推进段落孤行控制与页眉页脚组件。