5 votes

Comment rendre des pages HTML sous forme d'images PNG/JPEG en un seul clic en utilisant le tableau d'onglets d'URLs en Javascript uniquement ?

Je suis en train de construire une extension chrome utilisant Javascript qui récupère les URL des onglets ouverts et enregistre le fichier html, mais le problème avec le html est qu'il ne rend pas complètement les images sur les pages web. J'ai donc modifié mon code pour boucler chaque URL des onglets et ensuite enregistrer chaque page html en tant que fichier image automatiquement en un clic sur l'icône de téléchargement de l'extension chrome. J'ai fait des recherches pendant plus de 2 jours mais rien ne s'est produit. Veuillez voir mes fichiers de code et me guider. Je sais qu'il y a une bibliothèque dans nodejs mais je veux faire du html en jpeg/png en utilisant uniquement l'extension chrome.

Les seules icônes que je n'ai pas jointes sont celles que j'ai utilisées dans cette extension, tout le code que j'ai et le texte de l'extension. popup.js qui est commenté j'ai essayé.

Sortie actuelle du code ci-joint enter image description here

Mise à jour de popup.js

Fichier popup.js - Ce fichier contient des fonctions qui récupèrent toutes les URLs des onglets ouverts dans la fenêtre du navigateur.

// script for popup.html
window.onload = () => {  

    // var html2obj = html2canvas(document.body);
    // var queue  = html2obj.parse();
    // var canvas = html2obj.render(queue);
    // var img = canvas.toDataURL("image/png");

    let btn = document.querySelector("#btnDL");
    btn.innerHTML = "Download";

    function display(){
        // alert('Click button is pressed')
        window.open("image/url");
    }

    btn.addEventListener('click', display);
}

chrome.windows.getAll({populate:true}, getAllOpenWindows);

function getAllOpenWindows(winData) {

    var tabs = [];
    for (var i in winData) {
      if (winData[i].focused === true) {
          var winTabs = winData[i].tabs;
          var totTabs = winTabs.length;

          console.log("Number of opened tabs: "+ totTabs);

          for (var j=0; j<totTabs;j++) {

                tabs.push(winTabs[j].url);

                // Get the HTML string in the tab_html_string
                tab_html_string = get_html_string(winTabs[j].url)

                // get the HTML document of each tab
                tab_document = get_html_document(tab_html_string)

                console.log(tab_document)

                let canvasref = document.querySelector("#capture");
                canvasref.appendChild(tab_document.body);

                html2canvas(document.querySelector("#capture")).then(canvasref => {

                    document.body.appendChild(canvasref)
                    var img = canvasref.toDataURL("image/png");
                    window.open(img)

                });

          }
      }
    }
    console.log(tabs);
}

function get_html_document(tab_html_string){

    /**
     * Convert a template string into HTML DOM nodes
     */

    var parser = new DOMParser();
    var doc = parser.parseFromString(tab_html_string, 'text/html');
    return doc;

}

function get_html_string(URL_string){

    /**
     * Convert a URL into HTML string
     */

    let xhr = new XMLHttpRequest();
    xhr.open('GET', URL_string, false);

    try {
        xhr.send();
        if (xhr.status != 200) {
            alert(`Error ${xhr.status}: ${xhr.statusText}`);
        } else {
                return xhr.response                                
            }

    } catch(err) {
        // instead of onerror
        alert("Request failed");
    }
}

Fichier popup.html - Ce fichier représente la fonctionnalité d'icône et de clic sur la barre de recherche du navigateur Chrome.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <!-- <meta name="viewport" content="width=device-width, initial-scale=1.0"> -->
    <script src= './html2canvas.min.js'></script>
    <script src= './jquery.min.js'></script>
    <script src='./popup.js'></script>

    <title>Capture extension</title>

        <!--
          - JavaScript and HTML must be in separate files: see our Content Security
          - Policy documentation[1] for details and explanation.
          -
          - [1]: http://developer.chrome.com/extensions/contentSecurityPolicy.html
         -->
</head>
<body>

    <button id="btnDL"></button>

</body>
</html>

Fichier manifest.json - Ce fichier est utilisé par le navigateur Chrome pour exécuter l'extension Chrome.

{ 
      "manifest_version": 2,
      "name": "CIP screen capture",
      "description": "One-click download for files from open tabs",
      "version": "1.4.0.2",
      "browser_action": {
        "default_popup": "popup.html"
      },
      "permissions": [
        "downloads", "tabs", "<all_urls>"
      ],
      "options_page": "options.html"
}

4voto

joao_pimentel Points 556

Vous pouvez utiliser la bibliothèque html2canvas qui rend tout élément html, en particulier le body et, à partir du canevas résultant, vous pouvez faire en sorte que votre image

<script type="text/javascript" src="https://github.com/niklasvh/html2canvas/releases/download/v1.0.0-rc.7/html2canvas.min.js"></script>
<script>
  html2canvas(document.body).then(
    (canvas) => {
      var img = canvas.toDataURL("image/png"); 
    }
  );
</script>

Vous pouvez obtenir html2canvas à partir de n'importe quel CDN public, tel que celui-ci . Vous n'avez pas besoin de nodeJS. Ou peut-être directement depuis le dépôt git original

<script type="text/javascript" src="https://github.com/niklasvh/html2canvas/releases/download/v1.0.0-rc.7/html2canvas.min.js"></script>

Vous pouvez également enregistrer le canevas en tant que blob

html2canvas(document.body).then(function(canvas) {
    // Export canvas as a blob 
    canvas.toBlob(function(blob) {
        // Generate file download
        window.saveAs(blob, "yourwebsite_screenshot.png");
    });
});

0voto

SilentTremor Points 3045

C'est possible avec vanilla JS, je suppose que vanilla est plus susceptible d'être utilisé sur une extension, l'inconvénient est le résultat final, quand une bibliothèque tierce partie mon déjà corrigé les problèmes que vous rencontrez avec les polices et le style (html2canvas ou autre).

Donc, vanilla js, pour une raison quelconque le snippet de stack overflow ne permet pas window.open , démo ici : https://jsfiddle.net/j67nqsme/

Quelques mots sur la manière dont elle a été mise en œuvre :

  • en utilisant la transformation html en svg, une bibliothèque tierce peut être utilisée ici
  • utiliser canvas pour transformer svg en pdg ou jpg
  • exemple : possibilité d'exporter du html ou une page vers svg, png, jpg
  • il n'est pas à l'épreuve des balles - le rendu peut en souffrir, le style, les polices, les ratios, le media query

Disclaimer : Je ne vous aiderai pas à déboguer ou à trouver la solution de votre problème, c'est une réponse à votre question en utilisant vanilla js, à partir de là, c'est à vous de décider ce que vous utilisez ou comment vous l'utilisez.

Code source ci-dessous :

<html>
<body>
    <script>
        function export1() {
            const html = '<div style="color:red">this is <br> sparta </div>';
            renderHtmlToImage(html, 800, 600, "image/png");
        }

        function export2() {
            renderDocumentToImage(window.document, 800, 600, "image/png");
        }
        // format is: image/jpeg, image/png, image/svg+xml
        function exportImage(base64data, width, height, format) {
            var img = new Image();
            img.onload = function () {
                if ("image/svg+xml" == format) {
                    var w = window.open("");
                    w.document.write(img.outerHTML);
                    w.document.close();

                }
                else {
                    const canvas = document.createElement("Canvas");
                    canvas.width = width;
                    canvas.height = height;
                    const ctx = canvas.getContext('2d');
                    ctx.fillStyle = "white";
                    ctx.fillRect(0, 0, canvas.width, canvas.height);
                    ctx.drawImage(img, 0, 0);
                    var exportImage = new Image();
                    exportImage.onload = function () {
                        var w = window.open("");
                        w.document.write(exportImage.outerHTML);
                        w.document.close();
                    }
                    exportImage.src = canvas.toDataURL(format);
                }
            }
            img.src = base64data;
        }

        // format is: image/jpeg, image/png, image/svg+xml
        function renderHtmlToImage(html, width, height, format) {
            var svgData = '<svg xmlns="http://www.w3.org/2000/svg" width="' + width + '" height="' + height + '">'
                + '<foreignObject width="100%" height="100%">'
                + html2SvgXml(html)
                + '</foreignObject>'
                + '</svg>';
            var base64data = "data:image/svg+xml;base64," + btoa(svgData);
            exportImage(base64data, width, height, format);

        }

        function renderDocumentToImage(doc, width, height, format) {
            var svgData = '<svg xmlns="http://www.w3.org/2000/svg" width="' + width + '" height="' + height + '">'
                + '<foreignObject width="100%" height="100%">'
                + document2SvgXml(doc)
                + '</foreignObject>'
                + '</svg>';
            var base64data = "data:image/svg+xml;base64," + btoa(svgData);
            exportImage(base64data, width, height, format);
        }

        // plain html to svgXml
        function html2SvgXml(html) {
            var htmlDoc = document.implementation.createHTMLDocument('');

            htmlDoc.write(html);
            // process document
            return document2SvgXml(htmlDoc);
        }

        // htmlDocument to
        function document2SvgXml(htmlDoc) {
            // Set the xmlns namespace
            htmlDoc.documentElement.setAttribute('xmlns', htmlDoc.documentElement.namespaceURI);

            // Get XML
            var svcXml = (new XMLSerializer()).serializeToString(htmlDoc.body);
            return svcXml;
        }
    </script>
    <div>
        <h3 style="color:blue">My Title</h3>
        <div style="color:red">
            My Text
        </div>
        <button onclick="export1()">Export Plain Html</button>
        <button onclick="export2()">Export Entire Document</button>
    </div>
</body>
</html>

0voto

Keith Points 46288

Il y a trois façons d'aborder cette question :

  1. Rendu dans le javascript du client en utilisant une API telle que HTML2Canvas . Elle est isolée, s'exécute dans le navigateur, mais repose sur un réexamen qui peut fausser les détails de la page capturée (voir la plupart des problèmes avec H2C ). Cela peut convenir si vous ne voulez qu'un petit aperçu et que la différence n'est pas trop importante. Faites également attention car le rendu est lent et un peu lourd - les rendus en arrière-plan de grandes pages peuvent être remarqués par les utilisateurs, mais il en va de même pour les attentes pour le rendu des images.

  2. Utilisez un service qui exécute Chrome pour visiter la page, puis faites une capture d'écran. Vous pouvez écrire cela ou acheter un service comme Site-Shot pour le faire à votre place. Cela nécessite un service qui aura un coût, mais qui peut garantir que le rendu est exact et que la charge sur les machines des utilisateurs est minimale.

  3. Utilisez le API de capture des onglets de Chrome pour faire une capture d'écran de l'onglet. C'est probablement la meilleure option pour une extension, mais actuellement vous ne pouvez capturer que l'onglet actif actuel. captureOffscreenTab est à venir, mais pour l'instant uniquement en Canari derrière un drapeau.

Je recommanderais l'option 3, car le temps que vous terminiez le composant, vous pourriez avoir accès aux nouvelles fonctionnalités. Si vous devez publier rapidement, vous pouvez utiliser les options 1 ou 2 comme solution à court terme.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X