The glyph is rendered as an empty box using pillow - python

I'm trying to render every character in different fonts, and some fonts give me empty boxes instead of characters, and I honestly don't know what I'm doing wrong, I tried to change the layout engine, I was playing with encoding, but still I sometimes get empty boxes, and I really don't want to go through 250 thousand images to remove these empty boxes
My code is presented below:
def draw_glyph(font_file, unicode_char, glyph_size=128):
try:
font = ImageFont.truetype(
font=f"{font_file}",
encoding="",
size=glyph_size,
layout_engine=ImageFont.LAYOUT_RAQM,
)
except Exception:
font = None
if font is not None:
img = Image.new('L', (glyph_size, glyph_size), 'white')
draw = ImageDraw.Draw(img)
draw.text(
xy=(64, 64),
text=unicode_char,
font=font,
anchor='mm',
)
return img
return None

Related

Draw a Special text on a Picture with PIL

I just wanted to write some text on picture using PIL and Python 3.8.6 in my Discord Bot while a member joined but it did not shows correctly, Here is my code and result picture.
background = Image.open("./photos/Sans titre 1.png").convert("RGBA")
basewidth = 227
img = Image.open(BytesIO(response.content)).convert("RGBA")
wpercent = (basewidth/float(img.size[0]))
hsize = int((float(img.size[1])*float(wpercent)))
img = img.resize((basewidth,hsize), Image.ANTIALIAS)
cercle = Image.open("./photos/cercle_orange.png").convert("RGBA")
img_w, img_h = img.size
cr_w,cr_h = cercle.size
# make a blank image for the text, initialized to transparent text color
txt = Image.new("RGBA", background.size, (255,255,255,0))
msg = "WELCOME"
new_member = u"{}#{}".format(member.name,member.discriminator)
fnt = ImageFont.truetype("./fonts/DejaVuSans.ttf", 80)
fntname = ImageFont.truetype("./fonts/DejaVuSans.ttf",50)
# get a drawing context
d = ImageDraw.Draw(txt)
bg_w, bg_h = background.size
offset = ((bg_w - img_w) // 2, (bg_h - img_h) // 2)
w, h = d.textsize(msg,font=fnt)
w2, h2 = d.textsize(new_member,font=fntname)
d.text(((bg_w-w)/2,((bg_h-h)/2)+160), msg, font=fnt, fill='#FFAA39')
d.text((((bg_w-w2)/2),((bg_h-h2)/2)+220), new_member, font=fntname, fill=(255,255,255,255))
background.paste(profile, offset, profile)
my bot welcome picture in Discord
Discord Welcome Picture
i already search how to transfer the text to unicode and it didn't work however i changed the font that i use in my bot code, i want it to show the name 𝕯𝖆𝖗𝐀 𝔇𝔒𝕧𝒾𝖑 correctly in my code as this second picture from Koya Bot:
Koya Welcome Picture in Discord
Koya Welcome Picture
i Hope you can help me,Thank you guys for listening.
This behaviour of displaying squares typically happens when the font cannot render the specified characters, which could mean that the font is corrupted or simply that the specified font is missing glyphs for those specific characters. Most commonly used fonts have a wide range of glyphs that cover common scripts (latin, greek, hebrew, cyrillic, arabic, etc).
You might want to try changing the font to see if it that works, if it does, then the problem is the font, you might want to try finding another source for that font to see if it includes the necessary glyphs, or directly change the font.

Canvas not getting captured while saving tkinter python

[SOLVED]
Please don't judge the code. I just need to fix one bug with capturing canvas into file.
As you can see I've tried multiple solutions and still while saving file is all-white...
Do you have any soulutions to that?
This app is to generate randomly dots on canvas with option to save it.
it works when number of dots is above 40000 and rectangle is black.
But otherwise is white.
HEIGTH = 207
WIDTH = 207
def snapsaveCanvas():
fname = filename.get()
my_window.update_idletasks()
my_window.update()
canvas.update()
canvas.update_idletasks()
ps = canvas.postscript(colormode='color')
img = Image.open(io.BytesIO(ps.encode('utf-8')))
img.save(fname + ".bmp", 'bmp')
print("done")
canvas = tk.Canvas(frame2, width=HEIGTH, height=WIDTH, background='white')
canvas.grid(row=0, column=0)
canvas.create_rectangle(4, 4, 206, 206)
Ok, thanks for links.
I've tested several methods and one of them works.
taken from How can I convert canvas content to an image?
import win32gui
def snapsaveCanvas():
fileName = filename.get()
canvas.update()
canvas.update_idletasks()
HWND = canvas.winfo_id() # get the handle of the canvas
rect = win32gui.GetWindowRect(HWND) # get the coordinate of the canvas
im = ImageGrab.grab(rect).save(fileName + ".bmp")
print("done")

How can I create an object in wxPython using FloatCanvas and NavCanvas that updates with zoom?

I want to make a legend scale for a map. The scale would have to change based on the zoom level.
For example, at 100% zoom, there might be a rectangle with some text next to it that says '100 m'. When the zoom is changed to 200%, the text should then read '50 m'.
It'd be great if there is already something built in to handle this; but if not, it seems like I'd have to somehow retrieve the zoom level and boundaries of the current view to redraw the object.
My current implementation of the map is with NavCanvas. In my case, reading image files is appropriate. This is some of the code:
...
# Add Canvas
self.nav_canvas = NavCanvas.NavCanvas(self, -1,
size=(640, 480),
ProjectionFun=None,
Debug=0,
BackgroundColor="#777777")
self.canvas = self.nav_canvas.Canvas
...
def load_base_image(self):
self.image = skimage.io.imread("imported/base/" + self.image_name + ".png")
image_obj = wx.Image("imported/base/" + self.image_name + ".png")
image = FloatCanvas.ScaledBitmap2(image_obj,
XY = (0,0),
Height = image_obj.GetHeight(),
Position = 'tl')
self.canvas.AddObject(image)
self.canvas.Draw()
self.canvas.ZoomToBB()
What would be the easiest approach?

How can I write text on an image and not go outside of the border?

I have a gif that I'm breaking up frame by frame and saving them as images. I wrote text on them using ImageDraw, but now I'm running into a problem. The text is going outside of the border. The catch is that I'm grabbing a random gif from the internet using a script, so I can't hardcode either in the size of the font nor the amount text to write. How can I ensure that the text I add to the image stays inside the borders of the image?
Example of what's happening:
Screenshot
The section of code that deals with writing on the image:
meme_text = "When your kitten is thinking about tuna but has none"
for i in range(0,max_frame_int + 1):
writeimg = Image.open("frameinstance" + str(i) + ".png")
newimg = Image.new("RGB", writeimg.size)
newimg.paste(writeimg)
width_image = newimg.size[0]
height_image = newimg.size[1]
draw = ImageDraw.Draw(newimg)
# font = ImageFont.truetype(<font-file>, <font-size>)
font = ImageFont.truetype("impact.ttf", 50)
# draw.text((x, y),"Sample Text",(r,g,b))
draw.text((int(0.05*width_image), int(0.7*height_image)),meme_text,(255,255,255),font=font)
newimg.save("newimg" + str(i) +".png")
Your problem is you're not accounting for the size of the text that will be rendered vs. the width of the picture. if you change the font = ImageFont... line to the following:
for font_size in range(50, 0, -1):
font = ImageFont.truetype("impact.ttf", font_size)
if font.getsize(meme_text)[0] <= width_image:
break
else:
print 'no fonts fit!'
the script will find the largest font size that will fit all of the text.

Fitting text into a rectangle (width x by height y) with tkinter

I'm trying to make a program which will fit text into a rectangle (x by y) depending on the text, the font and the font size
Here is the code
def fit_text(screen, width, height, text, font):
measure_frame = Frame(screen) # frame
measure_frame.pack()
measure_frame.pack_forget()
measure = Label(measure_frame, font = font) # make a blank label
measure.grid(row = 0, column = 0) # put it in the frame
##########################################################
# make a certain number of lines
##########################################################
words = text.split(" ")
lines = []
num = 0
previous = 0
while num <= len(words):
measure.config(text = " ".join(words[previous:num])) # change text
line_width = measure.winfo_width() # get the width
print(line_width)
if line_width >= width: # if the line is now too long
lines.append(" ".join(words[previous:num - 1])) # add the last vsion which wasn't too long
previous = num - 1 # previous is now different
num = num + 1 # next word
lines.append(" ".join(words[previous:])) # add the rest of it
return "\n".join(lines)
from tkinter import *
window = Tk()
screen = Canvas(window)
screen.pack()
text = fit_text(screen, 200, 80, "i want to fit this text into a rectangle which is 200 pixels by 80 pixels", ("Purisa", 12))
screen.create_rectangle(100, 100, 300, 180)
screen.create_text(105, 105, text = text, font = ("Purisa", 12), anchor = "nw")
The problem with this is no matter what text is in the label the result from measure.winfo_width() is always 1. Here is where I found this from but it doesn't seem to work for me
The problem with your code is that you're using the width of a widget, but the width will be 1 until the widget is actually laid out on the screen and made visible, since the actual width depends on a number of factors that aren't present until that happens.
You don't need to put the text in a widget in order to measure it. You can pass a string to font.measure() and it will return the amount of space required to render that string in the given font.
For python 3.x you can import the Font class like this:
from tkinter.font import Font
For python 2.x you import it from the tkFont module:
from tkFont import Font
You can then create an instance of Font so that you can get information about that font:
font = Font(family="Purisa", size=18)
length = font.measure("Hello, world")
print "result:", length
You can also get the height of a line in a given font with the font.metrics() method, giving it the argument "linespace":
height = font.metrics("linespace")
The widget will not have a width until it is packed. You need to put the label into the frame, then pack it, then forget it.
I've actually stumbled across a way of doing this through trial and error
By using measure.update_idletasks() it calculates the width properly and it works! Bryan Oakley definitely has a more efficient way of doing it though but I think this method will be useful in other situations
P.S. I wouldn't mind some votes to get a nice, shiny, bronze, self-learner badge ;)

Categories

Resources