Pour comprendre cet article, il est recommandé d'être à l'aise avec ls JavaScript, Canvas API et DOM API

C'est encore mieux si vous êtes familiarisé avec SVG .

Bien que ce ne soit pas banal (pour des raisons de sécurité), il est possible de dessiner du contenu DOM (comme du HTML ) dans un élément canvas . Cet article, qui tire son origine de ce billet de Robert O'Callahan, explique comment le faire de manière sécurisée et sans danger, en respectant la spécification.

Un aperçu

Vous ne pouvez pas simplement dessiner du HTML dans un élément canvas. Ce qu'il est possible de faire en revanche est d'utiliser une image SVG renfermant le contenu que vous voulez restituer. Pour dessiner du contenu HTML, vous utiliserez un élément <foreignObject> contenant le HTML et ensuite dessinerez l'image SVG dans votre élément canvas.

Étape par étape

La seule partie difficile (et c'est sans doute surestimé) est de créer le fichier SVG de votre image. Tout ce dont vous avez besoin est de créer une chaîne de caractères contenant le XML pour le SVG et de construire un Blob composé de ce qui suit :

  1. Le type de media MIME du blob doit être "image/svg+xml".
  2. L'élément <svg>.
  3. Au sein de cet élément, l'élément <foreignObject>.
  4. Le XHTML (bien formé) lui-même, inséré dans le <foreignObject>.

En utilisant un objet URL comme décrit ci-dessus, vous pouvez insérer votre code HTML dans le même bloc de code plutôt que de le charger depuis une source externe. Vous pouvez bien sûr utiliser une source externe si vous préférez, à condition que son origine reste la même que celle du document actuel.

Exemple

HTML

<canvas id="canvas" style="border:2px solid black;" width="200" height="200">
</canvas>

JavaScript

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

var data = '<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">' +
           '<foreignObject width="100%" height="100%">' +
           '<div xmlns="http://www.w3.org/1999/xhtml" style="font-size:40px">' +
             '<em>I</em> like ' + 
             '<span style="color:white; text-shadow:0 0 2px blue;">' +
             'cheese</span>' +
           '</div>' +
           '</foreignObject>' +
           '</svg>';

var DOMURL = window.URL || window.webkitURL || window;

var img = new Image();
var svg = new Blob([data], {type: 'image/svg+xml'});
var url = DOMURL.createObjectURL(svg);

img.onload = function() {
  ctx.drawImage(img, 0, 0);
  DOMURL.revokeObjectURL(url);
}

img.src = url

L'exemple ci-dessus produira le résultat suivant :

ScreenshotLive sample

La variable data est réglée avec le contenu de l'image SVG (elle-même incluant le code HTML ) que l'on veut dessiner dans l'élément canvas .

On crée ensuite une nouvel élément  HTML <img> en appelant new Image(); on y ajoute data ; on alloue un objet URL et on dessine l'image dans le contexte en invoquant drawImage() au chargement.

Sécurité

Vous pouvez vous demander en quoi est-ce sécurisé, étant donné que l'on pourrait éventuellment lire des données sensibles depuis cet élément canvas. Voici pourquoi : cette solution repose sur le fait que l'implémentation des images SVG est très restrictive. Les images SVG ne sont pas autorisées à charger des ressources externes, y compris celles qui peuvent apparaître comme provenant du même domaine. Les ressources comme les images matricielles (images JPEG par exemples) ou les <iframe>s doivent être renseignées en tant que data: URI.

En plus de cela, vous ne pouvez pas insérer de script dans une image SVG et il n'y a donc pas de risque d'accès au DOM depuis d'autres scripts, les elements DOM des images SVG ne peuvent quant à eux pas recevoir d'événements d'entrée (input), il n'y a donc pas de moyens de charger des informations privilégiées dans un formulaire (comme un chemin absolu dans le fichier de l'élément <input>) puis de le rendre et d'en lire l'information grâce aux pixels.

Les styles des liens visités ne s'appliquent pas aux liens affichés dans les images SVG afin qu'aucune information concernant l'historique ne puisse être déduite, les thèmes natifs ne sont eux aussi pas appliqués dans les images SVG, rendant ainsi plus difficile la détermination de la plateforme de l'utilisateur.

L'élément canvas résultant doit avoir une origine nettoyée, c'est à dire que vous pouvez appeler toBlob(function(blob){…}) pour retourner un blob pour l'élément canvas ou toDataURL() pour retourner une data: URI encodée en Base64.

Dessin HTML

Le code SVG devant être du code XML valide, par opposition à la sérialisation html de HTML5, vous devez analyser HTML pour obtenir la sortie bien formée de l'analyseur HTML. Le code suivant est le moyen le plus simple d'analyser le code HTML.

var doc = document.implementation.createHTMLDocument('');
doc.write(html);

// Vous devez donner une valeur au xmlns si vous souhaitez immédiatement normaliser
// en une chaîne de caractères plutôt que de l'ajouter à un
// <foreignObject> dans le DOM
doc.documentElement.setAttribute('xmlns', doc.documentElement.namespaceURI);

// Avoir le balisage bien formé
html = (new XMLSerializer).serializeToString(doc);

Voir aussi

Étiquettes et contributeurs liés au document

Étiquettes : 
 Contributeurs à cette page : loella16, Delapouite, tregagnon, SphinxKnight
 Dernière mise à jour par : loella16,