Pillow: dibujo con texto chino ilegible

Agregar texto a una imagen es una necesidad común en el procesamiento de imágenes, por ejemplo, añadir marcas de agua, crear pósters, etc. Pillow proporcionaImageDrawel módulo para implementar esta función.

Pasos básicos

Los pasos básicos para añadir texto a una imagen son los siguientes:

  1. Abrir o crear una imagen
  2. Crear un objeto ImageDraw
  3. Especificar la fuente
  4. Usartext()el método para añadir texto
  5. Guardar la imagen

Ejemplo

Ejemplo

from PIL import Image, ImageDraw, ImageFont

# 1. Crear una nueva imagen
image = Image.new('RGB', (400, 200), color=(255, 255, 255))

# 2. Crear el objeto ImageDraw
draw = ImageDraw.Draw(image)

# 3. Especificar la fuente (aquí se usa la fuente predeterminada)
# Nota: es posible que la fuente predeterminada no admita chino
font = ImageFont.load_default()

# 4. Añadir texto
draw.text((10, 10), "Hello, Pillow!", fill="black", font=font)

# 5. Guardar la imagen
image.save('output.png')

Añadir fuentes chinas

Por defecto, la fuente predeterminada de Pillow no admite la visualización de caracteres chinos.

Para añadir chino en una imagen, necesitamos usar un archivo de fuente compatible con chino (normalmente en formato .ttf o .otf).

Obtener fuentes chinas

Puedes obtener fuentes chinas de las siguientes formas:

  1. Usar fuentes chinas incluidas en el sistema (como simsun.ttc en Windows)

  2. Descargar de sitios web de fuentes gratuitas (como Source Han Sans / 思源黑体, Alibaba PuHuiTi / 阿里巴巴普惠体, etc.)

  3. Comprar fuentes comerciales (ten en cuenta los problemas de derechos de autor)

Descarga de bibliotecas de fuentes chinas de código abierto:https://github.com/wordshub/free-font。

Código de ejemplo para usar fuentes chinas

Ejemplo

from PIL import Image, ImageDraw, ImageFont

# 1. Crear una nueva imagen
image = Image.new('RGB', (400, 200), color=(255, 255, 255))

# 2. Crear el objeto ImageDraw
draw = ImageDraw.Draw(image)

# 3. Especificar la fuente china
# Nota: necesitas reemplazarlo con la ruta del archivo de fuente existente en tu sistema
font_path = "SimHei.ttf"  # Ruta de la fuente SimHei (黑体)
font_size = 20
font = ImageFont.truetype(font_path, font_size)

# 4. Añadir texto chino
draw.text((10, 10), "¡Hola, Pillow!", fill="red", font=font)

# 5. Guardar la imagen
image.save('chinese_output.png')

El resultado de salida es el siguiente, el chino se muestra correctamente:


Técnicas avanzadas de composición tipográfica de texto

Control de posición del texto

text()El primer parámetro del método es la coordenada (x, y), que indica la posición de la esquina superior izquierda del texto. Podemos controlar la posición del texto mediante cálculos.

Ejemplo

from PIL import Image, ImageDraw, ImageFont

# 1. Crear una nueva imagen
image = Image.new('RGB', (400, 200), color=(255, 255, 255))

# 2. Crear el objeto ImageDraw
draw = ImageDraw.Draw(image)

# 3. Especificar la fuente china
# Nota: necesitas reemplazarlo con la ruta del archivo de fuente existente en tu sistema
font_path = "SimHei.ttf"  # Ruta de la fuente SimHei (黑体)
font_size = 20
font = ImageFont.truetype(font_path, font_size)

# 4. Añadir texto chino
# Centrar el texto
text = "Texto centrado"
bbox = draw.textbbox((0, 0), text, font=font)
text_width = bbox[2] - bbox[0]
text_height = bbox[3] - bbox[1]
image_width, image_height = image.size
x = (image_width - text_width) / 2
y = (image_height - text_height) / 2
draw.text((x, y), text, fill="red", font=font)

# 5. Guardar la imagen
image.save('chinese_output.png')

El resultado es el siguiente, el texto aparece centrado:

Manejo de texto multilínea

Pillow no admite directamente el ajuste de línea automático, pero podemos implementarlo manualmente:

Ejemplo

from PIL import Image, ImageDraw, ImageFont

# 1. Crear una nueva imagen
image = Image.new('RGB', (400, 200), color=(255, 255, 255))

# 2. Crear el objeto ImageDraw
draw = ImageDraw.Draw(image)

# 3. Especificar la fuente china
# Nota: necesitas reemplazarlo con la ruta del archivo de fuente existente en tu sistema
font_path = "SimHei.ttf"  # Ruta de la fuente SimHei (黑体)
font_size = 20
font = ImageFont.truetype(font_path, font_size)

# 4. Añadir texto chino
# Mostrar en varias líneas
# El texto chino que se va a mostrar
text = "Este texto es relativamente largo; debemos dividirlo en varias líneas para que se pueda leer mejor."
max_width = 200  # Ancho máximo por línea (píxeles)

lines = []         # Almacenar el texto separado en líneas
current_line = ""  # La línea actual que se está procesando

# Recorrer el texto por caracteres y determinar si se necesita un salto de línea
for char in text:
    test_line = current_line + char
    # Calcular el ancho de la línea actual y comprobar si supera el ancho máximo
    if draw.textbbox((0, 0), test_line, font=font)[2] <= max_width:
        current_line = test_line
    else:
        lines.append(current_line)  # La línea actual está llena, agregarla al resultado
        current_line = char         # La nueva línea comienza con el carácter actual
if current_line:
    lines.append(current_line)      # Agregar la última línea

y_text = 10  # Coordenada y inicial
# Dibujar el texto línea por línea
for line in lines:
    draw.text((10, y_text), line, fill="red", font=font)
    bbox = draw.textbbox((0, 0), line, font=font)
    line_height = bbox[3] - bbox[1]  # Calcular la altura de la línea actual
    y_text += line_height            # Actualizar la coordenada y para preparar el dibujo de la siguiente línea

# 5. Guardar la imagen
image.save('chinese_output.png')

El resultado de salida es el siguiente:

Configuración de estilos de texto

Podemos configurar el estilo del texto mediante archivos de fuente o las funciones de Pillow:

Ejemplo

from PIL import Image, ImageDraw, ImageFont

# 1. Crear una nueva imagen
image = Image.new('RGB', (400, 200), color=(255, 255, 255))

# 2. Crear el objeto ImageDraw
draw = ImageDraw.Draw(image)

# 3. Especificar la fuente china
# Nota: necesitas reemplazarlo con la ruta del archivo de fuente existente en tu sistema
font_path = "SimHei.ttf"  # Ruta de la fuente SimHei (黑体)
font_size = 20
font = ImageFont.truetype(font_path, font_size)
# 4. Añadir texto chino

# Configurar el color del texto
draw.text((10, 10), "Texto de color", fill=(255, 0, 0), font=font)  # Rojo

# Añadir contorno al texto (implementado dibujando varias veces)
text = "Texto con contorno"
position = (50, 50)
# Dibujar primero el fondo negro (contorno)
for x_offset in [-1, 0, 1]:
    for y_offset in [-1, 0, 1]:
        if x_offset != 0 or y_offset != 0:
            draw.text((position[0]+x_offset, position[1]+y_offset), text, fill="black", font=font)
# Luego dibujar el primer plano en blanco
draw.text(position, text, fill="white", font=font)

# 5. Guardar la imagen
image.save('chinese_output.png')

El resultado de salida es el siguiente:


Ejemplos de aplicaciones prácticas

Añadir una marca de agua a una imagen

Ejemplo

from PIL import Image, ImageDraw, ImageFont, ImageEnhance

# 1. Crear una nueva imagen

# Abrir la imagen original
original_image = Image.open("tiger.jpeg")

# Crear una capa transparente para la marca de agua
watermark = Image.new("RGBA", original_image.size, (0, 0, 0, 0))
draw = ImageDraw.Draw(watermark)

# Configurar la fuente de la marca de agua
font_path = "SimHei.ttf"  # Ruta de la fuente SimHei (黑体)
font_size = 60
font = ImageFont.truetype(font_path, font_size)
# Añadir el texto de la marca de agua
text = "WWW.example.com prueba de marca de agua"
bbox = draw.textbbox((0, 0), text, font=font)
text_width = bbox[2] - bbox[0]
text_height = bbox[3] - bbox[1]
x = original_image.width - text_width - 20
y = original_image.height - text_height - 20
draw.text((x, y), text, fill=(255, 0, 0, 128), font=font)  # Rojo semitransparente

# Combinar la marca de agua con la imagen original
watermarked_image = Image.alpha_composite(
    original_image.convert("RGBA"),
    watermark
)

# Guardar el resultado
watermarked_image.save("watermarked_photo.png")

El efecto es el siguiente:

Crear un póster

Ejemplo

from PIL import Image, ImageDraw, ImageFont

# Crear el fondo del póster
poster = Image.new("RGB", (800, 1200), (30, 30, 60))

draw = ImageDraw.Draw(poster)

# Configurar la fuente del título
title_font = ImageFont.truetype("SimHei.ttf", 60)
# Configurar la fuente del cuerpo del texto
body_font = ImageFont.truetype("SimHei.ttf", 30)

# Añadir el título
title = "Conferencia de procesamiento de imágenes con Python"
draw.text((50, 50), title, fill=(255, 255, 255), font=title_font)

# Añadir el cuerpo del texto
content = """Fecha: 15 de abril de 2025
Lugar: sala de reuniones en línea
Ponente: WWW.example.com
Contenido: usar la biblioteca Python Pillow para el procesamiento de imágenes"""

y_position = 150
for line in content.split("\n"):
    draw.text((50, y_position), line, fill=(220, 220, 220), font=body_font)
    y_position += 40

# Guardar el póster
poster.save("event_poster.png")

El efecto es el siguiente:

Con los métodos y ejemplos anteriores, deberías poder añadir fuentes chinas en Pillow con facilidad. Recuerda tener en cuenta los problemas de derechos de autor de las fuentes en las aplicaciones reales y ajustar el estilo y la posición del texto según sea necesario.

Otras extensiones