# Use html2canvas. JS to implement page screenshots and display or upload sample code

Time：2019-3-24

Recently, the project used html2canvas. JS to achieve the screenshot function of the page, but encountered a lot of pits, I hereby write a note to record.

When Using HTML 2 canvas, you may encounter problems such as only intercepting visual interfaces, no background color for screenshots, and the inability to intercept SVG tags, which are explained in detail below.

I. Import HTML 2 canvas. JS

This needn’t be said much, but can be obtained from github: https://github.com/niklasvh/html2canvas

You can also import links directly:<script src="https://cdn.bootcss.com/html2canvas/0.5.0-beta4/html2canvas.js"></script>

It is also very simple to use. Specific APIs can be searched on the Internet, and “image / png” can be used to generate png pictures.

Where $(“# XXX”) is the div you want to intercept, it can be retrieved outside by jquery, and of course, by document.  html2canvas($("#xxx"), {
onrendered: function (canvas) {
var url = canvas.toDataURL("image/png");
window.location.href = url;
}
});

Other types of images, such as jpg, image / jpeg, etc., can query APIs themselves.

Here, in fact, the simple screenshot has been completed, if the interface is a little more complex, there may be various pits, the next one to solve.

2. The problem that SVG cannot be intercepted

When we intercept a div, if the SVG tag exists in the div, it is generally not intercepted, such as intercepting a flow chart, we get the following:

As you can see, the line of the flow chart is not intercepted, that is, the SVG is not intercepted. At this time, the solution is to convert SVG into canvas and then take a screenshot, and directly code it.

Here, the each loop loops through all SVG tags and converts them all to canvas

if (typeof html2canvas !== 'undefined') {
// The following is the processing of SVG
var nodesToRecover = [];
var nodesToRemove = [];
var svgElem = cloneDom.find('svg');
svgElem.each(function (index, node) {
var parentNode = node.parentNode;
var svg = node.outerHTML.trim();

var canvas = document.createElement('canvas');
canvas.width = 650;
canvas.height = 798;
canvg(canvas, svg);
if (node.style.position) {
canvas.style.position += node.style.position;
canvas.style.left += node.style.left;
canvas.style.top += node.style.top;
}

nodesToRecover.push({
parent: parentNode,
child: node
});
parentNode.removeChild(node);

nodesToRemove.push({
parent: parentNode,
child: canvas
});

parentNode.appendChild(canvas);
});

}

Canvg.js and its dependency file rgbcolor.js are needed here. They can be downloaded or imported directly from the internet.

III. The Issue of Background Transparency

This is actually very simple, because it is transparent by default, HTML 2 canvas has a parameter backgroundto add background color, as follows:


html2canvas(cloneDom, {
onrendered: function(canvas) {
var url =canvas.toDataURL("image/png");
},
background:"#fafafa"
}); 

IV. The problem of intercepting only visible parts

If the div that needs to be intercepted goes beyond the interface, you may encounter the problem of incomplete interception. For example, in the figure above, only half of the content is hidden because the invisible part is hidden, while HTML 2 canvas cannot intercept the hidden dom.

So the solution at this time is to use cloning, which will need to intercept part of the clone on the bottom of the page, and then use HTML 2 canvas to intercept the entire div, and then remove this part of the content after interception, the complete code is as follows:

function showQRCode() {
scrollTo(0, 0);

// Clone node, default to false, that is, do not copy method properties, true is all replication.
var cloneDom = $("#d1").clone(true); // The Z-index attribute of the cloned node can be set as long as it is lower than the level of the cloned node. cloneDom.css({ "background-color": "#fafafa", "position": "absolute", "top": "0px", "z-index": "-1", "height": 798, "width": 650 }); if (typeof html2canvas !== 'undefined') { // The following is the processing of SVG var nodesToRecover = []; var nodesToRemove = []; Var svgElem = cloneDom. find ('svg'); //divReport is the ID of the DOM that needs to be intercepted into pictures svgElem.each(function (index, node) { var parentNode = node.parentNode; var svg = node.outerHTML.trim(); var canvas = document.createElement('canvas'); canvas.width = 650; canvas.height = 798; canvg(canvas, svg); if (node.style.position) { canvas.style.position += node.style.position; canvas.style.left += node.style.left; canvas.style.top += node.style.top; } nodesToRecover.push({ parent: parentNode, child: node }); parentNode.removeChild(node); nodesToRemove.push({ parent: parentNode, child: canvas }); parentNode.appendChild(canvas); }); // The clone node is dynamically appended to the body.$("body").append(cloneDom);

html2canvas(cloneDom, {
onrendered: function(canvas) {
var url =canvas.toDataURL("image/png");
window.location.href = url ;
CloneDom. remove (); // empty the content of the clone
},
background:"#fafafa"
});

}
}

Outside here, we will first clone a div, and set Z-index to the minimum to avoid the appearance of the interface. Then we will deal with the svg, which has been analyzed above. Finally, we can add the clone node to the body.

In onrendered, we can directly use location. href to jump to view pictures, save them, or write URLs to the SRC of img and display them on the interface, such as \$(‘# imgId’). attr (‘src’, url);

Finally, you can display the pictures you just intercepted in the interface:

5. Save the uploaded picture to the database and get the picture display in the interface.

Now that you have the url, you need to upload it to the back end, store it in the database, and load the image in another display interface. I’m usually used to using URLs to store image paths, not blobs.

Because I need to get pictures in another interface, I put them in a resource directory at the same level as webapp. The code is as follows:

// Store the picture and return to the picture path
BASE64Decoder decoder = new BASE64Decoder();
byte[] b = decoder.decodeBuffer(product.getProPic().substring("data:image/png;base64,".length()));
ByteArrayInputStream bais = new ByteArrayInputStream(b);
String url = "user_resource" + File.separator + "img" + File.separator + "product_"+UUID.randomUUID().toString().replace("-", "")+".png";
String totalUrl = System.getProperty("root") + url;
File w2 = new File(totalUrl);
ImageIO.write(bi1, "png", w2);

Product. setProPic (url); // Store the relative path of the picture in the database

Int res = productMapper. insertSelective (product); // Add to database

Because other logic is involved here, only part of the code is put in.

Here we use BASE64Decoder to store pictures. When we get pictures, we need to use substring to intercept the content of “data: image / png; base64” because “url” of the picture is behind. url.substring("data:image/png;base64,".length())

For the path, the URL in the code above is the content I stored in the database, while the total Url is the real path I stored when I actually wrote ImageIO. The root directory of the project obtained by the getProperty () method can be configured in web. XML as follows, and then System. getProperty (“root”) can be used.

<! - Configure the system to get the project root directory - >
<context-param>
<param-name>webAppRootKey</param-name>
<param-value>root</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.util.WebAppRootListener
</listener-class>
</listener>

Now the URL of the picture is stored in the database, and the picture itself is stored in the directory of the project under tomcat.

Finally, it is captured on the interface outside, just add the project name before the current url.< img class ="depot-img" src ="<%=request.getContextPath()%>/+e.proPic+" >

Then you can see the pictures displayed on the interface:

The above is the whole content of this article. I hope it will be helpful to everyone’s study, and I hope you will support developpaer more.

## Angular cli Ultimate Guide

Read the latest tutorial of angular 6 / rxjs, please visit the front-end fairy Road What is angular cli? Angular cli is a command line interface, which is used to realize the automatic development workflow. It allows you to do the following: Create a new angular application Running withLiveReloadSupported development servers to preview applications during […]