es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

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])

enter image description here

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

enter image description here

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

enter image description here

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.

Tags:  ,

Answer

  1. Avatar for 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 objeto Pen, el cual te permite controlar el proceso de renderizado. Aquí tienes un ejemplo de cómo puedes utilizarlo:

    from fontTools.ttLib import TTFont
    from fontTools.pens.numpyPen import NumpyPen
    
    font = TTFont('font.ttf')
    glyf = font['glyf']['A']
    
    pen = NumpyPen(None)
    glyf.draw(pen)
    
    image_array = pen.array
    

    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étodo glyf.draw(), el cual renderiza el glyf en la pluma. Finalmente, extraemos el array de numpy de la pluma utilizando la propiedad array.

    Para controlar el resultado final, puedes ajustar el tamaño del array de numpy y la escala de la pluma. Por ejemplo:

    width = 128
    height = 128
    scale = 1.0 / glyf.yMax  # escala para ajustar el glyf a la altura de la imagen
    
    pen = NumpyPen((width, height), scale=scale)
    glyf.draw(pen)
    
    image_array = pen.array
    

    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 objeto ImageDraw de PIL. Aquí tienes un ejemplo:

    from PIL import Image, ImageDraw, ImageFont
    
    x_size = 128
    y_size = 128
    font_size = 64
    text = 'A'
    
    font = ImageFont.truetype('font.ttf', font_size)
    ascent, descent = font.getmetrics()
    
    image = Image.new(mode='L', size=(x_size, y_size), color=224)
    draw = ImageDraw.Draw(image)
    
    # Dibujar línea de base y línea de descenso
    draw.line([0, ascent, x_size, ascent], fill=128)
    draw.line([0, y_size - descent, x_size, y_size - descent], fill=128)
    
    # Dibujar glyf
    x, y = font.getsize(text)
    draw.text(((x_size - x) // 2, (y_size - y) // 2), text, font=font, fill=0)
    
    image_array = np.array(image)
    

    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étodo draw.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.

Comments are closed.