Capturer les captures d’écran des éléments DOM: VS côté serveur. Approches côté client

Il y a quelques semaines, j'ai écrit sur Chatilyzer, un nouveau projet parallèle sur lequel je travaillais le mois dernier.

Présentation rapide de l’application et de son déroulement: Chatilyzer vous permet d’obtenir des statistiques sur vos discussions WhatsApp. Pour que l'application fonctionne, vous devez télécharger un fichier * .txt exporté d'un chat WhatsApp. Chatilyzer analyse et analyse le texte et en extrait des données intéressantes. Ensuite, vous êtes redirigé vers une page de résultats où vous voyez une belle visualisation de l’activité de votre chat.

Un exemple de page de résultats Chatilyzer

L'un des défis que j'ai eu lors du développement de cette application Web était de permettre aux utilisateurs de créer une capture d'écran de la page de résultats et de la télécharger afin de pouvoir la partager dans leur groupe - plutôt que de partager une URL à la page.

Approche côté serveur (NodeJS)

J'ai commencé avec l'approche côté serveur, en utilisant PhantomJS et un module NPM appelé «Node Webshot». Il a une API très simple qui vous permet de créer des captures d'écran à partir d'une URL donnée:

importer une image Web à partir de 'Webshot';

webshot ('https://chatilyzer.com', 'chat.png', fonction (err) {
  // capture d'écran maintenant enregistrée dans chat.png
});

Après avoir créé la capture d'écran, je devais la télécharger sur un stockage en nuage et renvoyer l'URL de l'image au côté client afin de permettre à l'utilisateur de télécharger l'image.

Avantages:

  • Un module prêt à l'emploi.
  • La capture d'écran est en cours d'enregistrement dans le nuage, de sorte qu'elle est disponible à tout moment.
  • Api flexible qui vous permet de définir la largeur et la hauteur désirées de la capture d'écran.

Les inconvénients:

  • Tout ou rien - la capture d'écran capture toute la page et vous ne pouvez pas contrôler un élément spécifique que vous souhaitez capturer.
  • Rendu - Si vous devez attendre le chargement de JS asynchrone avant de capturer la capture d'écran, vous risquez de rencontrer des problèmes.
  • Environnement - Étant donné que vous n’êtes pas dans un environnement de navigateur réel, PhantomJS ne gère pas les polices personnalisées / Google de manière appropriée, ce qui conduit à une police par défaut affichée dans votre capture d’écran.
  • Stockage - Après avoir créé la capture d'écran, vous devez l'enregistrer dans un stockage en nuage afin de renvoyer une URL d'image valide à l'utilisateur. Ce qui signifie, vous avez besoin d'un fournisseur de stockage en nuage qui pourrait potentiellement vous coûter plus d'argent.
  • Sécurité - Si les données de la capture d’écran sont sensibles, l’enregistrement d’une copie dans le cloud n’est pas une bonne approche.

EDIT: Après avoir reçu quelques commentaires de la communauté, il s’avère qu’une autre solution côté serveur utilise un module NPM appelé «Puppeteer» qui s’exécute au-dessus de Chrome sans tête. Voici comment créer une capture d’écran avec Puppeteer:

const puppeteer = require ('puppeteer');

(async () => {
  navigateur const = wait puppeteer.launch ();
  const page = wait browser.newPage ();
  wait page.goto ('https://chatilyzer.com');
  wait page.screenshot ({path: 'chatilyzer.png'});

  attendez browser.close ();
}) ();

Ce module résoudrait les problèmes Tout ou rien, le rendu et l’environnement, car il fournit le même moteur de rendu que Chrome.

Approche côté client

Le résultat de l’approche côté serveur ne convenant pas à mon cas d’utilisation, j’ai donc commencé à explorer d’autres options.

J'ai trouvé une bibliothèque JS extrêmement cool appelée “html2canvas”, qui, comme son nom l'indique, transformera un élément HTML en un élément canvas.

site html2canvas

Comme vous pouvez le constater, il est également très facile à utiliser. En gros, vous appelez la méthode html2canvas et transmettez un élément DOM en tant qu’argument. Cette méthode retourne une promesse que vous pouvez utiliser pour extraire un élément de la toile.

html2canvas (document.querySelector ("# capture")). then (canvasElm => {
    document.body.appendChild (canvasElm);
});

Ensuite, vous voulez permettre à votre utilisateur de télécharger la capture d'écran.

Pour ce faire, utilisez la méthode JS toDataURL, comme vous pouvez le voir ci-dessous:

// Obtenir une chaîne de données base64
var imageType = 'image / png';
var imageData = canvasElm.toDataURL (imageType);
// Ouvre la chaîne de données dans la fenêtre en cours
document.location.href = imageData.replace (imageType, 'image / octet-stream');

Il existe une autre bibliothèque JS appelée «canvas2image». Je recommande de l'utiliser plutôt que de l'écrire vous-même, car cela vous donne plus de flexibilité et vous permet également de générer une balise d'image à partir de l'élément canvas. Donc, vous pouvez obtenir le même résultat en utilisant:

Canvas2Image.saveAsPNG (canvasElm, largeur, hauteur);

Avantages:

  • WYSIWYG - Le résultat est 1: 1 de ce que vous voyez à l’écran.
  • Pas de côté serveur - Tous en cours d'exécution dans le navigateur.
  • Sécurité - Si les données de la capture d’écran sont sensibles, capturez-les côté client de manière beaucoup plus sécurisée car le serveur n’a pas connaissance des résultats et n’enregistrez pas de copie ailleurs.

Les inconvénients:

  • Compatibilité - html2canvas n'est pas pris en charge par tous les navigateurs
  • Cher - Bien que html2canvas retourne une promesse, cela reste une action coûteuse, et pour les composants volumineux et compliqués, cela peut prendre quelques secondes avant d’obtenir des résultats.
  • Vue étroite - Si vous utilisez un écran étroit (dans mobile par exemple), la capture d'écran sera aussi étroite que la capture de la vue réelle (ce qui pourrait être résolu en passant une largeur de correction comme argument à canvas2html ou en ouvrant un iframe avec la largeur souhaitée en arrière-plan, faites une capture d’écran à cet endroit et renvoyez les données de l’image avec postMessage).
  • Prise en charge des éléments - Tous les éléments HTML ne sont pas pris en charge dans html2canvas. Par exemple, les autres éléments de la toile, iframes et flash ne seront pas rendus du tout.

En conclusion

Il existe deux approches pour capturer une capture d'écran à partir d'éléments HTML, et vous devriez penser à ce qui convient à vos besoins.

L'approche côté serveur est celle que vous choisissez lorsque vous avez besoin d'une expérience multi-navigateur / plateforme, et vous ne savez pas si vos utilisateurs disposeront du bon navigateur pour capturer la capture d'écran. Le prix que vous devrez payer correspond à la fois au paiement physique pour le service de stockage en nuage et aux résultats inexacts.

L’approche côté client est bonne lorsque vous avez la certitude que vos utilisateurs disposeront d’un navigateur capable de capturer la capture d’écran (ou que vous êtes prêt à en payer le prix pour ceux qui ne le sont pas), et lorsque la précision est essentielle pour la capture d’écran.

Pensée rapide - Je suppose que la meilleure approche sera de combiner entre eux. Vous pouvez vérifier si la compatibilité de navigation du navigateur de l’utilisateur bénéficie de la prise en charge nécessaire pour la capture d’une capture d’écran et, dans le cas contraire, du recours à l’approche côté serveur.

J'espère que vous avez apprécié l'article. Clap il vous a plu :)

Connaissez-vous d'autres façons de créer des captures d'écran de pages Web avec NodeJS? Partager dans les commentaires!