Accueil > Debian, Python > Déterminer quelle est la meilleure distribution grâce à Python et PIL

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.

Carte de jeu pour Debian

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.

Montage du titre

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

Montage du logo

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…

Catégories :Debian, Python Étiquettes : ,
  1. 13 janvier 2013 à 10:46

    Sympa :-).
    (il manque la miniature nebsd)

  2. 20 janvier 2013 à 13:52

    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.

  3. 22 janvier 2014 à 16:18

    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

    • 25 janvier 2014 à 16:58

      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.

      • 26 janvier 2014 à 02:31

        Merci beaucoup !

  1. 3 août 2016 à 16:20

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur la façon dont les données de vos commentaires sont traitées.