使用PIL(Python图像库)编写带有语音符号的文本("nikud")
用PIL在图片上写简单的文字很简单。
draw = ImageDraw.Draw(img)
draw.text((10, y), text2, font=font, fill=forecolor )
但是,当我尝试写希伯来语的标点符号(叫做“nikud”或 ניקוד)时,这些字符的重叠效果就不对了。(我猜这个问题也适用于阿拉伯语和其他类似的语言。)
在支持的环境中,这两个词占用的空间/宽度是一样的(下面的例子取决于你的系统,所以看图片):
סֶפֶר ספר
但是当我用PIL绘制文本时,得到的是:
ס ֶ פ ֶ ר
因为这个库可能没有遵循字距调整的规则。
有没有办法让字符和希伯来语的标点符号占用相同的空间/宽度,而不需要手动调整字符的位置呢?
5 个回答
你在用什么系统呢?我在我的Gentoo系统上试过,这个功能对我来说是可以的;字母的顺序是反过来的(我只是从你的问题里复制粘贴的),我觉得这样是对的,虽然我对RTL语言了解不多。
Python 2.5.4 (r254:67916, May 31 2009, 16:56:01)
[GCC 4.3.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import Image as I, ImageFont as IF, ImageDraw as ID
>>> t= u"סֶפֶר ספר"
>>> t
u'\u05e1\u05b6\u05e4\u05b6\u05e8 \u05e1\u05e4\u05e8'
>>> i= I.new("L", (200, 200))
>>> d= ID.Draw(i)
>>> f= IF.truetype("/usr/share/fonts/dejavu/DejaVuSans.ttf", 20)
>>> d1.text( (100, 40), t, fill=255, font=f)
>>> i.save("/tmp/dummy.png", optimize=1)
生成的效果是:
补充说明:我得说,使用Deja Vu Sans
这个字体并不是偶然的;虽然我不是特别喜欢它(但我觉得它的字形比Arial好),它的可读性不错,支持的Unicode字符也很多,而且在很多非微软的应用程序中表现得比Arial Unicode MS
更好。
关于阿拉伯的标记符号,你可以使用Python加上Wand(一个Python库)和arabic_reshaper
(另一个Python库)以及arabic_reshaper
和bidi.algorithm
,然后把生成的文本传递给draw.text((10, 25), artext, font=font)
来绘制文本:
from wand.image import Image as wImage
from wand.display import display as wdiplay
from wand.drawing import Drawing
from wand.color import Color
import arabic_reshaper
from bidi.algorithm import get_display
reshaped_text = arabic_reshaper.reshape(u'لغةٌ عربيّة')
artext = get_display(reshaped_text)
fonts = ['C:\\Users\\PATH\\TO\\FONT\\Thabit-0.02\\DroidNaskh-Bold.ttf',
'C:\\Users\\PATH\\TO\\FONT\\Thabit-0.02\\Thabit.ttf',
'C:\\Users\\PATH\\TO\\FONT\\Thabit-0.02\\Thabit-Bold-Oblique.ttf',
'C:\\Users\\PATH\\TO\\FONT\\Thabit-0.02\\Thabit-Bold.ttf',
'C:\\Users\\PATH\\TO\\FONT\\Thabit-0.02\\Thabit-Oblique.ttf',
'C:\\Users\\PATH\\TO\\FONT\\Thabit-0.02\\majalla.ttf',
'C:\\Users\\PATH\\TO\\FONT\\Thabit-0.02\\majallab.ttf',
]
draw = Drawing()
img = wImage(width=1200,height=(len(fonts)+2)*60,background=Color('#ffffff'))
#draw.fill_color(Color('#000000'))
draw.text_alignment = 'right';
draw.text_antialias = True
draw.text_encoding = 'utf-8'
#draw.text_interline_spacing = 1
#draw.text_interword_spacing = 15.0
draw.text_kerning = 0.0
for i in range(len(fonts)):
font = fonts[i]
draw.font = font
draw.font_size = 40
draw.text(img.width / 2, 40+(i*60),artext)
print draw.get_font_metrics(img,artext)
draw(img)
draw.text(img.width / 2, 40+((i+1)*60),u'ناصر test')
draw(img)
img.save(filename='C:\\PATH\\OUTPUT\\arabictest.png'.format(r))
wdiplay(img)
有趣的是,经过五年,得到了@Nasser Al-Wohaibi的极大帮助,我终于明白该怎么做了:
需要用到一种叫BIDI的算法来反转文本。
# -*- coding: utf-8 -*-
from bidi.algorithm import get_display
import PIL.Image, PIL.ImageFont, PIL.ImageDraw
img= PIL.Image.new("L", (400, 200))
draw = PIL.ImageDraw.Draw(img)
font = PIL.ImageFont.truetype( r"c:\windows\fonts\arial.ttf", 30)
t1 = u'סֶפֶר ספר!'
draw.text( (10,10), 'before BiDi :' + t1, fill=255, font=font)
t2 = get_display(t1) # <--- here's the magic <---
draw.text( (10,50), 'after BiDi: ' + t2, fill=220, font=font)
img.save( 'bidi-test.png')
@Nasser的回答有额外的价值,可能只对阿拉伯文本相关(阿拉伯字母的形状和连接方式会根据相邻的字母而变化,而希伯来字母都是独立的),所以这次问题中只有BIDI部分是相关的。
在示例结果中,第二行是正确的形式,以及正确的发音符号位置。
感谢@tzot的帮助和代码片段
顺便提一下:
这是不同字体在希伯来文“nikud”下的表现示例。并不是所有字体的表现都一样:
