首页 / 博客 / 图片翻译 / 音视频翻译 / 支持 / 捐助 / 订阅
OCR软件对阿拉伯语等双向文本的支持
阿拉伯语、希伯来语、波斯语这些语言是从右往左书写的,而里面混杂的阿拉伯数字、英文等又是正常从左往右读的,所以也叫双向文字。图片OCR和翻译软件碰到这类语言,就需要额外处理一串问题:界面怎么显示、OCR输出的字符顺序怎么还原、单词怎么按正确顺序拼成行、导出PDF时又怎么让文字按阅读顺序排列。
这篇讲一下ImageTrans里对应的处理。
界面显示和文字渲染
JavaFX的Node有一个nodeOrientation属性。把它设成RIGHT_TO_LEFT之后,JavaFX会自动处理文本对齐、光标移动方向、标点符号落在哪一侧这些细节,不需要手工干预。
ImageTrans在显示双向文本的控件上都设了这个属性,包括原文框、译文框,以及文字排版引擎。
除了显示,还有一个从右往左阅读的项目设置,它影响的是排序。
阿拉伯语的段落,第一个词在最右边。如果按我们习惯的方式,用X坐标从小到大排序,整段的阅读顺序会完全反过来。所以这个开关会传给排序和合并相关的多个模块:
- 文本框排序
- 行内框排序
- 分镜检测
- 框合并
OCR的字符处理
ImageTrans用的是PaddleOCR系列模型(通过RapidOCR集成)。这类模型识别阿拉伯语时,输出的是视觉顺序——它是按图像像素从左往右扫的。
视觉顺序意味着:字母的实际书写顺序是反的,但数字因为视觉上本来就从左往右排,顺序反而是对的。
所以要做一次反转,但保留数字段的转换:
- 纯数字串:原样返回
- 其它:先整串反转,再把每一段连续的数字倒回来
举例来说,م٢٠٢٦要还原成٢٠٢٦م。
同时还要做一次括号镜像,把左右括号换过来。
但其它OCR不需要这个操作。
单词合并成行:从右往左
OCR出来的是一堆单词框,要先合并成行,再合并成段。
合并的做法是从一个种子框开始,不断往某个方向吃相邻的框。往哪个方向先吃,阿语要反过来:
growRightFirstRound = True ' 默认先往右
If right2left And horizontal Then
growRightFirstRound = False ' 阿语先往左
End If
先往左把同一行的词收进来;这一轮收不动了,再换个方向试一次;两个方向都收不动,这一行就结束了。
但只用合并方向还不够,还有一类混排的情况要单独处理。
阿拉伯语的行从右往左合并,这个顺序对阿拉伯词是正确的,但夹在行里的拉丁文必须保持从左往右——否则一个hello world合并完就变成了world hello。
所以当第一个框的末尾拖着两个字符以上的非阿拉伯字母,而第二个框也不是阿拉伯词时,就认为这两个框同属一个LTR文本段,需要把顺序对调。实现上就是把第一个框的尾段摘下来,接到第二个框后面:
source1 = source1 去掉尾巴 + " " + source2 + 尾巴
source2 = ""
比如第一个框是world、第二个框是hello,处理完就还原成了hello world。
输出PDF:shape和reverse
这是最麻烦的一步。
PDF本身不做复杂文本排版。PDFBox的showText拿到一个字符串,会逐个Unicode码点去查字体的cmap,查到字形就画出来。它不管阿拉伯语的上下文变形——同一个字母在词首、词中、词尾、单独出现时形状不同,这件事PDFBox不会帮你做。
所以ImageTrans自己做了两步。
第一步是shape:把每个字母替换成它在当前位置对应的变形。Unicode里有一块「阿拉伯语表述形式」区(U+FE70–FEFF)专门放这些变形字形。比如ت单独出现是FE95,在词首是FE97,词中是FE98,词尾是FE96。判断依据是前后字母能不能连写——像ا、د、ر这些字母只能跟前面连,后面连不上。
第二步是reverse:上一步的产物是一串「字形码」而不是「字符」。字符的顺序是逻辑序,而字形码的顺序必须是视觉序,也就是画在纸上的顺序。所以要把整串倒过来,这样从左到右画出来才是对的。
反转有个坑:数字不能跟着反转。所以这里不是简单的一步反转,而是按空格切词、逐词处理:
- 纯数字词:还原回去
- 阿拉伯词:保留,但把词内部的连续数字段倒回来
- 其它词(拉丁词等):攒成一组,整组反转
最后再镜像一次括号、清掉方向控制字符,才交给PDFBox画出去。
对字体的要求
这套做法依赖字体自带U+FE80–FEFC的表述形式字形。Arial、Tahoma、Segoe UI这些常见系统字体都有(历史原因,为了兼容老软件)。但也有一些字体没有,比如Windows自带的Arabic Typesetting,用它导出会直接报错。
可搜索性
有个意外的好处:PDF里存的明明是表述形式字形,但复制出来的却是正常的阿拉伯文。
原因是提取文本时会对每个词做一次NFKC归一化,而NFKC恰好会把U+FE70–FEFF兼容分解回基础字母。这是通用行为,不是某个库特有的,所以其它PDF阅读器也一样。导出的PDF既能正常显示,也能复制和搜索。
已知限制
- 字体必须包含表述形式字形(U+FE80–FEFC),否则导出会失败。如果你的字体踩到了这个问题,换一个覆盖完整的字体即可。
- 如果原文带变音符(harakat),它们会一起进入文字层。搜索时可能需要带上变音符才能精确匹配,具体行为取决于阅读器的实现。
- 连字(比如
لا)目前是用两个连着的字形拼出来的,视觉效果接近,提取时也能正确还原成两个字母。
相关阅读:如何确定图片中文字的阅读顺序
© 2026 BasicCAT ― Powered by Jekyll and Textlog theme