Python图像库 - 文本渲染

45 投票
6 回答
59910 浏览
提问于 2025-04-16 14:18

我正在尝试用PIL来渲染一些文字,但出来的效果,老实说,真是糟糕。

比如说,这是我在Photoshop里写的一些文字:

PhotoShop

而这是用PIL出来的效果:

PIL

你可以看到,PIL的效果实在不太令人满意。也许我有点挑剔,但有没有什么方法可以用PIL绘制文字,让效果更接近我参考的图片呢?

这是我在Python 2.7和PIL 1.1.7上使用的代码:

image = Image.new("RGBA", (288,432), (255,255,255))
usr_font = ImageFont.truetype("resources/HelveticaNeueLight.ttf", 25)
d_usr = ImageDraw.Draw(image)
d_usr = d_usr.text((105,280), "Travis L.",(0,0,0), font=usr_font)

6 个回答

12

我之前没用过PIL,但我快速看了一下它的Draw方法的文档,发现PIL主要是用来绘制简单的图形。而Photoshop则是用来处理复杂的图形。如果你想要的效果接近Photoshop,至少需要有字体提示和抗锯齿的功能。但PIL的文档里似乎并没有提到这些功能。你可能需要考虑使用其他工具,这些工具在图像上绘制文字的效果可能会更好。例如,ImageMagick(你可以使用8位版本,它可以处理标准的24位RGB颜色)。你可以在这里找到一些文字绘制的示例:http://www.imagemagick.org/Usage/draw/

21

可以试试 pycairo,这是一个用来绘图的Python库,它基于Cairo绘图工具。这个库特别适合做一些更精细的绘图,比如有抗锯齿效果的线条等等,而且你还可以生成基于矢量的图像。

不过,正确处理字体和布局是比较复杂的,需要用到“pango”和“pangocairo”这两个库。虽然这两个库是为了处理字体而设计的(所有的GTK+控件都用pango来渲染字体),但它们的文档和示例实在是太少了,帮助不大。

下面的示例展示了系统中可用的打印机,并且根据命令行传入的参数渲染了一段示例文本,使用了指定的字体。

# -*- coding: utf-8 -*-
import cairo
import pango
import pangocairo
import sys

surf = cairo.ImageSurface(cairo.FORMAT_ARGB32, 320, 120)
context = cairo.Context(surf)

#draw a background rectangle:
context.rectangle(0,0,320,120)
context.set_source_rgb(1, 1, 1)
context.fill()

#get font families:

font_map = pangocairo.cairo_font_map_get_default()
families = font_map.list_families()

# to see family names:
print [f.get_name() for f in   font_map.list_families()]

#context.set_antialias(cairo.ANTIALIAS_SUBPIXEL)

# Positions drawing origin so that the text desired top-let corner is at 0,0
context.translate(50,25)

pangocairo_context = pangocairo.CairoContext(context)
pangocairo_context.set_antialias(cairo.ANTIALIAS_SUBPIXEL)

layout = pangocairo_context.create_layout()
fontname = sys.argv[1] if len(sys.argv) >= 2 else "Sans"
font = pango.FontDescription(fontname + " 25")
layout.set_font_description(font)

layout.set_text(u"Travis L.")
context.set_source_rgb(0, 0, 0)
pangocairo_context.update_layout(layout)
pangocairo_context.show_layout(layout)

with open("cairo_text.png", "wb") as image_file:
    surf.write_to_png(image_file)

渲染的图像

69

我想出了一个我觉得还不错的解决办法。

我做的就是把文字放大,放到需要大小的三倍,然后再缩小回来,同时使用抗锯齿技术。虽然效果不是百分之百完美,但比起默认的效果要好很多,而且不需要用到cairo或pango这些工具。

比如说,

image = Image.new("RGBA", (600,150), (255,255,255))
draw = ImageDraw.Draw(image)
font = ImageFont.truetype("resources/HelveticaNeueLight.ttf", fontsize)

draw.text((10, 0), txt, (0,0,0), font=font)
img_resized = image.resize((188,45), Image.ANTIALIAS)

最后你会得到这样的效果,

最终效果

这个效果比我之前用同样字体得到的效果要好得多。

撰写回答