我正在尝试动态缩放文本,以放置在不同但已知尺寸的图像上。文本将作为水印应用。有没有办法根据图像尺寸来缩放文本?我不要求文本占据整个表面积,只是为了足够明显,这样它就很容易识别,很难删除。我使用的是Python图像库版本1.1.7。在Linux上。
我希望能够设置文本大小与图像尺寸的比例,比如1/10的大小或其他什么。
我一直在查看字体大小属性以更改大小,但我没有幸运地创建一个算法来缩放它。我想知道有没有更好的方法。
有没有关于如何实现这一点的想法?
谢谢
发布于 2011-02-05 04:43:15
您可以增加字体大小,直到找到合适的字体。font.getsize()
是一个函数,它告诉您呈现的文本有多大。
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()
函数只是小菜一碟。
发布于 2020-05-19 20:26:57
我知道这是一个古老的问题,已经用我也用过的solution回答过了。谢谢,@Paul!
不过,每次迭代都将字体大小增加1可能很耗时(至少对我这个可怜的小服务器来说是如此)。所以,例如。较小的文本(如"Foo")大约需要1-2秒,具体取决于图像大小。
为了解决这个问题,我调整了Pauls的代码,使其在某种程度上像二进制搜索一样搜索数字。
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
中获得了正确的字体大小)
这是在几分钟内完成的,所以任何改进都是非常感谢的!我希望这能帮助一些正在寻找更高性能的友好解决方案的人。
发布于 2021-02-08 02:08:46
尽管其他答案说字体大小不是线性缩放的,但在我测试的所有示例中,它们都是线性缩放的(在1-2%范围内)。
因此,如果您需要一个更简单、更高效的版本,并且可以在百分之几的范围内工作,您可以复制/粘贴以下内容:
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()
(完整示例):
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的图像,它将打印:
>> Font size found = 22 - Target ratio = 0.5 - Measured ratio = 0.502
我用不同的字体和图片大小测试了find_font_size()
,它在所有情况下都能工作。
如果你想知道这个函数是如何工作的,tested_font_size
基本上是用来找出如果我们使用这个特定的字体大小来生成文本会得到什么样的比例。然后,我们使用交叉乘法规则来获得目标字体大小。
我测试了tested_font_size
的不同值,发现只要它不太小,就没有任何区别。
https://stackoverflow.com/questions/4902198
复制相似问题