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
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!***
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.
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)
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()
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")