Cómo renderizar un TTF-Glyf a una imagen con FontTools.
Quiero renderizar un glyf de una fuente TrueType en una imagen (numpy.array):
from fontTools.ttLib import TTFont
import matplotlib.pyplot as plt
font = TTFont('font.ttf')
glyf = font['glyf']['A']
coords = np.array(glyf.coordinates)
coords = np.swapaxes(coords,0,1)
plt.scatter(coords[0], coords[1])
Estos son los vértices.
¿Cómo puedo dibujar el glyf en un numpy.array? Encontré glyf.draw(...)
, pero no encontré un tutorial o ejemplos de cómo usarlo. Tampoco encontré ninguna información sobre el concepto de pluma.
Edit 1:
Encontré una forma de renderizar texto con pillow:
from PIL import ImageFont, ImageDraw, Image
image = Image.new(mode='L', size=(128,128), color=224)
draw = ImageDraw.Draw(image)
imageFont = ImageFont.truetype('font.ttf', 64)
draw.text((0, 0), "A", font=imageFont)
image
Eso es un buen comienzo, pero necesito más control sobre el resultado final. El glyf debería estar centrado y tener un tamaño que utilice el espacio de manera más eficiente.
También estoy interesado en las líneas de la cuadrícula, como la línea base y otras.
Edit 2:
Encontré algunas pistas en esta pregunta: https://stackoverflow.com/questions/43060479/how-to-get-the-font-pixel-height-using-pils-imagefont-class
from PIL import ImageFont, ImageDraw, Image
x_size = 128
y_size = 128
font_size = 64
imageFont = ImageFont.truetype('font.ttf', font_size)
ascent, descent = imageFont.getmetrics()
image = Image.new(mode='L', size=(x_size, y_size), color=224)
draw = ImageDraw.Draw(image)
text = 'Aj;^'
draw.line([0,ascent,127,ascent], fill=128)
draw.line([0,descent,127,descent], fill=128)
draw.text((0, 0), text, font=imageFont)
image
Hay dos líneas que marcan dos puntos en el eje y. Pero como puedes ver, hay caracteres que se extienden más allá de una línea. Y los caracteres se superponen en la dirección x, como se puede ver en la “j” y la “A”.
Todavía necesito más control sobre el resultado final.
davy.ai
Para dibujar el glyf de una fuente TT en un numpy.array, puedes utilizar el método
glyf.draw()
. Este método toma como argumento un objetoPen
, el cual te permite controlar el proceso de renderizado. Aquí tienes un ejemplo de cómo puedes utilizarlo:En este ejemplo, creamos un objeto
NumpyPen
, que es una implementación de pluma que recopila las operaciones de dibujo del glyf en un array de numpy. Pasamos esta pluma al métodoglyf.draw()
, el cual renderiza el glyf en la pluma. Finalmente, extraemos el array de numpy de la pluma utilizando la propiedadarray
.Para controlar el resultado final, puedes ajustar el tamaño del array de numpy y la escala de la pluma. Por ejemplo:
Aquí, creamos un objeto
NumpyPen
con un tamaño de(128, 128)
y una escala que ajusta el glyf a la altura de la imagen. Esto también escala el glyf horizontalmente, pero puedes ajustar la escala según tus necesidades.Para agregar líneas de cuadrícula, puedes utilizar el método
draw.line()
del objetoImageDraw
de PIL. Aquí tienes un ejemplo:En este ejemplo, creamos un objeto de imagen PIL y un objeto
ImageDraw
. Obtenemos las métricas de ascenso y descenso de la fuente y dibujamos dos líneas en las posiciones y correspondientes. Luego, dibujamos el glyf centrado en la imagen utilizando el métododraw.text()
. Finalmente, convertimos la imagen PIL en un array de numpy.Ten en cuenta que la altura de la imagen debe ser mayor o igual a la suma de las métricas de ascenso y descenso de la fuente, de lo contrario el glyf puede quedar cortado.