Insérer une image dans un texte en Python est ce que j’ai souhaité faire aujourd’hui. Je me suis penché sur la question et voici ce que j’ai fait.
Insérer une image dans un texte en Python: prémices
Nous aurons besoin du module PIL ainsi que de numpy. Nous allons convertir dans un premier temps l’image suivante:
en une matrice.
img = Image.open("image.png") imgArray = np.array(img)
>>> imgArray.shape
(512, 768, 4)
Avec imgArray.shape, nous avons les dimensions de l’images (le dernier nombre ne va pas nous intéresser).
Maintenant, on créé une image vierge sur fond blanc:
tmp = Image.new('RGB', ( imgArray.shape[1] , imgArray.shape[0] ) , 'white' ) image_result = ImageDraw.Draw(tmp)
Dans cette nouvelle image, on va mettre une suite de « O » écrits en noir, et on va changer la couleur en rouge quand le « O » sera au niveau de ce qui était en noir dans l’image de départ.
Pour cela, on va d’abord choisir la fonte:
myFont = ImageFont.truetype('arial.ttf', 16)
Ensuite, on va faire des boucles (comme chez le coiffeur, mais en plus fun !).
for y in range( 0 , imgArray.shape[0] , 16): for x in range( 0 , imgArray.shape[1] , 16 ): r, v, b, t = imgArray[y, x] # r, v, b, t if (r,v,b) == (255,255,255): image_result.text((x, y), "O", font=myFont, fill=(0, 0, 0)) else: image_result.text((x, y), "O", font=myFont, fill=(255, 0, 0))
Maintenant, on affiche l’image:
tmp.show()
C’est plutôt pas mal pour un début, mais ça pique un peu les yeux non ?
Insérer une image dans un texte en Python: lettres aléatoires
Pour ne pas toujours mettre la même lettre (précédemment, le « O »), je vais faire appel au pseudo-hasard, et donc au module random et sa fonction choice, ainsi qu’au module string et à sa variable ascii_uppercase.
import numpy as np from PIL import Image, ImageDraw, ImageFont from string import ascii_uppercase from random import choice img = Image.open("image.png") imgArray = np.array(img) tmp = Image.new('RGB', ( imgArray.shape[1] , imgArray.shape[0] ) , 'white' ) image_result = ImageDraw.Draw(tmp) myFont = ImageFont.truetype('arial.ttf', 16) for y in range( 0 , imgArray.shape[0] , 16): for x in range( 0 , imgArray.shape[1] , 16 ): r, v, b, t = imgArray[y, x] # r, v, b, t if (r,v,b) == (255,255,255): image_result.text((x, y), choice(ascii_uppercase), font=myFont, fill=(0, 0, 0)) else: image_result.text((x, y), choice(ascii_uppercase), font=myFont, fill=(255, 0, 0)) tmp.save('result.jpg')
Bon, là, vous allez me dire : « C’est bien gentil Coco, mais le texte ne veut rien dire ». Ok ! Alors prenons un texte contenu dans un fichier externe…
Insérer une image dans un texte en Python: à partir d’un fichier externe
Voici une première proposition:
import numpy as np from PIL import Image, ImageDraw, ImageFont img = Image.open("image.png") imgArray = np.array(img) tmp = Image.new('RGB', ( imgArray.shape[1] , imgArray.shape[0] ) , 'white' ) image_result = ImageDraw.Draw(tmp) myFont = ImageFont.truetype('arial.ttf', 16) lorem = open("lorem-ipsum.txt", "r" , encoding='utf8').read() c = 0 # compteur de position de la lettre dans lorem for y in range( 0 , imgArray.shape[0] , 16): for x in range( 0 , imgArray.shape[1] , 16 ): r, v, b, t = imgArray[y, x] # r, v, b, t if (r,v,b) == (255,255,255): image_result.text((x, y), lorem[c], font=myFont, fill=(0, 0, 0)) else: image_result.text((x, y), lorem[c], font=myFont, fill=(255, 0, 0)) c += 1 tmp.save('result.jpg')
On se rapproche d’un résultat plutôt satisfaisant. Cependant, l’espace entre les lettres est trop important lorsque ce sont des minuscules… Il faut absolument y remédier.
Pour cela, je prends le parti prix de mettre toutes les lettres en majuscules et de diminuer les espaces, que j’avais fixées à 16 pixels précédemment.
import numpy as np from PIL import Image, ImageDraw, ImageFont from string import ascii_lowercase, ascii_uppercase img = Image.open("image.png") imgArray = np.array(img) tmp = Image.new('RGB', ( imgArray.shape[1] , imgArray.shape[0] ) , 'white' ) image_result = ImageDraw.Draw(tmp) myFont = ImageFont.truetype('arial.ttf', 12) lorem = open("lorem-ipsum.txt", "r" , encoding='utf8').read() c = 0 # compteur de position de la lettre dans lorem for y in range( 0 , imgArray.shape[0] , 12): for x in range( 0 , imgArray.shape[1] , 12 ): r, v, b, t = imgArray[y, x] # r, v, b, t if (r,v,b) == (255,255,255): image_result.text((x, y), lorem[c].upper(), font=myFont, fill=(0, 0, 0)) else: image_result.text((x, y), lorem[c].upper(), font=myFont, fill=(255, 0, 0)) c += 1 tmp.save('result.jpg')
Un autre exemple: Marylin
Partons de l’image suivante:
Et utilisons le script suivant:
import numpy as np from PIL import Image, ImageDraw, ImageFont from string import ascii_lowercase, ascii_uppercase img = Image.open("marylin.png") imgArray = np.array(img) tmp = Image.new('RGB', ( imgArray.shape[1] , imgArray.shape[0] ) , 'white' ) image_result = ImageDraw.Draw(tmp) myFont = ImageFont.truetype('arial.ttf', 12) lorem = open("lorem-ipsum.txt", "r" , encoding='utf8').read() c = 0 # compteur de position de la lettre dans lorem for y in range( 0 , imgArray.shape[0] , 12): for x in range( 0 , imgArray.shape[1] , 12 ): b,w = imgArray[y, x] # r, v, b, t if (b,w) == (255,255): image_result.text((x, y), lorem[c].upper(), font=myFont, fill=(200, 200, 200)) else: image_result.text((x, y), lorem[c].upper(), font=myFont, fill=(0, 0, 0)) c += 1 tmp.save('result.jpg')
Un autre exemple: pi dans pi
On part de l’image:
et on utilise un fichier texte contenant plein de décimales de pi:
On utilise enfin le programme suivant:
import numpy as np from PIL import Image, ImageDraw, ImageFont from string import ascii_lowercase, ascii_uppercase img = Image.open("pi.jpg") imgArray = np.array(img) tmp = Image.new('RGB', ( imgArray.shape[1] , imgArray.shape[0] ) , 'white' ) image_result = ImageDraw.Draw(tmp) myFont = ImageFont.truetype('arial.ttf', 12) pi = open("pi.txt", "r" , encoding='utf8').read().replace('\n','') c = 0 # compteur de position de la lettre dans lorem for y in range( 0 , imgArray.shape[0] , 12): for x in range( 0 , imgArray.shape[1] , 12 ): r, v,b = imgArray[y, x] # r, v, b, t if (r,v,b) == (255,255,255): image_result.text((x, y), pi[c].upper(), font=myFont, fill=(200, 200, 200)) else: image_result.text((x, y), pi[c].upper(), font=myFont, fill=(255, 0, 0)) c += 1 tmp.save('result-pi.jpg')
On obtient alors:
Bonjour et merci pour cet exemple,
chez moi cette ligne ne fonctionne pas
b,w = imgArray[y, x] # r, v, b, t
car imgArray vaut 0 ou 1
je n’ai pas trouvé mon erreur
Sans le code complet, il est impossible de répondre. Quel genre d’erreur ?