Вам нужно использовать 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)
.Когда этот пиксель имеет альфа-композицию на белом фоне, он становится (192, 192, 192, 255)
, который светлее серого, чем должен быть.Я думаю, что в вашем случае работа только над альфа-картой (т.е. YC_BACKCOLOR_TR = (0, 0, 0, 0)
) является разумным подходом, но мне любопытно, есть ли лучший или концептуально более простой способ сделать это.