Is there a way to outline text with a dark line in PIL? Is there a way to outline text with a dark line in PIL? python-3.x python-3.x

Is there a way to outline text with a dark line in PIL?


You can take a look at this Text Outline Using PIL:

import Image, ImageFont, ImageDrawimport win32api, osx, y = 10, 10fname1 = "c:/test.jpg"im = Image.open(fname1)pointsize = 30fillcolor = "red"shadowcolor = "yellow"text = "hi there"font = win32api.GetWindowsDirectory() + "\\Fonts\\ARIALBD.TTF"draw = ImageDraw.Draw(im)font = ImageFont.truetype(font, pointsize)# thin borderdraw.text((x-1, y), text, font=font, fill=shadowcolor)draw.text((x+1, y), text, font=font, fill=shadowcolor)draw.text((x, y-1), text, font=font, fill=shadowcolor)draw.text((x, y+1), text, font=font, fill=shadowcolor)# thicker borderdraw.text((x-1, y-1), text, font=font, fill=shadowcolor)draw.text((x+1, y-1), text, font=font, fill=shadowcolor)draw.text((x-1, y+1), text, font=font, fill=shadowcolor)draw.text((x+1, y+1), text, font=font, fill=shadowcolor)# now draw the text over itdraw.text((x, y), text, font=font, fill=fillcolor)fname2 = "c:/test2.jpg"im.save(fname2)os.startfile(fname2)


Check the stroke_width option, which implements stroke/border/outline effect. For shadow effect, you can draw with a small offset. Bellow is an example to add subtitle to image.

#!/usr/bin/env pythonfrom PIL import Image, ImageDraw, ImageFontdef add_subtitle(    bg,    text="nice",    xy=("center", 20),    font="font/SourceHanSansSC-Regular.otf",    font_size=53,    font_color=(255, 255, 255),    stroke=2,    stroke_color=(0, 0, 0),    shadow=(4, 4),    shadow_color=(0, 0, 0),):    """draw subtitle on image by pillow    Args:        bg(PIL image): image to add subtitle        text(str): subtitle        xy(tuple): absolute top left location of subtitle        ...: extra style of subtitle    Returns:        bg(PIL image): image with subtitle    """    stroke_width = stroke    xy = list(xy)    W, H = bg.width, bg.height    font = ImageFont.truetype(str(font), font_size)    w, h = font.getsize(text, stroke_width=stroke_width)    if xy[0] == "center":        xy[0] = (W - w) // 2    if xy[1] == "center":        xy[1] = (H - h) // 2    draw = ImageDraw.Draw(bg)    if shadow:        draw.text(            (xy[0] + shadow[0], xy[1] + shadow[1]), text, font=font, fill=shadow_color        )    draw.text(        (xy[0], xy[1]),        text,        font=font,        fill=font_color,        stroke_width=stroke_width,        stroke_fill=stroke_color,    )    return bgif __name__ == "__main__":    bg = Image.open("./Screenshot_20200626-131218.png")    bg = add_subtitle(bg)    bg.save("out.png")


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,ImageFontimport os#setting variblesimgFile = "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 imageimg = Image.open(imgFile)draw = ImageDraw.Draw(img)#get the size of the imageimgWidth,imgHeight = img.size#get text sizetxtWidth, txtHeight = draw.textsize(text, font=font)#get location to place textx = imgWidth - txtWidth - 100y = imgHeight - txtHeight - 100#create outline textfor 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 imagedraw.text((x,y), text, font=font, fill=textColor)img.save(output)print 'Finished'os.startfile(output)