从给定文本生成图像
Generate image from given text
我有一个函数可以使用 Pillow 生成给定文本的图像表示,将 text
、font
、font_size
和 color
用作输入。
该函数的工作原理是生成一个空的 RGBA 图像作为起点,然后在其上绘制文本,最后裁剪结果以仅保留文本。
现在,在 99% 的情况下,该功能运行良好,但对于更大的字体,我需要更大的 canvas 才能开始,否则文本会被截断。
出于这个原因,我将初始 canvas 设置为具有非常高的值,例如 (10k, 10k)
像素。这个初始图像大小减慢了整个过程,我想知道是否有一种方法可以获得相同的结果而不必求助于初始空图像,或者生成尽可能小的初始图像大小为了不
我的函数是这样的:
def text_to_image(
text: str,
font_filepath: str,
font_size: int,
color: Tuple[int, int, int, int],
) -> ImageType:
# ?: very big canvas size as to not to clip the text when rendered with bigger font sizes
canvas_size = (
10000,
10000,
)
img = Image.new("RGBA", canvas_size)
draw = ImageDraw.Draw(img)
draw_point = (0, 0)
font = ImageFont.truetype(font_filepath, size=font_size)
draw.multiline_text(draw_point, text, font=font, fill=color)
text_window = img.getbbox()
img = img.crop(text_window)
return img
示例结果:
编辑:
感谢@AKX 的超级快速响应解决了我的问题。对于任何感兴趣的人,函数变为
def text_to_image(
text: str,
font_filepath: str,
font_size: int,
color: Tuple[int, int, int, int],
) -> ImageType:
font = ImageFont.truetype(font_filepath, size=font_size)
img = Image.new("RGBA", font.getmask(text).size)
draw = ImageDraw.Draw(img)
draw_point = (0, 0)
draw.multiline_text(draw_point, text, font=font, fill=color)
text_window = img.getbbox()
img = img.crop(text_window)
return img
您可以使用 getmask()
函数获取与给定文本大小完全相同的灰度位图。
然后您可以创建一个具有所需背景颜色的空图像。
然后使用 im.paste()
纯色和遮罩在文本中绘制:
from PIL import Image, ImageFont
text = "Hello world!"
font_size = 36
font_filepath = "/Library/Fonts/Artegra_Sans-600-SemiBold-Italic.otf"
color = (67, 33, 116, 155)
font = ImageFont.truetype(font_filepath, size=font_size)
mask_image = font.getmask(text, "L")
img = Image.new("RGBA", mask_image.size)
img.im.paste(color, (0, 0) + mask_image.size, mask_image) # need to use the inner `img.im.paste` due to `getmask` returning a core
img.save("yes.png")
我有一个函数可以使用 Pillow 生成给定文本的图像表示,将 text
、font
、font_size
和 color
用作输入。
该函数的工作原理是生成一个空的 RGBA 图像作为起点,然后在其上绘制文本,最后裁剪结果以仅保留文本。
现在,在 99% 的情况下,该功能运行良好,但对于更大的字体,我需要更大的 canvas 才能开始,否则文本会被截断。
出于这个原因,我将初始 canvas 设置为具有非常高的值,例如 (10k, 10k)
像素。这个初始图像大小减慢了整个过程,我想知道是否有一种方法可以获得相同的结果而不必求助于初始空图像,或者生成尽可能小的初始图像大小为了不
我的函数是这样的:
def text_to_image(
text: str,
font_filepath: str,
font_size: int,
color: Tuple[int, int, int, int],
) -> ImageType:
# ?: very big canvas size as to not to clip the text when rendered with bigger font sizes
canvas_size = (
10000,
10000,
)
img = Image.new("RGBA", canvas_size)
draw = ImageDraw.Draw(img)
draw_point = (0, 0)
font = ImageFont.truetype(font_filepath, size=font_size)
draw.multiline_text(draw_point, text, font=font, fill=color)
text_window = img.getbbox()
img = img.crop(text_window)
return img
示例结果:
编辑:
感谢@AKX 的超级快速响应解决了我的问题。对于任何感兴趣的人,函数变为
def text_to_image(
text: str,
font_filepath: str,
font_size: int,
color: Tuple[int, int, int, int],
) -> ImageType:
font = ImageFont.truetype(font_filepath, size=font_size)
img = Image.new("RGBA", font.getmask(text).size)
draw = ImageDraw.Draw(img)
draw_point = (0, 0)
draw.multiline_text(draw_point, text, font=font, fill=color)
text_window = img.getbbox()
img = img.crop(text_window)
return img
您可以使用 getmask()
函数获取与给定文本大小完全相同的灰度位图。
然后您可以创建一个具有所需背景颜色的空图像。
然后使用 im.paste()
纯色和遮罩在文本中绘制:
from PIL import Image, ImageFont
text = "Hello world!"
font_size = 36
font_filepath = "/Library/Fonts/Artegra_Sans-600-SemiBold-Italic.otf"
color = (67, 33, 116, 155)
font = ImageFont.truetype(font_filepath, size=font_size)
mask_image = font.getmask(text, "L")
img = Image.new("RGBA", mask_image.size)
img.im.paste(color, (0, 0) + mask_image.size, mask_image) # need to use the inner `img.im.paste` due to `getmask` returning a core
img.save("yes.png")