Dans cet article, d’une série p5.js mes "briques" de connaissance, nous allons voir les différentes options qui s’offrent à nous pour charger des images et les afficher :
charger une image d’un répertoire du script ;
charger une image via son url ;
demander à l’utilisateur de déposer des images à modifier
Les difficultés liées à l’utilisation d’images
Difficulté 1 : avoir complétement chargé l’image avant d’agir dessus
Si on charge l’image dans le setup, l’ordre est donné de charger et notre script continue l’exécution du code. Si l’image est un peu longue à charger, notre code cherche à l’utiliser avant même qu’elle soit chargée. Il faut donc empêcher javascript d’agir sur l’image avant qu’elle ne soit entièrement chargée. On va donc travailler de manière « Asynchrone ». On va donc utiliser la fonction preload() lorsque c’est possible ou une fonction « callback » sinon. C’est ce que l’on va voir dans cet article.
On peut exécuter un script javascript sur son navigateur. Mais dès lors qu’on cherche à lui faire utiliser des fichiers associés, on tombe sur une erreur Cross-origin resource sharing (CORS).
C’est un mécanisme de sécurité, qui évite d’exécuter sur un site un fichier en provenance d’un autre site. Malheureusement, ça nous complique sérieusement la vie. Pour l’éviter, il faut obligatoirement utiliser serveur web :
Pour ce qui suit, je considère que nous utilisons un serveur, local ou non.
Charger avec preload()
La fonction preload() permet de charger une image et de ne pas l’utiliser tant qu’elle n’est pas complètement chargée. On peut l’utiliser pour une ou plusieurs images, présentes dans le répertoire du script ou via une url.
Ce script d’exemple p5.js montre comment on peut charger une image dans la fonction setup(). Cependant, si l’image est longue à charger, on peut avoir des dysfonctionnements, Cet autre exemple, de pointillisme, illustrent le fonctionnement de la fonction preload(). L’image est chargée d’abord puis utilisée dans les fonctions setup() et/ou draw().
function preload() {
img = loadImage('assets/moonwalk.jpg');
}
On peut également charger une image identifiée par une url :
Dans certains cas on doit réaliser des actions sur ce qui a été chargé avant toute autre manipulation. Pour préserver l’asynchronicité, on utilisera des fonctions « call back ».
La fonction loadImage peut contenir des fonctions callback qui se déclenche lorsque loadImage a réussi (une autre fonction peut se déclencher en cas d’échec. C’est ce qui se passe dans cet exemple :
var tree;
function setup() {
createCanvas(400, 400);
//Loop is off so it would load faster
noLoop()
}
function draw() {
background(128);
//when the image has finished loading, call our imageLoaded function (defined below)
tree = loadImage("birch.png", imageLoaded)
}
function imageLoaded(){ //this function could be called whatever we want
image(tree,200,200,100,200);
}
Dans le code ci-dessus, on réalise le chargement de l’image dans la fonction draw mais on ne l’affiche que lorsqu’elle est chargée car la fonction imageLoaded() est une fonction callback, qui ne s’éxécutera qu’au « succcès » de la fonction loadImage() qui l’a appelée.
Dans cette option (contenu du sketch), que j’ai mis énormément de temps à faire fonctionner, il y a une succession d’actions :
la fonction preload() exécute fetch sur une url puis (noter le .then{} qui suit le fetch), stocke l’url fournie en réponse dans la variable imgURL avant de charger l’image correspondant à cette url. Le chargement de l’image déclenche l’exécution (callback) de la fonction waitForElement().
la fonction waitForElement( variable ) transfère en tant que variable la réponse de loadImage. Tant que la variable est indéfinie, la fonction s’éxécute elle même (elle est construite de façon récursive) et recommence à s’exécuter toutes les 250 millisecondes. Une fois que variable est définie (l’image est chargée), drawLoop est passé à false.
la fonction draw s’éxécute en permanence mais ne fait rien lorsque la variable drawLoop est true. Ce n’est donc que quand l’image est chargée, elle même chargée lorsqu’on a son url, que l’image est affichée et l’url aussi sur le canevas.
/****************************************************************
https://editor.p5js.org/Anne-Laure/sketches/w_cCQUJyQ
Charger 1 image aléatoire sur unsplash et afficher son url
construite à partir de https://editor.p5js.org/Anne-Laure/sketches/JsVMS3ENO
****************************************************************/
var imgURL ;
var drawLoop = true ;
function preload() {
fetch(`https://source.unsplash.com/random/512x302`).then((response)=> {
imgURL = response.url ;
print("---", imgURL) ;
// charger l'image
img = loadImage( imgURL, waitForElement );
return imgURL ;
})
}
function setup() {
createCanvas(windowWidth, windowHeight);
// voir aussi https://p5js.org/reference/#/p5/loadJSON
print("aaa", imgURL) ;
}
function draw() {
if ( !drawLoop ) {
background(220) ;
image(img, 10,10) ;
text( imgURL, 10, img.height + 30 ) ;
}
}
function waitForElement( variable ){
// voir https://stackoverflow.com/questions/7307983/while-variable-is-not-defined-wait
if(typeof variable !== "undefined"){
//variable exists, do what you want
print("zzz", variable) ;
drawLoop = false ;
}
else{
setTimeout(waitForElement, 250);
}
}
Dans la console, on peut se faire une idée de ce qu’il se passe . La première ligne « aaa undefined » correspond à un print() dans setup(). On voit donc que cette ligne est exécutée alors que preload() n’a pas terminé. fetch() n’est pas une fonction à utiliser en principe dans preload, c’est pour ça. Mais je n’ai pas trouvé d’autre solution. La deuxième ligne « — » est exécutée dans preload et indique la valeur de imgURL sur la ligne suivante. Enfin à partir de « zzz » on voit le print() demandé lorsque l’image est totalement chargée. On voit ainsi quelles informations sont renvoyées une fois que l’image est chargée. Et par exemple print( variable.width ) afficherait 512.
chargement par l’utilisateur
C’est l’utilisateur qui va déposer les images à modifier. C’est la solution proposée par takawo dans ce script :
Takawo a trouvé une solution pour que ce soit l’utilisateur qui charge les fichiers à utiliser. Et il parvient à les traiter de manière asynchrone : tant que les fichiers n’ont pas tous été chargés et traités, rien ne se passe. Le code est visible ici, sur mon dépôt GitHub.
Et maintenant ?
Et voilà nous avons une quatrième brique ! Les autres briques sont et seront publiées dans cette même série, p5.js mes "briques" de connaissance.
Nous verrons dans une prochaine brique comment charger plusieurs images à la fois. Une autre brique consistera à charger des images aléatoires à partir d’une API. Nous utiliserons l’API du site d’images unsplash. On récupérera des données au format JSON et on chargera les url obtenues pour avoir des images manipulables.
Je ne peux pas simplement (en tous cas pas sans prendre des risques en matière de sécurité) mettre mes scripts de p5.js sur ce site. Alors quand je suis tombée par hasard sur cette vidéo de Daniel Shiffman expliquant comment créer une page gitHub pour héberger ses sketch p5.js j’ai regardé et j’ai mis en oeuvre immédiatement ! Ce que je décris ci-dessous n’est pas exactement ce qu’il propose car je n’ai pas réussi à faire fonctionner ça hors de la branche master.
Ce que l’on va faire
On aura un dépôt GitHub public où chacun pourra aller lire le contenu des fichiers que j’y aurai mis et une page pour chaque sketch qui en permettra l’exécution.
Les url seront sous la forme :
Pour l’accès aux fichiers : https://github.com/aldelpech/p5js-sketch/tree/master/NOM_DU_REPERTOIRE, par exemple https://github.com/aldelpech/p5js-sketch/tree/master/Ajustement_canevas_2020_05_09_13_46_20
Pour l’exécution directe : https://aldelpech.github.io/p5js-sketch/NOM_DU_REPERTOIRE, par exemple https://aldelpech.github.io/p5js-sketch/Ajustement_canevas_2020_05_09_13_46_20/
Pour l’accès au code raw (sans se connecter à GitHub) : https://raw.githubusercontent.com/aldelpech/p5js-sketch/master/NOM_DU_REPERTOIRE/sketch.js, par exemple https://raw.githubusercontent.com/aldelpech/p5js-sketch/master/Ajustement_canevas_2020_05_09_13_46_20/sketch.js
Créer un compte gitHub
Aller sur https://github.com/ et créer un compte si ce n’est pas encore fait.
Créer un depôt (repository en anglais)
Une fois qu’on est sur son compte, on peut créer un « repository » en cliquant sur le symbole + en haut à droite. Ici je crée le dépôt « p5js-sketch, en mode public, avec un fichier README.
Création d’un dépôt github public pour des sketches p5.js
Une fois que j’ai cliqué sur le bouton vert « Create repository », je dispose d’un nouveau depôt dont l’url est sous la forme https://github.com/USER/Nom-DEPOT (https://github.com/aldelpech/p5.js-sketches pour moi)
Transférer des fichiers au repository
Je voudrais transférer les fichiers qui m’ont permis de constituer la démonstration pour l’ article p5.js Brique 1 : un canevas “responsive”. Ces fichiers étaient dans un fichier compressé zio tel que téléchargé de l’éditeur de p5.js (https://editor.p5js.org/Anne-Laure/sketches/isSlIPoVn). Je les extrait avec mon ordinateur (windows). Et maintenant j’ai un répertoire contenant les 5 fichiers nécessaires à la démonstration :
Un répertoire de fichiers nécessaire à une animation p5.js
Il me suffit de prendre le répertoire et de le glisser dans mon repository gitHub.
Fichiers en cours de chargement par glisser-déposer
dans commit changes on précise sur quoi porte la modification (en fait le commit se fait vers master et pas maBranche) :
mieux vaut être clair et précis dans le commit
Lorsqu’on cliquer sur « commit changes », Github traite les fichiers et ça y est, j’ai un répertoire dans mon dépôt
Dans le dépôt, choisir l’onglet Settings en haut à droite. Descendre jusqu’à la partie GitHub Pages. Rien n’est réglé pour l’instant, il n’y aura pas d’affichage :
Les réglages de GitHub Pages ne sont pas encore faits
Je clique d’abord sur le bouton « Choose a theme ». Je choisis le thème Architect puis je clique sur le bouton vert « Select a theme ». Celà modifie le fichier readme.md. Je le commit :
Commit les modifications du Readme.md
Et maintenant je retourne dans l’onglet Settings et je descends jusqu’à GitHub Pages. Des réglages se sont faits !
Maintenant GitHub Pages est réglé et il a une adresse !
Si je communique le lien vers un fichier (par exemple ce lien pour le fichier sketch.js), le fichier devient visible dans GitHub si et seulement si on y est connecté.
Pour communiquer un lien accessible à une personne ne disposant pas d’un compte GitHub, il faut prendre le lien « RAW » et communiquer ce lien :
Nous avons tous des idées sur le travail à domicile, ses avantages, ses inconvénients et ses modalités. L’utilisation récente et massive du travail à distance montre qu’il y a cependant beaucoup à apprendre sur le sujet. Je démarre avec cet article une première liste de ressources qui peuvent être utiles pour se constituer un corpus de bonnes pratiques.
Outil Zoom de visioconférence, discord de partage de voix et d’écrans, ….
A explorer (je connais une entreprise qui l’utilise pour que ses salariés disposent de moyens de téléphoner à distance : Rainbow
Sur ce site, j’ai également écrit quelques articles qui peuvent être intéressants (les liens renvoient à des catégories d’article, il peut y avoir redondance) : sur des applications google, ou sur d’autres outils bureautique.
Avec Microsoft Office ou LibreOffice par exemple, il faut apprendre à utiliser tous les moyens existants de ne pas refaire plusieurs fois la même chose : styles, utilisation de modèles (templates), palette de couleurs standards, formulaires, publipostage, éventuellement macros.
Travailler en sécurité
J’ai suivi la formation en ligne à la sécurité numérique proposée par l’ANSSI, Agence nationale de la sécurité des systèmes d’information. C’était intéressant, et très utile.
Je pense qu’il est essentiel de réfléchir à la gestion des mots de passe : personnels et professionnels. Je ne vois pas comment on peut avoir une gestion correcte sans gestionnaire de mot de passe. Mais pour l’instant ce n’est pas simple d’en trouver un bon. Alors voici quelques pistes :
Avec les briques 1 et 2 – de cette série p5.js mes "briques" de connaissance – nous avons exploré la création de canevas « responsive » puis l’utilisation de « GRAPHICS » pour dessiner des rectangles sur des graphics, ou canevas virtuels. Cette fois ci nous allons dessiner des polygones avec des vertex à la place des rectangles. Un des polygones sera creux pour voir comment ça se passe. Nous obtiendrons ainsi quelque chose comme ça :
Des polygones, dont un creux, qui s’ajustent automatiquement à la taille de l’écran
J’ai fait ce sketch sur openProcessing.org, en p5.js :
Le script est intéressant pour son utilisation de beginShape et beginContour.
la fonction ajustPolygon(index, ep, w, h) crée les polygones (quadrilatères) 1 à 4 en calculant les coordonnées des extrémités (vertex) des 4 segments qui les constituent. Le polygone d’index 4, celui qui est représenté en bas à gauche, est « percé » d’un polygone à trois segments (un triangle). Ici les vertex sont donnés dans le sens des aiguille d’une montre si l’on veut juste indiquer un contour sans « percer » mais dans le sens inverse si l’on veut évider ou « percer ».
Et voilà nous avons une troisième brique ! Les autres briques sont et seront publiées dans cette même série, p5.js mes "briques" de connaissance.
Mon prochain objectif est de découper des images grâce à des graphics. Pour celà, il va me falloir maîtriser trois nouvelles briques au moins : charger des images prédéfinie, récupérer des images par une API ou via l’utilisateur, appliquer un masque de découpe à une image.
Commentaires récents