使用PIL在图片上添加文字

128

我的应用程序加载了一张图片,当用户点击它时,会出现一个文本区域(使用jquery),用户可以在图片上写入一些文字。这些文字应该加在图像上。

经过一些研究,我发现 PIL(Python Imaging Library)可以帮助我实现这个功能。因此,我尝试了几个示例来看看它的工作原理,并成功地在图像上写入了文本。但是当我在 web 环境中尝试使用 PIL 时,我发现与在 Python Shell 中的效果有所不同。我的意思是文本区域中的文本非常大。如何在使用 PIL 时实现与文本区域相同大小的文本?

文本是多行的。我怎样才能使它在图像中也是多行的,而且还要使用 PIL

除了使用 PIL,是否有更好的方法?我不确定这是否是最佳实现。

HTML:

<img src="images/test.jpg"/>

这是正在被编辑的图片

var count = 0;
$('textarea').autogrow();
$('img').click(function(){
    count = count + 1;
    if (count > 1){
        $(this).after('<textarea />');
        $('textarea').focus();
    }   
});

使用 jQuery 添加文本区域。 此外,文本区域是绝对定位和固定大小的。

我应该将其放在表单中,以便获取图像上文本区域的坐标吗? 当用户单击时,我想在图像上写入文本并将其保存在图像上。


为什么你想使用PIL在图像上写文本(我不确定PIL是否有帮助)。难道在叠加层中显示文本不足以满足你的需求吗?这是最常用于滑块的方法。 - lalit
1
我需要它用于一个项目,我希望图像能够被保存。Pil可以使用ImageDraw在图像上绘制文本,不知道是否还有其他方法。 - Apostolos
如果您能提供您正在使用的Python代码,那将非常有帮助。 - lalit
尚未在Django中实现。我尝试在交互式Python控制台中了解PIL的工作原理。想先看看它是否有效,然后再将其转移到Django中。 - Apostolos
你的代码中的$符号是什么意思? - Mugen
10个回答

217

我认为PIL中可用的ImageFont模块可以帮助解决文本字体大小问题。只需确定适合您的字体类型和大小,然后使用以下函数更改字体值。

# font = ImageFont.truetype(<font-file>, <font-size>)
# font-file should be present in provided path.
font = ImageFont.truetype("sans-serif.ttf", 16)

所以你的代码将类似于:

from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw 

img = Image.open("sample_in.jpg")
draw = ImageDraw.Draw(img)
# font = ImageFont.truetype(<font-file>, <font-size>)
font = ImageFont.truetype("sans-serif.ttf", 16)
# draw.text((x, y),"Sample Text",(r,g,b))
draw.text((0, 0),"Sample Text",(255,255,255),font=font)
img.save('sample-out.jpg')

如果你想根据用户在TextArea中提供的文本数量来更改字体大小,则可能需要付出额外的努力。

要添加换行(多行文本),只需大致估计一行可以放多少个字符,然后您可以编写一个预处理函数来处理您的文本,该函数基本上查找每行最后一个字符并将此字符之前的空格转换为新行。


1
这是我的初步想法。那么,我需要将字体放在特定的文件夹中才能在我的Web服务器上工作吗?我认为是的。换行文本?有标准的方法还是必须自己实现一个? - Apostolos
您可以将字体文件放在网站服务器上的任何位置。只需确保提供的路径是正确的即可。 - lalit
12
我尝试在Windows机器上运行你的代码,但出现了字体错误self.font = core.getfont(file, size, index, encoding) IOError: cannot open resource。我该如何提供字体文件的路径? - LWZ
5
要运行上述代码,请确保字体文件位于执行上述代码的当前目录中。如果您将其用于程序中,请指定文件的完整路径,例如“C:\ Windows \ Fonts \ sans-serif.ttf”。您需要确保的另一件事是为该文件授予适当的读取权限。 - lalit
4
font = ImageFont.truetype("./arial.ttf", 30);draw.textsize(msg, font=font)。这段代码意思是从"./arial.ttf"路径下加载字体文件,定义大小为30。然后使用该字体计算文本“msg”的尺寸。 - WeizhongTu
显示剩余4条评论

38

更极简的例子(在图像的左上角用默认字体以黑色绘制“Hello world!”):

...
from PIL import ImageDraw
...
ImageDraw.Draw(
    image  # Image
).text(
    (0, 0),  # Coordinates
    'Hello world!',  # Text
    (0, 0, 0)  # Color
)

我也意识到可以在没有指定字体的情况下使用 .text。但是如果没有指定字体,有没有一种方法可以指定大小呢? - Lori
1
load_default似乎没有指定字体大小的方法。 :/ - Solomon Ucko
如何使用此功能控制字体大小? - Gulzar
1
@Gulzar 很遗憾,似乎没有任何方法可以控制字体大小。 - Solomon Ucko

18
你可以在项目的根目录下创建一个名为 "fonts" 的文件夹,并将你的字体(sans_serif.ttf)文件放在那里。然后,你可以像这样做:

您可以在项目的根目录中创建一个名为“ fonts”的目录,并在其中放置您的字体文件(sans_serif.ttf)。然后,您可以进行以下操作:

fonts_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'fonts')
font = ImageFont.truetype(os.path.join(fonts_path, 'sans_serif.ttf'), 24)

15

首先安装pillow

pip install pillow

例子

from PIL import Image, ImageDraw, ImageFont

image = Image.open('Focal.png')
width, height = image.size 

draw = ImageDraw.Draw(image)

text = 'https://devnote.in'
textwidth, textheight = draw.textsize(text)

margin = 10
x = width - textwidth - margin
y = height - textheight - margin

draw.text((x, y), text)

image.save('devnote.png')

# optional parameters like optimize and quality
image.save('optimized.png', optimize=True, quality=50)

13

首先,您需要下载字体类型...例如:https://www.wfonts.com/font/microsoft-sans-serif

之后,使用以下代码来绘制文本:

from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw 
img = Image.open("filename.jpg")
draw = ImageDraw.Draw(img)
font = ImageFont.truetype(r'filepath\..\sans-serif.ttf', 16)
draw.text((0, 0),"Draw This Text",(0,0,0),font=font) # this will draw text with Blackcolor and 16 size

img.save('sample-out.jpg')

12

其他答案中未提到的一件事是检查文本大小。通常需要确保文本适合图像(例如,如果过大,则缩短文本),或确定绘制文本的位置(例如,顶部居中对齐的文本)。 Pillow/PIL提供了两种方法来检查文本大小,一种是通过ImageFont,另一种是通过ImageDraw。如下所示,字体无法处理多行文本,而ImageDraw可以。

In [28]: im = Image.new(mode='RGB',size=(240,240))                                                            
In [29]: font = ImageFont.truetype('arial')
In [30]: draw = ImageDraw.Draw(im)
In [31]: t1 = 'hello world!'
In [32]: t2 = 'hello \nworld!'
In [33]: font.getsize(t1), font.getsize(t2) # the height is the same
Out[33]: ((52, 10), (60, 10)) 
In [35]: draw.textsize(t1, font), draw.textsize(t2, font)  # handles multi-lined text
Out[35]: ((52, 10), (27, 24)) 

感谢您指出这个差别。我确实想要在多行中获得正确的文本大小。 - fcole90

8

使用Pillow,您还可以使用ImageDraw模块在图像上绘制内容。您可以绘制线条、点、椭圆、矩形、弧线、位图、和弦、饼图、多边形、形状以及文字。

from PIL import Image, ImageDraw
blank_image = Image.new('RGBA', (400, 300), 'white')
img_draw = ImageDraw.Draw(blank_image)
img_draw.rectangle((70, 50, 270, 200), outline='red', fill='blue')
img_draw.text((70, 250), 'Hello World', fill='green')
blank_image.save('drawn_image.jpg')

我们使用new()方法创建一个Image对象。这将返回一个没有加载图像的Image对象。然后我们向图像添加矩形和一些文本,最后保存它。


3

我最近也需要实现同样的功能。我在 PyPI 上创建了一个包,可能会很有用:pynter

您可以按照以下步骤在图像中添加文本:

  1. 下载一张图片:curl https://i.imgur.com/XQCKcC9.jpg -o ./image.jpg

  2. 下载字体:curl https://fonts.google.com/download?family=Roboto -o ./roboto.zip ; unzip ./roboto.zip -d ./Roboto

  3. pip install pynter

from pynter.pynter import generate_captioned
font_path = './Roboto/Roboto-Regular.ttf'
image_path = './image.jpg'
im = generate_captioned('China lands rover on Mars'.upper(), image_path=image_path, size=(1080, 1350),
                        font_path=font_path, filter_color=(0, 0, 0, 40))
im.show()
im.convert('RGB').save('drawn_image.jpg')

这将是结果:

enter image description here


-2

目前你的回答不够清晰。请编辑并添加更多细节,以帮助其他人理解它如何回答所提出的问题。你可以在帮助中心找到有关如何撰写好答案的更多信息。 - Community
虽然这个链接可能回答了问题,但最好在此处包含答案的基本部分并提供参考链接。如果链接页面更改,仅有链接的答案可能会变得无效。-【来自审查】 - Jakob Em

-11

如何在图像文件上添加文字,只需复制/粘贴下面的代码

<?php
$source = "images/cer.jpg";
$image = imagecreatefromjpeg($source);
$output = "images/certificate".rand(1,200).".jpg";
$white = imagecolorallocate($image,255,255,255);
$black = imagecolorallocate($image,7,94,94);
$font_size = 30;
$rotation = 0;
$origin_x = 250;
$origin_y = 450;
$font = __DIR__ ."/font/Roboto-Italic.ttf";
$text = "Dummy";
$text1 = imagettftext($image,$font_size,$rotation,$origin_x,$origin_y,$black,$font,$text);
     imagejpeg($image,$output,99);
?> <img src="<?php echo $output; ?>"> <a href="<?php echo $output;    ?>" download="<?php echo $output; ?>">Download Certificate</a>

1
这是PHP,问题是关于Python的。 - moi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接