• 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 01/02/2019

Ajoutez un peu d'intelligence !

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

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érer 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 !

Écrire sur une image

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

Écrire 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 !

Écrire 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 ! :-)

Renvoyer 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. C'est exactement ce que nous permettent les tests fonctionnels ! Nous verrons cela dans le prochain chapitre !

Code du chapitre

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

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