图片翻译后文字挤出边框?用 Pillow 测量译文,不再靠字符数猜宽度

图片里的中文短句翻成英文或德文后,文字挤出了原来的按钮。把字号调小以后虽然放进去了,手机上却很难读。这类问题经常发生在商品图、海报和说明图的本地化过程中。

根因不一定是翻译太长,而是排版程序把"字符数"当成了"占用宽度"。同样十几个字符,不同字体、字号和字母组合,画出来的宽度可以不同。

下面用 Pillow 做一个单行排版检查:在固定文本框内测量译文,寻找允许范围内的字号;放不下就返回待复核,不一直缩小。这个例子只研究文字排版,不包含 OCR、翻译模型或背景擦除。

1. 先划出真正能用的空间

假设图片里的文本框宽 360 px、高 72 px,四周各留 12 px 内边距,可用空间就是:

text 复制代码
可用宽度 = 360 - 12 × 2 = 336 px
可用高度 = 72 - 12 × 2 = 48 px

这两个尺寸应该来自设计要求或已确认的文字区域。OCR 检测框通常只是原文字的包围区域,不一定等于设计允许使用的最大文本框;旁边可能还有图标、商品轮廓和不能遮挡的内容。

图中尺寸是本文构造实验的参数,不是图片翻译行业的固定标准。判断是否放得下,应同时检查宽和高,并使用最终渲染时相同的字体、字号与绘制参数。

2. 用 textbbox 检查,不用 len 估算

len(text) 统计字符串长度,不测量字形。这里用 ImageDraw.textbbox() 获取文字包围框,再比较 right-left 与 bottom-top。

别把 textlength() 与包围框宽度混为一谈:前者用于获得排版前进距离;斜体等字形可能伸出该距离。要判断视觉区域是否越界,包围框更直接。如果绘制时加了描边,也要在测量时传入相同的 stroke_width。

下面代码只处理一行非空文字,字号允许 24--48 px。为了让逻辑容易检查,直接从大到小遍历;几十个候选字号无需先设计复杂搜索算法。

bash 复制代码
python -m pip install Pillow==12.3.0
python fit_text.py /path/to/your/font.ttf

字体路径必须指向你有权使用、且覆盖目标字符的字体。本次实际运行使用 macOS 的 PingFang 字体;换字体或平台后需要重新测量。

python 复制代码
import sys
from PIL import Image, ImageDraw, ImageFont

FONT_PATH = sys.argv[1]  # Use a font that covers all characters.
BOX = (360, 72)
PADDING = 12
MIN_SIZE, MAX_SIZE = 24, 48
probe = ImageDraw.Draw(Image.new('RGB', (1, 1)))

def fit_one_line(text):
    if not text or '\n' in text:
        raise ValueError('one non-empty line required')
    for size in range(MAX_SIZE, MIN_SIZE - 1, -1):
        font = ImageFont.truetype(FONT_PATH, size)
        left, top, right, bottom = probe.textbbox((0, 0), text, font=font)
        if (right-left <= BOX[0]-2*PADDING
                and bottom-top <= BOX[1]-2*PADDING):
            return size, (left, top, right, bottom)
    return None

for text in ['Free shipping', 'Kostenloser Versand', '免费配送',
             'Kostenloser Versand bei allen Bestellungen']:
    result = fit_one_line(text)
    print(text, len(text), result)
    # A failure must go to layout review; never silently shrink forever.

注意:函数里的最小字号只是本实验的约束,不是可读性标准。最终图片显示在手机上时还会缩放,应按投放尺寸、观看距离和内容层级确定阈值。

3. 同一个框,四段文字得到不同结果

本次使用 Pillow 12.3.0,文本框 360 × 72 px、内边距 12 px,测得:

文字 字符数 选择的字号 文字包围框宽 × 高
Free shipping 13 48 px 302 × 46 px
Kostenloser Versand 19 34 px 325 × 26 px
免费配送 4 48 px 192 × 46 px
Kostenloser Versand bei allen Bestellungen 42 无可用字号 返回 None

这些短句为手工准备的排版样本。最后一句额外包含"所有订单"的范围限定,仅作为更长字符串测试,不应被看成前三句的等义翻译,也不是某款翻译产品的输出。

图中三行均由同一字体文件、上述字号与测量规则绘制。框能容纳文字只说明几何检查通过,不说明译文准确、风格合适或视觉层级理想。

如果需要把测量结果画到框内,别忽略包围框的左上偏移。例如从 (x, y) 开始放置一个文本框,可以这样对齐可见字形:

python 复制代码
size, (left, top, right, bottom) = result
font = ImageFont.truetype(FONT_PATH, size)
draw.text(
    (x + PADDING - left, y + PADDING - top),
    text, font=font, fill="black"
)

这里要求 result 不是 None,draw 是目标图片的 ImageDraw 对象。减去 left、top 是为了让可见字形从内边距起点开始;需要基线对齐的一组标签,则应另设统一基线,不能逐行随意顶对齐。

4. 放不下时,需要决策,不只是再缩一点

当函数返回 None,可以按内容性质选择下一步:

  • 允许换行: 扩展成多行排版,同时测量总高度与行距。英文等语言通常按词换行;中日韩文字还要考虑行首行尾禁则,不能机械按固定字符数截断。
  • 允许改框: 增加文本框宽高或调整局部布局,但先检查是否遮挡商品、尺寸线与其他内容。
  • 允许改文案: 由懂目标语言的人调整表达,保留价格、数量、适用范围和条件;不要让排版程序自动删除"仅限""不包含"等限定词。
  • 不允许改动: 标记待人工处理。比起把关键说明压成不可读的小字,明确失败更利于交付。

多行、竖排、阿拉伯语等复杂场景不能直接套用本文单行函数。字体回退、双向文字和字形塑形需要合适的排版引擎支持;出现缺字方框时,即使包围框通过也不能算成功。

5. 图片翻译交付时,分开检查文字与画面

如果使用现成的图片翻译工作台,比如 LingFlow,可以通过其图片翻译流程生成结果,再预览和下载。本文的 Pillow 检查适用于拿到文字区域与待绘制文本后的独立排版步骤;它不是对产品内部实现的说明,也不能从已经合成的结果图自动还原可编辑文字层。

本次只核实了产品的公开介绍与物料,没有把这些手工排版样本上传作为产品效果测试。图片翻译结果的复核可以分成两遍:先核对数字、单位、否定词和修饰范围,再检查文字是否遮挡主体、是否越框以及在实际展示尺寸下能否读清。

还要区分三种不同能力:可以下载图片、可以检查文字位置、可以直接编辑图片里的文字。拿到一张 PNG,并不意味着它包含可编辑的文字图层。需要精修时,保留源设计文件、字体和译文清单,会比只保存最终图片更容易返工。

参考资料

相关推荐
2601_962780911 小时前
2027风险管理岗准备路线:数学与应用数学专业如何补齐金融、SQL与Python
python·sql·金融
老唐7771 小时前
Transformer原理大白话讲解
人工智能·python·深度学习·神经网络·计算机视觉·ai·transformer
佳木逢钺1 小时前
从火灾模拟到系统热寂:一个双非运维如何用零 GPU 推导出多智能体系统的终极死锁
人工智能·python·算法·多智能体
fwc1 小时前
第T9周:猫狗识别2
python·深度学习
砚底藏山河1 小时前
数据新鲜度 SLA 监控
java·大数据·python·maven
Wzx1980121 小时前
Python Agent 短期记忆设计:从对话历史到 LangGraph Checkpointer
开发语言·python
ljt27249606611 小时前
Python笔记(五)--读写文件
笔记·python
破茧蝴蝶10 小时前
Python分布式爬虫完整教程
开发语言·python