Implementation Code of the JavaScript screenshot function and javascript screenshot code
I recently participated in the development of related pages of Netease hearth stone box. I have a requirement on the card group sharing page (Address: hearth stone box card group sharing: you can share this group with friends in the form of images. The original practice was to use the server to convert the page into an image and then return the image address to the front-end. Well, this is quite good, and the server can cache the converted images. The next request can return the image address directly. There is no problem in principle. However, the problem is that the pictures converted in the background are occasionally inconsistent with the page content. Sometimes, some content is missing, so miss PM is upset and said that the problem must be solved. The interface for converting pages to images is implemented in the background. It's about luan! In the dark of Self-happiness, the miserable thing happened, said colleagues in the background, because some content on the page is asynchronously loaded (for example, the QR code at the bottom is generated through canvas), the server conversion is unstable, and sometimes the content of asynchronous rendering cannot be intercepted. To put it bluntly, he cannot solve this problem. Let's change the front-end. Who told the front-end to use Asynchronous rendering? Finally, the Leader asked me to try to use JS directly. This not only reduces the pressure on the server, but also solves the above bug.
At the beginning, I thought the idea of using JS was very ridiculous (I am ignorant, but the frontend has been developing too fast over the past few years): first, JS has no permission to call the functions of the operating system, secondly, the browser (BOM) does not provide related interfaces. What should I do? Search for Google. Search for JS html to png and click render-html-to-an-image. Some people mentioned in the answer that dom can be converted into a canvas! Canvas again! I couldn't help but get excited. It was really a treasure of the mountains and water! Then I searched dom to canvas and came to the well-known mdn document Drawing_DOM_objects_into_a_canvas. Then, I began to read the documents of zhuang (bi. As mentioned at the beginning of the document, dom cannot be converted into a canvas, but dom can be converted into svg, and then svg can be drawn into the canvas. Some may ask, why do we need to convert dom into svg first? This may be because svg uses xml to represent the same structure as dom.
The following is a step by step tutorial in the official document:
1. The Blob media type must be"image/svg+xml"
2. An svg element is required.
3. Insert foreignObject Element
4. Add the compliant html in the foreignObject Element
It is so easy to convert the dom into a canvas, just the above steps. The following is a simple demo provided in the document:
<!doctype html>
Copy the code and run it. Wow, it's awesome. There are two cool lines of art on the browser!
Well, it turns dom into canvas so easy? Then I passdocument.body.innerHTML Take all the dom in the body and put it in the foreignObject element. Isn't it OK to cut the whole page?
Demo is just a Hello World, but the Dom structure in the actual project is much more complicated than this one. For example, external style sheets, images, and some labels may not comply with xml specifications (such as the absence of closed tags ). The following is a simple example. container is defined in the style label instead of in-row style. The style does not take effect after the font is red and converted to an image.
<!doctype html>
Since the external style does not take effect, we can traverse all dom elements through JS and add all styles to the inline style through the element. style object. This idea sounds good, but I can't write a function that converts an external style into a inline style. The demand is tight, and there is no time to worry about it. So I want to find out if there are any ready-made databases. So I went to google again. Fortunately, I found a library named html2canvas, which is very powerful but easy to use. in this simple way, you can bring down my entire page:
function convertHtml2Canvas() { html2canvas(document.body, { allowTaint: false, taintTest: true }).then(function(canvas) { document.body.appendChild(canvas); }).catch(function(e) { console.error('error', e); }); }
At present, there is another problem, that is, this method intercepts the entire page by default (that is, it will take your innerHeight and innerWidth as the boundary, there will be a lot of white space). However, my card group only occupies a small part of the page. I only want the card group. Actually, canvas is easy to handle. We can handle it. The general idea is: 1. Convert the canvas object obtained above into Blob and put it into an img element. Then draw img. src into the canvas. This callcanvas.drawImageMethod to intercept what we want. The following two functions convert a canvas to an image and, in turn, convert an image to a canvas.
// Converts canvas to an image function convertCanvasToImage(canvas) { var image = new Image(); image.src = canvas.toDataURL("image/png", 0.1); return image; } // Converts image to canvas; returns new canvas element function convertImageToCanvas(image, startX, startY, width, height) { var canvas = document.createElement("canvas"); canvas.width = width; canvas.height = height; canvas.getContext("2d").drawImage(image, startX, startY, width, height, 0, 0, width, height); return canvas; }
Then, change the convertHtml2Canvas we wrote above to the following:
function convertHtml2Canvas() { html2canvas(document.body, { allowTaint: false, taintTest: true }).then(function(canvas) { var img = convertCanvasToImage(canvas); document.body.appendChild(img); img.onload = function() { img.onload = null; canvas = convertImageToCanvas(img, 0, 0, 384, 696); img.src = convertCanvasToImage(canvas).src; $(img).css({ display: 'block', position: 'absolute', top: 0, left: 400 + 'px' }); } }).catch(function(e) { console.error('error', e); }); }
At this time, you can take part of its page content. The effect is shown on the card group sharing test page. The left part of the page is the DOM structure, and the right part is the image converted using html2canvas. It looks exactly the same, no problem.
The JS page is written here, because it is only just getting in touch, and many things cannot be understood. Thank you for your advice. I will go into the source code of html2canvas to further understand the principle of dom to canvas.
Summary
The above is the implementation code of the JavaScript screenshot function introduced by xiaobian. I hope it will be helpful to you. If you have any questions, please leave a message and I will reply to you in a timely manner. Thank you very much for your support for the help House website!