I recently used html2canvas.js when writing projects, which can realize the screenshot function of the page, but I encountered many pitfalls, so I will write an essay to record them.
When using html2canvas, you may encounter problems such as only the visual interface can be captured, the screenshot has no background color, and the svg tag cannot be captured. The following is a detailed explanation.
1. Import html2canvas.jsNeedless to say, this can be obtained from github: https://github.com/niklasvh/html2canvas
You can also import the link directly: <script src=https://cdn.bootcss.com/html2canvas/0.5.0-beta4/html2canvas.js></script>
It is also very simple to use. You can find the specific API online and just use image/png to generate png images.
Among them, $(#xxx) is the div you want to intercept. It can be obtained through jquery. Of course, it can also be obtained through document.
html2canvas($(#xxx), { onrendered: function (canvas) { var url = canvas.toDataURL(image/png); window.location.href = url; } });
For other types of pictures such as jpg, image/jpeg, etc., you can query the API by yourself.
In fact, the simple screenshot has been completed here. If the interface is a little more complicated, various pitfalls may appear. Let’s solve them one by one.
2. Problem that svg cannot be interceptedWhen we intercept a div, if there is an svg tag in the div, it cannot be intercepted under normal circumstances. For example, if we intercept a flow chart, we will get something like this:
It can be seen that the lines of the flow chart are not intercepted, that is, the svg is not intercepted. The solution at this time is to convert the svg into canvas and then take a screenshot, and directly upload the code.
The each loop here is to loop through all svg tags and convert 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 directly from the Internet or imported directly.
3. The problem of background transparencyThis is actually very simple, because it is transparent by default. There is a parameter background in html2canvas to add a background color, as follows:
html2canvas(cloneDom, { onrendered: function(canvas) { var url =canvas.toDataURL(image/png); }, background:#fafafa});4. The problem of only being able to capture the visible part
If the div that needs to be intercepted exceeds the interface, you may encounter the problem of incomplete interception. As shown in the picture above, there is only half of the content. This is because the invisible part is hidden, and html2canvas cannot intercept the hidden DOM.
So the solution at this time is to use cloning, place a copy of the part that needs to be intercepted at the bottom of the page, and then use html2canvas to intercept the complete div. After the interception is completed, remove this part of the content. The complete code is as follows:
function showQRCode() { scrollTo(0, 0); //Clone node, the default is false, that is, the method attributes are not copied, and true is all copies. var cloneDom = $(#d1).clone(true); //Set the z-index attribute of the cloned node, as long as it is lower than the node being cloned. 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 a picture 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); }); //Dynamicly append the cloned node to the body. $(body).append(cloneDom); html2canvas(cloneDom, { onrendered: function(canvas) { var url =canvas.toDataURL(image/png); window.location.href = url ; cloneDom.remove(); // Clear cloned content}, background:#fafafa }); } }
Here, first clone the div to be intercepted and set the z-index to the minimum to avoid causing an unsightly interface. Then the svg is processed, which has been analyzed above. Finally, the clone node is appended to the body. Can.
In onrendered, we can directly use location.href to jump to view the image, save it, or write the url into the src of img and display it on the interface, such as $('#imgId').attr('src' ,url);
Finally, the picture just captured can be displayed on the interface:
5. Upload the image and save it to the database, and obtain the image for display in the interface.Now that the URL is obtained, it needs to be uploaded to the backend, stored in the database, and then loaded into another displayed interface. I am generally used to using url to store image paths instead of blob storage.
Because I need to get the image in another interface, I stored the image in a resource directory at the same level as the webapp. The code is as follows:
//Store the picture and return the picture path BASE64Decoder decoder = new BASE64Decoder(); byte[] b = decoder.decodeBuffer(product.getProPic().substring(data:image/png;base64,.length())); ByteArrayInputStream bais = new ByteArrayInputStream(b); BufferedImage bi1 = ImageIO.read(bais); 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 image into the database int res = productMapper.insertSelective(product); //Add to the database
Because other logic is involved here, only part of the code is included.
BASE64Decoder is used here to store images. After we obtain the image, we need to use substring to intercept the content of data:image/png;base64, because the following is the url of the image, url.substring(data:image/png;base64,.length())
.
For the path, the url in the above code is the content I stored in the database, and the totalUrl is the real path stored during the actual write operation of ImageIO. The root directory of the project obtained by the getProperty() method can be configured in web.xml The following content, and then System.getProperty(root) can be used.
<!-- Configure the system to obtain 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 image is stored in the database, and the image itself is stored in the directory of the project under tomcat.
Finally, to get it from the interface, just add the project name in front of the current url < img class =depot-img src =<%=request.getContextPath()%>/`+e.proPic+` >
.
Then you can see the picture displayed on the interface:
The above is the entire content of this article. I hope it will be helpful to everyone’s study. I also hope everyone will support VeVb Wulin Network.