# OnlyOffice xlsx 行高、合并单元格截断与渲染核查(2026-06-17 万达表确立) 汇总表的「校区整体风险分析」段是横跨整行的合并单元格(如 A11:L11),内容长达 800~1200+ 字、30~47 个逻辑行。OnlyOffice 渲染这类超长合并单元格时极易**截断显示**,而 Maggie 对「文字必须完整显示不截断」是硬要求。本文件记录踩过的坑、真实成因、以及可复用的核查方法。 ## 一、行高 409.5/409.6pt 不是格式天花板,是 OnlyOffice 网页编辑器的 clamp 值 这是反复出现的谜题:**自己设了 760pt 的行,交付后再打开变成了 409.6pt。** 实测厘清三层行为,别再被误导: | 层 | 行为 | 实测结论 | |---|---|---| | **xlsx 文件格式本身** | openpyxl 写 `row_dimensions[N].height = 900` → 存盘 → 读回 = 900 | ✅ 文件层**不限制**行高,900pt 能正常写入并保留 | | **OnlyOffice x2t 批量引擎** | xlsx(900pt) 经容器内 x2t 做 xlsx→xlsx round-trip → 读回 row 仍 = 900 | ✅ **不 clamp**。从文件层写的高行高,x2t 渲染/转换链路认 | | **OnlyOffice 网页版编辑器** | 在浏览器里打开编辑、点保存 | ❌ **会把超过 ~409.5pt 的行高压回 409.5/409.6**。这就是「我的 760 变成 409.6」的真凶 | **结论与操作要点:** - 「调高行高让全部内容显示」在技术上**可行**——只要**从文件层(openpyxl 脚本)写入并经交付链路上传**,不要让结果再被网页编辑器存盘一次。 - 一旦用户/自己在 OnlyOffice **网页端编辑并保存**过,超限行高就被打回 409.5。若交付后还要网页端再编辑,高行高保不住。 - 设了 `height` 即自动 `customHeight=True`(openpyxl 中 `customHeight` 无 setter,不要试图直接赋值,会 `AttributeError`)。 - **若 Maggie 明确说「就按当前最高行距,不用调」→ 不折腾,保持现状交付。** 别因为自己测出能调高就擅自改——方案≠授权。 ## 二、数据完整 ≠ 视图不截断(核查别只看 pdftotext) OnlyOffice/x2t 导 PDF 时,**被行高裁掉的文字仍会写进 PDF 文本层**。所以: - `pdftotext` 提取到尾部锚点句 = 数据在文件里(867 字符全在),**但不等于在编辑器视图里可见**。 - 真正的「截断」是**视图层**问题(行高 < 内容所需高度时底部被裁),不是数据丢失。 - 因此「数据完整性」用 pdftotext 验,「视图是否截断」要靠**行高是否 ≥ 内容估算高度**来判断(见下方脚本),或渲染成图片肉眼看。 - ⚠️ 另一个坑:x2t 导 PDF 时**对超长合并单元格本身也会截断渲染**(PDF 里只画出前一部分,如只渲染「12,000」后面没了)——这是导出视图的固有限制,不代表数据丢。判断数据完整以 openpyxl 读单元格 `.value` 字符数为准。 ## 三、可复用核查工具 ### 行高分析脚本(再跑用) `scripts/xlsx-rowheight-analyze.py <文件.xlsx>`:只读分析每个 sheet 的长内容单元格,按合并宽度 + 字号估算所需视觉行数和建议行高,与当前行高对比,标出「可能截断」的行。不改文件。中文每字≈2.1 宽度单位、每视觉行≈15.5pt(10pt 字)是经验系数。 ### x2t round-trip 测 clamp / 渲染(本地 OnlyOffice 实例) 容器 `nextcloud-onlyoffice-1`,x2t 路径 `/var/www/onlyoffice/documentserver/server/FileConverter/bin/x2t`。 ```bash # xlsx→xlsx round-trip(测网页引擎是否 clamp 行高;format 257 = xlsx) docker cp in.xlsx nextcloud-onlyoffice-1:/tmp/t/in.xlsx docker exec nextcloud-onlyoffice-1 bash -c 'cat > /tmp/t/c.xml < /tmp/t/in.xlsx/tmp/t/out.xlsx 257true EOF LD_LIBRARY_PATH=/var/www/onlyoffice/documentserver/server/FileConverter/bin /var/www/onlyoffice/documentserver/server/FileConverter/bin/x2t /tmp/t/c.xml' # format 513 = PDF(渲染成 PDF 看版面);之后主机 pdftoppm -png -r 110 out.pdf 转图 ``` - x2t 退出码 `88` = 目标 format code 不对(不是文件坏)。xlsx→xlsx 用 257,xlsx→PDF 用 513;不要走 8193 bin 中间格式做 xlsx round-trip。 - 主机有 `soffice`/`libreoffice`、`pdftoppm`/`pdfinfo`/`pdftotext`、中文字体 wqy-zenhei,可做降级渲染。 ### 截断检测(文本锚点法) 取目标长单元格**尾部**几句独特锚点,去掉空格后在 PDF 全文 grep——但记住第二节:命中只证明数据在,视图是否截断仍以行高估算为准。 ## 四、一句话 SOP 1. 估算:`scripts/xlsx-rowheight-analyze.py 文件.xlsx` → 看哪些行 `当前行高 < 建议行高`。 2. 若需调高且用户同意:openpyxl 设 `row_dimensions[N].height = 建议值`,从文件层写、走交付链路上传,**别再用网页端编辑保存**。 3. 若用户说保持当前最高 → 不动。 4. 数据完整性单独用 openpyxl 读 `.value` 字符数确认,不靠 PDF。