Rendering HTML elements to <canvas>

HtmlHtml5 Canvas

Html Problem Overview


Is there a way to have an arbitrary HTML element rendered in a canvas (and then access its buffer...).

Html Solutions


Solution 1 - Html

You won't get real HTML rendering to <canvas> per se currently, because canvas context does not have functions to render HTML elements.

There are some emulations:

html2canvas project http://html2canvas.hertzen.com/index.html (basically a HTML renderer attempt built on Javascript + canvas)

HTML to SVG to <canvas> might be possible depending on your use case:

https://github.com/miohtama/Krusovice/blob/master/src/tools/html2svg2canvas.js

Also if you are using Firefox you can hack some extended permissions and then render a DOM window to <canvas>

https://developer.mozilla.org/en-US/docs/HTML/Canvas/Drawing_Graphics_with_Canvas?redirectlocale=en-US&redirectslug=Drawing_Graphics_with_Canvas#Rendering_Web_Content_Into_A_Canvas

Solution 2 - Html

Take a look on MDN (archived)

It will render html element using creating SVG images.

For Example: There is <em>I</em> like <span style="color:white; text-shadow:0 0 2px blue;">cheese</span> HTML element. And I want to add it into <canvas id="canvas" style="border:2px solid black;" width="200" height="200"></canvas> Canvas Element.

Here is Javascript Code to add HTML element to canvas.

var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');

var data = '<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="font-size:40px">' +
  '<em>I</em> like <span style="color:white; text-shadow:0 0 2px blue;">cheese</span>' +
  '</div>' +
  '</foreignObject>' +
  '</svg>';

var DOMURL = window.URL || window.webkitURL || window;

var img = new Image();
var svg = new Blob([data], {
  type: 'image/svg+xml;charset=utf-8'
});
var url = DOMURL.createObjectURL(svg);

img.onload = function() {
  ctx.drawImage(img, 0, 0);
  DOMURL.revokeObjectURL(url);
}

img.src = url;

<canvas id="canvas" style="border:2px solid black;" width="200" height="200"></canvas>

Solution 3 - Html

Here is code to render arbitrary HTML into a canvas:

function render_html_to_canvas(html, ctx, x, y, width, height) {
    var xml = html_to_xml(html);
    xml = xml.replace(/\#/g, '%23');
    var data = "data:image/svg+xml;charset=utf-8,"+'<svg xmlns="http://www.w3.org/2000/svg" width="'+width+'" height="'+height+'">' +
                        '<foreignObject width="100%" height="100%">' +
                        xml+
                        '</foreignObject>' +
                        '</svg>';

    var img = new Image();
    img.onload = function () {
        ctx.drawImage(img, x, y);
    }
    img.src = data;
}

function html_to_xml(html) {
    var doc = document.implementation.createHTMLDocument('');
    doc.write(html);

    // You must manually set the xmlns if you intend to immediately serialize     
    // the HTML document to a string as opposed to appending it to a
    // <foreignObject> in the DOM
    doc.documentElement.setAttribute('xmlns', doc.documentElement.namespaceURI);

    // Get well-formed markup
    html = (new XMLSerializer).serializeToString(doc.body);
    return html;
}

example:

const ctx = document.querySelector('canvas').getContext('2d');
const html = `
<p>this
<p>is <span style="color:red; font-weight: bold;">not</span>
<p><i>xml</i>!
<p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABWElEQVQ4jZ2Tu07DQBBFz9jjvEAQqAlQ0CHxERQ0/AItBV9Ew8dQUNBQIho6qCFE4Nhex4u85OHdWAKxzfWsx0d3HpazdGITA4kROjl0ckFrnYJmQlJrKsQZxFOIMyEqIMpADGhSZpikB1hAGsovdxABGuepC/4L0U7xRTG/riG3J8fuvdifPKnmasXp5c2TB1HNPl24gNTnpeqsgmj1eFgayoHvRDWbLBOKJbn9WLGYflCCpmM/2a4Au6/PTjdH+z9lCJQ9vyeq0w/ve2kA3vaOnI6k4Pz+0Y24yP3Gapy+Bw6qdfsCRZfWSWgclCCVXTZu5LZFXKJJ2sepW2KYNCENB3U5pw93zLoDjNK6E7rTFcgbkGYJtiLckxCiw4W1OURsxUE5BokQiQj3JIToVtKwlhsurq+YDYbMBjuU/W3KtT3xIbrpAD7E60lwQohuaMtP8ldI0uMbGfC1r1zyWPUAAAAASUVORK5CYII=">`;
render_html_to_canvas(html, ctx, 0, 0, 300, 150);


function render_html_to_canvas(html, ctx, x, y, width, height) {
  var data = "data:image/svg+xml;charset=utf-8," + '<svg xmlns="http://www.w3.org/2000/svg" width="' + width + '" height="' + height + '">' +
    '<foreignObject width="100%" height="100%">' +
    html_to_xml(html) +
    '</foreignObject>' +
    '</svg>';

  var img = new Image();
  img.onload = function() {
    ctx.drawImage(img, x, y);
  }
  img.src = data;
}

function html_to_xml(html) {
  var doc = document.implementation.createHTMLDocument('');
  doc.write(html);

  // You must manually set the xmlns if you intend to immediately serialize     
  // the HTML document to a string as opposed to appending it to a
  // <foreignObject> in the DOM
  doc.documentElement.setAttribute('xmlns', doc.documentElement.namespaceURI);

  // Get well-formed markup
  html = (new XMLSerializer).serializeToString(doc.body);
  return html;
}

<canvas></canvas>

Solution 4 - Html

The CSS element() function may eventually help some people here, even though it's not a direct answer to the question. It allows you to use an element (and all children, including videos, cross-domain iframes, etc.) as a background image (and anywhere else that you'd normally use url(...) in your CSS code). Here's a blog post that shows what you can do with it.

It has been implemented in Firefox since 2011, and is being considered in Chromium/Chrome (don't forget to give the issue a star if you care about this functionality).

Solution 5 - Html

RasterizeHTML is a very good project, but if you need to access the canvas it wont work on chrome. due to the use of <foreignObject>.

If you need to access the canvas then you can use html2canvas

I am trying to find another project as html2canvas is very slow in performance

Solution 6 - Html

According to the HTML specification you can't access the elements of the Canvas. You can get its context, and draw in it manipulate it, but that is all.

BUT, you can put both the Canvas and the html element in the same div with a aposition: relative and then set the canvas and the other element to position: absolute. This ways they will be on the top of each other. Then you can use the left and right CSS properties to position the html element.

If the element doesn't shows up, maybe the canvas is before it, so use the z-index CSS property to bring it before the canvas.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questiongotch4View Question on Stackoverflow
Solution 1 - HtmlMikko OhtamaaView Answer on Stackoverflow
Solution 2 - HtmlSuresh MahawarView Answer on Stackoverflow
Solution 3 - HtmlCpnCrunchView Answer on Stackoverflow
Solution 4 - Htmluser10898116View Answer on Stackoverflow
Solution 5 - HtmlMohamed El PrinceView Answer on Stackoverflow
Solution 6 - HtmlRichard OtvosView Answer on Stackoverflow