首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >PIL如何根据图像大小缩放文本大小

PIL如何根据图像大小缩放文本大小
EN

Stack Overflow用户
提问于 2011-02-05 03:41:36
回答 3查看 72.7K关注 0票数 52

我正在尝试动态缩放文本,以放置在不同但已知尺寸的图像上。文本将作为水印应用。有没有办法根据图像尺寸来缩放文本?我不要求文本占据整个表面积,只是为了足够明显,这样它就很容易识别,很难删除。我使用的是Python图像库版本1.1.7。在Linux上。

我希望能够设置文本大小与图像尺寸的比例,比如1/10的大小或其他什么。

我一直在查看字体大小属性以更改大小,但我没有幸运地创建一个算法来缩放它。我想知道有没有更好的方法。

有没有关于如何实现这一点的想法?

谢谢

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-02-05 04:43:15

您可以增加字体大小,直到找到合适的字体。font.getsize()是一个函数,它告诉您呈现的文本有多大。

代码语言:javascript
复制
from PIL import ImageFont, ImageDraw, Image

image = Image.open('hsvwheel.png')
draw = ImageDraw.Draw(image)
txt = "Hello World"
fontsize = 1  # starting font size

# portion of image width you want text width to be
img_fraction = 0.50

font = ImageFont.truetype("arial.ttf", fontsize)
while font.getsize(txt)[0] < img_fraction*image.size[0]:
    # iterate until the text size is just larger than the criteria
    fontsize += 1
    font = ImageFont.truetype("arial.ttf", fontsize)

# optionally de-increment to be sure it is less than criteria
fontsize -= 1
font = ImageFont.truetype("arial.ttf", fontsize)

print('final font size',fontsize)
draw.text((10, 25), txt, font=font) # put the text on the image
image.save('hsvwheel_txt.png') # save it

如果这对您来说效率不够高,您可以实现一个根查找方案,但是我猜与您的其他图像编辑过程相比,font.getsize()函数只是小菜一碟。

票数 91
EN

Stack Overflow用户

发布于 2020-05-19 20:26:57

我知道这是一个古老的问题,已经用我也用过的solution回答过了。谢谢,@Paul!

不过,每次迭代都将字体大小增加1可能很耗时(至少对我这个可怜的小服务器来说是如此)。所以,例如。较小的文本(如"Foo")大约需要1-2秒,具体取决于图像大小。

为了解决这个问题,我调整了Pauls的代码,使其在某种程度上像二进制搜索一样搜索数字。

代码语言:javascript
复制
breakpoint = img_fraction * photo.size[0]
jumpsize = 75
while True:
    if font.getsize(text)[0] < breakpoint:
        fontsize += jumpsize
    else:
        jumpsize = jumpsize // 2
        fontsize -= jumpsize
    font = ImageFont.truetype(font_path, fontsize)
    if jumpsize <= 1:
        break

就像这样,它增加字体大小,直到它在断点之上,然后从那里开始向上和向下(每次向下将跳转大小减半),直到具有正确的大小。

这样,我就可以将200+附近的步骤减少到大约10步,也就是从大约1-2秒减少到0.04到0.08秒。

这是对Pauls代码的临时替换(用于while语句及其后面的2行,因为您已经在while中获得了正确的字体大小)

这是在几分钟内完成的,所以任何改进都是非常感谢的!我希望这能帮助一些正在寻找更高性能的友好解决方案的人。

票数 10
EN

Stack Overflow用户

发布于 2021-02-08 02:08:46

尽管其他答案说字体大小不是线性缩放的,但在我测试的所有示例中,它们都是线性缩放的(在1-2%范围内)。

因此,如果您需要一个更简单、更高效的版本,并且可以在百分之几的范围内工作,您可以复制/粘贴以下内容:

代码语言:javascript
复制
from PIL import ImageFont, ImageDraw, Image

def find_font_size(text, font, image, target_width_ratio):
    tested_font_size = 100
    tested_font = ImageFont.truetype(font, tested_font_size)
    observed_width, observed_height = get_text_size(text, image, tested_font)
    estimated_font_size = tested_font_size / (observed_width / image.width) * target_width_ratio
    return round(estimated_font_size)

def get_text_size(text, image, font):
    im = Image.new('RGB', (image.width, image.height))
    draw = ImageDraw.Draw(im)
    return draw.textsize(text, font)

然后可以像这样使用函数find_font_size() (完整示例):

代码语言:javascript
复制
width_ratio = 0.5  # Portion of the image the text width should be (between 0 and 1)
font_family = "arial.ttf"
text = "Hello World"

image = Image.open('image.jpg')
editable_image = ImageDraw.Draw(image)
font_size = find_font_size(text, font_family, image, width_ratio)
font = ImageFont.truetype(font_family, font_size)
print(f"Font size found = {font_size} - Target ratio = {width_ratio} - Measured ratio = {get_text_size(text, image, font)[0] / image.width}")

editable_image.text((10, 10), text, font=font)
image.save('output.png')

对于225x225的图像,它将打印:

代码语言:javascript
复制
>> Font size found = 22 - Target ratio = 0.5 - Measured ratio = 0.502

我用不同的字体和图片大小测试了find_font_size(),它在所有情况下都能工作。

如果你想知道这个函数是如何工作的,tested_font_size基本上是用来找出如果我们使用这个特定的字体大小来生成文本会得到什么样的比例。然后,我们使用交叉乘法规则来获得目标字体大小。

我测试了tested_font_size的不同值,发现只要它不太小,就没有任何区别。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/4902198

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档