mirror of
https://github.com/niklasvh/html2canvas.git
synced 2023-08-10 21:13:10 +03:00
refactored renderer
This commit is contained in:
parent
7d7deca342
commit
a313524aa4
@ -48,11 +48,11 @@ _html2canvas.Renderer = function(parseQueue, options){
|
|||||||
throw new Error("Unknown renderer");
|
throw new Error("Unknown renderer");
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( typeof renderer._create !== "function" ) {
|
if ( typeof renderer !== "function" ) {
|
||||||
throw new Error("Invalid renderer defined");
|
throw new Error("Invalid renderer defined");
|
||||||
}
|
}
|
||||||
return renderer;
|
return renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
return getRenderer(options.renderer)._create(parseQueue, options, document, createRenderQueue(parseQueue), _html2canvas);
|
return getRenderer(options.renderer)(parseQueue, options, document, createRenderQueue(parseQueue), _html2canvas);
|
||||||
};
|
};
|
||||||
|
@ -5,6 +5,7 @@ window.html2canvas = function(elements, opts) {
|
|||||||
// general
|
// general
|
||||||
logging: false,
|
logging: false,
|
||||||
elements: elements,
|
elements: elements,
|
||||||
|
background: "#fff",
|
||||||
|
|
||||||
// preload options
|
// preload options
|
||||||
proxy: "",
|
proxy: "",
|
||||||
|
@ -1,233 +1,138 @@
|
|||||||
_html2canvas.Renderer.Canvas = function( options ) {
|
_html2canvas.Renderer.Canvas = function(options) {
|
||||||
|
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
var doc = document,
|
var doc = document,
|
||||||
canvas = options.canvas || doc.createElement('canvas'),
|
safeImages = [],
|
||||||
usingFlashcanvas = false,
|
testCanvas = document.createElement("canvas"),
|
||||||
_createCalled = false,
|
testctx = testCanvas.getContext("2d"),
|
||||||
canvasReadyToDraw = false,
|
canvas = options.canvas || doc.createElement('canvas');
|
||||||
methods,
|
|
||||||
flashMaxSize = 2880; // flash bitmap limited to 2880x2880px // http://stackoverflow.com/questions/2033792/argumenterror-error-2015-invalid-bitmapdata
|
|
||||||
|
|
||||||
|
|
||||||
if (canvas.getContext){
|
function createShape(ctx, args) {
|
||||||
h2clog("html2canvas: Renderer: using canvas renderer");
|
ctx.beginPath();
|
||||||
canvasReadyToDraw = true;
|
args.forEach(function(arg) {
|
||||||
} else if ( options.flashcanvas !== undefined ){
|
ctx[arg.name].apply(ctx, arg['arguments']);
|
||||||
usingFlashcanvas = true;
|
|
||||||
h2clog("html2canvas: Renderer: canvas not available, using flashcanvas");
|
|
||||||
var script = doc.createElement("script");
|
|
||||||
script.src = options.flashcanvas;
|
|
||||||
|
|
||||||
script.onload = (function(script, func){
|
|
||||||
var intervalFunc;
|
|
||||||
|
|
||||||
if (script.onload === undefined) {
|
|
||||||
// IE lack of support for script onload
|
|
||||||
|
|
||||||
if( script.onreadystatechange !== undefined ) {
|
|
||||||
|
|
||||||
intervalFunc = function() {
|
|
||||||
if (script.readyState !== "loaded" && script.readyState !== "complete") {
|
|
||||||
window.setTimeout( intervalFunc, 250 );
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// it is loaded
|
|
||||||
func();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
window.setTimeout( intervalFunc, 250 );
|
|
||||||
|
|
||||||
} else {
|
|
||||||
h2clog("html2canvas: Renderer: Can't track when flashcanvas is loaded");
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return func;
|
|
||||||
}
|
|
||||||
|
|
||||||
})(script, function(){
|
|
||||||
|
|
||||||
if (typeof window.FlashCanvas !== "undefined") {
|
|
||||||
h2clog("html2canvas: Renderer: Flashcanvas initialized");
|
|
||||||
window.FlashCanvas.initElement( canvas );
|
|
||||||
|
|
||||||
canvasReadyToDraw = true;
|
|
||||||
if ( _createCalled !== false ) {
|
|
||||||
methods._create.apply( null, _createCalled );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
ctx.closePath();
|
||||||
doc.body.appendChild( script );
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
methods = {
|
function safeImage(item) {
|
||||||
_create: function( zStack, options, doc, queue, _html2canvas ) {
|
if (safeImages.indexOf(item['arguments'][0].src ) === -1) {
|
||||||
|
testctx.drawImage(item['arguments'][0], 0, 0);
|
||||||
if ( !canvasReadyToDraw ) {
|
try {
|
||||||
_createCalled = arguments;
|
testctx.getImageData(0, 0, 1, 1);
|
||||||
return canvas;
|
} catch(e) {
|
||||||
|
testCanvas = doc.createElement("canvas");
|
||||||
|
testctx = testCanvas.getContext("2d");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
safeImages.push(item['arguments'][0].src);
|
||||||
var ctx = canvas.getContext("2d"),
|
|
||||||
storageContext,
|
|
||||||
i,
|
|
||||||
queueLen,
|
|
||||||
a,
|
|
||||||
newCanvas,
|
|
||||||
bounds,
|
|
||||||
testCanvas = document.createElement("canvas"),
|
|
||||||
hasCTX = ( testCanvas.getContext !== undefined ),
|
|
||||||
storageLen,
|
|
||||||
renderItem,
|
|
||||||
testctx = ( hasCTX ) ? testCanvas.getContext("2d") : {},
|
|
||||||
safeImages = [],
|
|
||||||
fstyle;
|
|
||||||
|
|
||||||
canvas.width = canvas.style.width = (!usingFlashcanvas) ? options.width || zStack.ctx.width : Math.min(flashMaxSize, (options.width || zStack.ctx.width) );
|
|
||||||
canvas.height = canvas.style.height = (!usingFlashcanvas) ? options.height || zStack.ctx.height : Math.min(flashMaxSize, (options.height || zStack.ctx.height) );
|
|
||||||
|
|
||||||
fstyle = ctx.fillStyle;
|
|
||||||
ctx.fillStyle = (zStack.backgroundColor === "transparent" || zStack.backgroundColor === "rgba(0, 0, 0, 0)") ? "#fff" : zStack.backgroundColor;
|
|
||||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
||||||
ctx.fillStyle = fstyle;
|
|
||||||
|
|
||||||
var createShape = function(args) {
|
|
||||||
ctx.beginPath();
|
|
||||||
args.forEach(function(arg) {
|
|
||||||
ctx[arg.name].apply(ctx, arg['arguments']);
|
|
||||||
});
|
|
||||||
ctx.closePath();
|
|
||||||
};
|
|
||||||
|
|
||||||
if ( options.svgRendering && zStack.svgRender !== undefined ) {
|
|
||||||
// TODO: enable async rendering to support this
|
|
||||||
ctx.drawImage( zStack.svgRender, 0, 0 );
|
|
||||||
} else {
|
|
||||||
for ( i = 0, queueLen = queue.length; i < queueLen; i+=1 ) {
|
|
||||||
|
|
||||||
storageContext = queue.splice(0, 1)[0];
|
|
||||||
storageContext.canvasPosition = storageContext.canvasPosition || {};
|
|
||||||
|
|
||||||
//this.canvasRenderContext(storageContext,parentctx);
|
|
||||||
|
|
||||||
// set common settings for canvas
|
|
||||||
ctx.textBaseline = "bottom";
|
|
||||||
|
|
||||||
if (storageContext.clip){
|
|
||||||
ctx.save();
|
|
||||||
ctx.beginPath();
|
|
||||||
// console.log(storageContext);
|
|
||||||
ctx.rect(storageContext.clip.left, storageContext.clip.top, storageContext.clip.width, storageContext.clip.height);
|
|
||||||
ctx.clip();
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (storageContext.ctx.storage){
|
|
||||||
|
|
||||||
for (a = 0, storageLen = storageContext.ctx.storage.length; a < storageLen; a+=1){
|
|
||||||
|
|
||||||
renderItem = storageContext.ctx.storage[a];
|
|
||||||
|
|
||||||
|
|
||||||
switch(renderItem.type){
|
|
||||||
case "variable":
|
|
||||||
ctx[renderItem.name] = renderItem['arguments'];
|
|
||||||
break;
|
|
||||||
case "function":
|
|
||||||
if (renderItem.name === "fillRect") {
|
|
||||||
if (!usingFlashcanvas || renderItem['arguments'][0] + renderItem['arguments'][2] < flashMaxSize && renderItem['arguments'][1] + renderItem['arguments'][3] < flashMaxSize) {
|
|
||||||
ctx.fillRect.apply( ctx, renderItem['arguments'] );
|
|
||||||
}
|
|
||||||
} else if (renderItem.name === "createPattern") {
|
|
||||||
ctx.fillStyle = ctx.createPattern(renderItem['arguments'][0], "repeat");
|
|
||||||
} else if (renderItem.name === "drawShape") {
|
|
||||||
createShape(renderItem['arguments']);
|
|
||||||
} else if (renderItem.name === "fillText") {
|
|
||||||
if (!usingFlashcanvas || renderItem['arguments'][1] < flashMaxSize && renderItem['arguments'][2] < flashMaxSize) {
|
|
||||||
ctx.fillText.apply( ctx, renderItem['arguments'] );
|
|
||||||
}
|
|
||||||
} else if (renderItem.name === "drawImage") {
|
|
||||||
|
|
||||||
if (renderItem['arguments'][8] > 0 && renderItem['arguments'][7] > 0) {
|
|
||||||
if ( hasCTX && options.taintTest ) {
|
|
||||||
if ( safeImages.indexOf( renderItem['arguments'][ 0 ].src ) === -1 ) {
|
|
||||||
testctx.drawImage( renderItem['arguments'][ 0 ], 0, 0 );
|
|
||||||
try {
|
|
||||||
testctx.getImageData( 0, 0, 1, 1 );
|
|
||||||
} catch(e) {
|
|
||||||
testCanvas = doc.createElement("canvas");
|
|
||||||
testctx = testCanvas.getContext("2d");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
safeImages.push( renderItem['arguments'][ 0 ].src );
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx.drawImage.apply( ctx, renderItem['arguments'] );
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ctx[renderItem.name].apply(ctx, renderItem['arguments']);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if (storageContext.clip){
|
|
||||||
ctx.restore();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
h2clog("html2canvas: Renderer: Canvas renderer done - returning canvas obj");
|
|
||||||
|
|
||||||
queueLen = options.elements.length;
|
|
||||||
|
|
||||||
if (queueLen === 1) {
|
|
||||||
if (typeof options.elements[ 0 ] === "object" && options.elements[ 0 ].nodeName !== "BODY" && usingFlashcanvas === false) {
|
|
||||||
// crop image to the bounds of selected (single) element
|
|
||||||
bounds = _html2canvas.Util.Bounds( options.elements[ 0 ] );
|
|
||||||
newCanvas = doc.createElement('canvas');
|
|
||||||
newCanvas.width = bounds.width;
|
|
||||||
newCanvas.height = bounds.height;
|
|
||||||
ctx = newCanvas.getContext("2d");
|
|
||||||
|
|
||||||
ctx.drawImage( canvas, bounds.left, bounds.top, bounds.width, bounds.height, 0, 0, bounds.width, bounds.height );
|
|
||||||
canvas = null;
|
|
||||||
return newCanvas;
|
|
||||||
}
|
|
||||||
} /*else {
|
|
||||||
// TODO clip and resize multiple elements
|
|
||||||
|
|
||||||
for ( i = 0; i < queueLen; i+=1 ) {
|
|
||||||
if (options.elements[ i ] instanceof Element) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return canvas;
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isTransparent(backgroundColor) {
|
||||||
|
return (backgroundColor === "transparent" || backgroundColor === "rgba(0, 0, 0, 0)");
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderItem(ctx, item) {
|
||||||
|
switch(item.type){
|
||||||
|
case "variable":
|
||||||
|
ctx[item.name] = item['arguments'];
|
||||||
|
break;
|
||||||
|
case "function":
|
||||||
|
if (item.name === "createPattern") {
|
||||||
|
if (item['arguments'][0].width > 0 && item['arguments'][0].height > 0) {
|
||||||
|
try {
|
||||||
|
ctx.fillStyle = ctx.createPattern(item['arguments'][0], "repeat");
|
||||||
|
}
|
||||||
|
catch(e) {
|
||||||
|
h2clog("html2canvas: Renderer: Error creating pattern", e.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (item.name === "drawShape") {
|
||||||
|
createShape(ctx, item['arguments']);
|
||||||
|
} else if (item.name === "drawImage") {
|
||||||
|
if (item['arguments'][8] > 0 && item['arguments'][7] > 0) {
|
||||||
|
if (options.taintTest || (options.taintTest && safeImage(item))) {
|
||||||
|
ctx.drawImage.apply( ctx, item['arguments'] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ctx[item.name].apply(ctx, item['arguments']);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return function(zStack, options, doc, queue, _html2canvas) {
|
||||||
|
|
||||||
|
var ctx = canvas.getContext("2d"),
|
||||||
|
storageContext,
|
||||||
|
i,
|
||||||
|
queueLen,
|
||||||
|
newCanvas,
|
||||||
|
bounds,
|
||||||
|
fstyle;
|
||||||
|
|
||||||
|
canvas.width = canvas.style.width = options.width || zStack.ctx.width;
|
||||||
|
canvas.height = canvas.style.height = options.height || zStack.ctx.height;
|
||||||
|
|
||||||
|
fstyle = ctx.fillStyle;
|
||||||
|
ctx.fillStyle = (isTransparent(zStack.backgroundColor) && options.background !== undefined) ? options.background : zStack.backgroundColor;
|
||||||
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
ctx.fillStyle = fstyle;
|
||||||
|
|
||||||
|
|
||||||
|
if ( options.svgRendering && zStack.svgRender !== undefined ) {
|
||||||
|
// TODO: enable async rendering to support this
|
||||||
|
ctx.drawImage( zStack.svgRender, 0, 0 );
|
||||||
|
} else {
|
||||||
|
for ( i = 0, queueLen = queue.length; i < queueLen; i+=1 ) {
|
||||||
|
storageContext = queue.splice(0, 1)[0];
|
||||||
|
storageContext.canvasPosition = storageContext.canvasPosition || {};
|
||||||
|
|
||||||
|
// set common settings for canvas
|
||||||
|
ctx.textBaseline = "bottom";
|
||||||
|
|
||||||
|
if (storageContext.clip){
|
||||||
|
ctx.save();
|
||||||
|
ctx.beginPath();
|
||||||
|
// console.log(storageContext);
|
||||||
|
ctx.rect(storageContext.clip.left, storageContext.clip.top, storageContext.clip.width, storageContext.clip.height);
|
||||||
|
ctx.clip();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (storageContext.ctx.storage) {
|
||||||
|
storageContext.ctx.storage.forEach(renderItem.bind(null, ctx));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (storageContext.clip){
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
h2clog("html2canvas: Renderer: Canvas renderer done - returning canvas obj");
|
||||||
|
|
||||||
|
queueLen = options.elements.length;
|
||||||
|
|
||||||
|
if (queueLen === 1) {
|
||||||
|
if (typeof options.elements[0] === "object" && options.elements[0].nodeName !== "BODY") {
|
||||||
|
// crop image to the bounds of selected (single) element
|
||||||
|
bounds = _html2canvas.Util.Bounds(options.elements[0]);
|
||||||
|
newCanvas = doc.createElement('canvas');
|
||||||
|
newCanvas.width = bounds.width;
|
||||||
|
newCanvas.height = bounds.height;
|
||||||
|
ctx = newCanvas.getContext("2d");
|
||||||
|
|
||||||
|
ctx.drawImage(canvas, bounds.left, bounds.top, bounds.width, bounds.height, 0, 0, bounds.width, bounds.height);
|
||||||
|
canvas = null;
|
||||||
|
return newCanvas;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return canvas;
|
||||||
};
|
};
|
||||||
|
|
||||||
return methods;
|
|
||||||
|
|
||||||
};
|
};
|
Loading…
x
Reference in New Issue
Block a user