用PIL(LOW)绘制重叠的轮廓文字

时间:2019-06-14 05:43:47

标签: python python-3.x python-imaging-library

我正在尝试使用PILLOW绘制轮廓文本,以使字符重叠。但是,重叠是以“ z层”方式发生的,即字符仍然是不透明的,并不是真正的透明。

我的代码如下:

YC_CHARS = '0123456789'
YC_LENGTH = 6
YC_WIDTH = 200
YC_HEIGHT = 60
YC_BACKCOLOR = (255, 255, 255, 255)
YC_BACKCOLOR_TR = (255, 255, 255, 0)
YC_TEXTCOLOR = (0, 0, 0, 255)
YC_FONTS =  ['fonts/antquab.ttf', 'fonts/ariblk.ttf', 'fonts/arlrdbd.ttf',
             'fonts/comic.ttf', 'fonts/impact.ttf']
YC_FONTSZ = list(range(40, 51, 5))

def synth_captcha():

    def outline_text(dr, pos, text, fnt, stroke, fill):
        "Draw outline-style text"
        dr.text((pos[0]-1, pos[1]), text, font=fnt, fill=stroke)
        dr.text((pos[0]+1, pos[1]), text, font=fnt, fill=stroke)
        dr.text((pos[0], pos[1]-1), text, font=fnt, fill=stroke)
        dr.text((pos[0], pos[1]+1), text, font=fnt, fill=stroke)
        dr.text(tuple(pos), text, font=fnt, fill=fill)

    img = Image.new('RGB', (YC_WIDTH, YC_HEIGHT), color=YC_BACKCOLOR)

    digit_offset = [random.randint(1, 3), random.randint(1, 10)]
    digit_sz = [0, 0]
    digit_offset = [1, 0]

    for i in range(YC_LENGTH):

        digit = random.choice(YC_CHARS)        
        font = ImageFont.truetype(random.choice(YC_FONTS), random.choice(YC_FONTSZ))
        draw = ImageDraw.Draw(img, mode='RGBA')

        digit_offset[0] += digit_sz[0] + random.randint(-digit_sz[0]//1.5, 0)
        digit_sz = draw.textsize(digit, font=font)
        digit_offset[1] = random.randint(1, max(2, YC_HEIGHT - digit_sz[1] - 2))
        outline_text(draw, digit_offset, digit, font, YC_TEXTCOLOR, YC_BACKCOLOR_TR)

    img.save('img.png')

此代码产生以下图像:
actual image

但是我需要如下所示:
expected image

1 个答案:

答案 0 :(得分:0)

您需要use Image.alpha_composite来绘制部分不透明的东西。

示例代码:

def synth_captcha():

    def outline_text(dr, pos, text, fnt, stroke, fill):
        "Draw outline-style text"
        dr.text((pos[0]-1, pos[1]), text, font=fnt, fill=stroke)
        dr.text((pos[0]+1, pos[1]), text, font=fnt, fill=stroke)
        dr.text((pos[0], pos[1]-1), text, font=fnt, fill=stroke)
        dr.text((pos[0], pos[1]+1), text, font=fnt, fill=stroke)
        dr.text(tuple(pos), text, font=fnt, fill=fill)

    img = Image.new('RGBA', (YC_WIDTH, YC_HEIGHT), color=YC_BACKCOLOR)

    digit_offset = [random.randint(1, 3), random.randint(1, 10)]
    digit_sz = [0, 0]
    digit_offset = [1, 0]

    for i in range(YC_LENGTH):

        digit = random.choice(YC_CHARS)        
        font = ImageFont.truetype(random.choice(YC_FONTS), random.choice(YC_FONTSZ))
        txt = Image.new('RGBA', img.size, YC_BACKCOLOR_TR)
        draw = ImageDraw.Draw(txt)

        digit_offset[0] += digit_sz[0] + random.randint(-digit_sz[0]//1.5, 0)
        digit_sz = draw.textsize(digit, font=font)
        digit_offset[1] = random.randint(1, max(2, YC_HEIGHT - digit_sz[1] - 2))
        outline_text(draw, digit_offset, digit, font, YC_TEXTCOLOR, YC_BACKCOLOR_TR)

        img = Image.alpha_composite(img, txt)

    return img

编辑:将YC_BACKCOLOR_TR更改为(0, 0, 0, 0)会产生更立体的笔触。我不确定为什么,但是它可能与dr.text处理字符边界处的透明度的方式有关。

我的猜测是,它只是将RGBA值混合为4d向量,因此对于通常以50%不透明度绘制的像素,将(0, 0, 0, 255)(255, 255, 255, 0)混合会产生(128, 128, 128, 128)。当该像素以alpha方式合成到白色背景上时,它变成(192, 192, 192, 255),比应有的灰度要浅。我认为在您的情况下,仅在Alpha贴图(即YC_BACKCOLOR_TR = (0, 0, 0, 0))上工作是一种合理的方法,但我很好奇是否有更好或概念上更简单的方法可以做到这一点。