Outline text on image in Python

谁都会走 提交于 2021-01-02 06:26:20

问题


I have been using PIL Image

I am trying to draw text on an image. I want this text to have a black outline like most memes. I've attempted to do this by drawing a shadow letter of a bigger font behind the letter in front. I've adjusted the x and y postions of the shadow accordingly. The shadow is slightly off though. The letter in front should be exactly in the middle of the shadow letter, but this isn't the case. The question mark certainly isn't centered horizontally, and all the letters are too low vertically. The outline also just doesn't look good.


Below is a minimum reproducible example to produce the image above.

Link to the font

Link to original image

from PIL import Image, ImageDraw, ImageFont
    
    caption = "Why is the text slightly off?"
    img = Image.open('./example-img.jpg')
    d = ImageDraw.Draw(img)
    x, y = 10, 400
    font = ImageFont.truetype(font='./impact.ttf', size=50)
    shadowFont = ImageFont.truetype(font='./impact.ttf', size=60)
    for idx in range(0, len(caption)):
        char = caption[idx]
        w, h = font.getsize(char)
        sw, sh = shadowFont.getsize(char)  # shadow width, shadow height
        sx = x - ((sw - w) / 2)  # Shadow x
        sy = y - ((sh - h) / 2)  # Shadow y
        # print(x,y,sx,sy,w,h,sw,sh)
        d.text((sx, sy), char, fill="black", font=shadowFont)  # Drawing the text
        d.text((x, y), char, fill=(255,255,255), font=font)  # Drawing the text
        x += w + 5
    
    img.save('example-output.jpg')

Another approach includes drawing the text 4 times in black behind the main text at positions slightly higher, slightly lower, slightly left, and slightly right, but these have also not been optimal as shown below

Code to produce the image above

    from PIL import Image, ImageDraw, ImageFont
    
    caption = "Why does the Y and i look weird?"
    x, y = 10, 400
    font = ImageFont.truetype(font='./impact.ttf', size=60)
    img = Image.open('./example-img.jpg')
    d = ImageDraw.Draw(img)
    shadowColor = (0, 0, 0)
    thickness = 4
    d.text((x - thickness, y - thickness), caption, font=font, fill=shadowColor, thick=thickness)
    d.text((x + thickness, y - thickness), caption, font=font, fill=shadowColor, thick=thickness)
    d.text((x - thickness, y + thickness), caption, font=font, fill=shadowColor, thick=thickness)
    d.text((x + thickness, y + thickness), caption, font=font, fill=shadowColor, thick=thickness)
    d.text((x, y), caption, spacing=4, fill=(255, 255, 255), font=font)  # Drawing the text
    img.save('example-output.jpg')

回答1:


I don't know since what version, but about a year ago Pillow added text stroking. You probably need to update it if you haven't do so lately. Example usage with stroke_width of 2:

from PIL import Image, ImageDraw, ImageFont

caption = 'I need to update my Pillow'
img = Image.open('./example-img.jpg')
d = ImageDraw.Draw(img)
font = ImageFont.truetype('impact.ttf', size=50)
d.text((10, 400), caption, fill='white', font=font,
       stroke_width=2, stroke_fill='black')
img.save('example-output.jpg')



回答2:


You can use mathlibplot text Stroke effect which uses PIL.

Example:

import matplotlib.pyplot as plt
import matplotlib.patheffects as path_effects
import matplotlib.image as mpimg

fig = plt.figure(figsize=(7, 5))
fig.figimage(mpimg.imread('seal.jpg'))
text = fig.text(0.5, 0.1, 'This text stands out because of\n'
                          'its black border.', color='white',
                          ha='center', va='center', size=30)
text.set_path_effects([path_effects.Stroke(linewidth=3, foreground='black'),
                       path_effects.Normal()])
plt.savefig('meme.png')

Result:




回答3:


As @Abang pointed out, use stroke_width and stroke_fill.

Link for more details

Code:

from PIL import Image, ImageDraw, ImageFont

caption = 'Ans: stroke_width & stroke_fill'
img = Image.open('./example-img.jpg')
d = ImageDraw.Draw(img)
font = ImageFont.truetype('impact.ttf', size=50)
d.text((60, 400), caption, fill='white', font=font, spacing = 4, align = 'center',
       stroke_width=4, stroke_fill='black')
img.save('example-output.jpg')



来源:https://stackoverflow.com/questions/62737084/outline-text-on-image-in-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!