Estoy usando el módulo ImageFont de PIL para cargar fuentes para generar imágenes de texto. Quiero que el texto esté bien unido al borde, sin embargo, cuando uso ImageFont para obtener la altura de la fuente, parece que incluye el relleno del carácter. Como indica el rectángulo rojo. 
c = 'A' font = ImageFont.truetype(font_path, font_size) width = font.getsize(c)[0] height = font.getsize(c)[1] im = Image.new("RGBA", (width, height), (0, 0, 0)) draw = ImageDraw.Draw(im) draw.text((0, 0), 'A', (255, 255, 255), font=font) im.show('charimg')Si puedo obtener la altura real del carácter, entonces podría omitir las filas delimitadoras en el rectángulo inferior, ¿podría obtener esta información de la fuente? Gracias.
El tamaño exacto depende de muchos factores. Solo te mostraré cómo calcular diferentes métricas de fuente.
font = ImageFont.truetype('arial.ttf', font_size) ascent, descent = font.getmetrics() (width, baseline), (offset_x, offset_y) = font.font.getsize(text)offset_yascent - offset_ydescentfont.getmask(text).getbbox()Espero eso ayude.
La respuesta más votada está desactualizada. Hay una nueva función en Pillow 8.0.0: ImageDraw.textbbox . Consulte las notas de la versión para otras funciones relacionadas con el texto agregadas en Pillow 8.0.0.
Tenga en cuenta que ImageDraw.textsize , ImageFont.getsize e ImageFont.getoffset están rotos y no deben usarse para código nuevo. Estos han sido reemplazados efectivamente por las nuevas funciones con una API más limpia. Vea la documentación para más detalles.
Para obtener un cuadro delimitador ajustado para una cadena completa, puede usar el siguiente código:
from PIL import Image, ImageDraw, ImageFont image = Image.new("RGB", (200, 80)) draw = ImageDraw.Draw(image) font = ImageFont.truetype("arial.ttf", 30) draw.text((20, 20), "Hello World", font=font) bbox = draw.textbbox((20, 20), "Hello World", font=font) draw.rectangle(bbox, outline="red") print(bbox) # (20, 26, 175, 48) image.show() Puede combinarlo con el nuevo ImageDraw.textlength para obtener cuadros delimitadores individuales por letra:
from PIL import Image, ImageDraw, ImageFont image = Image.new("RGB", (200, 80)) draw = ImageDraw.Draw(image) font = ImageFont.truetype("arial.ttf", 30) xy = (20, 20) text = "Example" draw.text(xy, text, font=font) x, y = xy for c in text: bbox = draw.textbbox((x, y), c, font=font) draw.rectangle(bbox, outline="red") x += draw.textlength(c, font=font) image.show()Tenga en cuenta que esto ignora el efecto del interletraje. Kering actualmente no funciona con el diseño de texto básico, pero podría presentar una ligera imprecisión con el diseño Raqm. Para solucionarlo, agregaría la longitud del texto de pares de letras en su lugar:
for a, b in zip(text, text[1:] + " "): bbox = draw.textbbox((x, y), a, font=font) draw.rectangle(bbox, outline="red") x += draw.textlength(a + b, font=font) - draw.textlength(b, font=font)from PIL import Image, ImageDraw, ImageFont im = Image.new('RGB', (400, 300), (200, 200, 200)) text = 'AQj' font = ImageFont.truetype('arial.ttf', size=220) ascent, descent = font.getmetrics() (width, height), (offset_x, offset_y) = font.font.getsize(text) draw = ImageDraw.Draw(im) draw.rectangle([(0, 0), (width, offset_y)], fill=(237, 127, 130)) # Red draw.rectangle([(0, offset_y), (width, ascent)], fill=(202, 229, 134)) # Green draw.rectangle([(0, ascent), (width, ascent + descent)], fill=(134, 190, 229)) # Blue draw.rectangle(font.getmask(text).getbbox(), outline=(0, 0, 0)) # Black draw.text((0, 0), text, font=font, fill=(0, 0, 0)) im.save('result.jpg') print(width, height) print(offset_x, offset_y) print('Red height', offset_y) print('Green height', ascent - offset_y) print('Blue height', descent) print('Black', font.getmask(text).getbbox())Calcular píxel de área
from PIL import Image, ImageDraw, ImageFont im = Image.new('RGB', (400, 300), (200, 200, 200)) text = 'AQj' font = ImageFont.truetype('arial.ttf', size=220) ascent, descent = font.getmetrics() (width, height), (offset_x, offset_y) = font.font.getsize(text) draw = ImageDraw.Draw(im) draw.rectangle([(0, offset_y), (font.getmask(text).getbbox()[2], ascent + descent)], fill=(202, 229, 134)) draw.text((0, 0), text, font=font, fill=(0, 0, 0)) im.save('result.jpg') print('Font pixel', (ascent + descent - offset_y) * (font.getmask(text).getbbox()[2]))