Maison > interface Web > js tutoriel > le corps du texte

JavaScript implémente la fonction de capture d'écran

巴扎黑
Libérer: 2017-08-14 14:07:38
original
1931 Les gens l'ont consulté

Je pense que l'idée d'utiliser JS pour prendre des captures d'écran est très ridicule. Tout d'abord, JS n'a pas la permission d'appeler la fonction de capture d'écran du système d'exploitation. Deuxièmement, le navigateur (BOM) ne fournit pas de fonction. interface de capture d'écran pertinente. Après quelques réflexions, j'ai eu quelques idées. Ce qui suit est une brève introduction au code d'implémentation de la fonction de capture d'écran js à travers un exemple de code

J'ai récemment participé au développement de. pages associées de NetEase Hearthstone Box et je travaille sur une page de partage de groupe de cartes (Adresse : Partage de groupe de cartes Hearthstone Box), il y a une exigence : les utilisateurs peuvent partager ce groupe de cartes avec des amis sous forme d'images. L'approche originale consistait à utiliser le serveur pour convertir la page en image, puis à renvoyer l'adresse de l'image au front-end. Eh bien, c'est plutôt bien, et le serveur peut également mettre en cache les images converties, et la requête suivante peut renvoyer directement l'adresse de l'image. Il n’y a rien de mal à cela en principe. Cependant, un problème survient : les images converties en arrière-plan sont parfois incohérentes avec le contenu de la page, et parfois du contenu manque. La sœur PM est très mécontente et dit que ce problème doit être résolu. Quoi qu’il en soit, l’interface de conversion des pages en images se fait en arrière-plan, ce ne sont pas mes affaires ! Juste au moment où j'étais secrètement heureux, quelque chose de tragique s'est produit. Un collègue en arrière-plan a déclaré que, parce que certains contenus de la page sont chargés de manière asynchrone (par exemple, le code QR en bas est généré via Canvas), la conversion du serveur est parfois instable. Le contenu rendu de manière asynchrone ne peut pas être intercepté. Pour le dire franchement, il n'a aucun moyen de résoudre ce problème. Changeons le front-end. Qui a dit au front-end d'utiliser le rendu asynchrone ? Enfin, le leader m'a demandé d'essayer si je pouvais utiliser directement JS pour prendre des captures d'écran, ce qui non seulement réduirait la pression sur le serveur, mais résoudrait également le bug ci-dessus.

Au début, je trouvais l'idée d'utiliser JS pour faire des captures d'écran très ridicule (c'est la faute de mon ignorance, le front-end s'est développé trop vite ces dernières années) : Tout d'abord, JS le fait ne pas avoir l'autorisation d'appeler la fonction de capture d'écran du système d'exploitation, et deuxièmement, le navigateur (BOM) ne fournit pas non plus d'interface de capture d'écran pertinente. Que dois-je faire ? Si vous avez des questions, veuillez contacter Google. Ensuite, j'ai recherché : JS html vers png, puis j'ai trouvé ceci : render-html-to-an-image. Je commence à avoir quelques idées. Quelqu'un dans la réponse a mentionné que vous pouvez convertir le DOM en canevas, hein ! C'est encore Canvas ! Je ne pouvais pas m'empêcher d'être excité. C'était vraiment difficile de trouver un moyen de sortir des montagnes et des rivières, mais il y avait encore un brillant avenir dans un autre village ! Ensuite, j'ai cherché dom to canvas et suis arrivé au document mdn bien connu Drawing_DOM_objects_into_a_canvas. Puis j'ai commencé à lire le document sérieusement. Comme mentionné au début du document, vous ne pouvez pas convertir le DOM en canevas, mais vous pouvez convertir le DOM en SVG, puis dessiner le SVG dans le canevas. Certaines personnes peuvent se demander pourquoi devons-nous d’abord convertir dom en svg ? Cela peut être dû au fait que SVG utilise une représentation XML et que la structure est cohérente avec DOM.
Ce qui suit est le tutoriel étape par étape du document officiel :

1. Le type de média de Blob doit être "image/svg+xml"

2. 🎜>

3. Insérez un élément

dans l'élément svg foreignObject

4. Mettez du HTML conforme à la spécification dans l'élément ForeignObject

La conversion de dom en canevas est aussi simple. comme l'étape ci-dessus. Ce qui suit est une démo simple donnée dans le document :


<!doctype html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Document</title>
</head>
<body>
<canvas id="canvas" style="border:2px solid black;" width="200" height="200">
</canvas>
<script>
 var canvas = document.getElementById(&#39;canvas&#39;);
 var ctx = canvas.getContext(&#39;2d&#39;);
 var data = &#39;<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">&#39; +
  &#39;<foreignObject width="100%" height="100%">&#39; +
  &#39;<p xmlns="http://www.w3.org/1999/xhtml" style="font-size:40px">&#39; +
  &#39;<em>I</em> like &#39; +
  &#39;<span style="color:white; text-shadow:0 0 2px blue;">&#39; +
  &#39;cheese</span>&#39; +
  &#39;</p>&#39; +
  &#39;</foreignObject>&#39; +
  &#39;</svg>&#39;;
 var DOMURL = window.URL || window.webkitURL || window;
 var img = new Image();
 var svg = new Blob([data], {type: &#39;image/svg+xml&#39;});
 var url = DOMURL.createObjectURL(svg);
 img.onload = function() {
  ctx.drawImage(img, 0, 0);
  DOMURL.revokeObjectURL(url);
 }
 img.src = url;
</script>
</body>
</html>
Copier après la connexion
Copiez le code et exécutez-le, c'est trop cool. Une chose sympa apparaît sur le navigateur. Il y a deux lignes de mots artistiques !

Eh bien, il s'avère que convertir un dom en toile est si simple ? Ensuite, j'utilise

pour supprimer tout le DOM du corps et le mettre dans l'élément ForeignObject, n'est-ce pas OK et la page entière est capturée ? document.body.innerHTML

La démo n'est qu'un Hello World, mais la structure Dom dans le projet réel est beaucoup plus compliquée que cela. Par exemple, les feuilles de style externes, les images et certaines balises peuvent ne pas être conformes au XML. spécification (telle que balise de fermeture manquante, etc.). Voici un exemple simple. .container n'utilise pas de styles en ligne, mais est défini dans la balise de style. Une fois convertie en image, le style ne prendra pas effet.


<!doctype html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <title>Document</title>
 <style>
  .container {
   color: red;
  }
 </style>
</head>
<body>
<p class="container" >
 Hello World!
</p>
<canvas id="canvas" style="border:2px solid black;" width=200" height="200">
</canvas>
<script>
 var canvas = document.getElementById(&#39;canvas&#39;);
 var ctx = canvas.getContext(&#39;2d&#39;);
 var data = &#39;<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">&#39; +
  &#39;<foreignObject width="100%" height="100%">&#39; +
  &#39;<p xmlns="http://www.w3.org/1999/xhtml" style="font-size:40px">&#39; +
  document.querySelector(&#39;.container&#39;).innerHTML +
  &#39;</p>&#39; +
  &#39;</foreignObject>&#39; +
  &#39;</svg>&#39;;
 var DOMURL = window.URL || window.webkitURL || window;
 var img = new Image();
 var svg = new Blob([data], {type: &#39;image/svg+xml&#39;});
 var url = DOMURL.createObjectURL(svg);
 img.onload = function() {
  ctx.drawImage(img, 0, 0);
  DOMURL.revokeObjectURL(url);
 }
 img.src = url;
</script>
</body>
</html>
Copier après la connexion
Étant donné que les styles externes ne prennent pas effet, nous pouvons parcourir tous les éléments dom via JS et ajouter tous les styles aux styles en ligne via l'objet element.style. Cette idée semble bonne, mais je ne peux vraiment pas écrire la fonction qui convertit les styles externes en styles en ligne. La demande est forte et je n'ai pas beaucoup de temps pour m'amuser, je souhaite donc rechercher des bibliothèques prêtes à l'emploi. Je suis donc retourné sur Google. Heureusement, j'ai tout de suite trouvé une bibliothèque appelée html2canvas. C'est une super bibliothèque, très puissante, mais très simple à utiliser. Avec une méthode aussi simple, je peux faire une capture d'écran de ma page entière :

<🎜. >

function convertHtml2Canvas() {
  html2canvas(document.body, {
   allowTaint: false,
   taintTest: true
  }).then(function(canvas) {
   document.body.appendChild(canvas);
  }).catch(function(e) {
   console.error(&#39;error&#39;, e);
  });
 }
Copier après la connexion

目前还有一个问题,就是这种方法默认是把整个页面截取下来的(就是说,会以你的innerHeight和innerWidth为边界,会存在大量的空白),可是,我的卡组只是占了页面的一小部分,我只想要卡组的部分啊。其实已经有了canvas就好办了,我们可以对它进行处理啊。大概思路是:1.把上面得到的canvas对象转成Blob并放到一个img元素。然后再把img.src绘制到canvas里面。这时候调用canvas.drawImage方法就可以截取我们想要的内容了。下面的两个函数分别是把canvas转成image以及反过来把image转成canvas。


// Converts canvas to an image
 function convertCanvasToImage(canvas) {
  var image = new Image();
  image.src = canvas.toDataURL("image/png", 0.1);
  return image;
 }
 // Converts image to canvas; returns new canvas element
 function convertImageToCanvas(image, startX, startY, width, height) {
  var canvas = document.createElement("canvas");
  canvas.width = width;
  canvas.height = height;
  canvas.getContext("2d").drawImage(image, startX, startY, width, height, 0, 0, width, height);
  return canvas;
 }
Copier après la connexion

然后,再把我们上面的写的 convertHtml2Canvas 改成下面的:


function convertHtml2Canvas() {
  html2canvas(document.body, {
   allowTaint: false,
   taintTest: true
  }).then(function(canvas) {
   var img = convertCanvasToImage(canvas);
   document.body.appendChild(img);
   img.onload = function() {
    img.onload = null;
    canvas = convertImageToCanvas(img, 0, 0, 384, 696);
    img.src = convertCanvasToImage(canvas).src;
    $(img).css({
     display: &#39;block&#39;,
     position: &#39;absolute&#39;,
     top: 0,
     left: 400 + &#39;px&#39;
    });
   }
  }).catch(function(e) {
   console.error(&#39;error&#39;, e);
  });
 }
Copier après la connexion

这时候就可以把它的页面的某部分内容进行截取下来了。效果如卡组分享测试页面。页面左边部分是DOM结构的,右边部分是则是使用html2canvas转换出来的图片。长得一模一样,毫无毛病哈。

关于JS页面截图的就写到这里啦,因为也只刚刚接触,很多东西也理解得不到位,欢迎各大神指点。后面会深入学习一下html2canvas的源码,进一步理解dom to canvas的原理。

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal