Pillow 13 渲染 CRLF 文本报 raqm_layout() failed
Pillow 13.0.0 搭配 libraqm 0.11.0 时,CRLF 残留的回车可能触发多段落拒绝。按应用换行约定归一化,并对测量、换行和绘制一同核验。
升级 Pillow 13.0.0 后,网页表单提交的多行文本突然报 RuntimeError: raqm_layout() failed.,相同代码在没有 RAQM 的机器上却正常。先查看文本中是否含 \r\n 或单独的 \r,并记录实际的字体布局引擎。
明确组合为 Pillow 13.0.0、libraqm 0.11.0,且环境有可用的 RAQM 与 fribidi。libraqm 0.11.0 拒绝跨多个段落的输入,Pillow 多行路径又只按 \n 拆行,CRLF 中的 \r 会残留在送给布局器的行内。其他段落分隔符也可能触发相似错误,不能将它归为字体文件必然损坏。
先明确回车在应用中是什么意思
如果应用约定 CRLF 和单独 CR 都表示换行,可以在输入边界把它们统一成 LF,然后让 Pillow 的多行接口处理:
normalized = text.replace("\r\n", "\n").replace("\r", "\n")
bounds = draw.multiline_textbbox((10, 10), normalized, font=font)
draw.multiline_text((10, 10), normalized, font=font)
text、draw、font 是原有文本、绘图对象与字体。实际代码还应让测量和绘制使用相同的 spacing、anchor、direction、features 与 language。这里先替换 CRLF,再替换余下的 CR,避免把一组 CRLF 变成两个换行。
这项调整改变了输入解释。旧版本接受 \r,并不代表旧图像一定把它画成换行;归一化后,像素和文字度量可能与旧图不同。需要兼容历史模板时,应保存旧输出对照并确认新的换行政策,而不是承诺视觉完全不变。
单行测量与多行绘制要分开
font.getlength()、font.getbbox() 的单行调用不能直接接受经过归一化的整段多行文本来代替多行布局。用单行测量结果安排多行画布,容易在异常消失后留下裁切、对齐或行距错误。
也不要不加区分地使用 str.splitlines() 接管所有控制字符。它还会识别一些目前布局器可以处理的分隔符,从而改变原有行为。若业务需要把 U+2029 等字符也视为换行,应把这个决定写进输入规则,并针对这些字符测量和绘制。
将布局引擎改成 BASIC 虽可能避开这项拒绝,却会改变双向文本和复杂文字的布局能力。涉及阿拉伯文等文字时,不能只因为不再报错就认为结果可用;不应作为无说明的统一降级。
验收跟着真实部署环境走
记录 Pillow、RAQM、fribidi 版本与字体文件。覆盖 LF、CRLF、单独 CR,以及应用允许或拒绝的其他段落分隔符;对每种输入同时检查自动换行、边界框、画布裁切与最终可见文字。没有 RAQM 的开发机通过,不能代替带 RAQM 的部署环境验收。
保留原始文本和已归一化文本的处理关系,避免后续又按另一套规则测量。公开输出不应残留意外控制字符;若某种输入明确不支持,在调用布局器前按应用规则拒绝并给出可理解的提示。
当前正式版 13.0.0 仍有上述 LF 拆分与布局组合。后续变更接受哪些分隔符、是否改变单行接口契约,需要核对具体发行版,不能由一次开发分支讨论推定已经发布修复。


