2

I'm trying to take a full screenshot of a webpage and noticed that Chrome has built into their devtools a command to do that. Is there a way to call this command using Javascript in the console or on the webpage?

Edit: to distinguish this question from the referenced, already-answered question on Stack Overflow, I'm asking whether a solution exists to fully capture the webpage without looking at the html and parsing that with javascript. There's apps to do this on the Chrome extension store; however, they rely on the captureVisibleTab API which isn't as fluid as the devtool command that doesn't seem to require scrolling and stitching.


Answer: In the general case, you cannot have simple Javascript in the browser call functions and methods implemented in the devtools library; primarily due to security concerns, your Javascript is sandboxed.

The one exception is if you are making a Chrome extension, where you can specify permissions to the Chrome debugger API. This API allows you to access the Chrome Devtools Protocol, which then allows you to call devtool commands. I found this through a question asking how to access the emulator on devtools. In that post, you can find an example of an extension that accesses the emulator.

As for the full-page screenshot command, I reviewed the source code for the native implementation and puppeteer implementation [1], and found a way to re-implement it for a client-side extension.

{
    "name": "",
    "version": "0.1.0",
    "description": "",
    "permissions": [
        "tabs",
        "debugger"
    ],
    "manifest_version": 2,
    "background": {
      "scripts": ["background.js"],
      "persistent": false
    },
    "browser_action": {
    }
}
'use strict';
const protocolVersion = "1.3"

/**
 * @param {!Element} canvas
 */
function saveScreenshot(canvas) {
    let fileName = "hello"
    const link = document.createElement('a');
    link.download = fileName + '.png';
    console.log(canvas)
    canvas.toBlob(function(blob) {
        console.log(blob)
        link.href = URL.createObjectURL(blob);
        link.click();
    });
};

function getPNG(tabId) {
    chrome.debugger.attach({
        tabId: tabId
    }, protocolVersion, function() {
        chrome.debugger.sendCommand({
            tabId: tabId
        }, "Page.getLayoutMetrics", {}, function(object) {
            console.log(object)
            const {height, width} = object.contentSize
            chrome.debugger.sendCommand({
                tabId: tabId
            }, "Emulation.setDeviceMetricsOverride", {height: height, width: width, deviceScaleFactor: 1, mobile: false}, function() {
                console.log("hello world")
                chrome.debugger.sendCommand({
                    tabId: tabId
                }, "Page.captureScreenshot", {}, function(screenshot) {
                    console.log(screenshot)

                    const pageImage = new Image();
                    pageImage.src = 'data:image/png;base64,' + screenshot.data;
                    pageImage.onload = function() {
                        const canvas = document.createElement('canvas');
                        canvas.width = pageImage.naturalWidth;
                        canvas.height= pageImage.naturalHeight;

                        const ctx = canvas.getContext('2d');
                        ctx.imageSmoothingEnabled = false;
                        ctx.drawImage(pageImage, 0, 0);
                        console.log(canvas, pageImage)
                        saveScreenshot(canvas);
                    }

                    chrome.deugger.detach({
                        tabId: tabId
                    })

                })
            })
        })
    })
}

chrome.runtime.onInstalled.addListener(function() {
    console.log("installed");
});

chrome.browserAction.onClicked.addListener(function() {
    chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
        var currTab = tabs[0];
        if (currTab) {
            getPNG(currTab.id)
        }
    });
});

[1] Puppeteer is a server-side NodeJS library to control Chromium over devtools protocol. As of the current implementation, you cannot run puppeteer in the browser with something like Webpack.

Sentient
  • 781
  • 2
  • 10
  • 23
  • 1
    DevTools commands are generally not accessible from JavaScript. – Barmar Aug 04 '19 at 03:15
  • Damn. I wonder if there's a way to replicate what Chrome does. It doesn't seem to try to guess from the html the page rendered to the user but has access to that window itself. The answers to the other post seem to all be guessing html. To edit, I've found previously it is possible to view the DevTools by inspecting the inspector, but you can't use those script due to CORS. – Sentient Aug 04 '19 at 04:53

0 Answers0