Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pillow Fails Rendering Urdu Text for Different Fonts

I am trying to generate image for some Urdu text using Pillow. Using the same code to generate normal English works like a charm but when I do the same with Urdu text things just does not go as smooth.

Following is the code and result when done with English:

from PIL import Image, ImageFont, ImageDraw

from matplotlib import pyplot as plt
import numpy as np
from bidi.algorithm import get_display

text_string = u'Hello how are you doing?'

img = Image.new('RGB', (720, 480))
draw = ImageDraw.Draw(img)

draw.text((25,40), text_string, fill='white')

img.save('pil_text_font.png')

And the resultant image: enter image description here

Following is the code and result when done with Urdu:

from PIL import Image, ImageFont, ImageDraw

from matplotlib import pyplot as plt
import numpy as np
from bidi.algorithm import get_display

text_string = u'نیدرلینڈز کی ملکہ پاکستان آ رہی ہیں'

img = Image.new('RGB', (720, 480))
draw = ImageDraw.Draw(img)
font = ImageFont.truetype('../UrduFontsDirectory' + data.iloc[14]['Path'], 25)

draw.text((25,40), text_string, fill='white', font=font)

img.save('pil_text_font.png')

And the resultant image: enter image description here

Also I tried using Arabic Reshaper which resolved the alignment on rendering issue but yet some characters never get rendered:

from PIL import Image, ImageFont, ImageDraw

from matplotlib import pyplot as plt
import numpy as np
from bidi.algorithm import get_display
from arabic_reshaper import reshape

text_string = u'نیدرلینڈز کی ملکہ پاکستان آ رہی ہیں'
text_string = get_display(reshape(text_string))

img = Image.new('RGB', (720, 480))
draw = ImageDraw.Draw(img)
font = ImageFont.truetype('../UrduFontsDirectory' + data.iloc[14]['Path'], 25)

draw.text((25,40), text_string, fill='white', font=font)

img.save('pil_text_font.png')

And the resultant iamge: enter image description here

like image 533
Tayyab Avatar asked Nov 16 '19 07:11

Tayyab


1 Answers

On further R&D found out that this is still an issue specifically for Urdu and no solution has been worked out for it yet: As per described here.

However, I was able to find a work around for this using the good old .NET. For someone who might face similar problem may use following to generate Urdu text images (all of the fonts supported):

//Create the font using your font file    
var modernFont = new PrivateFontCollection();
modernFont.AddFontFile("NafeesNaskh.ttf");//Load font from the font file

var font= new Font(modernFont.Families[0], 12);//The second argument is the font size

//first, create a dummy bitmap just to get a graphics object
Image img = new Bitmap(1, 1);
Graphics drawing = Graphics.FromImage(img);

//free up the dummy image and old graphics object
img.Dispose();
drawing.Dispose();

//create a new image of the right size
img = new Bitmap(500, 40);

drawing = Graphics.FromImage(img);

//paint the background
drawing.Clear(Color.Black);

//create a brush for the text
Brush textBrush = new SolidBrush(Color.White);

drawing.DrawString("نیدرلینڈز کی ملکہ پاکستان آ رہی ہیں", font, textBrush, new Rectangle(0, 0, img.Width, img.Height), new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
drawing.Save();

textBrush.Dispose();
drawing.Dispose();
string path = "./" + Id[i] + "_" + font.Name + ".jpg";
img.Save(path);

Also here is the resultant image:

enter image description here

Also it provides many more features like getting the image size for the text a given font and font size and also centering your content.

Image img = new Bitmap(1, 1);
Graphics drawing = Graphics.FromImage(img);
//Size of image for current text, font and font size
SizeF textSize = drawing.MeasureString("نیدرلینڈز کی ملکہ پاکستان آ رہی ہیں", font);
img.Dispose();
drawing.Dispose();

Also in the above example the center aligning code is as follows:

 drawing.DrawString("نیدرلینڈز کی ملکہ پاکستان آ رہی ہیں", font, textBrush, new Rectangle(0, 0, img.Width, img.Height), new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });

You can modify to have the text aligned to left, right, top or bottom as per your requirement.

Also for further details do refer to the documentation here.

like image 145
Tayyab Avatar answered Nov 17 '22 00:11

Tayyab