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
<!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('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%">' + '<p 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>' + '</p>' + '</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; </script> </body> </html>
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
<!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('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%">' + '<p xmlns="http://www.w3.org/1999/xhtml" style="font-size:40px">' + document.querySelector('.container').innerHTML + '</p>' + '</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; </script> </body> </html>
function convertHtml2Canvas() { html2canvas(document.body, { allowTaint: false, taintTest: true }).then(function(canvas) { document.body.appendChild(canvas); }).catch(function(e) { console.error('error', e); }); }
目前还有一个问题,就是这种方法默认是把整个页面截取下来的(就是说,会以你的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; }
然后,再把我们上面的写的 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: 'block', position: 'absolute', top: 0, left: 400 + 'px' }); } }).catch(function(e) { console.error('error', e); }); }
这时候就可以把它的页面的某部分内容进行截取下来了。效果如卡组分享测试页面。页面左边部分是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!