Python 有没有办法在PIL中用暗线勾勒出文本的轮廓?

Python 有没有办法在PIL中用暗线勾勒出文本的轮廓?,python,image,python-3.x,image-processing,python-imaging-library,Python,Image,Python 3.x,Image Processing,Python Imaging Library,我正在使用python/PIL在一组PNG图像上编写文本。我能够得到我想要的字体,但我现在想用黑色勾勒出文本的轮廓 这就是我所拥有的:如您所见,如果背景是白色,则很难阅读 这就是目标: 有没有办法通过PIL来实现这一点?如果没有,我愿意听取其他建议,但没有承诺,因为我已经开始了一个使用PIL的python大型项目 处理在图像上绘制的代码部分: for i in range(0,max_frame_int + 1): writeimg = Image.open("frameinstan

我正在使用python/PIL在一组
PNG
图像上编写文本。我能够得到我想要的字体,但我现在想用黑色勾勒出文本的轮廓

这就是我所拥有的:如您所见,如果背景是白色,则很难阅读

这就是目标:

有没有办法通过PIL来实现这一点?如果没有,我愿意听取其他建议,但没有承诺,因为我已经开始了一个使用PIL的python大型项目

处理在图像上绘制的代码部分:

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")
适用于范围内的i(0,最大帧数+1):
writeimg=Image.open(“frameinstance”+str(i)+“.png”)
newimg=Image.new(“RGB”,writeimg.size)
newimg.paste(writeimg)
宽度\图像=newimg.size[0]
高度\图像=新尺寸[1]
draw=ImageDraw.draw(newimg)
#font=ImageFont.truetype(,)
字体大小在(50,0,-1)范围内:
font=ImageFont.truetype(“impact.ttf”,字体大小)

如果font.getsize(meme_text)[0]您可以查看以下内容:


当我需要为帧计数器执行此操作时,我就是这样处理此问题的。如果你开始把厚度推得太远,那么你需要更多的绘图来覆盖你缺少的区域

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)

我在互联网上寻找它,我发现PIL没有添加文本边框的本地支持。在这种情况下,我将基于创建此提议方法

我发现这个解决方案的问题是如何在较大的边框大小上创建平滑的边框。

如果我们在360度或2pi弧度上行走,添加相同的文本,我们可以创建一个更好的文本边框功能实现

下面是示例函数

    def add_text(image, text, location, font, fontsize=14, fontcolor=(0, 0, 0), 
                 border=0, border_color=(0, 0, 0), points=15):
        font_format = ImageFont.truetype(font, fontsize)
        drawer = ImageDraw.Draw(image)

        if border:
            (x, y) = location
            for step in range(0, math.floor(border * points), 1):
                angle = step * 2 * math.pi / math.floor(border * points)
                drawer.text((x - border * math.cos(angle), y - border * math.sin(angle)), text, border_color, font=font_format)
        drawer.text(location, text, fontcolor, font=font_format)
        return image
相同的图像、文本和配置生成下一个

检查选项,该选项实现了
笔划/边框/轮廓
效果。对于
阴影
效果,可以使用小偏移进行绘制。下面是一个为图像添加字幕的示例

#!/usr/bin/env python
from PIL import Image, ImageDraw, ImageFont


def 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 bg


if __name__ == "__main__":
    bg = Image.open("./Screenshot_20200626-131218.png")
    bg = add_subtitle(bg)
    bg.save("out.png")

要单独提供链接,可以使用评论部分。如果您有答案或观点需要证明,请使用“答案”部分。顺便说一句,这是一个有用的链接:)当然,谢谢。此解决方案存在一些问题,这些问题在像素尺寸较大时会变得明显。相反,最好使用ImageDraw.text支持的内置
stroke\u width
stroke\u fill
参数:“如果背景为白色,则难以读取”。可能不是故意的,但在那张照片上,这句话很好笑!这回答了你的问题吗?看起来大约一年前,
Pillow
添加了一个选项来概括文本。这回答了你的问题吗?这对我有用。我对内部部分使用了一个循环来缩短代码:``dxy=[(dx,dy)for dx in[-1,0,1]for dy in[-1,0,1]]for I in range(1,1+outline):for dx,dy in dxy:draw.text((x+dxi,y+dyi),**kwshadow)``这是迄今为止最好的答案。不需要额外的代码(stroke_width和stroke_fill参数完全不同),就可以实现OP想要的功能。
    def add_text(image, text, location, font, fontsize=14, fontcolor=(0, 0, 0), 
                 border=0, border_color=(0, 0, 0), points=15):
        font_format = ImageFont.truetype(font, fontsize)
        drawer = ImageDraw.Draw(image)

        if border:
            (x, y) = location
            for step in range(0, math.floor(border * points), 1):
                angle = step * 2 * math.pi / math.floor(border * points)
                drawer.text((x - border * math.cos(angle), y - border * math.sin(angle)), text, border_color, font=font_format)
        drawer.text(location, text, fontcolor, font=font_format)
        return image
#!/usr/bin/env python
from PIL import Image, ImageDraw, ImageFont


def 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 bg


if __name__ == "__main__":
    bg = Image.open("./Screenshot_20200626-131218.png")
    bg = add_subtitle(bg)
    bg.save("out.png")