Giter Club home page Giter Club logo

rasterizehtml.js's Introduction

rasterizeHTML.js

NPM version

Renders HTML into the browser's canvas.

See the API.

Install

$ npm install rasterizehtml

Then include a script tag with node_modules/rasterizehtml/dist/rasterizeHTML.allinone.js or require through browserify.

Example

var canvas = document.getElementById("canvas");
rasterizeHTML.drawHTML('Some ' +
                       '<span style="color: green; font-size: 20px;">HTML</span>' +
                       ' with an image <img src="someimg.png">',
                       canvas);

See the examples page. The code also ships with examples, make sure to run npm test first to compile the library.

How does it work

For security reasons rendering HTML into a canvas is severly limited. Firefox offers such a function via ctx.drawWindow(), but only with Chrome privileges (see https://developer.mozilla.org/en/Drawing_Graphics_with_Canvas).

As described in http://robert.ocallahan.org/2011/11/drawing-dom-content-to-canvas.html and https://developer.mozilla.org/en/HTML/Canvas/Drawing_DOM_objects_into_a_canvas however it is possible by embedding the HTML into an SVG image as a <foreignObject> and then drawing the resulting image via ctx.drawImage().

In addition SVG is not allowed to link to external resources and so rasterizeHTML.js will load external images, fonts and stylesheets and store them inline via data: URIs (or inline style elements respectively).

Limitations

All resources (HTML page, CSS, images, fonts and JS) that are needed for drawing the page can only be loaded if from the same origin, unless techniques like CORS are used. I.E. drawURL() can only load pages from the same domain as the current page and all draw methods can equally only embed styling and images from that domain.

The code is tested under Firefox, Chrome & Safari.

There's basic support for Microsoft Edge, however it will not work under any version of Internet Explorer.

Also the individual browsers still have some issues when rendering SVGs with embedded HTML to the canvas.

The full list of limitations is here.

TypeScript

Import type definitions as follows:

import * as rasterizeHTML from 'rasterizehtml';

Development

Run npm test.

For tests against individual browsers run python3 -m http.server and open http://localhost:8000/test/SpecRunner.html.

Where is it used?

  • CSS Critic, a lightweight tool for regression testing of Cascading Style Sheets
  • ...

rasterizehtml.js's People

Contributors

cburgmer avatar greenkeeperio-bot avatar kuranes avatar orentrutner avatar arturkulig avatar kevinoid avatar qingwei-li avatar

Stargazers

Lowell avatar Leon Vogt avatar Liu Yu avatar  avatar Leroy avatar 胡小根 avatar Tariq West avatar Dony Xu avatar Jin avatar 马叉虫 avatar  avatar Doracoin avatar  avatar Tobias Röder avatar Ilya Medvedev avatar Anton Vasin avatar Daniel Herr avatar  avatar acvv_khalil avatar Kirell Benzi avatar J Fran Matheu avatar Michael Geiger avatar SleepyZone avatar  avatar lefarcen avatar qaqmty avatar Natanael dos Santos Feitosa avatar Ivone avatar ahnan avatar Igor Alexeenko avatar 003d avatar Onur avatar  avatar Ray silva de arruda avatar Mike Woods avatar  avatar  avatar juju avatar Charbo avatar jiengsad avatar josh avatar Alex Gunnarson avatar Andrii Matenka avatar yuiseki avatar علی به نیک avatar Maxim avatar  avatar ITs-WHY avatar Shashank Mishra avatar  avatar kakajun avatar  avatar Cellivar avatar cristiano avatar Alan Gao avatar Awen avatar  avatar yg-alt avatar JayYuen avatar i'DLisT avatar Krtolica Vujadin avatar Toko Khutsishvili avatar kinoko avatar 幸福拾荒者 avatar Chengzi avatar  avatar topppy avatar 尼采般地抒情 avatar 文宇祥 avatar  avatar Lyndon丶 avatar  avatar  avatar funlang.org avatar TianQian avatar zhaopengdev avatar cao avatar fantasticit avatar DengXin avatar Zaimuddin Hassan avatar  avatar  avatar  avatar 王洪莹 avatar zeromike avatar Younes avatar Ze-Zheng Wu avatar Sean Kooyman avatar  avatar  avatar Reza Ebrahimi avatar Travis avatar nekocode avatar Pedro Gómez avatar Latte avatar Terence Ge avatar Asbjørn Ulsberg avatar yanbabyer avatar  avatar Leonard Hertel avatar

Watchers

Sam Hasler avatar  avatar  avatar Konstantin Smotrin avatar Michael Hoffer avatar send2vinnie avatar Jim Nevin avatar shenzhou avatar 迁移到 leogiese avatar timelyportfolio avatar James Cloos avatar Chetan Dhembre avatar Benjamin McFerren avatar Florian Neumann avatar Michael Anthony avatar David Snelling avatar DaGlob avatar  avatar Wayne Wang avatar  avatar jorry有桥 avatar  avatar  avatar  avatar 疯魔慕薇 avatar 方帅 avatar gloriagao avatar  avatar Sandeep Rana avatar Sourabh avatar  avatar  avatar 冯淼森 avatar  avatar LEO avatar Luffy avatar Wei avatar Kelly Bigley avatar Joy Reynolds avatar Sogrey avatar  avatar 王智魁 avatar MacroCheng avatar Manu Mathew avatar  avatar  avatar Dasom Hwang avatar SieBenChen avatar  avatar  avatar Mark Manyen avatar  avatar xiuquanxu avatar

rasterizehtml.js's Issues

Integration test broken

The integration test does not correctly test the resulting image, as setting executeJs to false in integrationTestPage.html still passed the test, although half of the page is not rendered.

This is probably connected to HumbleSoftware/js-imagediff#11.

Configurable option for caching subsequent loads

The cache: false option forces a full load of repeated occurrences of a URL. For loads in short succession that is probably not needed and could be optimised to ease the load. In addition, inlining elements can take some time on complex pages and caching those results could massively speed up the process.

Better to cleanup *after* callback?

Wouldn't it make more sense to call the successCallback before calling cleanUp() in module.renderSvg(), so that the callback can make use of the blob URL if needed?

Font-face rules with several parts get mangled

A font-face definition like

@font-face {
  font-family: "font";
  src: local("font"), url(font.ttf) format("truetype");
}

gets changed to

@font-face {
  font-family: "font";
  src: local("font") url(font.ttf) format("truetype");
}

Observe the missing comma. This possibly stems from the CSSParser.

Broken in Firefox 18

Firefox 18 has stopped rendering a "data:image/svg+xml" URI including a inside an element. The resulting img element gets assigned a zero width & height.

Removing the foreignObject results in showing the the with the SVG's correct height & width.

Chrome freezes when using rasterizeHTML.drawDocument() on a large page.

Chrome freezes when using rasterizeHTML.drawDocument() on a large page. It appears that rasterizeHTML is iterating through a loop too many times. The following error appears 27 times in the console:

Blocked script execution in 'http://redacted' because the document's frame is sandboxed and the 'allow-scripts' permission is not set. rasterizeHTML.allinone.js:11

The error does not appear in Firefox. Also, I can confirm that my code is not calling rasterizeHTML.drawDocument in a loop.

Here is my code.

function drawPostageStamp(){ var postageWidth = $('#redacted').width(); var postageHeight = $('#redacted').height();
  if ($('#postage_stamp').length == 0){

     $('body').append('<canvas id="postage_stamp" width="' + postageWidth + '" height="' + postageHeight + '"></canvas>')

     var postageTopMargin = $('#redacted').offset().top;
     var newPostageWidth = postageWidth * 0.08

     $('#postage_stamp').css({'width':newPostageWidth, "top":postageTopMargin, "right":0, "z-index":10, "position":"fixed"})
     $('body').append('<div id="stamp_bar" style="position:fixed; top:140px; right:0px; width:' + newPostageWidth * .95 + 'px; height:10px; opacity:0.5; background-color:lightblue; z-index:11"></div>')

     $('#stamp_bar').hide();

  };

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

  //Clear the Canvas
  // Store the current transformation matrix
  ctx.save();


  // Use the identity matrix while clearing the canvas
  ctx.setTransform(1, 0, 0, 1, 0, 0);
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  //Restore the transform
  ctx.restore();

  //Set Canvas height (different from css height) of
  //canvas
  $('#postage_stamp').attr('height', postageHeight);

  //Draw the document into the canvas
  setTimeout(function(){
     rasterizeHTML.drawDocument(window.document,canvas,stampInit());
  }, 500);

};

Thanks! I love the library, BTW. Other than this issue, I haven't had any trouble with it, and the results look amazing!

Uncaught TypeError when running example.html

I get this error when running example.html, or when trying to use rasterizeHTML.js in any way, both in Chrome and Safari:

Uncaught TypeError: Cannot call method 'parseOptionalParameters' of undefined

Support IE

If IE supports rendering HTML inside an SVG we should support that. Possibly by solving #20 first, as the current CSS parser does not support IE9.

Integrate with Travis CI

Will use phantomjs and with that Webkit. So we would need to disable failing tests due to said Webkit bug with same origin policy.

Chrome Warning

'BlobBuilder is deprecated. Use "Blob" constructor instead.'

Question: Need to add high resolution elements

Hi,

As we are using SVG I am sure there must be an option to scale the image size multiple times without loosing quality before adding it to canvas.

I am trying to do it but on increasing the image size the quality gets worst - pixelated.

trying this: http://jsfiddle.net/cburgmer/NfE3c/8/ - context.drawImage(image, 0, 0, image.width, image.height, 0, 0, 500, 1250);

Please let me know if there is a way.

Thank you
Satya

Don't load CSS files twice

Using @import and one can reference a CSS document multiple times. Do not load such documents more than once. Especially work around circular references.

Allow to only render a given selector

As a user I want to only render certain parts of a page.

Idea:

  1. Load the page to a big enough iframe. Disable running JS if not requested: element.setAttribute("sandbox", "allow-same-origin");
  2. Run element.getBoundingClientRect() to capture its offset
  3. Generate an SVG with a foreign object that is big enough to capture the selected element, shift inversely to the element's offset: <foreignObject x="-XOFFSET" y="-YOFFSET" width="XOFFSET+WIDTH" height="YOFFSET+HEIGHT">

Issues:

  • What size to use for the iframe? Using the size of the target element will force line-breaks and overlaps on certain documents.
  • Element offsets might change when rendered in the SVG

Support @import in CSS

Parsing of url() is already implemented, so is loading of external CSS. Just needs a bit of bringing together.

Webkit fails to render SVGs

Including SVGs in the HTML leads to a parsing error. Is it possible to add SVG support?

Example SVG:

<svg xmlns="http://www.w3.org/2000/svg" version="1.1">
   <circle cx="100" cy="50" r="40" stroke="black" stroke-width="2" fill="red" />
</svg> 

Publish to NPM

Publish to NPM and possibly document use via browserify.

Background image workaround influences document's CSS

The workaround making sure that background images are properly rendered in a canvas influences the overall page's CSS.

Currently for each drawHTML/drawURL… a SVG object is added to the DOM. CSS embedded in those SVGs influence the DOM's CSS.

Probably the quickest solution is to remove the SVG once the canvas has been rendered.

Report errors when sourcing web fonts

While for all the other supported resources an error is reported back with the given URL that failed to load, this is not yet implemented for loading web fonts.

Font-face rule triggers INDEX_SIZE_ERR

A font-face rule following other rules (array index > 0) triggers the following error in Chrome:

RangeError: INDEX_SIZE_ERR
    at CSSStyleSheet.CSSOM.CSSStyleSheet.insertRule (http://localhost:8000/lib/CSSOM.js:629:9)
    at window.rasterizeHTMLInline.changeFontFaceRuleSrc (http://localhost:8000/src/inlineCss.js:138:20)
    at http://localhost:8000/src/inlineCss.js:481:17
    at funcFinishCallback (http://localhost:8000/src/inlineUtil.js:60:21)
    at http://localhost:8000/src/inlineCss.js:472:17
    at http://localhost:8000/src/inlineUtil.js:123:13
    at XMLHttpRequest.<anonymous> (http://localhost:8000/src/inlineUtil.js:94:17)

The issue is caused by CSSOM not correctly setting the parentStyleSheet on inserted rules.

Text rendered 1 px small under Chrome (fine on Firefox)

I tried the latest version on a trivial markup, and while it does exactly what I expected on Firefox, it renders the text as extremely small in Chrome 30.0.1599.69 m.

I can see that it renders SOMETHING though in the picture, but it appears to only be 1 pixel high.

<!DOCTYPE html>
<html>
<head>
    <title>rasterizeHTML.js example</title>
    <script type="text/javascript" src="rasterizeHTML.allinone.js"></script>
</head>
<body>
    <canvas id="canvas" width="400" height="200"></canvas>
    <script type="text/javascript">
        var canvas = document.getElementById("canvas");

        rasterizeHTML.drawHTML('Some <span style="color: red">HTML</span>', canvas);
    </script>
</body>
</html>

Any ideas what I'm doing wrong?
rasterizehtml_bug

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.