• 8 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 18/02/2022

Ajoutez un peu d'intelligence !

Vous avez vu, dans les chapitres précédents, comment créer une application Flask, la configurer et intégrer des fonctionnalités intéressantes telles que l'authentification par Facebook.

Dans ce chapitre vous ajouterez la dernière fonctionnalité manquante : la génération d'une image à partager sur Facebook.

Cette image contiendra le prénom de la personne suivi de la description trouvée préalablement.

Générez une image de fond

Dans sa documentation, Facebook conseille que les images à partager aient les dimensions suivantes : 1 200 x 630 pixels.

L'image basique sera donc un rectangle de 1200 x 630 pixels coloré en bleu turquoise (une des couleurs du template).

Créez une nouvelle classe dans utils.py.

utils.py

class OpenGraphImage:

    def __init__(self, first_name, description):
      self.base()

    def base(self):
      # create a basic image
      pass

Puis utilisez la librairie Pillow (Python Imaging Library) pour générer l'image.

Commencez par l'installer en utilisant PIP :

$ pip install Pillow

La librairie contient un module Image qui fait exactement ce que nous souhaitons :

utils.py

from PIL import Image

...

class OpenGraphImage:

    def __init__(self, first_name, description):
      background = self.base()

    def base(self):
      img = Image.new('RGB', (1200, 630), '#18BC9C')
      return img

Afin de visualiser l'image créée, utilisez la méthode show().

class OpenGraphImage:

    def __init__(self, first_name, description):
      background = self.base()
      background.show()

Il est temps de tester !

Commencez par commenter la partie du script qui concerne les modèles pendant un bref instant et créez une instance à la fin :

utils.py

# import random

from PIL import Image

# from fbapp.models import Content
#
# def find_content(gender):
#     contents = Content.query.filter(Content.gender == Content.GENDERS[gender]).all()
#     return random.choice(contents)

...

description = """
    Toi, tu sais comment utiliser la console ! Jamais à court d'idées pour réaliser ton objectif, tu es déterminé-e et persévérant-e. Tes amis disent d'ailleurs volontiers que tu as du caractère et que tu ne te laisses pas marcher sur les pieds. Un peu hacker sur les bords, tu aimes trouver des solutions à tout problème. N'aurais-tu pas un petit problème d'autorité ? ;-)
    """
OpenGraphImage('Céline', description)

Puis exécutez le script :

$ python fbapp/utils.py

L'image apparaît ! Youpi !

Écrivez sur une image

La seconde étape consiste à écrire deux éléments sur l'image de base : le prénom et la description.

Écrivez le prénom

Créez une nouvelle méthode : print_on_image() qui prend plusieurs arguments : l'image de base sur laquelle écrire, le texte, la taille de police et la position dans l'image de base.

Créez une instance, pour le prénom, dont la taille de police est égale à 70px.

La hauteur représente la coordonnée, en ordonnée, à partir de laquelle le logiciel commence à tracer des lettres. Indiquez "50" afin de commencer à écrire à 50px du bord supérieur

utils.py

class OpenGraphImage:
  def __init__(self, first_name, description):
    background = self.base()
    self.print_on_img(background, first_name.capitalize(), 70, 50)
    background.show()

    def print_on_img(self, img, text, size, height):
      pass

Puis nous utilisons deux nouveaux modules de la librairie : ImageFont et ImageDraw.

ImageFont permet d'utiliser une police de caractère personnalisée et ImageDraw de dessiner sur une image.

Dois-je installer une nouvelle police ? On n'en a aucune dans le projet, si ?

Vous n'avez rien à installer ! Regardez dans le dossier static/fonts ! ;-)

utils.py

# Nous avons besoin d'interagir avec le système pour charger la police de caractère.
import os

from PIL import Image, ImageFont, ImageDraw

...

class OpenGraphImage:

    ...

    def print_on_img(self, img, text, size, height):
        # On commence par charger la police utilisée.
        font = ImageFont.truetype(os.path.join('fbapp', 'static', 'fonts', 'Arcon-Regular.otf'), size)

        # Création d'une nouvelle instance
        draw = ImageDraw.Draw(img)

        # textsize renvoie la largeur et la hauteur en pixel
        # d'une chaine de caractères donnée.
        w, h = draw.textsize(text, font)

        # Calcul de la position pour que le texte soit centré
        # et non pas aligné à gauche.  
        position = ((img.width - w) / 2, height)

        # Ajout du texte à l'image.
        draw.text(position, text, (255, 255, 255), font=font)

Lancez le script... et ça fonctionne !

Écrivez la description

Écrire la description demande un peu plus de réflexion. Avez-vous trouvé pourquoi ?

Si vous exécutez le script en passant en paramètres une phrase assez longue, Python renverra une erreur. En effet, vous essayez d'écrire hors de l'image !

Il faut donc :

  • découper la phrase d'origine en plusieurs sous-phrases,

  • imprimer ces dernières sur l'image.

Voici notre solution :

utils.py

import textwrap

class OpenGraphImage:

    def __init__(self, first_name, description):
      ...
      # textwrap découpe une chaine de caractères
      # sans couper les mots au milieu.
      sentences = textwrap.wrap(description, width=60)

      # current_h : Hauteur à laquelle commencer à écrire .
      # pad : pixels à ajouter entre chaque ligne, en hauteur.
      current_h, pad = 180, 10

      for sentence in sentences:
          w, h = self.print_on_img(background, sentence, 40, current_h)

          # on incrémente la hauteur pour créer une nouvelle ligne
          # en-dessous.
          current_h += h + pad

      background.show()

    def print_on_img(self, img, text, size, height):
      ...
      # Nous devons renvoyer la largeur et la hauteur
      # pour imprimer le texte.
      return (w, h)

Lancez le script et admirez votre travail ! :-)

Renvoyez le chemin vers l'image dans la vue

L'image est créée mais comment l'enregistrer ?

Utilisez la méthode save() qui prend en paramètres le chemin vers le dossier où enregistrer l'image.

Créez une nouvelle méthode protégée, _path, qui renverra ce chemin :

utils.py

class OpenGraphImage:

    # nous ajoutons le paramètre uid
    def __init__(self, uid, first_name, description):
        ...
        background.save(self._path(uid))

    def _path(self, uid):
        # Le nom de l'image est l'identifiant Facebook de la personne.
        # Cela nous garantit de ne pas avoir de doublon.
        return os.path.join('fbapp', 'static', 'tmp', '{}.jpg'.format(uid))

Enfin, ajoutez une nouvelle méthode qui renverra le nom de l'image uniquement :

utils.py

class OpenGraphImage:
    def __init__(self, uid, first_name, description):
        self.location = self._location(uid)
        # ...

    def _location(self, uid):
        return 'tmp/{}.jpg'.format(uid)

Vous pouvez désormais utiliser cette méthode dans la vue !

views.py

from .utils import find_content, OpenGraphImage

...

@app.route('/result/')
def result():
    ...
    img = OpenGraphImage(uid, user_name, description).location

Comment vérifier que le script fonctionne ?

Lancez le serveur et allez sur l'URL suivante :

http://localhost:5000/result/?first_name=C%C3%A9line&id=1933433063608371&gender=female

Elle devrait se charger normalement.

Ouvrez l'inspecteur et regardez le contenu du head : vous devriez voir que la balise méta og:url contient désormais votre nouvelle image !

Copiez l'URL de la balise et collez-la dans la barre de navigation. Elle devrait ressembler à celle-ci :

http://localhost:5000/index/?img=tmp%2F1933433063608371.jpg

Là encore, regardez le contenu du head : la balise méta og:image devrait maintenant contenir votre toute nouvelle photo de couverture ! L'URL devrait ressembler à la suivante :

http://localhost:5000/static/tmp/1933433063608371.jpg

D'ailleurs, vous ne trouvez pas que tester tout ceci devient un peu contraignant ? Moi, si. J'ai bien envie de tester le parcours utilisateur afin de ne plus avoir à le faire à la main.

Récupérez le code du chapitre

Retrouvez l'intégralité du code de ce chapitre à cette adresse.

En résumé

Dans ce chapitre, vous avez vu comment :

  • Générer et manipuler une image grâce à la librairie externe Pillow

    • Pillow est disponible depuis le gestionnaire de paquets Pypi

    • Pour travailler sur une image, Pillow vient avec les objets  Image  ,ImageFont  etImageDraw

  • Créer le chemin d’une image et le retourner dans une vue Flask

    • Utiliser le module  os  de Python pour manipuler des chemins

    • Ajouter un paramètre avec l’image dans la fonction  render_template()  de la vue pour la passer au template 

  • Tester de manière simple l’application en ouvrant l’inspecteur de code du navigateur

    • Cela permet de vérifier le contenu des balises HTML généré par le template

Votre application web est désormais fonctionnelle ! Il ne reste plus qu’à la tester et à la déployer en production, mais avant cela, vérifiez que vous avez bien compris les notions vues dans cette partie avec le quizz qui suit.

Exemple de certificat de réussite
Exemple de certificat de réussite