How to implement page screenshot function in JS

How to implement page screenshot function in JS

"Page screenshot" is a requirement often encountered by the front end, such as page poster generation, pop-up picture sharing, etc. Because the browser does not have a native screenshot API, it is necessary to use canvas to export pictures to meet the needs.

Feasibility

  1. Solution 1: Rewrite DOM into canvas, call canvas's toBlob or toDataURL method to upload to Qiniu Cloud or server immediately
  2. Solution 2: Use the third-party library html2canvas.js to implement canvas, and elegantly generate canvas without changing the existing DOM of the page

Solution selection

Solution 1: You need to manually calculate the Computed Style of each DOM element, and then calculate the size, position and other attributes of the element on the canvas.

Difficulty of Solution 1

  • The existing HTML page needs to be abandoned and rewritten using canvas.
  • When the page structure is complex, it is not easy to reconstruct it using canvas.
  • Have a certain canvas foundation.

Solution 2: The project has more than 20,000 stars on Github, and the author is still actively maintaining it. The API is very simple and can be used out of the box in existing projects.

html2canvas

Because it is a common demand, the community will have mature solutions. Try the community's solutions first.

<div id="capture" style="padding: 10px; background: #f5da55">
    <h4 style="color: #000; ">Hello world!</h4>
</div>
html2canvas(document.querySelector("#capture")).then(canvas => {
    document.body.appendChild(canvas)
});

The above is the example usage of the official website. A new canvas DOM appears on the web page. Next we just need to convert the canvas into an image. Here we use canvas's native toDataURL and toBlob methods to go to Qiniu Cloud.

Please be careful when using. If there are cross-domain images in the produced canvas, you need to configure allowTaint to true.

If it is a native canvas implementation, the canvas needs all cross-domain image requests to be completed before drawing. There are two solutions

  • Solution 1: Write the img tag in HTML and the corresponding image URL in src. The disadvantage is obvious, it will pollute the layout structure of the page.
  • Solution 2: Use js and new Image(). Set src to the corresponding image URL and handle related operations in the onload callback. Advantages: The most feasible, but there is the problem of callback hell. Let's rewrite it using Promise
function asyncImage(url) {
    const img = new Image();
    img.src = url;
    img.setAttribute('crossOrigin', 'anonymous');
    return new Promise((resolve, reject) => {
        img.onload = () => resolve(img);
        img.onerror = reject;
    });
}

OK, we are done. Can we deliver the requirements now? I was happy to submit the test, but when I tested it on the mobile terminal, I found that the pictures produced were very blurry. This won't work, it's obviously much lower (it didn't pass the test orz).

GitHub has a corresponding solution portal, this answer also solves many people's problems

Basic principle: double the width and height of the canvas. Use css to set the canvas style to 1x the size.

    var shareContent = YourTargetElem; 
    var width = shareContent.offsetWidth; 
    var height = shareContent.offsetHeight; 
    var canvas = document.createElement("canvas"); 
    var scale = 2 || window.devicePixelRatio ; //You can also use device pixel ratio canvas.width = width * scale; 
    canvas.height = height * scale; 
    canvas.getContext("2d").scale(scale, scale); 

    var opts = {
        scale: scale, 
        canvas: canvas, 
        logging: true, 
        width: width, 
        height: height 
    };
    html2canvas(shareContent, opts).then(function (canvas) {
        var context = canvas.getContext('2d');

        var img = Canvas2Image.convertToImage(canvas, canvas.width, canvas.height);

        document.body.appendChild(img);
        $(img).css({
            "width": canvas.width / 2 + "px",
            "height": canvas.height / 2 + "px",
        })
    });

We already know the principle, and the image is indeed much clearer after actual operation. But the problem is still not solved.

Although reducing the size improves the clarity, we need the image to be of the original size. .

After many unsuccessful attempts, I finally decided to give up using the framework. Just use native canvas to make one!

Canvas drawing

We know that on devices with high-definition screens, any images, texts, lines, and shapes drawn on the canvas may appear blurry. This can be effectively solved by introducing hidpi-canvas from GitHub.

  1. First, go to GitHub and download the hidpi-canvas.js file: Portal;
  2. Import the hidpi-canvas.js file into the project;
  3. Call the getPixelRatio() function to get the ratio value;
  4. In drawImage(), multiply width and height by ratio;
  5. The final canvas is exported as a blog, converted into a file object and uploaded to Qiniu Cloud.

The core code is as follows

    function asyncImage(url) {
        const img = new Image();
        img.src = url;
        img.setAttribute('crossOrigin', 'anonymous');
        return new Promise((resolve, reject) => {
            img.onload = () => resolve(img);
            img.onerror = reject;
        });
    }
    async function drawCanvas(){
        var canvas = document.querySelector('canvas');
        var context = canvas.getContext('2d');
        var ratio = getPixelRatio(context); // Key code canvas.width = 300 * ratio; // Canvas width canvas.height = 300 * ratio; // Canvas height var divWidth = 300 * ratio; // Used to center the content var divHeight = 300 * ratio; // Used to center the content const image = await asyncImage('picUrl')
        const imgWidth = 550
        const imgHeight = 300
        context.drawImage(this, 50, 50, imgWidth * ratio, imgHeight * ratio)
        // Some other code
        const Blob = canvas.toBlob((Blob)=>{
            //Upload to Qiniu Cloud});
    } 

The final generated image is finally clear...it just needs to adapt to different screens according to the dom's offsetWidth.

Summarize

If the image clarity requirement is not high, or the image requirement is to generate a thumbnail. Using html2canvas is a very good choice.
Otherwise, the pictures drawn with canvas are clearer.

This is the end of this article about how to implement the page screenshot function with JS. For more relevant JS page screenshot function content, please search for previous articles on 123WORDPRESS.COM or continue to browse the following related articles. I hope everyone will support 123WORDPRESS.COM in the future!

You may also be interested in:
  • JavaScript screenshot function implementation code
  • js uses clipboardData to implement screenshot and paste function
  • How to use Phantomjs to take screenshots of web pages in Python
  • How to take screenshots of web pages using Phantomjs and Node

<<:  VMware Workstation Installation (Linux Kernel) Kylin Graphic Tutorial

>>:  Solutions to MySql crash and service failure to start

Recommend

Solution to MySQL Installer is running in Community mode

Today I found this prompt when I was running and ...

Randomly generate an eight-digit discount code and save it to the MySQL database

Currently, many businesses are conducting promoti...

How to use the markdown editor component in Vue3

Table of contents Install Importing components Ba...

Three ways to implement virtual hosts under Linux7

1. Same IP address, different port numbers Virtua...

How to solve the timeout during pip operation in Linux

How to solve the timeout problem when pip is used...

JavaScript to implement login form

This article example shares the specific code of ...

Solution to invalid margin-top of elements in div tags

Just as the title says. The question is very stran...

Getting Started Tutorial for Beginners ④: How to bind subdirectories

To understand what this means, we must first know ...

How to clear default styles and set common styles in CSS

CSS Clear Default Styles The usual clear default ...

Example of customizing the style of the form file selection box

Copy code The code is as follows: <!DOCTYPE ht...

Detailed explanation of Vue monitoring attribute graphic example

Table of contents What is the listener property? ...

How to try to add sticky effect to your CSS

Written in front I don’t know who first discovere...

MySQL 8.0.11 installation summary tutorial diagram

Installation environment: CAT /etc/os-release Vie...

MySQL 5.7.17 installation and configuration tutorial under CentOS6.9

CentOS6.9 installs Mysql5.7 for your reference, t...