Module externe PIL / Pillow pour python

PIL (Python Imaging Library) est une bibliothèque graphique écrite par Fredrik Lundh à partir de 1995, et reprise en 2010 sous le nom de Pillow par Jeffrey A. Clark et d’autres personnes. La transition s’étant effectuée en bonne intelligence, le nom du module est resté PIL. Cette page est basée sur la version 11.1.0 de Debian 13 Trixie.

Cette page suit les recommandations de 1990 pour une orthographe réformée.

Page en cours d’écriture, surtout selon mes besoins

Voyez la page modules pour les généralités. Pour rappel,

1. Fichiers et images

1.1 Créer un objet-image
1.2 Charger et sauvegarder une image
1.3 Attributs

1. Fichiers et images

1.1 Créer un objet-image

new()

img0 =Image.new(mode, (w, h), couleur) crée une image selon un mode (voir ci-après), un tuple représentant le couple largeur-hauteur en pixels et une couleur de fond.

img0 =Image.new("RGB", (1024, 756), "black") initialise une image de 1024×756 à fond noir
img0 =Image.new("RGBA", (540, 960), (0, 0, 0, 0)) initialise un fond transparent, susceptible de recevoir des collages ??? d(e partie d)’images contenant un canal alpha.

copy()

nv0 =img0.copy() copie en créant une nouvelle image. À utiliser en cas de stockage dans une liste de différentes étapes de l’évoltion d’une image : liste0.append(img0.copy()), sinon toutes les cellules contiendront finalement la dernière version.

crop() permet de créer un objet-image en sélectionnant une partie d’image.

canaux

img0.getbands() retourne un tuple composé des canaux (“bands„), ("R", "G", "B") pour une image "RGB"
(r, g, b, a) =img0.split() sépare les canaux d’une image (le tuple de réception doit être défini en fonction du mode de l’image)
img0 =Image.merge(mode, (c1, c2…)) intègre différents canaux pour former une image.

c =img0.getchannel(couche) isole une couche ("1", "L", "R", "G", "B", "A"…) d’une image
img0.getchannel(canal) crée une image de type L (256 niveaux) formée du seul canal spécifié : 1, L, R, G‌, B‌, A

tupmult0 =img0.getextrema() renvoie un (ensemble de) tuples (min, max) pour chaque canal de l’image
tup0 =img0.getchannel("R").getextrema() retourne un tuple contenant les valeurs extrêmes pour la couche "R" (rouge)

1.2 Charger et sauvegarder une image

open() : ouvrir une image existante

Le module est capable de charger les images en format ARG, BMP, CUR, DCX, EPS (ghostscript), FLI, FPX, GBR, GD, GIF, ICO, IM, IMT, IPTC, JPEG, MCIDAS, MPEG, MSP, PCX, PDF, PhotoCD, PIXAR, PNG, PPM, PSD, SGI, SUN, TGA, TIFF, WMF, XBM et XPM.

objet =Image.open(chemin/fichier) charge une image pour la transformer en un objet susceptible d’être édité.

Les combinaisons entre images devant être de même format, il peut être nécessaire de convertir l’image dès le chargement :

img0 =Image.open(chemin/fichier).convert("RGBA")

save() : sauvegarder un objet-image

Le module sauvegarde les images sous les formats BMP, EPS (sans ghostscript, GIF (fixes ou animées), IM, JPEG, MSP, PDF, PNG, PPM, TIFF et XBM.

objet.save(chemin/fichier.ext, format=None, **params) sauvegarde un objet en un fichier image. Sans spécification de format, c’est l’extension du fichier qui le détermine.

À confirmer : **params signifie que les paramètres peuvent être passés par une série d’affectations en fin de parenthèse :
img0.save("mamie.png", Software="Python+PIL", comment="L’été 1993")

images animées

liste0[0].save(chemin/image.gif, save_all=True, append_images=liste0[1:], duration=durees, loop=n) convertit en GIF animée une liste d’images, en parallèle avec la liste de leur durée d’exposition.

1.3 Attributs d’une image

Pour l’objet img0,

w =img0.width permet de récupérer la largeur de l’image
h =img0.height permet de récupérer la hauteur de l’image
tup =img0.size renvoie un tuple contenant la largeur et la hauteur de l’image
w, h =img0.size permet de récupérer dans deux variables différentes la largeur et la hauteur de l’image

mode =img0.mode retourne une chaine représentant le mode (voir créer)

img0.info contient un dictionnaire sur différents attributs : la densité, la compression, l’orientation, la durée pour les animées… selon le type de l’image. img0.info[''] peut exprimer :

Autres «clés» rencontrées : 'Raw profile type exif', 'icc_profile', 'xmp', 'progressive', 'progression'. Il ne pas trop se fier à ce genre d’informations, pas toujours standard, qui contiennent parfois des données binaires ; PIL‌ ne peut pas toujours les interpréter.

2. Transformations

2.1 Copier /‌ coller

Pour ces «copier / coller», les images ne doivent pas être de même dimensions.

crop()

Pour créer un objet-image identique à un autre, utiliser copy().

rect0 =img0.crop((x0, y0, x1, y1)) crée un nouvel objet-image à partir de la copie d’une partie rectangulaire d’une image, dont les coordonnées sont rassemblées dans un tuple, commençant du point x0, y0 en haut à gauche au point x1, y1 en bas à droite.

paste()

Cet objet est modifiéimg0.paste(rec0, coord, masque0) colle un rectangle d’image aux coordonnées (x, y)

2.2 Assembler des images

Pour les assemblages, les images doivent être de même dimensions.

nv0 =Image.blend(image1, image2, t) superpose deux images selon la valeur du taux t, entre 0.0 (première image seulement) et 1.0 (seconde uniquement).

nv0 =Image.composite(image1, image2, masque0) superpose deux images, avec un taux variable défini par l’image masque. L’image masque doit avoir pour mode "1", "L" ou "RGBA". Pour un masque en 256 niveaux de gris (L, essai en PNG), le blanc conserve la première image et le noir impose la seconde.

nv0 =Image.alpha_composite(fond0, img0) permet le dépôt d’une image sur une image de fond, les deux ayant les mêmes dimensions et le même mode avec canal alpha.

Cet objet est modifiéimg0.putalpha(alpha) ajoute un canal alpha à une image, ou le remplace. Un mode L ou RGB est converti en LA or RGBA. alpha doit être une image L or 1 de même taille, ou un entier de 0 (transparent) à 255 (opaque) pour un canal alpha uniforme.

2.3 Dimensions

0
1
2
3
4
5

resize()

originale

L’image utilisée pour les exemples est un PNG à 256 niveaux de gris de 82×82 réduite à 55×55 à gauche et élargie à 115×115. Afin de rendre les aberrations plus visibles, surtout visibles sur des surfaces très délimitées, l’image originale est dessinée en noir (niveau 0) et blanc (255). Survoler les images produites offre un mode loupe ×2.

nv0 =img0.resize((x, y), Image.MODE) renvoie une image redimensionnée, mais le résultat n’est proportionnel que dans la mesure où les nouvelles dimensions sont proportionnelles aux anciennes (x /w = y /h). Pour (w, h) =img0.size :

MODEs de redimensionnement :

thumbnail()

Cet objet est modifiéimg0.thumbnail((nw, nh), Image.MODE) rétrécit une image (“thumbnail„ signifie «miniature») en respectant les proportions de l’image et selon les modes de redimensionnement décrits à la méthode resize() ci-dessus. Les nouvelles dimensions limitent la largeur et la hauteur permises pour la nouvelle image :

Cet objet est modifiéimg0.thumbnail((10000, 120)) réduit proportionnellement toute image de moins de 10 000px de largeur à la hauteur de 120px.

2.4 Transpositions

transpose()

Les transpositions suivantes conservent la largeur et la hauteur de l’image produite :

nv0= img0.transpose(Image.FLIP_LEFT_RIGHT) inversion gauche-droite de l’image
nv0= img0.transpose(Image.FLIP_TOP_BOTTOM) inversion haut-bas de l’image
nv0= img0.transpose(Image.Transpose.ROTATE_180) symétrie centrale (composition des deux précédentes)

Les transpositions suivantes inversent la largeur et la hauteur de l’image produite :

nv0= img0.transpose(Image.Transpose.ROTATE_90) rotation d’un quart de tour dans le sens trigonométrique
nv0= img0.transpose(Image.Transpose.ROTATE_270) rotation d’un quart de tour dans le sens horaire
nv0= img0.transpose(Image.TRANSPOSE) rotation anti-horaire d’un quart de cercle et inversion haut-bas
nv0 =img.transpose(Image.TRANSVERSE) rotation horaire d’un quart de cercle et inversion haut-bas

rotate()

img0.rotate(degres) tourne l’image avec précision. rotate() ne se préocuppe pas des dimensions de l’image produite : des parties seront coupées, sauf dans la rotation de 180° (symétrie centrale) ou dans les quarts de tour d’une image carrée.

Attention : PIL-Pillow compte les angles en degrés (dans le sens trigonométrique, possibilité d’une partie décimale), tandis que les fonctions trigonométriques du module math attendent des angles exprimés radian. Voici les formules de conversion :

…traduites en fonctions :

import math

def rad(d) :
  return d /180 *math.pi

def deg(r) :
  return r *180 /math.pi

print(math.cos(rad(45)))  # 0.7071067811865476
print(deg(math.atan(2)))  # 63.43494882292201 (degrés et partie décimale)

3. Filtres

effect_spread()

(nv0=?) img0.effect_spread(n) disperse les pixels de façon aléatoire, avec distance maximale de n pixels). Si la nouvelle paire x, y tombe en dehors de l’image, l’échange de pixels n’a pas lieu, ce qui veut dire que si n est très élevé, la méthode a peu d’effet sur l’image.

Images animées

img0.is_animated contient un booléen True ou False selon que l’objet contient plus d’une image ("frame"), donc animée (GIF et MNG?), ou non
img0.n_frames contient le nombre d’images d’une image animée

img0.tell() retourne le frame actuel (0 par défaut pour le premier frame)
img0.seek(i) pointe le frame i d’une image animée, de 0 à n_frames -1

for i in range(img0.n_frames) :
  seek(i) # {pas clair}

Et encore

show()

img0.show("titre") fait apparaître l’image au format PNG dans une fenêtre d’application extérieure au titre aléatoire ; titre devrait s’appliquer à la fenêtre mais ne fonctionne pas nécessairement.

img0.getpixel((x, y)) retourne la couleur aux coordonnées (x, y), sous forme de tuple si l’image a plusieurs couches
img0.putpixel((x, y), couleur) impose une couleur aux coordonnées (x, y), la couleur doit être un tuple de valeurs si l’image a plusieurs couches