在Python中使用给定的字体正确渲染文本并准确检测其边界 [英] Properly render text with a given font in Python and accurately detect its boundaries

查看:277
本文介绍了在Python中使用给定的字体正确渲染文本并准确检测其边界的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这可能很简单,我也认为应该如此,但事实并非如此.我必须花一个星期的时间才能完成这项工作,但是我对自己的爱无法实现.

This might strike as something very simple, and I too thought it'd be, but it apparently isn't. I must've spent a week trying to make this work, but I for the love of me can't manage to do so.

我需要的

我需要用Python中的任何给定字体(类似手写体)呈现任何给定的字符串(仅包含标准字符).字体必须从TTF文件中加载.我还需要能够准确地检测出其边界(最好在绘制之前,在垂直和水平方向上获得文本的确切开始和结束位置).最后,如果输出是一个我可以继续处理的数组,而不是将图像文件写入磁盘,那么这真的会让我的生活更轻松.

I need to render any given string (only containing standard characters) with any given font (handwritten-like) in Python. The font must be loaded from a TTF file. I also need to be able to accurately detect its borders (get the exact start and end position of the text, vertically and horizontally), preferably before drawing it. Lastly, it'd really make my life easier if the output is an array which I can then keep processing, and not an image file written to disc.

我尝试过的事情

Imagemagick绑定(即魔杖):在设置图像大小并在其上呈现文本之前,无法弄清楚如何获取文本指标.

Imagemagick bindings (namely Wand): Couldn't figure out how to get the text metrics before setting the image size and rendering the text on it.

通过Pycairo绑定的Pango:几乎不存在的文档,无法弄清楚如何从文件中加载TrueType字体.

Pango via Pycairo bindings: nearly inexistent documentation, couldn't figure out how to load a TrueType font from a file.

PIL(枕头):最有前途的选择.我已经设法准确地计算了任何文本的高度(令人惊讶的是,高度getsize返回的不是),但是某些字体的宽度似乎有问题.不仅如此,那些宽度较宽的字体也会被错误地渲染.即使将图像放大到足够大,它们也会被切除.

PIL (Pillow): The most promising option. I've managed to accurately calculate the height for any text (which surprisingly is not the height getsize returns), but the width seems buggy for some fonts. Not only that, but those fonts with buggy width also get rendered incorrectly. Even when making the image large enough, they get cut off.

以下是一些示例,文字为"Puzzling":

Here are some examples, with the text "Puzzling":

字体:恋人争吵

结果:

字体:法加尔多斯小姐

结果:

这是我用来生成图像的代码:

This is the code I'm using to generate the images:

from PIL import Image, ImageDraw, ImageFont
import cv2
import numpy as np
import glob
import os

font_size = 75
font_paths = sorted(glob.glob('./fonts/*.ttf'))
text = "Puzzling"
background_color = 180
text_color = 50
color_variance = 60
cv2.namedWindow('display', 0)

for font_path in font_paths:

    font = ImageFont.truetype(font_path, font_size)
    text_width, text_height = font.getsize(text)

    ascent, descent = font.getmetrics()
    (width, baseline), (offset_x, offset_y) = font.font.getsize(text)

    # +100 added to see that text gets cut off
    PIL_image = Image.new('RGB', (text_width-offset_x+100, text_height-offset_y), color=0x888888)
    draw = ImageDraw.Draw(PIL_image)
    draw.text((-offset_x, -offset_y), text, font=font, fill=0)

    cv2.imshow('display', np.array(PIL_image))
    k = cv2.waitKey()
    if chr(k & 255) == 'q':
        break

一些问题

字体是问题吗?一些同事告诉我可能是这样,但是我不这么认为,因为Imagemagick可以通过命令行正确地渲染它们.

Are the fonts the problem? I've been told by some colleagues that might be it, but I don't think so, since they get rendered correctly by the Imagemagick via command line.

我的代码有问题吗?我在做错什么导致文本被截断吗?

Is my code the problem? Am I doing something wrong which is causing the text to get cut off?

最后,这是PIL中的错误吗?在这种情况下,您建议我使用哪个库解决问题?我应该再给Pango和Wand再试一次吗?

Lastly, is it a bug in PIL? In that case, which library do you recommend I use to solve my problem? Should I give Pango and Wand another try?

推荐答案

pyvips 似乎正确地做到这一点.我试过了:

pyvips seems to do this correctly. I tried this:

$ python3
Python 3.7.3 (default, Apr  3 2019, 05:39:12) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pyvips
>>> x = pyvips.Image.text("Puzzling", dpi=300, font="Miss Fajardose", fontfile="/home/john/pics/MissFajardose-Regular.ttf")
>>> x.write_to_file("x.png")

制作:

pyvips文档对选项进行了快速介绍:

The pyvips docs have a quick intro to the options:

https://libvips.github.io/pyvips/vimage .html#pyvips.Image.text

或者C库文档有更多详细信息:

Or the C library docs have a lot more detail:

http://libvips.github.io /libvips/API/current/libvips-create.html#vips-text

它会生成一个抗锯齿文本的单波段8位图像,您可以将其用于进一步处理,传递给NumPy或PIL等.在简介中有一节介绍了如何将libvips图像转换为数组:

It makes a one-band 8-bit image of the antialiased text which you can use for further processing, pass to NumPy or PIL, etc etc. There's a section in the intro on how to convert libvips images into arrays:

https://libvips.github.io/pyvips/intro .html#numpy-and-pil

这篇关于在Python中使用给定的字体正确渲染文本并准确检测其边界的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆