Déterminer quelle est la meilleure distribution grâce à Python et PIL
N’avez-vous jamais discuté des mérites de telle ou telle distribution Linux (ou BSD) avec d’autres personnes (chacun essayant de démontrer que celle qu’il utilise au quotidien est la meilleure) ? Grâce à cet article, vous n’aurez toujours pas La réponse mais vous aurez une réponse indiscutable : il s’agit de la jouer aux cartes. Les cartes sont créées avec Python Imaging Library
, une bibliothèque Python de manipulation d’image. L’article explique la façon de les réaliser.
Chaque carte possède un ensemble de caractéristiques, la plus forte remporte le pli. Ce principe de jeu existe depuis les années 70 (Ace_Trumps, Super Top Ass). L’ensemble des 26 cartes créées est visible ici.
L’objectif de l’article est de montrer comment on peut concevoir la création de la carte, pas le détail des paramètres de chaque fonction. Pour cela, la documentation et de nombreuses explications foisonnent déjà sur le web. C’est pourquoi, par exemple, les calculs de dimensionnement ne seront pas expliqués.
Prérequis : installer PIL (ou Pillow)
Deux possibilités :
- utiliser le système de paquet de votre distribution (python-imaging pour Debian) ;
- utiliser Pypi : PIL n’est pas disponible, il faut installer Pillow. Cela ne change pas la façon d’utiliser la bibliothèque :
from PIL import Image, ImageDraw, ImageFont
Image
sert à instancier une image, ImageDraw
à la modifier, ImageFont
à choisir une police de caractère.
Créer une carte
La base consiste à instancier un objet image sur lequel les modifications vont être apportées. Une fois les modifications réalisées, on enregistre le résultat sur le disque :
def draw_card(distrib): img = Image.open(BACKGROUND_PATH) #ajout des textes, images, etc. img.save(distrib["img_name"] + ".png")
La carte est une superposition de couches, qui sont toutes fusionnées en une seule image. On a donc un fond sur lequel les autres éléments sont superposés.
Parmi les éléments remarquables :
Textes dans un cartouche
Le titre et les caractéristiques des distributions sont faits de la même manière. Il n’existe pas d’effet avec PIL pour dessiner automatiquement une bordure. Elle est réalisée en plaçant deux rectangles l’un sur l’autre, celui de dessous étant plus large et haut.
def draw_title(img, title): """ pour dessiner le titre avec le fond et la bordure autour img est l'image PIL title est la chaine de caracteres a afficher ("Distribution") """ draw = ImageDraw.Draw(img) draw_cartouche(draw, 25, 55) font = ImageFont.truetype(FONT_PATH, TITLE_FONT_SIZE) width, height = draw.textsize(title, font=font) x = center(width) draw.text((x, 29), title, font=font, fill=TEXT_COLOR) def draw_cartouche(draw, upper_height, lower_height): """pour dessiner les deux rectangles""" draw.rectangle(((MARGIN_LEFT, upper_height), (CARD_WIDTH - MARGIN_RIGHT, lower_height)), fill="#8e6f32") BORDER = 5 draw.rectangle(((MARGIN_LEFT + BORDER, upper_height + BORDER), (CARD_WIDTH - MARGIN_RIGHT - BORDER, lower_height - BORDER)), fill="#e9b654")
draw.textsize()
permet de connaître les dimensions que prendrait la chaîne passée en paramètre. Cela permet de faire un calcul (dans la fonction center()
, omise dans l’extrait ci-dessus) pour centrer le texte.
Le logo de la distribution
L’affichage du logo suit la même logique en intercalant une image (nommée supernova.png) entre le fond et le logo de la distribution. Pour avoir un joli rendu , on décale simplement en hauteur l’image (y
) car les deux images n’ont pas la même taille.
def draw_logo(img, filename): """on colle supernova puis le fichier correspondant au parametre filename""" image_path = SRC_IMGS_DIR + "supernova.png" nova = Image.open(image_path) nova_width, nova_height = nova.size x = center(nova_width) y = 60 img.paste(nova.convert("RGBA"), (x, y, x + nova_width, y + nova_height), mask=nova.convert('RGBA')) image_path = SRC_IMGS_DIR + filename + ".png" distro = Image.open(image_path) distro_width, distro_height = distro.size x = center(distro_width) y = 90 img.paste(distro.convert("RGBA"), (x, y, x + distro_width, y + distro_height), mask=distro.convert('RGBA'))
L’exercice de factorisation de cette fonction est laissé aux lecteurs qui s’ennuient et qui ne sont pas partis faire autre chose (ce que je ne comprend pas d’ailleurs).
Le numéro de la carte
Le numéro de la carte en bas à gauche est affiché de biais. Si les images peuvent subir une rotation, les textes ne sont affichés qu’horizontalement. La solution est donc de coller le texte dans une image intermédiaire. Cette image subira une rotation puis sera collée sur l’image finale de la même manière que précédemment :
def draw_card_index(img, number): """pour dessiner 'number' de biais""" HEIGHT = WIDTH = 19 num_img = Image.new("RGBA", (WIDTH, HEIGHT), (0, 0, 0, 0)) num_draw = ImageDraw.Draw(num_img) font = ImageFont.truetype(SANS_PATH, TEXT_FONT_SIZE) num_draw.text((0, 0), number, font=font, fill="brown") n = num_img.rotate(-45) X, Y = 7, 378 img.paste(n, (X, Y, X + WIDTH, Y + HEIGHT), mask=n)
À noter que la rotation faite ici prend peu de précaution et les nombres à deux chiffres sont légèrement tronqués. Le paramètre expand
peut être ajouté à rotate()
pour éviter la perte, mais l’image est automatiquement agrandie.
Code source et ressources
La documentation de PIL est précieuse.
Un tutoriel dont certains effets ont été réutilisés pour les cartes.
Les données sur les cartes proviennent principalement de Distrowatch. Les logos des distributions sont aussi ceux affichés sur Distrowatch. « first stable » représente la première version stable avec le nom actuel de la distribution ou ce qui pourrait être considéré comme équivalent. « based on » indique le nom de la distribution parente. La valeur « Indep. » signifie qu’elle n’est basée sur aucune autre distribution. Si elle est suivie d’une étoile, cela signifie qu’elle est maintenant indépendante mais a été basée sur une autre distribution par le passé.
Le fond de carte et l’effet supernova ont été réalisés avec The Gimp.
L’archive contenant le code source du script au cas où quelqu’un voudrait le réutiliser, ainsi que les logos et les cartes générées est fournie au format .tar.xz. Le code a été écrit dans un but de démo. Il est bien perfectible…
Sympa :-).
(il manque la miniature nebsd)
Merci, c’est corrigé.
Pour ceux qui ne connaitraient pas le principe du jeu :
Le paquet de carte est séparé à parts égales entre chaque joueur.
Le joueur ayant la main chosit une des caractéristiques de sa carte. Le joueur possédant la carte avec la plus forte valeur dans cette caractéristique remporte les cartes des autres joueurs et annonce la caractéristique à prendre en compte pour la carte suivante.
Le gagnant est le joueur ayant accumulé toutes les cartes.
Bonjour.
J’ai la version 3.1.2 de Python et je suis embetté, il semble qu’il n’y a pas encore de version de PIL pour Python 3.x.x
Comment puis je faire pour enregistrer une image du net vers mon DD ? obligé d’utiliser PIL ?
MERCIIII
PIL sert à manipuler des images, pas à les télécharger.
Pour télécharger des images, il est possible d’utiliser urllib.request (pour python3) ou la bibliothèque requests.
Merci beaucoup !