问题
I'm using python/PIL to write text on a set of PNG
images. I was able to get the font I wanted, but I'd like to now outline the text in black.
This is what I have: as you can see, if the background is white it is difficult to read.
This is the goal:
Is there a way to accomplish this with PIL? If not, I am open to hearing other suggestions, but no promises because I've already begun a large project in python using PIL.
The section of code that deals with drawing on the images:
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>)
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!')
# 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")
回答1:
You can take a look at this Text Outline Using PIL
回答2:
This is how I handled the problem when I needed to do it for frame counters. Just a heads up if you start to push this too far for the thickness, then you will need more draws to cover your areas you're missing.
from PIL import Image,ImageDraw,ImageFont
import os
#setting varibles
imgFile = "frame_0.jpg"
output = "frame_edit_0.jpg"
font = ImageFont.truetype("arial.ttf", 30)
text = "SEQ_00100_SHOT_0004_FR_0001"
textColor = 'white'
shadowColor = 'black'
outlineAmount = 3
#open image
img = Image.open(imgFile)
draw = ImageDraw.Draw(img)
#get the size of the image
imgWidth,imgHeight = img.size
#get text size
txtWidth, txtHeight = draw.textsize(text, font=font)
#get location to place text
x = imgWidth - txtWidth - 100
y = imgHeight - txtHeight - 100
#create outline text
for adj in range(outlineAmount):
#move right
draw.text((x-adj, y), text, font=font, fill=shadowColor)
#move left
draw.text((x+adj, y), text, font=font, fill=shadowColor)
#move up
draw.text((x, y+adj), text, font=font, fill=shadowColor)
#move down
draw.text((x, y-adj), text, font=font, fill=shadowColor)
#diagnal left up
draw.text((x-adj, y+adj), text, font=font, fill=shadowColor)
#diagnal right up
draw.text((x+adj, y+adj), text, font=font, fill=shadowColor)
#diagnal left down
draw.text((x-adj, y-adj), text, font=font, fill=shadowColor)
#diagnal right down
draw.text((x+adj, y-adj), text, font=font, fill=shadowColor)
#create normal text on image
draw.text((x,y), text, font=font, fill=textColor)
img.save(output)
print 'Finished'
os.startfile(output)
回答3:
This answer is based on others but uses the .create_text ((x1, y1), ...)
function in tkinter. Additionally it focuses on achieving a large outline when needed whilst avoiding shadow effect:
Here is a closeup:
Here is the main function:
def create_text((x1, y1), **kwargs):
# mycanvas.create_text((X1, Y1 + PanelHgt/Scale), text=str(Mon[MonN]) + \
# " [" + str(Mon[MonW]) + " x " + \
# str(Mon[MonH]) +"]", \
# fill="white", shawdowfill="black", thick=0, \
# anchor="nw", font=(None, MonFont))
if 'thick' in kwargs:
thick = kwargs.pop('thick')
if thick > 5 : thick = 0
else :
thick = 0
if 'shadowfill' in kwargs:
shadowfill = kwargs.pop('shadowfill')
else:
mycanvas.create_text((x1, y1), **kwargs)
return
if 'fill' in kwargs:
fill = kwargs.pop('fill')
else:
fill = "black"
x = x1 + 1 + thick
y = y1 + 1 + thick
if thick>1: thickless=thick-1
else: thickless=1
while thickless > 0:
mycanvas.create_text((x-thickless, y+thick), fill=shadowfill, **kwargs)
mycanvas.create_text((x+thickless, y+thick), fill=shadowfill, **kwargs)
mycanvas.create_text((x-thick, y-thickless), fill=shadowfill, **kwargs)
mycanvas.create_text((x+thick, y+thickless), fill=shadowfill, **kwargs)
thickless-=1
thick-=1
mycanvas.create_text((x, y), fill=fill, **kwargs)
Here's sample code to call the function:
InvertColor="white"
ShadowColor="black"
String=str(Win[WinN][0:30]) + "\n " \
+ str(Win[WinW]) + " x " + str(Win[WinH])
# if top appliciton indicadtor pannel special formtting
if ( Win[WinH] == PanelHgt ) :
color="light grey"
InvertColor="black"
String=Win[WinN]
mycanvas.create_rectangle(X1, Y1, X2, Y2, fill=color)
mycanvas.create_text((CentX, CentY), text=String, fill=InvertColor, \
font=(None, 11))
else :
color=Colors[j]
j+=1
if j==ColorCnt : j=0
create_rectangle(X1, Y1, X2, Y2, fill=color, alpha=.6)
create_text((CentX, CentY), text=String, fill=InvertColor, \
shadowfill=ShadowColor, thick=4, \
font=(None, 11))
The key line is:
shadowfill=ShadowColor, thick=4
- If you omit
thick
it defaults to0
which is a thin shadow and probably best in most circumstances. - The maximum shadow thickness is set to 5 for sanity checking buy you can simply change the line:
if thick > 5 : thick = 0
- If you omit
shadowfill
then no shadow is drawn at all.
If code isn't understandable don't hesitate to ask questions in comments.
OTOH this is my first python project (still a WIP) so constructive criticism is welcome!
来源:https://stackoverflow.com/questions/41556771/is-there-a-way-to-outline-text-with-a-dark-line-in-pil