Pillow Fails Rendering Urdu Text for Different Fonts - python

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:
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:
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:

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:
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.

Related

Problem in how to do image processing for some images - Error: AttributeError: type object 'Image' has no attribute 'open

I get an error when performing image processing for some images using python. The error is:
"AttributeError: type object 'Image' has no attribute 'open'".
I would be happy if you can review the code below and help me to fix this error. 
#imprint text on image
from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw
from IPython.display import Image
list2 = ['mydata/marketst670503.jpg','mydata/marketst8407.jpg','mydata/potsdamriot6805.jpg','mydata/rescue671221a.jpg']
outfile = 'sample-text.jpg'
for line in list2:
print (line)
img = Image.open(line)
draw = ImageDraw.Draw(img)
# font = ImageFont.truetype(<font-file>, <font-size>)
font = ImageFont.truetype("Colombia.ttf", 200)
draw.text((0, 0),"Sample Text",(255,0,0),font=font)
img.save(outfile)
display(Image(filename=outfile))
Notice! you have 2 imports under THE SAME NAME, overriding eachother.
I would make this change:
#mabe you replace the original import to a more nutral name..
import PIL.Image as Image
from PIL import ImageFont
from PIL import ImageDraw
from IPython.display import Image as DisplayImage # this line fixes your problem
list2 = ['mydata/marketst670503.jpg','mydata/marketst8407.jpg','mydata/potsdamriot6805.jpg','mydata/rescue671221a.jpg']
outfile = 'sample-text.jpg'
for line in list2:
print (line)
img = Image.open(line)
draw = ImageDraw.Draw(img)
# font = ImageFont.truetype(<font-file>, <font-size>)
font = ImageFont.truetype("Colombia.ttf", 200)
draw.text((0, 0),"Sample Text",(255,0,0),font=font)
img.save(outfile)
display(Image(filename=outfile))
and for next time, don't confuse yourself! choose a more nutral name then Image, and there won't be duplicates :)
*** Edited!***

How Tkinter could load png images with transparent backgrounds?

Some weeks ago i load a png image into my Tkinter Canvas and drawed with create_image, but now i can't do this anymore, i tried convert with ImageTk but png did not display
I have the following code:
load = Image.open("mouse.png")
self.img = ImageTk.PhotoImage(load)
self.draw.create_image(100,100,image=self.img,anchor = NW)
self.draw.image = self.img
I just need to present a png image
Try this
vSmallIco = (15, 15)
self.original = Image.open('.//data//img//plus.png')
resized = self.original.resize(vSmallIco, Image.ANTIALIAS)
self.plusIco = ImageTk.PhotoImage(resized)
self.medIco = ttk.Label(self.mf, image=self.plusIco, style='Main.TLabel')
this is done with this import
from PIL import Image, ImageTk
Also, please use a *.png image if you wish to use png.

How I can load a font file with PIL.ImageFont.truetype without specifying the absolute path?

When I write the code in Windows, this code can load the font file just fine:
ImageFont.truetype(filename='msyhbd.ttf', size=30);
I guess the font location is registered in Windows registry.
But when I move the code to Ubuntu, and copy the font file over to /usr/share/fonts/, the code cannot locate the font:
self.font = core.getfont(font, size, index, encoding)
IOError: cannot open resource
How can I get PIL to find the ttf file without specifying the absolute path?
To me worked this on xubuntu:
from PIL import Image,ImageDraw,ImageFont
# sample text and font
unicode_text = u"Hello World!"
font = ImageFont.truetype("/usr/share/fonts/truetype/freefont/FreeMono.ttf", 28, encoding="unic")
# get the line size
text_width, text_height = font.getsize(unicode_text)
# create a blank canvas with extra space between lines
canvas = Image.new('RGB', (text_width + 10, text_height + 10), "orange")
# draw the text onto the text canvas, and use blue as the text color
draw = ImageDraw.Draw(canvas)
draw.text((5,5), u'Hello World!', 'blue', font)
# save the blank canvas to a file
canvas.save("unicode-text.png", "PNG")
canvas.show()
Windows version
from PIL import Image, ImageDraw, ImageFont
unicode_text = u"Hello World!"
font = ImageFont.truetype("arial.ttf", 28, encoding="unic")
text_width, text_height = font.getsize(unicode_text)
canvas = Image.new('RGB', (text_width + 10, text_height + 10), "orange")
draw = ImageDraw.Draw(canvas)
draw.text((5, 5), u'Hello World!', 'blue', font)
canvas.save("unicode-text.png", "PNG")
canvas.show()
The output is the same as above:
According to the PIL documentation, only Windows font directory is searched:
On Windows, if the given file name does not exist, the loader also looks in Windows fonts directory.
http://effbot.org/imagingbook/imagefont.htm
So you need to write your own code to search for the full path on Linux.
However, Pillow, the PIL fork, currently has a PR to search a Linux directory. It's not exactly clear yet which directories to search for all Linux variants, but you can see the code here and perhaps contribute to the PR:
https://github.com/python-pillow/Pillow/pull/682
There is a Python fontconfig package, whereby one can access system font configuration, The code posted by Jeeg_robot can be changed like so:
from PIL import Image,ImageDraw,ImageFont
import fontconfig
# find a font file
fonts = fontconfig.query(lang='en')
for i in range(1, len(fonts)):
if fonts[i].fontformat == 'TrueType':
absolute_path = fonts[i].file
break
# the rest is like the original code:
# sample text and font
unicode_text = u"Hello World!"
font = ImageFont.truetype(absolute_path, 28, encoding="unic")
# get the line size
text_width, text_height = font.getsize(unicode_text)
# create a blank canvas with extra space between lines
canvas = Image.new('RGB', (text_width + 10, text_height + 10), "orange")
# draw the text onto the text canvas, and use black as the text color
draw = ImageDraw.Draw(canvas)
draw.text((5,5), u'Hello World!', 'blue', font)
# save the blank canvas to a file
canvas.save("unicode-text.png", "PNG")
canvas.show()
On mac, I simply copy the font file Arial.ttf to the project directory and everything works.
On Mac I had some fonts in the project dependencies
$ find . -name *.ttf*
./venv/lib/python3.7/site-packages/werkzeug/debug/shared/ubuntu.ttf
./venv/lib/python3.7/site-packages/reportlab/fonts/Vera.ttf
./venv/lib/python3.7/site-packages/reportlab/fonts/VeraBI.ttf
./venv/lib/python3.7/site-packages/reportlab/fonts/VeraBd.ttf
./venv/lib/python3.7/site-packages/reportlab/fonts/VeraIt.ttf
so I passed in Vera like so
font = ImageFont.truetype(r'./venv/lib/python3.7/site-packages/reportlab/fonts/Vera.ttf', 50)
you can also get a font like this but the size was too small
font = ImageFont.load_default()
In Windows 10 while using Visual code, i had to do as below to make it work.
font = ImageFont.truetype(os.environ['LOCALAPPDATA'] + "/Microsoft/Windows/Fonts/Dance Floor.ttf", 10)

Load image in tkinter from pygame surface in python 3

I would like to load an image in tkinter from a pygame surface and I am having a problem.
This is what I am currently trying:
image= pygame.image.tostring(surf, 'RGB')
tkimage= tkinter.PhotoImage(data= image)
canvas.create_image(0, 0, tkimage)
but I unfortunately get this error:
_tkinter.TclError: couldn't recognize image data
The PhotoImage class can only read GIF and PGM/PPM files, either directly from a file or as base64 encoded string.
You should use the Python Imaging Library for loading and creating the image for Tk.
Here's an example:
import pygame
from PIL import Image
import ImageTk
import Tkinter
# load image in pygame
pygame.init()
surf = pygame.image.load('bridge.png')
# export as string / import to PIL
image_str = pygame.image.tostring(surf, 'RGB') # use 'RGB' to export
w, h = surf.get_rect()[2:]
image = Image.fromstring('RGB', (w, h), image_str) # use 'RGB' to import
# create Tk window/widgets
root = Tkinter.Tk()
tkimage = ImageTk.PhotoImage(image) # use ImageTk.PhotoImage class instead
canvas = Tkinter.Canvas(root)
canvas.create_image(0, 0, image=tkimage)
canvas.pack()
root.mainloop()
------- UPDATE ------
import pygame
from pygame.locals import *
from PIL import Image
import ImageTk
import Tkinter
# load image in pygame
pygame.init()
surf = pygame.image.load('pic_temp.png') # you can use any Surface a Camers is also an Surface
mode = "RGB"
# export as string / import to PIL
image_str = pygame.image.tostring(surf, mode) # use 'RGB' to export
size = (640, 480)
#image = Image.fromstring(mode, size, image_str)
# use frombuffer() - fromstring() is no longer supported
image = Image.frombuffer(mode, size, image_str, 'raw', mode, 0, 1) # use 'RGB' to import
# create Tk window/widgets
root = Tkinter.Tk()
tkimage = ImageTk.PhotoImage(image) # use ImageTk.PhotoImage class instead
label = Tkinter.Label(root, image=tkimage)
label.pack()
root.mainloop()

PIL Draw.text and Lower Resolution

I have the following PIL code to print text in an image
import os, sys
import PIL
from PIL import ImageFont
from PIL import Image
from PIL import ImageDraw
img = Image.open("one.jpg")
draw = ImageDraw.Draw(img)
font = ImageFont.truetype("/usr/share/fonts/truetype/msttcorefonts/Times_New_Roman.ttf",27)
draw.text((100, 100), "test test test", font=font)
img.save("out.jpg")
This works on one.jpg file. However on another test file called two.jpg, it doesn't print anything. From what I see, the only difference between two documents is the lower resolution on two.jpg. The file one.jpg is 200x200 dpi, two.jpg is 60x60 dpi.
How can I get draw.text to work in lower res?
Thanks,
You need to specify a color for the text:
import os
import sys
import ImageFont
import Image
import ImageDraw
img = Image.open("two.jpg")
draw = ImageDraw.Draw(img)
font = ImageFont.truetype("/usr/share/fonts/truetype/msttcorefonts/Times_New_Roman.ttf",27)
draw.text((100, 100), "test test test", font=font, fill = 'blue')
img.save("out.jpg")

Categories