Agregar texto en la imagen usando PIL

94

Tengo una aplicación que carga una imagen y cuando el usuario hace clic en ella, aparece un área de texto para esta imagen (usando jquery), donde el usuario puede escribir algo de texto en la imagen. Que debe agregarse en Image.

Después de investigar un poco al respecto, pensé que PIL(Biblioteca de imágenes de Python) puede ayudarme a hacer esto. Así que probé un par de ejemplos para ver cómo funciona y logré escribir texto en una imagen. Pero creo que hay alguna diferencia cuando lo intento usando Python Shelly en un entorno web. Quiero decir que el texto del área de texto es muy grande en px. ¿Cómo puedo lograr el mismo tamaño de texto cuando uso PIL que el del área de texto?

El texto es multilínea. ¿Cómo puedo hacer que sea multilínea en la imagen también, usando PIL?

¿Existe una forma mejor que usar PIL? No estoy del todo seguro, si esta es la mejor implementación.

html:

<img src="images/test.jpg"/>

es la imagen que se está editando

var count = 0;
$('textarea').autogrow();
$('img').click(function(){
    count = count + 1;
    if (count > 1){
        $(this).after('<textarea />');
        $('textarea').focus();
    }   
});

el jquery para agregar el área de texto. Además, el área de texto es posición: tamaño absoluto y fijo.

¿Debo colocarlo dentro de un formulario para poder obtener las coordenadas del área de texto en la imagen? Quiero escribir texto en la imagen cuando el usuario hace clic y guardarlo en la imagen.

Apostolos
fuente
Por qué desea escribir texto en una imagen usando PIL (y no estoy seguro de si PIL ayuda en eso). ¿No es lo suficientemente bueno que muestre texto superpuesto, que se usa con mayor frecuencia en los controles deslizantes?
lalit
1
Lo necesito para un proyecto, quiero que se guarde la imagen. Pil puede dibujar texto en una imagen usando ImageDraw, no sé si hay otra forma.
Apostolos
Será útil si puede proporcionar el código Python que está utilizando.
lalit
aún no implementado en django. Intenté ver cómo funciona PIL en la consola interactiva de Python. Primero quiere ver si funciona y luego transferirlo a Django.
Apostolos
¿Cuál es el símbolo $ en su código?
Mugen

Respuestas:

173

Creo que el módulo ImageFont disponible en PILdebería ser útil para resolver el problema del tamaño de fuente del texto. Simplemente verifique qué tipo y tamaño de fuente es apropiado para usted y use la siguiente función para cambiar los valores de fuente.

# font = ImageFont.truetype(<font-file>, <font-size>)
# font-file should be present in provided path.
font = ImageFont.truetype("sans-serif.ttf", 16)

Entonces su código se verá similar a:

from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw 

img = Image.open("sample_in.jpg")
draw = ImageDraw.Draw(img)
# font = ImageFont.truetype(<font-file>, <font-size>)
font = ImageFont.truetype("sans-serif.ttf", 16)
# draw.text((x, y),"Sample Text",(r,g,b))
draw.text((0, 0),"Sample Text",(255,255,255),font=font)
img.save('sample-out.jpg')

Es posible que deba hacer un esfuerzo adicional para calcular el tamaño de fuente. En caso de que desee cambiarlo según la cantidad de texto que el usuario haya proporcionado TextArea.

Para agregar ajuste de texto (cosa de líneas múltiples) simplemente tome una idea aproximada de cuántos caracteres pueden venir en una línea, luego probablemente pueda escribir una función de preprocesamiento para su texto, que básicamente encuentra el carácter que será el último en cada línea y convierte el espacio en blanco antes de este carácter en una nueva línea.

lalit
fuente
1
Ese es mi pensamiento inicial. Entonces, ¿necesito que mis fuentes estén en una carpeta específica en mi servidor web para que funcione? Creo que sí. ¿Envolviendo texto? ¿Existe una forma estándar o debo implementar una?
Apostolos
Puede mantener el archivo de fuente en cualquier lugar de su servidor web. Solo asegúrese de que la ruta que proporcione sea correcta.
lalit
7
@lalit Probé tu código en una máquina con Windows y recibí un error para la fuente self.font = core.getfont(file, size, index, encoding) IOError: cannot open resource. ¿Cómo puedo proporcionar la ruta al archivo de fuente?
LWZ
3
@LWZ, para ejecutar el código anterior, solo asegúrese de que el archivo de fuente esté en el directorio actual en el que está ejecutando el código anterior. En caso de que lo esté usando en su programa, simplemente especifique la ruta completa para su archivo, por ejemplo, 'C: \ Windows \ Fonts \ sans-serif.ttf'. Otra cosa que debe asegurarse aquí es otorgar los permisos de lectura adecuados al archivo.
lalit
3
font = ImageFont.truetype ("./ arial.ttf", 30); dibujar.textsize (msg, font = font);
WeizhongTu
16

Puede crear un directorio de "fuentes" en una raíz de su proyecto y poner su archivo de fuentes (sans_serif.ttf) allí. Entonces puedes hacer algo como esto:

fonts_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'fonts')
font = ImageFont.truetype(os.path.join(fonts_path, 'sans_serif.ttf'), 24)
svpp
fuente
15

Un ejemplo aún más mínimo (dibuja "¡Hola mundo!" En negro y con la fuente predeterminada en la parte superior izquierda de la imagen):

...
from PIL import ImageDraw
...
ImageDraw.Draw(
    image  # Image
).text(
    (0, 0),  # Coordinates
    'Hello world!',  # Text
    (0, 0, 0)  # Color
)
Salomón Ucko
fuente
8

Primero, debe descargar un tipo de fuente ... por ejemplo: https://www.wfonts.com/font/microsoft-sans-serif .

Después de eso, use este código para dibujar el texto:

from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw 
img = Image.open("filename.jpg")
draw = ImageDraw.Draw(img)
font = ImageFont.truetype(r'filepath\..\sans-serif.ttf', 16)
draw.text((0, 0),"Draw This Text",(0,0,0),font=font) # this will draw text with Blackcolor and 16 size

img.save('sample-out.jpg')
Kumar S
fuente
5

Con Pillow, también puede dibujar en una imagen usando el módulo ImageDraw. Puede dibujar líneas, puntos, elipses, rectángulos, arcos, mapas de bits, acordes, rebanadas, polígonos, formas y texto.

from PIL import Image, ImageDraw
blank_image = Image.new('RGBA', (400, 300), 'white')
img_draw = ImageDraw.Draw(blank_image)
img_draw.rectangle((70, 50, 270, 200), outline='red', fill='blue')
img_draw.text((70, 250), 'Hello World', fill='green')
blank_image.save('drawn_image.jpg')

creamos un objeto Image con el método new (). Esto devuelve un objeto Imagen sin imagen cargada. Luego agregamos un rectángulo y algo de texto a la imagen antes de guardarla.

Tamil Selvan S
fuente
4

Una cosa que no se menciona en otras respuestas es verificar el tamaño del texto. A menudo es necesario asegurarse de que el texto se ajuste a la imagen (por ejemplo, acortar el texto si es demasiado grande) o para determinar la ubicación para dibujar el texto (por ejemplo, texto alineado en la parte superior central). Pillow / PIL ofrece dos métodos para verificar el tamaño del texto, uno a través de ImageFont y otro a través de ImageDraw. Como se muestra a continuación, la fuente no admite líneas múltiples, mientras que ImageDraw sí.

In [28]: im = Image.new(mode='RGB',size=(240,240))                                                            
In [29]: font = ImageFont.truetype('arial')
In [30]: draw = ImageDraw.Draw(im)
In [31]: t1 = 'hello world!'
In [32]: t2 = 'hello \nworld!'
In [33]: font.getsize(t1), font.getsize(t2) # the height is the same
Out[33]: ((52, 10), (60, 10)) 
In [35]: draw.textsize(t1, font), draw.textsize(t2, font)  # handles multi-lined text
Out[35]: ((52, 10), (27, 24)) 
lange
fuente
Gracias por resaltar esta diferencia. De hecho, estaba buscando obtener el tamaño de texto correcto en varias líneas.
fcole90
-9

Para agregar texto en un archivo de imagen, simplemente copie / pegue el código a continuación

<?php
$source = "images/cer.jpg";
$image = imagecreatefromjpeg($source);
$output = "images/certificate".rand(1,200).".jpg";
$white = imagecolorallocate($image,255,255,255);
$black = imagecolorallocate($image,7,94,94);
$font_size = 30;
$rotation = 0;
$origin_x = 250;
$origin_y = 450;
$font = __DIR__ ."/font/Roboto-Italic.ttf";
$text = "Dummy";
$text1 = imagettftext($image,$font_size,$rotation,$origin_x,$origin_y,$black,$font,$text);
     imagejpeg($image,$output,99);
?> <img src="<?php echo $output; ?>"> <a href="<?php echo $output;    ?>" download="<?php echo $output; ?>">Download Certificate</a>
Ramsevak kumar
fuente