簡體   English   中英

如何僅使用 Javascript 中的 URL 選項卡數組將 HTML 頁面渲染為 PNG/JPEG 圖像?

[英]How to render HTML pages as PNG/JPEG images on single click using URLs Tabs array in Javascript only?

我正在使用 Javascript 構建一個 chrome 擴展程序,它獲取打開的選項卡的 URL 並保存 html 文件,但 html 的問題是它不能在網頁上完全呈現圖像。 因此,我更改了代碼以循環選項卡的每個 URL,然后單擊 chrome 擴展程序的下載圖標自動將每個 html 頁面保存為圖像文件。 我已經研究了超過 2 天,但什么也沒發生。 請查看我的代碼文件並指導我。 我知道 nodejs 中有庫,但我想僅使用 chrome 擴展名對 jpeg/png maker 執行 html。

只有我沒有附加的圖標,我在這個擴展中使用過,我擁有的所有代碼和我嘗試過的popup.js中的文本。

附代碼的當前output 在此處輸入圖像描述

更新了 popup.js

文件popup.js - 此文件具有獲取瀏覽器中打開的選項卡的所有 URL 的功能 window

// 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");
    }
}

文件popup.html - 此文件表示 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>

文件manifest.json - 這個文件被 chrome 瀏覽器用來執行 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"
}

您可以使用庫html2canvas呈現任何 html 元素,尤其是body元素,並從生成的 canvas 中獲得您的圖像

<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>

您可以從任何公共 CDN 獲取 html2canvas,例如這個 你不需要nodeJS。 或者直接來自原始 git 存儲庫

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

您還可以將 canvas 保存為 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");
    });
});

使用 vanilla JS 是可能的,我猜 vanilla 更有可能用於擴展,缺點是最終結果,當第 3 方庫我已經修復了 fonts 和樣式(html2canvas 或其他)時會遇到的問題。

所以,香草js,由於某種原因堆棧溢出片段不允許 window.open ,這里演示: https://jsfiddle.net/j67nqsme/

關於它是如何實施的幾句話:

  • 使用 html 到 svg 轉換,此處可以使用第 3 方庫
  • 使用 canvas 將 svg 轉換為 pdg 或 jpg
  • 示例可以導出 html 或頁面到 svg, png, jpg
  • 它不是防彈的 - 渲染可能會受到影響,樣式,fonts,比率,媒體查詢

免責聲明:我不會幫助您調試或找到問題的解決方案,它是使用 vanilla js 對您的問題的回答,從那里您決定使用什么或如何使用它。

源代碼如下:

<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>

有3種方法可以解決這個問題:

  1. 使用像HTML2Canvas這樣的 API 在客戶端 javascript 中渲染它。 它是隔離的,在瀏覽器中運行,但依賴於重新渲染,這可能會使捕獲的頁面的詳細信息出錯(請參閱H2C 的大多數問題)。 如果您只想要一個小預覽並且不介意奇怪的差異,那可能會很好。 還要小心,因為渲染速度很慢並且有些重量級 - 用戶可能會注意到大頁面的背景渲染,但等待圖像渲染也是如此。

  2. 使用運行 Chrome 的服務訪問該頁面,然后對其進行截圖。 你可以寫這個或者購買像Site-Shot這樣的服務來為你做。 這需要一項服務,該服務會產生成本,但可以保證渲染准確並確保用戶機器上的負載最小。

  3. 使用Chrome 選項卡捕獲 API來截取選項卡。 這可能是擴展的最佳選擇,但目前您只能捕獲當前活動選項卡。 captureOffscreenTab即將推出,但目前僅在 Canary 后面有一個標志。

我推薦選項 3,因為當您完成組件時,您可以訪問新功能。 如果您需要盡快發布,您可以使用 1 或 2 作為短期解決方案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM