
Cuando empecé este blog, mi idea era mantenerlo lo más minimalista posible. La información debería ser lo más importante, así que decidí no usar ninguna imagen. Después de terminar los primeros posts me di cuenta de que cuando comparto estos posts en las redes sociales necesitaría una imagen para las etiquetas meta de opengraph.
Pero no podía simplemente "perder el tiempo" creando imágenes para cada post. Así que decidí automatizar este proceso con Python.
La idea
La idea era crear un script que tomara el título del post y creara una imagen con el título en ella. Ya había creado una plantilla con un cuadro donde debería colocarse el título, y en el script tendría que darle algunos límites para que el título encajara en el cuadro.
Instalar las dependencias
pip install opencv-python pillow
El script - Version para Windows
import cv2
from PIL import Image, ImageDraw, ImageFont
import argparse
def add_text_to_image(input_image_path, output_image_path, text, rectangle_coords, text_color):
"""
Añade texto en un rectangulo en la imagen proporcionada, y guarda la imagen modificada.
Args:
input_image_path (str): Ruta a la imagen de entrada.
output_image_path (str): Ruta para guardar la imagen de salida.
text (str): Texto que se añadirá a la imagen.
rectangle_coords (tuple): Coordenadas (x, y, ancho, alto) del rectángulo donde debe caber el texto.
text_color (str): Código hexadecimal de color para el color del texto.
"""
# Abre la imagen usando PIL para preservar la transparencia
pil_image = Image.open(input_image_path).convert("RGBA")
# Obtiene un contexto de dibujo en la imagen
draw = ImageDraw.Draw(pil_image)
# Define una tipografia (puedes cambiar la tipografia y el tamaño según tus preferencias)
font = ImageFont.truetype("consola.ttf", 36)
# Obtiene el ancho y el alto del rectángulo
rect_x, rect_y, rect_width, rect_height = rectangle_coords
# Divide el texto en palabras
words = text.split()
wrapped_lines = []
current_line = words[0]
# Envuelve el texto dentro del rectángulo
for word in words[1:]:
test_line = current_line + " " + word
test_size = draw.textbbox((0, 0), test_line, font=font)
if test_size[2] <= rect_width:
current_line = test_line
else:
wrapped_lines.append(current_line)
current_line = word
wrapped_lines.append(current_line)
wrapped_text = "\n".join(wrapped_lines)
# Obtiene el cuadro delimitador del texto
wrapped_text_bbox = draw.textbbox((0, 0), wrapped_text, font=font)
# Calcula la posición para que el texto encaje dentro del rectángulo
text_x = rect_x + (rect_width - (wrapped_text_bbox[2] - wrapped_text_bbox[0])) // 2
text_y = rect_y + (rect_height - (wrapped_text_bbox[3] - wrapped_text_bbox[1])) // 2
# Añade texto a la imagen con el color de texto especificado
draw.text((text_x, text_y), wrapped_text, font=font, fill=text_color)
# Reemplaza los espacios con guiones en el texto para generar el nombre de la imagen de salida
output_image_name = text.replace(" ", "-") + ".png"
output_image_path = output_image_name
# Guarda la imagen en formato PNG
pil_image.save(output_image_path, "PNG")
# Example usage
if __name__ == "__main__":
# Argument parser for getting text input from the command line
parser = argparse.ArgumentParser(description="Add text to an image within a specified rectangle.")
parser.add_argument("text", help="Text to be added to the image.")
args = parser.parse_args()
input_image_path = "social-banner.png"
# Convierte los espacios en el texto en guiones para el nombre de la imagen de salida
output_image_name = text.replace(" ", "-") + ".png"
# Obtiene el texto del argumento de la línea de comandos
text = args.text
rectangle_coords = (354, 260, 494, 158) # (x, y, width, height) of the rectangle
text_color = "#2a2a2a" # Hex color code for the text color
output_image_path = os.path.join(script_dir, output_image_name)
add_text_to_image(input_image_path, output_image_path, text, rectangle_coords, text_color)
El script - version para macOS
He tenido que modificar el script para que funcione en macOS, ya que me daba un OSError cuando intentaba usar la tipografia consola.ttf.
En macOS tendremos que poner la tipografia en el mismo directorio que el script, y luego usar el método os.path.join para obtener la ruta a la tipografia.
import cv2
from PIL import Image, ImageDraw, ImageFont
import argparse
def add_text_to_image(input_image_path, output_image_path, text, rectangle_coords, text_color, font_path):
"""
Añade texto en un rectangulo en la imagen proporcionada, y guarda la imagen modificada.
Args:
input_image_path (str): Ruta a la imagen de entrada.
output_image_path (str): Ruta para guardar la imagen de salida.
text (str): Texto que se añadirá a la imagen.
rectangle_coords (tuple): Coordenadas (x, y, ancho, alto) del rectángulo donde debe caber el texto.
text_color (str): Código hexadecimal de color para el color del texto.
"""
# Abre la imagen usando PIL para preservar la transparencia
pil_image = Image.open(input_image_path).convert("RGBA")
# Obtiene un contexto de dibujo en la imagen
draw = ImageDraw.Draw(pil_image)
font = ImageFont.truetype(font_path, 36)
rect_x, rect_y, rect_width, rect_height = rectangle_coords
words = text.split()
wrapped_lines = []
current_line = words[0]
for word in words[1:]:
test_line = current_line + " " + word
test_size = draw.textbbox((0, 0), test_line, font=font)
if test_size[2] <= rect_width:
current_line = test_line
else:
wrapped_lines.append(current_line)
current_line = word
wrapped_lines.append(current_line)
wrapped_text = "\n".join(wrapped_lines)
wrapped_text_bbox = draw.textbbox((0, 0), wrapped_text, font=font)
text_x = rect_x + (rect_width - (wrapped_text_bbox[2] - wrapped_text_bbox[0])) // 2
text_y = rect_y + (rect_height - (wrapped_text_bbox[3] - wrapped_text_bbox[1])) // 2
draw.text((text_x, text_y), wrapped_text, font=font, fill=text_color)
output_image_name = text.replace(" ", "-") + ".png"
output_image_path = output_image_name
pil_image.save(output_image_path, "PNG")
# Example usage
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Add text to an image within a specified rectangle.")
parser.add_argument("text", help="Text to be added to the image.")
args = parser.parse_args()
input_image_path = "social-banner.png"
text = args.text
output_image_name = text.replace(" ", "-") + ".png"
script_dir = os.path.dirname(os.path.realpath(__file__))
font_path = os.path.join(script_dir, "consola.ttf")
rectangle_coords = (354, 260, 494, 158) # (x, y, width, height) of the rectangle
text_color = "#2a2a2a" # Hex color code for the text color
output_image_path = os.path.join(script_dir, output_image_name)
add_text_to_image(input_image_path, output_image_path, text, rectangle_coords, text_color, font_path)
Ejemplo
