Writing text with diacritic ("nikud", vocalization marks) using PIL (Python Imaging Library)
Asked Answered
F

5

8

Writing simple text on an image using PIL is easy.

draw = ImageDraw.Draw(img)
draw.text((10, y), text2, font=font, fill=forecolor )

However, when I try to write Hebrew punctuation marks (called "nikud" or ניקוד), the characters do not overlap as they should. (I would guess this question is relevant also to Arabic and other similar languages.)

On supporting environment, these two words take up the same space/width (the below example depends on your system, hence the image):

סֶפֶר ספר

However when drawing the text with PIL I get:

ס ֶ פ ֶ ר

since the library probably doesn't obey kerning(?) rules.

Is it possible to have the character and Hebrew punctuation mark take up the same space/width without manually writing character positioning?

image - nikud and letter spacing http://tinypic.com/r/jglhc5/5

image url: http://tinypic.com/r/jglhc5/5

Faro answered 14/6, 2009 at 17:28 Comment(0)
F
5

funny, after 5 years, and with great help fron @Nasser Al-Wohaibi, I realized how to do it:

Reversing the text with a BIDI algorithm was needed.

# -*- 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's answer has extra value that's probably relevant only to arabic texts (the letters in arabic change shape and connected-ness based on their neiboring letters, in hebrew all letters are separate), so only the bidi part was relevant for this question.

in the sample result, the 2nd line is the correct form, and correct vocalization marks positioning.

before and after bidi

thank you @tzot for help + code snippets

a-propos:

samples of different font behavior with Hebrew "nikud". Not all fonts behave the same: sample PIL written, bidi hebrew text, with nikud, in different fonts

Faro answered 9/9, 2014 at 18:22 Comment(1)
Hi there, I've had a similar problem using Pillow. Did you ever figure out a fix to get the nikud aligned properly regardless of the font?Casease
W
9

As for Arabic diacritics : Python +Wand(Python Lib) +arabic_reshaper(Python Lib) +bidi.algorithme(Python Lib). The same applies to PIL/Pillow, you need to use the arabic_reshaper and bidi.algorithm and pass the generated text to 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)

Arabic typography in images

Wilburn answered 8/9, 2014 at 14:59 Comment(0)
F
5

funny, after 5 years, and with great help fron @Nasser Al-Wohaibi, I realized how to do it:

Reversing the text with a BIDI algorithm was needed.

# -*- 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's answer has extra value that's probably relevant only to arabic texts (the letters in arabic change shape and connected-ness based on their neiboring letters, in hebrew all letters are separate), so only the bidi part was relevant for this question.

in the sample result, the 2nd line is the correct form, and correct vocalization marks positioning.

before and after bidi

thank you @tzot for help + code snippets

a-propos:

samples of different font behavior with Hebrew "nikud". Not all fonts behave the same: sample PIL written, bidi hebrew text, with nikud, in different fonts

Faro answered 9/9, 2014 at 18:22 Comment(1)
Hi there, I've had a similar problem using Pillow. Did you ever figure out a fix to get the nikud aligned properly regardless of the font?Casease
D
2

What system are you working on? It works for me on my Gentoo system; the order of the letters is reversed (I just copy-pasted from your question), which seems correct to me although I don't know much about RTL languages.

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)

produces:

the example text rendered as white on black

EDIT: I should say that using the Deja Vu Sans font was not accidental; although I don't like it much (and yet I find its glyphs better than Arial), it's readable, it has extended Unicode coverage, and it seems to work better with many non-MS applications than Arial Unicode MS.

Doha answered 19/6, 2009 at 21:26 Comment(4)
You didn't really answer, but you help seeing the bug: Only DejaVuSans.ttf and Lucidaxxx.ttf behave correctly under PIL! All the rest of my TTF files produced wrong output (but they behave nicely outside of PIL) You can try other fonts, e.g. Arial.ttfFaro
A TrueType font (or OpenType font) does not necessarily mean it's a complete and useful font in all applications. Michael Kaplan (working for MS currently and very related to Unicode issues) calls ArialUni an "MS Office font", not an "OS font", whatever he means by it, here: blogs.msdn.com/michkap/archive/2007/07/15/3890144.aspxDoha
for the sake of completeness, you didn't use the bidi algorithm from bidi.algorithm import get_display; reversed = get_display(orig) Faro
@BerryTsakala: thanks; it seems that the bidi module came into existence about a year after I typed the answer above, so it is normal that there is no mention about it! :) In any case, you produced a more complete answer yourself.Doha
S
1

for all languages Arabic, Hebrew, Japanese even english you can use this code:

from bidi.algorithm import get_display
import arabic_reshaper
final_text = get_display(arabic_reshaper.reshape("اللغة العربية"))

this will fix the all problems but don't forget to use Unicode fonts such as enter link description here

Sholapur answered 29/3, 2021 at 15:15 Comment(0)
D
-2

Looks to me that the case is quite simple. You can use True Type fonts and use

Here's the example:True type fonts for PIL

Here you can find Hebrew True Type fonts: Hebrew true type fonts

Good luck or like we saying in Hebrew - Mazal' Tov.

Dietrich answered 15/6, 2009 at 0:10 Comment(1)
Thanks for replying, but you haven't answer the question. As i wrote - I know how to write TTFs, and I already have TTF fonts.Faro

© 2022 - 2024 — McMap. All rights reserved.