How to turn HTML webpage into an Image?
Tags: html, javascript, webdev, css
Published: 2022-04-10 11:51:08

While working in one of my project I had to implement a feature where I have turn an HTML webpage to an Image. The first thought that occurred to me was to use an inbuilt library but like [dom-to-image](https://github.com/tsayen/dom-to-image) or using [Chrome Headless](https://developers.google.com/web/updates/2017/04/headless-chrome) or a wrapper library like [Puppeteer](https://github.com/puppeteer/puppeteer). While working I came across this technique using pure Javascript.


Let's try to achieve this without using any library.

## Converting HTML webpage into an Image by using Canvas.
We cannot directly draw the HTML into Canvas due to the security reasons. We will follow another approach which will be safer.

### Steps
* Create SVG Image that will contain the rendering content.

```html
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">
</svg>
```

* Insert a [`<foreignObject>`](https://web.archive.org/web/20180627211734/https://developer.mozilla.org/en-US/docs/Web/SVG/Element/foreignObject) element inside the SVG which will contain the HTML.

```html
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">' +
    <foreignObject width="100%" height="100%">
    </foreignObject>
</svg>
```

* Add the XHTML content inside the `<foreignObject>` node.

```html
<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200">' +
    <foreignObject width="100%" height="100%">
        <div xmlns="http://www.w3.org/1999/xhtml">. 
          <style>em{color:red;}</style>
             Hey there...
        </div>
    </foreignObject>
</svg>
```

* Create the image object and set the src of an image to the data url of the image.

```js 
const tempImg = document.createElement('img')
tempImg.src = 'data:image/svg+xml,' + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"><foreignObject width="100%" height="100%"><div xmlns="http://www.w3.org/1999/xhtml">Hey there...</div></foreignObject></svg>')
```
  
* Draw this Image onto Canvas and set canvas data to target `img.src`.
```js 
const newImg = document.createElement('img')
newImg.src = 'data:image/svg+xml,' + encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"><foreignObject width="100%" height="100%"><div xmlns="http://www.w3.org/1999/xhtml">Hey there...</div></foreignObject></svg>')

// add event listener to image.
newImg.addEventListener('load', onNewImageLoad)

// method to draw image to canvas and set data to target img.src

function onNewImageLoad(e){
  ctx.drawImage(e.target, 0, 0)
  targetImg.src = canvas.toDataURL()
}
```

You can find the complete code in the CodeSandox! 

{% embed https://codesandbox.io/embed/html-to-image-conversion-bx13h7?fontsize=14&hidenavigation=1&theme=dark %}


### Reasons why using SVG and Canvas is safe?
Implementation of SVG image is very restrictive as we don't allow SVG image to load an external resource even one that appears on the same domain. Scripting in an SVG image is not allowed, there is no way to access the DOM of an SVG image from other scripts, and DOM elements in SVG images cannot receive input events. Thus there is no way to load privileged information into a form control (such as a full path in a `<input type="file">`) and render it.

The restriction that script can't directly touch DOM nodes that get rendered to the canvas is important from the security point of view.

I tried to cover this topic and steps in brief. Please feel free to add on related to this topic. 😅


Happy Learning!👩‍💻