用PIL(低)绘制重叠的轮廓文本

2024-04-26 12:47:23 发布

您现在位置:Python中文网/ 问答频道 /正文

我试着用枕头画出轮廓的文字,这样字符就重叠了。但是,重叠是以“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


Tags: textposstrokefontsrandomttffilloffset
1条回答
网友
1楼 · 发布于 2024-04-26 12:47:23

你需要use ^{}来绘制部分不透明的东西。你知道吗

示例代码:

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))是一个合理的方法,但是我很好奇是否有更好的或者概念上更简单的方法来实现这一点。你知道吗

相关问题 更多 >