前言
最近有文字轉圖片的需求,但是不太想下載 APP,就使用 Python Pillow 實現了一個,效果如下:
PIL 提供了 PIL.ImageDraw.ImageDraw.text
方法,可以方便的把文字寫到圖片上,簡單示例如下:
from PIL import Image, ImageDraw, ImageFont# get an imagebase = Image.open('Pillow/Tests/images/hopper.png').convert('RGBA')# make a blank image for the text, initialized to transparent text colortxt = Image.new('RGBA', base.size, (255,255,255,0))# get a fontfnt = ImageFont.truetype('Pillow/Tests/fonts/FreeMono.ttf', 40)# get a drawing contextd = ImageDraw.Draw(txt)# draw text, half opacityd.text((10,10), "Hello", font=fnt, fill=(255,255,255,128))# draw text, full opacityd.text((10,60), "World", font=fnt, fill=(255,255,255,255))out = Image.alpha_composite(base, txt)out.show()
為什么要計算文字的寬高呢?把文字直接寫到背景圖不可以么?
Pillow PIL.ImageDraw.ImageDraw.text
寫文字是按換行符 /n 換行的,如果個字符串特別長,文字部分就會超出背景圖的寬度,所以第一步我們需要先把文本按固定的寬度計算出高度。
像圖上寫的這樣,文字轉圖片分三步:
計算文字寬高 生成響應尺寸背景圖 把文字寫到圖片上計算文字寬高
這里背景圖寬度是固定的,所以文字的寬可以不用計算。 PIL.ImageDraw.ImageDraw.text
是通過 /n 來換行的,那我們只需要在文字合適的位置加上 /n 就可以了。
第一個想到的是 textwrap 方法,textwrap 可以實現通過調整換行符的位置來格式化文本。但 textwrap 還有一個問題就是它是根據字符長度來分隔的,但文本中的字符并不是等寬的,通過 textwrap 格式化后的文字寫到圖片上效果可能是這樣的:
使用這種方式,如果我們要調整字體大小,每一行的長度都還需要再重新調整。
為了保證每一行寬度盡可能的一致,這里使用 PIL.ImageDraw.ImageDraw.textsize
獲取字符寬高,然后按約定寬度把長文本分隔成文本列表,然后把列表每行文字寫到圖片上。
def get_paragraph(text, note_width): # 把每段文字按約定寬度分隔成幾行 txt = Image.new('RGBA', (100, 100), (255, 255, 255, 0)) # get a drawing context draw = ImageDraw.Draw(txt) paragraph, sum_width = '', 0 line_numbers, line_height = 1, 0 for char in text: w, h = draw.textsize(char, font) sum_width += w if sum_width > note_width: line_numbers += 1 sum_width = 0 paragraph += '/n' paragraph += char line_height = max(h, line_height) if not paragraph.endswith('/n'): paragraph += '/n' return paragraph, line_height, line_numbersdef split_text(text): # 將文本按規定寬度分組 max_line_height, total_lines = 0, 0 paragraphs = [] for t in text.split('/n'): # 先按 /n 把文本分段 paragraph, line_height, line_numbers = get_paragraph(t) max_line_height = max(line_height, max_line_height) total_lines += line_numbers paragraphs.append((paragraph, line_numbers)) line_height = max_line_height total_height = total_lines * line_height # 這里返回分好的段,文本總高度以及行高 return paragraphs, total_height, line_height
新聞熱點
疑難解答