Autoriser les images et canevas provenant d'autres origines
===========================================================

HTML permet d'utiliser l'attribut `crossorigin` sur les images. Utilisé avec un en-tête CORS adéquat, les images définies par `<img>` provenant d'origines étrangères pourront être utilisées au sein d'un élément `<canvas>` comme si elles avaient été chargées depuis l'origine courante.

Pour plus de détails sur l'attribut `crossorigin`, voir les attributs de paramétrage du CORS.

Canevas corrompu et sécurité
----------------------------

Les pixels composant un canevas pouvant venir de différentes sources, notamment d'images ou de vidéos récupérées depuis des hôtes tiers, il est nécessaire de se prémunir contre certains problèmes de sécurité.

Dès que des données sont chargées dans le canevas depuis une autre origine sans avoir été « approuvées » par le CORS, le canevas devient **corrompu** (*tainted*). Dès qu'un canevas est corrompu, il n'est plus considéré comme sécurisé et toute tentative de récupérer des données depuis les données de l'image résultera en une exception.

Si la source du contenu tiers est un élément HTML `<img>` ou SVG `<svg>`, il n'est plus permis de récupérer le contenu du canevas.

Si la source du contenu tiers est une image obtenue à partir d'un `HTMLCanvasElement` ou d'une `ImageBitMap` (en-US) et que la source de l'image ne respecte pas les règles quant à l'unicité de l'origine, il ne sera pas possible de lire le contenu du canevas.

Appeler l'une des méthodes suivantes sur un canevas corrompu déclenchera une erreur :

* `getImageData()` sur le contexte du canevas
* `toBlob()` (en-US) sur l'élément `<canvas>`
* `toDataURL()` (en-US) sur le canevas

L'exception levée par de tels appels sera une exception `SecurityError`. Cette mesure protège les utilisateurs contre l'exposition de données privées via des images provenant de sites tiers sans permission.

Stocker une image provenant d'une origine tierce
------------------------------------------------

Dans cet exemple, on souhaite autoriser la récupération et l'enregistrement d'images provenant d'une autre origine. Pour parvenir à ce résultat, il faudra configurer le serveur et également écrire du code pour le site web.

### Configuration serveur

Pour commencer, configurons le serveur stockant les images avec un en-tête `Access-Control-Allow-Origin` qui permet un accès multi-origines aux fichiers images.

Dans la suite de cet exemple, on prendra le cas d'un site est servi via Apache. On pourra utiliser le fragment de configuration serveur Apache pour les images CORS :


```xml
<IfModule mod\_setenvif.c>
  <IfModule mod\_headers.c>
    <FilesMatch "\.(bmp|cur|gif|ico|jpe?g|png|svgz?|webp)$">
      SetEnvIf Origin ":" IS_CORS
      Header set Access-Control-Allow-Origin "*" env=IS_CORS
    </FilesMatch>
  </IfModule>
</IfModule>
```


Pour résumer, cela permet de configurer le serveur afin de pouvoir accéder aux fichiers graphiques (ceux avec les extensions ".bmp", ".cur", ".gif", ".ico", ".jpg", ".jpeg", ".png", ".svg", ".svgz", and ".webp") depuis d'autres origines, d'où qu'elles soient sur Internet.

### Implémenter l'enregistrement

Maintenant que le serveur est configuré pour permettre la récupération d'image depuis plusieurs origines, on peut écrire le code qui permet à l'utilisateur d'enregistrer les images en stockage local comme si elles étaient servies depuis le même domaine que le code.

Pour cela, on utilise l'attribut `crossorigin` en définissant `crossOrigin` (en-US) sur l'élément `HTMLImageElement` sur lequel l'image sera chargée. Ainsi, on indique au navigateur de demander un accès multi-origine lors du téléchargement de l'image.

#### Démarrer le téléchargement

Voici le code qui démarre le téléchargement (déclenché par exemple lorsque l'utilisateur clique sur un bouton « Télécharger ») :


```js
function startDownload() {
  let imageURL =
    "https://cdn.glitch.com/4c9ebeb9-8b9a-4adc-ad0a-238d9ae00bb5%2Fmdn\_logo-only\_color.svg?1535749917189";

  downloadedImg = new Image();
  downloadedImg.crossOrigin = "Anonymous";
  downloadedImg.addEventListener("load", imageReceived, false);
  downloadedImg.src = imageURL;
}
```


Ici, l'URL de l'image à télécharger est codée en dur mais cette valeur pourrait très bien provenir d'un argument passé à la fonction. Pour démarrer le téléchargement, on crée un nouvel objet `HTMLImageElement` grâce au constructeur `Image()`. L'image est ensuite configurée afin de permettre un téléchargement multi-origine grâce à l'attribut `crossOrigin` paramétré avec `"Anonymous"` (qui permet le téléchargement, non-authentifié, d'une image multi-origine). Un gestionnaire d'évènement est ajouté afin de réagir à l'évènement `load` lorsque l'image a été reçue.

Enfin, l'attribut `src` (en-US) de l'image est défini avec l'URL de l'image à télécharger et le téléchargement démarre.

#### Recevoir et enregistrer l'image

Voici le fragment de code exécuté lorsque l'image a été téléchargée :


```js
function imageReceived() {
  let canvas = document.createElement("canvas");
  let context = canvas.getContext("2d");

  canvas.width = downloadedImg.width;
  canvas.height = downloadedImg.height;

  context.drawImage(downloadedImg, 0, 0);
  imageBox.appendChild(canvas);

  try {
    localStorage.setItem("saved-image-example", canvas.toDataURL("image/png"));
  } catch (err) {
    console.log("Error: " + err);
  }
}
```


`imageReceived()` est invoquée lorsque l'évènement `"load"` est déclenché sur l'élément `HTMLImageElement` qui reçoit l'image téléchargée. Cet évènement se produit lorsque l'ensemble des données téléchargées est disponible. Cette fonction commence par créer un nouvel élément `<canvas>` qui sera utilisé afin de convertir l'image en une URL de donnée. On récupère également un accès au contexte du canevas pour dessiner en 2D (`CanvasRenderingContext2D`) dans la variable `context`.

La taille du canevas est ajustée afin que ses dimensions correspondent à celles de l'image. L'image est ensuite dessinée dans le canevas grâce à `drawImage()`. Le canevas est alors inséré dans le document et l'image y devient visible.

Enfin, on enregistre l'image dans le stockage local. Pour cela, on utilise les méthodes de l'API *Web Storage* en passant par la variable globale `localStorage`. La méthode `toDataURL()` (en-US) est utilisée afin de convertir l'image en une URL de données représentant une image PNG qui est enregistrée dans l'espace local grâce à la méthode `setItem()`.

Vous pouvez essayer ou adapter cet exemple sur Glitch.

Voir aussi
----------

* Utilisation d'images inter-domaines dans WebGL et Chrome 13
* Spécification HTML : l'attribut `crossorigin`
* L'API *Web Storage*