5.1 KiB
5.1 KiB
OnlyOffice xlsx 行高、合并单元格截断与渲染核查(2026-06-17 万达表确立)
汇总表的「校区整体风险分析」段是横跨整行的合并单元格(如 A11:L11),内容长达 8001200+ 字、3047 个逻辑行。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。
# 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 <<EOF
<?xml version="1.0" encoding="utf-8"?>
<TaskQueueDataConvert xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<m_sFileFrom>/tmp/t/in.xlsx</m_sFileFrom><m_sFileTo>/tmp/t/out.xlsx</m_sFileTo>
<m_nFormatTo>257</m_nFormatTo><m_bIsNoBase64>true</m_bIsNoBase64>
</TaskQueueDataConvert>
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
- 估算:
scripts/xlsx-rowheight-analyze.py 文件.xlsx→ 看哪些行当前行高 < 建议行高。 - 若需调高且用户同意:openpyxl 设
row_dimensions[N].height = 建议值,从文件层写、走交付链路上传,别再用网页端编辑保存。 - 若用户说保持当前最高 → 不动。
- 数据完整性单独用 openpyxl 读
.value字符数确认,不靠 PDF。