Files
hermes-skills/skills/legal/contract-portfolio-analysis/references/onlyoffice-xlsx-render-and-rowheight.md
T

6.5 KiB

OnlyOffice xlsx 渲染自查 + 行高 409.5 上限真相

用途:交付前用 Maggie 实际看的引擎(OnlyOffice,非 LibreOffice)把汇总表 xlsx 渲染成 PDF/图片做视觉自查;并厘清"长内容行高调不上去"的根因,避免重复踩坑浪费时间。 来源:2026-06-17 万达行高验证 + 世茂重做渲染自查。

一、x2t 渲染 xlsx → PDF(用 OnlyOffice 引擎,保真度最高)

OnlyOffice 文档转换器 x2t 在容器 nextcloud-onlyoffice-1 内,是 Maggie 在线编辑/查看时的同款引擎。比 libreoffice --headless --convert-to pdf 更能反映她看到的真实效果。

format code:513 = PDF。

完整配方(已验证可用)

# 1. 容器内建可写目录(默认root建后chmod 777,让ds用户能写pdf输出)
docker exec nextcloud-onlyoffice-1 bash -c 'rm -rf /tmp/sx; mkdir -p /tmp/sx; chmod 777 /tmp/sx'

# 2. 主机预先写好转换配置 xml(关键:不要在容器内用 > 重定向,会因权限失败),cp进去
#    /tmp/s_convert.xml 内容:
#    <?xml version="1.0" encoding="utf-8"?>
#    <TaskQueueDataConvert xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
#    <m_sFileFrom>/tmp/sx/s.xlsx</m_sFileFrom>
#    <m_sFileTo>/tmp/sx/s.pdf</m_sFileTo>
#    <m_nFormatTo>513</m_nFormatTo>
#    <m_bIsNoBase64>true</m_bIsNoBase64>
#    </TaskQueueDataConvert>
docker cp /path/to/target.xlsx nextcloud-onlyoffice-1:/tmp/sx/s.xlsx
docker cp /tmp/s_convert.xml      nextcloud-onlyoffice-1:/tmp/sx/s.xml
docker exec nextcloud-onlyoffice-1 bash -c 'chmod 666 /tmp/sx/s.xlsx /tmp/sx/s.xml'

# 3. 以 ds 用户身份跑 x2t(x2t 本身就是 ds 进程,必须 -u ds)
X2T=/var/www/onlyoffice/documentserver/server/FileConverter/bin/x2t
docker exec -u ds nextcloud-onlyoffice-1 bash -c \
  "LD_LIBRARY_PATH=/var/www/onlyoffice/documentserver/server/FileConverter/bin $X2T /tmp/sx/s.xml 2>&1; echo x2t=\$?"

# 4. 取回 + 转图片自查
docker cp nextcloud-onlyoffice-1:/tmp/sx/s.pdf /tmp/out.pdf
pdftoppm -png -r 100 /tmp/out.pdf /tmp/out_img/s

⚠️ 权限坑(踩过3次才通)

  • x2tds 用户运行,ds 的 HOME(/var/www/onlyoffice/documentserver不可写
  • ds 能写 /tmp/var/lib/onlyoffice/documentserver/App_Data
  • 致命点:若用 root 建 /tmp/xxx 目录,ds 写不进 → Permission denied + x2t=126/2。修复=建目录后 chmod 777
  • 第二个坑:在容器内用 cat > s.xml <<EOF 重定向写 xml 也会因 ds 权限失败。正确做法:主机写好 xml,docker cp 进去,不在容器内重定向。
  • 成功标志:x2t=0/tmp/sx/s.pdfds ds 所有、size>0。

截断检测用文本提取,不靠肉眼

渲染图片若无 vision 工具看不了内容时,用 pdftotext 抽全文,grep 各板块末尾独特锚点句是否都在(在=数据完整无截断)。比看图更可靠。

⚠️ pdftotext 会按列宽把长句折行,直接 grep 完整句会假阴性——先 tr -d '\n' | tr -d ' ' 把整页拍平再 grep(见主 SKILL Pitfall 1b 末条)。

⚠️ LibreOffice headless 渲超高行 xlsx 会卡死/被 SIGKILL → 直接走 x2t,别耗重试(2026-06-22 悦拾光实证)

交付前想出 PDF 自查时,别先试 libreoffice --headless --convert-to pdf——当 xlsx 含超高行 + 海量文本单元格(如 K列法律风险 800字、行高 600–700pt)时,LibreOffice headless 转换阶段会卡死,前台 timeout 到点被 -15、加 -env:UserInstallation 独立 profile 重试仍 -9(SIGKILL)。诊断特征:libreoffice --version 秒回正常、free -h 内存充足(11G+ 可用),唯独 --convert-to 这一步挂——证明不是环境/内存问题,是 LibreOffice 对「超高行+超长单元格」headless 排版的已知缺陷。

  • 别浪费在 LibreOffice 上反复试(本次连耗 4 次 -9/-15 才转向):内存够、版本正常却 --convert-to 挂,立即判定为超高行触发的 LO 缺陷,直接切到本文上半「x2t 渲染」配方。x2t 是 Maggie 实际看文件的引擎、对超高行无此问题,本就该优先用它,不该先绕 LibreOffice。
  • 主 SKILL 已有铁律「LibreOffice 与 OnlyOffice 不同源、最终验收用 x2t」——本条补充其故障模式:LO 不只是「页数不准」,遇超高行会直接转换失败,更没有当 fallback 的价值。
  • 清残留:转换挂掉常留 soffice 僵尸进程,重试前 pkill -9 -f soffice; pkill -9 -f oosplash

⚠️ 程序化截断自检:用 skill 自带脚本,别每次手写行高估算(2026-06-22 悦拾光教训)

交付前判断「K列长文会不会被行高截断」,直接跑 scripts/xlsx-rowheight-analyze.py <文件.xlsx>(只读,按列宽折行估每行所需高度、标出「当前行高 < 建议行高」的行),不要在 execute_code 里临时手写一版行高估算函数——本次就因手写估算严重偏低(K列 800字实际需 43 行≈665pt,手写版只给了 21 行≈321pt),自检时才发现差一倍,白绕一圈。脚本已沉淀正确的 CJK 折行口径(中文按2宽、按 \n 切段逐段折行、向上取整),照用即可。设完行高用同口径复检 可显行数 ≥ 需求行数 全绿再渲染。

二、行高 409.5 pt 上限真相(别再浪费时间调高)

长内容单元格"行高调不上去"的根因已查清:

行为
xlsx 文件格式 允许 >409.5pt(openpyxl 写 900 读回 900)
OnlyOffice x2t 批量引擎 接受 900pt,round-trip 不 clamp
OnlyOffice 网页版编辑器 存盘时 clamp 到 ~409.5pt ← 这是 Maggie 编辑保存后高行变矮的真因
  • 实测:给行设 760pt 交付,Maggie 在 OnlyOffice 网页版打开编辑保存后,被压回 409.6pt。不是 xlsx 上限,是网页编辑器 clamp
  • Maggie 的决定(2026-06-17):"行距搞不定就算了,就按照目前的最高行距就好。" → 统一用 409.6pt,不再折腾调更高
  • 实务影响:单格约容纳 18–20 个折行;超长内容(如 K 列 700+ 字、第三部分 800+ 字)在网页在线编辑视图可滚动看全、数据层完整,只有导 PDF 给客户打印时才需另调版式(拆单元格/缩字号)。平时 409.6 即可,与万达定稿一致。
  • 若某份确需更高且不经网页编辑器存盘(直接文件层交付),x2t 引擎会认 900pt——但 Maggie 已拍板用 409.6,除非她另有指示,不要自作主张调高。