Python 图像库 - 文本渲染

发布于 2024-10-25 06:37:51 字数 638 浏览 1 评论 0原文

我正在尝试使用 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)

I'm trying to render some text using PIL, but the result that comes out is, frankly, crap.

For example, here's some text I wrote in Photoshop:

PhotoShop

and what comes out of PIL:

PIL

As you can see, the results from PIL is less than satisfactory. Maybe I'm just being picky, but is there any way to draw text using PIL that gets results more close to my reference image?

Here's the code I'm using on Python 2.7 with 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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

万劫不复 2024-11-01 06:37:52

我提出了自己认为可以接受的解决方案。

我所做的是将文本渲染得很大,比如需要的大小的 3 倍,然后使用抗锯齿功能对其进行缩放,它不是 100% 完美,但它比默认值要好得多,并且不需要 cairo 或潘戈。

例如,

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)

你最终得到这个结果

final result

这比我之前得到的结果要好得多字体。

I came up with my own solution that I find acceptable.

What I did was render the text large, like 3x the size it needs to be then scale it resize it down with antialiasing, it's not 100% perfect, but it's a hell of a lot better than default, and doesn't require cairo or pango.

for example,

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)

and you endup with this result,

final result

which is a lot better than what I was getting before with the same font.

我恋#小黄人 2024-11-01 06:37:52

尝试使用 pycairo - Cairo 绘图库的 python 绑定 - 它对于更精致的绘图很有用,带有抗锯齿线,
等等 - 您也可以生成基于矢量的图像

正确处理字体,并且布局很复杂,并且需要使用
还有“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)

渲染图像

Try using pycairo - the python bindings for the Cairo drawing library -- it is usefull for more refined drawing, with antialiased lines,
and such - and you can generate vector based images as well

Correctly handling fonts, and layout is complicated, and requires the use of
the "pango" and "pangocairo" libraries as well. Although they are made
for serious font work (all GTK+ widgets do use pango for font rendering),
the available docuemtnation and examples are extremely poor.

The sample bellow shows the prints available in the system and renders the
sample text in a font family passed as parameter on the command line.

# -*- 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)

Rendred image

情徒 2024-11-01 06:37:52

我从未使用过 PIL,但快速浏览一下 Draw 方法的文档表明 PIL 提供了一种渲染简单图形的方法。 Photoshop 提供了一种渲染复杂图形的方法。要获得接近 Photoshop 的效果,至少需要字体提示和抗锯齿功能。 PIL 的文档甚至没有暗示具有此类功能。您可能想考虑使用外部工具,它可以更好地在图像上渲染文本。例如,ImageMagick(您需要使用 8 位版本,它处理标准 24 位 RGB)。您可以在这里找到一些文本绘制示例:http://www.imagemagick.org/Usage/draw/

I've never used PIL, but a quick review of the documentation for the Draw method indicates that PIL provides a way to render simple graphics. Photoshop provides a way to render complex graphics. To get anywhere close to Photoshop-like results requires, at a minimum, font hinting and anti-aliasing. PIL's documentation doesn't even hint at having such capabilities. You may want to look at using an external tool that might do a better job of rendering text on images. For example, ImageMagick (you'll want to use the 8-bit version, which handles standard 24-bit RGB). You can find some text drawing samples here: http://www.imagemagick.org/Usage/draw/

ˇ宁静的妩媚 2024-11-01 06:37:52

在 python3 中,有一个别名字体的选项。我在任何地方都找不到这个答案,希望它能帮助像我这样在谷歌上找到这个问题并不得不挖掘很长时间才能找到答案的人。

draw = ImageDraw.Draw(img)
        draw.fontmode = "L"

在此处的文档中提到

In python3 there is an option for aliased fonts. I couldn't find this answer anywhere, hopefully it helps someone like me who found this question on google and had to dig a long time to find the answer.

draw = ImageDraw.Draw(img)
        draw.fontmode = "L"

Mentioned in the docs here

妖妓 2024-11-01 06:37:52

建议:使用 Wand 或其他成像库

这是一个使用 wand 的示例 -

from wand.color import Color
from wand.image import Image
from wand.drawing import Drawing
from wand.compat import nested

with Drawing() as draw:
    with Image(width=1000, height=100, background=Color('lightblue')) as img:
        draw.font_family = 'Indie Flower'
        draw.font_size = 40.0
        draw.push()
        draw.fill_color = Color('hsl(0%, 0%, 0%)')
        draw.text(0,int(img.height/2 + 20), 'Hello, world!')
        draw.pop()
        draw(img)
        img.save(filename='image.png')

出现的图像-

Suggestion: use Wand or a different Imaging library

Here's an example with wand -

from wand.color import Color
from wand.image import Image
from wand.drawing import Drawing
from wand.compat import nested

with Drawing() as draw:
    with Image(width=1000, height=100, background=Color('lightblue')) as img:
        draw.font_family = 'Indie Flower'
        draw.font_size = 40.0
        draw.push()
        draw.fill_color = Color('hsl(0%, 0%, 0%)')
        draw.text(0,int(img.height/2 + 20), 'Hello, world!')
        draw.pop()
        draw(img)
        img.save(filename='image.png')

image that comes out-

ペ泪落弦音 2024-11-01 06:37:52

从你的例子来看:

d_usr = ImageDraw.Draw(image)
d_usr.fontmode = "1" ### NEW
d_usr.text((105,280), "Travis L.",(0,0,0), font=usr_font)

From your example:

d_usr = ImageDraw.Draw(image)
d_usr.fontmode = "1" ### NEW
d_usr.text((105,280), "Travis L.",(0,0,0), font=usr_font)
蓦然回首 2024-11-01 06:37:52

您还可以尝试将字体写两次,这样可以极大地提高质量。

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)
d_usr = d_usr.text((105,280), "Travis L.",(0,0,0), font=usr_font)

You can also try to write the font two times it increases the quality immense.

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)
d_usr = d_usr.text((105,280), "Travis L.",(0,0,0), font=usr_font)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文