Screenshot (image generation) on the Web side is not a high frequency requirement, and of course there is not much data, so I have to check and check. However, Canvas and SVG are two implementation schemes with similar principles. They convert DOM into images instead of true screenshot, but their implementation methods are completely different.

Canvas implementation

How to convert DOM to Canvas image? Naturally, it has to be drawn little by little to the canvas, which is a hassle to think about. Through the analysis of github’s well-known screenshot library Niklasvh/HTML2Canvas (7K + STAR) source code, carves out its general ideas:

  • Recursively fetch all the DOM nodes of the target template, populate it with a rederList, and append information such as whether they are top-level elements/containers containing content

  • A Canvas renderQueue is calculated by sorting the rederList by CSS attributes such as Z-index postion float and element hierarchy information

  • The renderQueue is iterated, the CSS style is converted to a parameter that setFillStyle can recognize, and the corresponding canvas method is called according to nodeType. For example, fillText is called for text, image drawImage is called, and fillRect is called for div that sets the background color

  • Fill the page with the drawn canvas

No matter the calculation of sorting priority or the conversion from CSS to Canvas, there is no doubt that it is a lot of trouble, especially in real business scenarios. DOM templates often contain complex styles and typesetting. Html2canvas uses more than 20 JS to realize this transformation, which is extremely complicated. After all, we don’t need to reinvent the wheel.

Canvas conversions are more flexible and only need to ensure that the browser supports Canvas, but they have a significant disadvantage: they are slow. The reason, of course, is that a lot of computation and recursive calls are unavoidable. However, HTML2Canvas code makes heavy use of promises, so HTML2Canvas supports asynchronous operations.

Limitations:

  • Cannot cross domain cross domain resources

  • Unable to render iframe, Flash, etc., but SVG is currently supported

It is worth mentioning that although html2Canvas home page indicates that it is still in the laboratory environment, it has been used in the production environment by Twitter and others since 2014, so the stability should be guaranteed despite many restrictions.

Canvas is so complex, is there an easier way?

There is, of course, SVG

SVG implementation

First, SVG is inherently vector graphics; Second, SVG can be described in XML; Second, the tag used to describe SVG includes a foreignObject tag that can load XML (XHTML) documents from other namespaces. That is, with SVG, we don’t need to do a little bit of traversal, converting nodes; Instead of calculating complex element priorities, just throw all the DOM to be rendered into
and let the browser render the rest.

Let’s get this straight:

  • First, we declare a basic SVG template that requires some basic description information, most importantly, the
    tag pair

  • Embed foreignObject for the DOM template template to be rendered

  • Build SVG images using BLOBS

  • Take the URL and assign it to

<div id='text'> <h1 style="background-color: #ccc; width: 200px; height: 200px;" >Hello World</h1> </div>Copy the code

Copy the code
/ / this code in chrome only under test through the function html2Svg (domStr) {/ / create the template string var svgXML = ` < SVG XMLNS = "http://www.w3.org/2000/svg" width="200" height="200"> <foreignObject width="100%" height="100%">${generateXML(html)}</foreignObject> </svg>` Var SVG = new Blob([svgXML], {type: 'image/SVG + XML'}) / / use DOMURL createObjectURL remove object var url = window. Url. CreateObjectURL (SVG); Var img = new Image() img.src = url return img} // Since 'foreignObject' only references XML documents, / / so we need to format the DOM function generateXML (domStr) {var doc = document. Implementation. CreateHTMLDocument ("); doc.write(html); doc.documentElement.setAttribute('xmlns', doc.documentElement.namespaceURI); doc = parseStyle(doc) console.log(doc) html = (new XMLSerializer).serializeToString(doc).replace('<! DOCTYPE html>',''); return html }Copy the code

As you can see, it is very simple to implement this way, and without the complicated computation and recursion, rendering speed is naturally better than the former. With SVG, however, there are a number of limitations to consider. One of the most serious questions is:SVG cannot load external resourcesThat is, in SVG, bothOr CSS background images, these resources are not loaded. When using Canvas implementation, since we draw each node, there is no problem of resource reference.Using SVG, however, is equivalent to handing the document to SVG and rendering it again, which is a black box operation that we have no control over and is limited by SVG

Luckily, a guy with the nickname Christoph Burgmer wrote a library called Rasterizehtml.js that circumvents many of these limitations through a series of hacks. I know you’re wondering how he did it. In a nutshell, rasterizehtml.js does these hacks on top of our base implementation:

  • Convert the URL of to dataURI

  • Remove background-color from the style, modify the URL and reinsert the style sheet

  • See source code…

Of course, all rasterizehtml.js can do for us is deal with resource reference issues and browser compatibility issues. More SVG restrictions are not to be bypsed, and the library’s documentation officially lists a full page of them, which is pretty depressing to read. Such as:

  • Cross-domain resources cannot be loaded

  • Resources such as LazyLoad loaded through JS cannot be loaded

  • Inline or JS operation background-image cannot be loaded

  • See the documentation for

Consider the rationale for rasterizehtml.js to understand why these limitations are unavoidable: Rasterizehtml.js can only handle static resources that already exist, and it can’t handle dynamic JS generation in real time.

At present, rasterizehtml. js has been used in the function of Zhihu-opinion feedback.

reference

Source developer.mozilla.org/en-US/docs/… API/DrawingDOMobjectsintoacanvas


Did this article help you? Welcome to join the front End learning Group wechat group: