SoFunction
Updated on 2025-03-02

Summary of 5 ways to implement web screenshots in JavaScript

Recently, I have studied how to use JavaScript to implement web screenshots, including JS running in the browser and nodeJs running in the background. I mainly looked at the following:

  • PhantomJS

  • Puppeteer(chrome headless)

  • SlimerJS

  • dom-to-image

  • html2canvas

The web pages tested use WebGL technology, so the following summary will be related to WebGL.

Noun definition

headless browser

Interfaceless browser, mostly used for web page automation testing, web screenshots, web page network monitoring, etc.

PhantomJS

PhantomJS is a headless browser that can be programmed through JS and uses the QtWebKit kernel.

The code to implement the screenshot, assuming the file name is:

// Create a web page instancevar page = require('webpage').create();
// Load the page('/', function () {
    // Take a screenshot of the web page and save it to a file    ('');
    ();
})

run:

phantomjs 

There is no problem with normal pages, but if you run a page containing WebGL, you will find that the screenshot is wrong. After some investigation, it was found that WebGL, github issue is not supported.

Summarize:

  • PhantomJs has been stopped, so it is not recommended to continue using it. One reason for stopping maintenance is that the headless version released by Chrome has had a certain impact on it.

  • WebGL is not supported. However, some developers still say that they can add WebGL support to PhantomJS themselves. However, this solution is currently beyond my knowledge and has not continued to study it.

Puppeteer(chrome headless)

Puppeteer is a Node library that provides an API for controlling chrome and chromium. The headless mode is run by default and the interface is also supported.

Code to implement screenshots:

const puppeteer = require('puppeteer');

(async () => {
    const browser = await ();
    const page = await ();
    await ({ // Set the window size    width: 600,
    height: 800
    });
    await (''); // Open the page    await ({path: ''}); // path: save the screenshot file
    await ();
})();

run:

node 

Let's take a look at it nextscreenshotThe implementation principle of the method:

screenshotThe source code is located inlib/cjs/puppeteer/common/In the file, it is an asynchronous method:

async screenshot(options = {}) {
    // ...
    return this._screenshotTaskQueue.postTask(() => this._screenshotTask(screenshotType, options));
}
async _screenshotTask(format, options) {
    // ...
    const result = await this._client.send('', {
    format,
    quality: ,
    clip,
    });
    // ...
}

thisthis._client.sendWhat's it? Don't worry, let's re-read the definition of Puppeteer:

Puppeteer is a Node library which provides a high-level API to control Chrome or Chromium over the DevTools Protocol.

Have you seen the DevTools Protocol at the end? What is this:

The Chrome DevTools Protocol allows for tools to instrument, inspect, debug and profile Chromium, Chrome and other Blink-based browsers.

For detailed explanations, please read this blog.

Simply put, Puppeteer sends data following Chrome Devtools Protocol to the browser through WebSocket, and commands the browser to perform some operations. Then, the browser returns the result to Puppeteer through WebSocket. This process is asynchronous, so looking at the source code you will find a lot of async/await.

soscreenshotThe method is to call the captureScreenshot of Chrome Devtools Protocol.

Summarize:

  • Supports WebGL.

  • If the web page is more complicated, the screenshot time is quite long. The page I tested was several hundred milliseconds.

  • Puppeteer is a package of (CDP) Chrome Devtools Protocol functionality. Most of the functions are transmitted to CDP through WebSocket.

SlimerJS

SlimerJS is similar to PhantomJS. The difference is that SlimerJS is based on Firefox's browser engine Gecko, not Webkit.

SlimerJS can be installed through npm, the latest version is. However, the compatible version of Firefox is 53.0 to 59.0. I think the latest version of Firefox is now 82. Because I have installed the latest version of Firefox in my machine, I also have to install an old version of Firefox, such as 59.0. You can refer to this article to install the old version of Firefox browser. I have a Mac system, and it feels that installation is quite easy.

Code to implement screenshots:

var page = require('webpage').create();
("", function (status) {
     = { width:1024, height:768 };
    ('');
});

run

// Set Firefox path for mac operating systemexport SLIMERJSLAUNCHER=/Applications//Contents/MacOS/firefox
./node_modules/.bin/slimerjs  // I'm a locally installed slimer package

It should be noted thatSLIMERJSLAUNCHER=/Applications//Contents/MacOS/firefoxThe startup is the default installation path of Firefox. Because I had Firefox browser from the beginning, I started the latest version of the browser, and then I reported an error, saying it was incompatible. I installed a version of Firefox 59 in the previous section, so what is the path to this Firefox browser?

In the application, I named this old version of Firefox Firefox59, and then this path is/Applications//Contents/MacOS/firefox. ResetSLIMERJSLAUNCHERAfter the 59 version of Firefox browser, I found that it was successful.

However, Puppeteer will open the browser interface by default, which is non-headless mode. If you want to use headless mode, you can

    ./node_modules/.bin/slimerjs --headless 

However, WebGL is not supported in headless mode.

When I was writing the example, one of the obvious differences I found is that Puppeteer screenshots are asynchronous functions, while SlimerJS screenshots are synchronous functions? Driven by curiosity, I looked at the source code (src/modules/slimer-sdk/):

render: function(filename, options) {
    // ...
    let canvas = (
    ,
    ,
    , this);
    }
    (function(blob) {
    let reader = new ();
     = function() {
        content = ;
    }
    (blob);
    }, , );
    // ...
}

(src/modules/):

getScreenshotCanvas : function(window, ratio, onlyViewport, webpage) {
    // ...
    // create the canvas
    let canvas = ("http:///1999/xhtml", "canvas");
     = canvasWidth;
     = canvasHeight;

    let ctx = ("2d");
    (ratio, ratio);
    (window, , , , , "rgba(0,0,0,0)");
    ();

    return canvas;
}

The key code is that line. What? Does JS native API also support direct screenshots?
(): Only Firefox supports non-standard definition standard API that has been abandoned.

Summarize

  • The Firefox versions supported by version 1.0 are 53.0 to 59.0. The latest version of Firefox is not guaranteed to be available.

  • In headless mode, WebGL is not supported.

dom-to-image

dom-to-image: an open source library for front-end screenshots. The working principle is:
SVG's foreignObject tag can wrap any html content. Then, in order to render a node, the following steps are mainly carried out:

  • Recursively copy the original dom node and descendant node;

  • Recursively apply the styles of the original node and descendant node to the corresponding copied nodes and descendant nodes;

  • Font processing;

  • Image processing;

  • Serialize the copied node, insert it into foreignObject, then form an svg, and then generate a data URL;

  • If you want to get PNG content or original pixel values, you can first create an image using the data URL, render the image using an off-screen canvas, and then get the desired data from the canvas.

During the test, I found that external resources could not be loaded, so I gave up after a simple understanding.

html2canvas

html2canvas. I checked the Internet and felt that there is an article written well: a brief analysis of two ways to implement web screenshots in js. If you are interested, you can take a look.

Unverified conjecture

Although the two latter are front-end implementation methods, combined with the headless library mentioned above, back-end screenshots can also be implemented. Taking Puppeteer's API as an example, you can use it first(options)Add a library of front-end screenshots to the web page, and then(pageFunction[, ...args])In-housepageFunctionJust write the corresponding screenshot code in the function, because the execution context of the pageFunction is the web page context, so you can get itdocumentetc.

This is the end of this article about 5 methods to implement web screenshots in JavaScript. For more related JavaScript web screenshots, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!