web-dev-qa-db-fra.com

Ajouter du texte sur une image à l'aide de PIL

J'ai une application qui charge une image et lorsque l'utilisateur clique dessus, une zone de texte apparaît pour cette image (en utilisant jquery), où l'utilisateur peut écrire du texte sur l'image. Ce qui devrait être ajouté sur l'image.

Après avoir fait quelques recherches à ce sujet, je me suis dit que PIL (bibliothèque d'imagerie Python) pouvait m'aider à le faire. J'ai donc essayé quelques exemples pour voir comment cela fonctionne et j'ai réussi à écrire du texte sur une image. Mais je pense qu'il y a une différence quand je l'essaie en utilisant Python Shell et dans l'environnement Web. Je veux dire que le texte sur la zone de texte est très grand en px. Comment puis-je obtenir la même taille de texte en utilisant PIL que celui de la zone de texte?

Le texte est multiligne. Comment puis-je le rendre multiligne dans l'image aussi, en utilisant PIL?

Existe-t-il un meilleur moyen que d'utiliser la notice personnelle? Je ne suis pas tout à fait sûr, si c'est la meilleure mise en œuvre.

html:

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

c'est l'image en cours d'édition

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

le jQuery pour ajouter le textarea. La zone de texte est également position: taille absolue et fixe.

Devrais-je le placer dans un formulaire pour obtenir les coordonnées de textarea sur une image? Je veux écrire du texte sur l'image lorsque l'utilisateur clique dessus et l'enregistrer sur l'image.

80
Apostolos

Je pense que ImageFont module disponible dans PIL devrait être utile pour résoudre le problème de la taille de la police du texte. Il suffit de vérifier quel type et quelle taille de police vous convient et utilisez la fonction suivante pour modifier les valeurs de police.

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

Votre code ressemblera donc à:

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

Vous devrez peut-être déployer des efforts supplémentaires pour calculer la taille de la police. Si vous souhaitez le modifier en fonction de la quantité de texte que l'utilisateur a fourni dans TextArea.

Pour ajouter du retour à la ligne (chose multiligne), prenez simplement une idée approximative du nombre de caractères pouvant entrer dans une ligne. Ensuite, vous pouvez probablement écrire une fonction de pré-traitement pour votre texte. Cette fonction permet de trouver le dernier caractère de chaque ligne et convertit les espaces avant ce caractère en nouvelle ligne.

146
lalit

Vous pouvez créer un répertoire "polices" dans une racine de votre projet et y placer votre fichier de polices (sans_serif.ttf). Ensuite, vous pouvez faire quelque chose comme ça:

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)
13
svpp

Exemple encore plus minimaliste (dessine "Hello world!" En noir et avec la police par défaut en haut à gauche de l'image):

...
from PIL import ImageDraw
...
ImageDraw.Draw(
    image  # Image
).text(
    (0, 0),  # Coordinates
    'Hello world!',  # Text
    (0, 0, 0)  # Color
)
6
Solomon Ucko

Tout d'abord, vous devez télécharger un type de police ... par exemple: https://www.wfonts.com/font/Microsoft-sans-serif .

Après cela, utilisez ce code pour dessiner le texte:

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')
3
Kumar S

Avec Pillow, vous pouvez également dessiner sur une image à l'aide du module ImageDraw. Vous pouvez dessiner des lignes, des points, des ellipses, des rectangles, des arcs, des bitmaps, des accords, des pieslices, des polygones, des formes et du texte.

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

nous créons un objet Image avec la méthode new (). Ceci retourne un objet Image sans image chargée. Nous ajoutons ensuite un rectangle et du texte à l'image avant de l'enregistrer.

1
Tamil Selvan S

Une chose qui n’a pas été mentionnée dans d’autres réponses est de vérifier la taille du texte. Il est souvent nécessaire de s’assurer que le texte correspond à l’image (par exemple, raccourcir le texte s’il est trop grand) ou de déterminer l’emplacement où dessiner le texte (par exemple, un texte aligné en haut au centre). Pillow/PIL propose deux méthodes pour vérifier la taille du texte, l'une via ImageFont et l'autre via ImageDraw. Comme indiqué ci-dessous, la police ne gère pas les lignes multiples, contrairement à ImageDraw.

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)) 
0
lange