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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4902198/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 18:02:27  来源:igfitidea点击:

PIL how to scale text size in relation to the size of the image

pythonfontsimage-manipulationpython-imaging-libraryscaling

提问by Shpongle

I'm trying to dynamically scale text to be placed on images of varying but known dimensions. The text will be applied as a watermark. Is there any way to scale the text in relation to the image dimensions? I don't require that the text take up the whole surface area, just to be visible enough so its easily identifiable and difficult to remove. I'm using Python Imaging Library version 1.1.7. on Linux.

我正在尝试动态缩放文本以放置在不同但已知尺寸的图像上。文本将作为水印应用。有没有办法根据图像尺寸缩放文本?我不要求文本占据整个表面区域,只是为了足够可见,以便易于识别且难以删除。我正在使用 Python 图像库版本 1.1.7。在 Linux 上。

I would like to be able to set the ratio of the text size to the image dimensions, say like 1/10 the size or something.

我希望能够设置文本大小与图像尺寸的比例,比如大小的 1/10 之类的。

I have been looking at the font size attribute to change the size but I have had no luck in creating an algorithm to scale it. I'm wondering if there is a better way.

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

Any ideas on how I could achieve this?

关于如何实现这一目标的任何想法?

Thanks

谢谢

采纳答案by Paul

You could just increment the font size until you find a fit. font.getsize()is the function that tells you how large the rendered text is.

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

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

If this is not efficient enough for you, you can implement a root-finding scheme, but I'm guessing that the font.getsize()function is small potatoes compared to the rest of your image editing processes.

如果这对您来说不够有效,您可以实施寻根方案,但我猜这个font.getsize()功能与您的其他图像编辑过程相比是小土豆。

回答by Pharaun

In general when you change the font sizing its not going to be a linear change in size of the font.

一般来说,当您更改字体大小时,它不会是字体大小的线性变化。

Non-linear Scaling

非线性缩放

Now this often depends on the software, fonts, etc... This example was taken from Typophileand uses LaTex + Computer Modern font. As you can see its not exactly a linear scaling. So if you are having trouble with non-linear font scaling then I'm not sure how to resolve it, but one suggestion maybe is to.

现在这通常取决于软件、字体等...这个例子取自Typophile并使用 LaTex + Computer Modern 字体。正如您所看到的,它不完全是线性缩放。因此,如果您在非线性字体缩放方面遇到问题,那么我不确定如何解决它,但一个建议可能是。

  1. Render the font as closely to the size that you want, then scale that up/down via regular image scaling algorithm...
  2. Just accept that it won't exactly be linear scaling and try to create some sort of table/algorithm that will select the closest point size for the font to match up with the image size.
  1. 将字体渲染成您想要的大小,然后通过常规图像缩放算法放大/缩小...
  2. 接受它不会完全是线性缩放并尝试创建某种表格/算法,该算法将为字体选择最接近的点大小以匹配图像大小。

回答by Nachtalb

I know this is an old question that has already been answered with a solutionthat I too have used. Thanks, @Paul!

我知道这是一个老问题,我也用过的解决方案已经回答了这个问题。谢谢,@保罗!

Though with increasing the font size by one for each iteration can be time-consuming (at least for me on my poor little server). So eg. small text (like "Foo") would take around 1 - 2 seconds, depending on the image size.

尽管每次迭代将字体大小增加 1 可能会很耗时(至少对于我在我可怜的小服务器上)。所以例如。小文本(如“Foo”)大约需要 1 - 2 秒,具体取决于图像大小。

To solve that I adjusted Pauls code so that it searches for the number somewhat like a binary search.

为了解决这个问题,我调整了 Pauls 代码,使其搜索数字有点像二进制搜索。

breakpoint = img_fraction * photo.size[0]?
jumpsize = 75?
while True:?
    if font.getsize(text)[0] < breakpoint:?
        fontsize += jumpsize?
    else:?
        jumpsize = int(jumpsize / 2)?
        fontsize -= jumpsize?
    font = ImageFont.truetype(font_path, fontsize)?
    if jumpsize <= 1:?
        break?

Like this, it increases the font size until it's above the breakpoint and from there on out it goes up and down with (cutting the jump size in half with each down) until it has the right size.

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

With that, I could reduce the steps from around 200+ to about 10 and so from around 1-2 sec to 0.04 to 0.08 sec.

有了这个,我可以将步骤从大约 200+ 减少到大约 10,因此从大约 1-2 秒减少到 0.04 到 0.08 秒。

This is a drop-in replacement for Pauls code (for the whilestatement and the 2 lines after it because you already get the font correct font size in the while)

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

This was done in a few mins so any improvements are appreciated! I hope this can help some who are looking for a bit more performant friendly solution.

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