mirror of
https://github.com/niklasvh/html2canvas.git
synced 2023-08-10 21:13:10 +03:00
Split renderers to their own objects
This commit is contained in:
parent
62fcedba6f
commit
ffcd5c04fb
@ -22,6 +22,7 @@
|
|||||||
<file name="Queue.js"/>
|
<file name="Queue.js"/>
|
||||||
<file name="Renderer.js"/>
|
<file name="Renderer.js"/>
|
||||||
<file name="Util.js"/>
|
<file name="Util.js"/>
|
||||||
|
<file name="renderers/Canvas.js"/>
|
||||||
<file name="html2canvas-post.txt"/>
|
<file name="html2canvas-post.txt"/>
|
||||||
</filelist>
|
</filelist>
|
||||||
</path>
|
</path>
|
||||||
|
@ -37,6 +37,11 @@ For more information and examples, please visit the <a href="http://html2canvas.
|
|||||||
|
|
||||||
### Changelog ###
|
### Changelog ###
|
||||||
|
|
||||||
|
v0.34 -
|
||||||
|
|
||||||
|
* Split renderers to their own objects (<a href="#">niklasvh</a>)
|
||||||
|
* Simplified API, cleaned up code (<a href="https://github.com/niklasvh/html2canvas/commit/c7d526c9eaa6a4abf4754d205fe1dee360c7660e">niklasvh</a>)
|
||||||
|
|
||||||
v0.33 - 2.3.2012
|
v0.33 - 2.3.2012
|
||||||
|
|
||||||
* SVG taint fix, and additional taint testing options for rendering (<a href="https://github.com/niklasvh/html2canvas/commit/2dc8b9385e656696cb019d615bdfa1d98b17d5d4">niklasvh</a>)
|
* SVG taint fix, and additional taint testing options for rendering (<a href="https://github.com/niklasvh/html2canvas/commit/2dc8b9385e656696cb019d615bdfa1d98b17d5d4">niklasvh</a>)
|
||||||
|
419
src/Renderer.js
419
src/Renderer.js
@ -8,15 +8,8 @@
|
|||||||
_html2canvas.Renderer = function(parseQueue, options){
|
_html2canvas.Renderer = function(parseQueue, options){
|
||||||
|
|
||||||
|
|
||||||
var queue = [],
|
var queue = [];
|
||||||
canvas,
|
|
||||||
usingFlashcanvas = false,
|
|
||||||
flashMaxSize = 2880, // flash bitmap limited to 2880x2880px // http://stackoverflow.com/questions/2033792/argumenterror-error-2015-invalid-bitmapdata
|
|
||||||
doc = document;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function sortZ(zStack){
|
function sortZ(zStack){
|
||||||
var subStacks = [],
|
var subStacks = [],
|
||||||
stackValues = [],
|
stackValues = [],
|
||||||
@ -63,411 +56,11 @@ _html2canvas.Renderer = function(parseQueue, options){
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function canvasRenderer(zStack){
|
|
||||||
|
|
||||||
sortZ(zStack.zIndex);
|
|
||||||
|
|
||||||
|
|
||||||
var ctx = canvas.getContext("2d"),
|
sortZ(parseQueue.zIndex);
|
||||||
storageContext,
|
if ( typeof options.renderer._create !== "function" ) {
|
||||||
i,
|
throw Error("Invalid renderer defined");
|
||||||
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;
|
|
||||||
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
||||||
ctx.fillStyle = fstyle;
|
|
||||||
|
|
||||||
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 === "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]){
|
|
||||||
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 = document.createElement("canvas");
|
|
||||||
testctx = testCanvas.getContext("2d");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
safeImages.push( renderItem['arguments'][ 0 ].src );
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ctx.drawImage.apply( ctx, renderItem['arguments'] );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
if (storageContext.clip){
|
|
||||||
ctx.restore();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
h2clog("html2canvas: Renderer: Canvas renderer done - returning canvas obj");
|
|
||||||
|
|
||||||
// this.canvasRenderStorage(queue,this.ctx);
|
|
||||||
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 options.renderer._create( parseQueue, options, document, queue, _html2canvas );
|
||||||
|
|
||||||
function svgRenderer(zStack){
|
|
||||||
sortZ(zStack.zIndex);
|
|
||||||
|
|
||||||
var svgNS = "http://www.w3.org/2000/svg",
|
|
||||||
svg = doc.createElementNS(svgNS, "svg"),
|
|
||||||
xlinkNS = "http://www.w3.org/1999/xlink",
|
|
||||||
defs = doc.createElementNS(svgNS, "defs"),
|
|
||||||
i,
|
|
||||||
a,
|
|
||||||
queueLen,
|
|
||||||
storageLen,
|
|
||||||
storageContext,
|
|
||||||
renderItem,
|
|
||||||
el,
|
|
||||||
settings = {},
|
|
||||||
text,
|
|
||||||
fontStyle,
|
|
||||||
clipId = 0;
|
|
||||||
|
|
||||||
svg.setAttribute("version", "1.1");
|
|
||||||
svg.setAttribute("baseProfile", "full");
|
|
||||||
|
|
||||||
svg.setAttribute("viewBox", "0 0 " + Math.max(zStack.ctx.width, options.width) + " " + Math.max(zStack.ctx.height, options.height));
|
|
||||||
svg.setAttribute("width", Math.max(zStack.ctx.width, options.width) + "px");
|
|
||||||
svg.setAttribute("height", Math.max(zStack.ctx.height, options.height) + "px");
|
|
||||||
svg.setAttribute("preserveAspectRatio", "none");
|
|
||||||
svg.appendChild(defs);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for (i = 0, queueLen = queue.length; i < queueLen; i+=1){
|
|
||||||
|
|
||||||
storageContext = queue.splice(0, 1)[0];
|
|
||||||
storageContext.canvasPosition = storageContext.canvasPosition || {};
|
|
||||||
|
|
||||||
//this.canvasRenderContext(storageContext,parentctx);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
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":
|
|
||||||
settings[renderItem.name] = renderItem['arguments'];
|
|
||||||
break;
|
|
||||||
case "function":
|
|
||||||
if (renderItem.name === "fillRect") {
|
|
||||||
|
|
||||||
el = doc.createElementNS(svgNS, "rect");
|
|
||||||
el.setAttribute("x", renderItem['arguments'][0]);
|
|
||||||
el.setAttribute("y", renderItem['arguments'][1]);
|
|
||||||
el.setAttribute("width", renderItem['arguments'][2]);
|
|
||||||
el.setAttribute("height", renderItem['arguments'][3]);
|
|
||||||
el.setAttribute("fill", settings.fillStyle);
|
|
||||||
svg.appendChild(el);
|
|
||||||
|
|
||||||
} else if(renderItem.name === "fillText") {
|
|
||||||
el = doc.createElementNS(svgNS, "text");
|
|
||||||
|
|
||||||
fontStyle = settings.font.split(" ");
|
|
||||||
|
|
||||||
el.style.fontVariant = fontStyle.splice(0, 1)[0];
|
|
||||||
el.style.fontWeight = fontStyle.splice(0, 1)[0];
|
|
||||||
el.style.fontStyle = fontStyle.splice(0, 1)[0];
|
|
||||||
el.style.fontSize = fontStyle.splice(0, 1)[0];
|
|
||||||
|
|
||||||
el.setAttribute("x", renderItem['arguments'][1]);
|
|
||||||
el.setAttribute("y", renderItem['arguments'][2] - (parseInt(el.style.fontSize, 10) + 3));
|
|
||||||
|
|
||||||
el.setAttribute("fill", settings.fillStyle);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// TODO get proper baseline
|
|
||||||
el.style.dominantBaseline = "text-before-edge";
|
|
||||||
el.style.fontFamily = fontStyle.join(" ");
|
|
||||||
|
|
||||||
text = doc.createTextNode(renderItem['arguments'][0]);
|
|
||||||
el.appendChild(text);
|
|
||||||
|
|
||||||
|
|
||||||
svg.appendChild(el);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} else if(renderItem.name === "drawImage") {
|
|
||||||
|
|
||||||
if (renderItem['arguments'][8] > 0 && renderItem['arguments'][7]){
|
|
||||||
|
|
||||||
// TODO check whether even any clipping is necessary for this particular image
|
|
||||||
el = doc.createElementNS(svgNS, "clipPath");
|
|
||||||
el.setAttribute("id", "clipId" + clipId);
|
|
||||||
|
|
||||||
text = doc.createElementNS(svgNS, "rect");
|
|
||||||
text.setAttribute("x", renderItem['arguments'][5] );
|
|
||||||
text.setAttribute("y", renderItem['arguments'][6]);
|
|
||||||
|
|
||||||
text.setAttribute("width", renderItem['arguments'][3]);
|
|
||||||
text.setAttribute("height", renderItem['arguments'][4]);
|
|
||||||
el.appendChild(text);
|
|
||||||
defs.appendChild(el);
|
|
||||||
|
|
||||||
el = doc.createElementNS(svgNS, "image");
|
|
||||||
el.setAttributeNS(xlinkNS, "xlink:href", renderItem['arguments'][0].src);
|
|
||||||
el.setAttribute("width", renderItem['arguments'][0].width);
|
|
||||||
el.setAttribute("height", renderItem['arguments'][0].height);
|
|
||||||
el.setAttribute("x", renderItem['arguments'][5] - renderItem['arguments'][1]);
|
|
||||||
el.setAttribute("y", renderItem['arguments'][6] - renderItem['arguments'][2]);
|
|
||||||
el.setAttribute("clip-path", "url(#clipId" + clipId + ")");
|
|
||||||
// el.setAttribute("xlink:href", );
|
|
||||||
|
|
||||||
|
|
||||||
el.setAttribute("preserveAspectRatio", "none");
|
|
||||||
|
|
||||||
svg.appendChild(el);
|
|
||||||
|
|
||||||
|
|
||||||
clipId += 1;
|
|
||||||
/*
|
|
||||||
ctx.drawImage(
|
|
||||||
renderItem['arguments'][0],
|
|
||||||
renderItem['arguments'][1],
|
|
||||||
renderItem['arguments'][2],
|
|
||||||
renderItem['arguments'][3],
|
|
||||||
renderItem['arguments'][4],
|
|
||||||
renderItem['arguments'][5],
|
|
||||||
renderItem['arguments'][6],
|
|
||||||
renderItem['arguments'][7],
|
|
||||||
renderItem['arguments'][8]
|
|
||||||
);
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
if (storageContext.clip){
|
|
||||||
ctx.restore();
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
h2clog("html2canvas: Renderer: SVG Renderer done - returning SVG DOM obj");
|
|
||||||
|
|
||||||
return svg;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//this.each(this.opts.renderOrder.split(" "),function(i,renderer){
|
|
||||||
|
|
||||||
//options.renderer = "svg";
|
|
||||||
|
|
||||||
switch(options.renderer.toLowerCase()){
|
|
||||||
case "canvas":
|
|
||||||
canvas = doc.createElement('canvas');
|
|
||||||
if (canvas.getContext){
|
|
||||||
h2clog("html2canvas: Renderer: using canvas renderer");
|
|
||||||
return canvasRenderer(parseQueue);
|
|
||||||
} else {
|
|
||||||
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 );
|
|
||||||
canvasRenderer(parseQueue);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
doc.body.appendChild( script );
|
|
||||||
|
|
||||||
return canvas;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "svg":
|
|
||||||
if (doc.createElementNS){
|
|
||||||
h2clog("html2canvas: Renderer: using SVG renderer");
|
|
||||||
return svgRenderer(parseQueue);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//});
|
|
||||||
|
|
||||||
|
|
||||||
return this;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -30,15 +30,17 @@ html2canvas = function( elements, opts ) {
|
|||||||
|
|
||||||
// render options
|
// render options
|
||||||
|
|
||||||
|
flashcanvas: undefined, // path to flashcanvas
|
||||||
width: null,
|
width: null,
|
||||||
height: null,
|
height: null,
|
||||||
renderer: "canvas",
|
|
||||||
taintTest: true // do a taint test with all images before applying to canvas
|
taintTest: true // do a taint test with all images before applying to canvas
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
options = _html2canvas.Util.Extend(opts, options);
|
options = _html2canvas.Util.Extend(opts, options);
|
||||||
|
|
||||||
|
options.renderer = options.renderer || html2canvas.Renderer.Canvas( options );
|
||||||
|
|
||||||
_html2canvas.logging = options.logging;
|
_html2canvas.logging = options.logging;
|
||||||
options.complete = function( images ) {
|
options.complete = function( images ) {
|
||||||
|
|
||||||
@ -82,3 +84,8 @@ html2canvas = function( elements, opts ) {
|
|||||||
log: h2clog
|
log: h2clog
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
html2canvas.log = h2clog; // for renderers
|
||||||
|
html2canvas.Renderer = {
|
||||||
|
Canvas: undefined // We are assuming this will be used
|
||||||
|
};
|
206
src/renderers/SVG.js
Normal file
206
src/renderers/SVG.js
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
/*
|
||||||
|
html2canvas @VERSION@ <http://html2canvas.hertzen.com>
|
||||||
|
Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
|
||||||
|
http://www.twitter.com/niklasvh
|
||||||
|
|
||||||
|
Released under MIT License
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// WARNING THIS file is outdated, and hasn't been tested in quite a while
|
||||||
|
|
||||||
|
html2canvas.Renderer.SVG = function( options ) {
|
||||||
|
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
var doc = document,
|
||||||
|
svgNS = "http://www.w3.org/2000/svg",
|
||||||
|
svg = doc.createElementNS(svgNS, "svg"),
|
||||||
|
xlinkNS = "http://www.w3.org/1999/xlink",
|
||||||
|
defs = doc.createElementNS(svgNS, "defs"),
|
||||||
|
i,
|
||||||
|
a,
|
||||||
|
queueLen,
|
||||||
|
storageLen,
|
||||||
|
storageContext,
|
||||||
|
renderItem,
|
||||||
|
el,
|
||||||
|
settings = {},
|
||||||
|
text,
|
||||||
|
fontStyle,
|
||||||
|
clipId = 0,
|
||||||
|
methods;
|
||||||
|
|
||||||
|
|
||||||
|
methods = {
|
||||||
|
_create: function( zStack, options, doc, queue, _html2canvas ) {
|
||||||
|
svg.setAttribute("version", "1.1");
|
||||||
|
svg.setAttribute("baseProfile", "full");
|
||||||
|
|
||||||
|
svg.setAttribute("viewBox", "0 0 " + Math.max(zStack.ctx.width, options.width) + " " + Math.max(zStack.ctx.height, options.height));
|
||||||
|
svg.setAttribute("width", Math.max(zStack.ctx.width, options.width) + "px");
|
||||||
|
svg.setAttribute("height", Math.max(zStack.ctx.height, options.height) + "px");
|
||||||
|
svg.setAttribute("preserveAspectRatio", "none");
|
||||||
|
svg.appendChild(defs);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
for (i = 0, queueLen = queue.length; i < queueLen; i+=1){
|
||||||
|
|
||||||
|
storageContext = queue.splice(0, 1)[0];
|
||||||
|
storageContext.canvasPosition = storageContext.canvasPosition || {};
|
||||||
|
|
||||||
|
//this.canvasRenderContext(storageContext,parentctx);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
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":
|
||||||
|
settings[renderItem.name] = renderItem['arguments'];
|
||||||
|
break;
|
||||||
|
case "function":
|
||||||
|
if (renderItem.name === "fillRect") {
|
||||||
|
|
||||||
|
el = doc.createElementNS(svgNS, "rect");
|
||||||
|
el.setAttribute("x", renderItem['arguments'][0]);
|
||||||
|
el.setAttribute("y", renderItem['arguments'][1]);
|
||||||
|
el.setAttribute("width", renderItem['arguments'][2]);
|
||||||
|
el.setAttribute("height", renderItem['arguments'][3]);
|
||||||
|
el.setAttribute("fill", settings.fillStyle);
|
||||||
|
svg.appendChild(el);
|
||||||
|
|
||||||
|
} else if(renderItem.name === "fillText") {
|
||||||
|
el = doc.createElementNS(svgNS, "text");
|
||||||
|
|
||||||
|
fontStyle = settings.font.split(" ");
|
||||||
|
|
||||||
|
el.style.fontVariant = fontStyle.splice(0, 1)[0];
|
||||||
|
el.style.fontWeight = fontStyle.splice(0, 1)[0];
|
||||||
|
el.style.fontStyle = fontStyle.splice(0, 1)[0];
|
||||||
|
el.style.fontSize = fontStyle.splice(0, 1)[0];
|
||||||
|
|
||||||
|
el.setAttribute("x", renderItem['arguments'][1]);
|
||||||
|
el.setAttribute("y", renderItem['arguments'][2] - (parseInt(el.style.fontSize, 10) + 3));
|
||||||
|
|
||||||
|
el.setAttribute("fill", settings.fillStyle);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// TODO get proper baseline
|
||||||
|
el.style.dominantBaseline = "text-before-edge";
|
||||||
|
el.style.fontFamily = fontStyle.join(" ");
|
||||||
|
|
||||||
|
text = doc.createTextNode(renderItem['arguments'][0]);
|
||||||
|
el.appendChild(text);
|
||||||
|
|
||||||
|
|
||||||
|
svg.appendChild(el);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} else if(renderItem.name === "drawImage") {
|
||||||
|
|
||||||
|
if (renderItem['arguments'][8] > 0 && renderItem['arguments'][7]){
|
||||||
|
|
||||||
|
// TODO check whether even any clipping is necessary for this particular image
|
||||||
|
el = doc.createElementNS(svgNS, "clipPath");
|
||||||
|
el.setAttribute("id", "clipId" + clipId);
|
||||||
|
|
||||||
|
text = doc.createElementNS(svgNS, "rect");
|
||||||
|
text.setAttribute("x", renderItem['arguments'][5] );
|
||||||
|
text.setAttribute("y", renderItem['arguments'][6]);
|
||||||
|
|
||||||
|
text.setAttribute("width", renderItem['arguments'][3]);
|
||||||
|
text.setAttribute("height", renderItem['arguments'][4]);
|
||||||
|
el.appendChild(text);
|
||||||
|
defs.appendChild(el);
|
||||||
|
|
||||||
|
el = doc.createElementNS(svgNS, "image");
|
||||||
|
el.setAttributeNS(xlinkNS, "xlink:href", renderItem['arguments'][0].src);
|
||||||
|
el.setAttribute("width", renderItem['arguments'][0].width);
|
||||||
|
el.setAttribute("height", renderItem['arguments'][0].height);
|
||||||
|
el.setAttribute("x", renderItem['arguments'][5] - renderItem['arguments'][1]);
|
||||||
|
el.setAttribute("y", renderItem['arguments'][6] - renderItem['arguments'][2]);
|
||||||
|
el.setAttribute("clip-path", "url(#clipId" + clipId + ")");
|
||||||
|
// el.setAttribute("xlink:href", );
|
||||||
|
|
||||||
|
|
||||||
|
el.setAttribute("preserveAspectRatio", "none");
|
||||||
|
|
||||||
|
svg.appendChild(el);
|
||||||
|
|
||||||
|
|
||||||
|
clipId += 1;
|
||||||
|
/*
|
||||||
|
ctx.drawImage(
|
||||||
|
renderItem['arguments'][0],
|
||||||
|
renderItem['arguments'][1],
|
||||||
|
renderItem['arguments'][2],
|
||||||
|
renderItem['arguments'][3],
|
||||||
|
renderItem['arguments'][4],
|
||||||
|
renderItem['arguments'][5],
|
||||||
|
renderItem['arguments'][6],
|
||||||
|
renderItem['arguments'][7],
|
||||||
|
renderItem['arguments'][8]
|
||||||
|
);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
if (storageContext.clip){
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
h2clog("html2canvas: Renderer: SVG Renderer done - returning SVG DOM obj");
|
||||||
|
|
||||||
|
return svg;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return methods;
|
||||||
|
|
||||||
|
|
||||||
|
};
|
225
src/renderers/canvas.js
Normal file
225
src/renderers/canvas.js
Normal file
@ -0,0 +1,225 @@
|
|||||||
|
/*
|
||||||
|
html2canvas @VERSION@ <http://html2canvas.hertzen.com>
|
||||||
|
Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
|
||||||
|
http://www.twitter.com/niklasvh
|
||||||
|
|
||||||
|
Released under MIT License
|
||||||
|
*/
|
||||||
|
|
||||||
|
html2canvas.Renderer.Canvas = function( options ) {
|
||||||
|
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
|
var doc = document,
|
||||||
|
canvas = options.canvas || doc.createElement('canvas'),
|
||||||
|
usingFlashcanvas = false,
|
||||||
|
_createCalled = false,
|
||||||
|
canvasReadyToDraw = false,
|
||||||
|
methods,
|
||||||
|
flashMaxSize = 2880; // flash bitmap limited to 2880x2880px // http://stackoverflow.com/questions/2033792/argumenterror-error-2015-invalid-bitmapdata
|
||||||
|
|
||||||
|
|
||||||
|
if (canvas.getContext){
|
||||||
|
html2canvas.log("html2canvas: Renderer: using canvas renderer");
|
||||||
|
canvasReadyToDraw = true;
|
||||||
|
} else if ( options.flashcanvas !== undefined ){
|
||||||
|
usingFlashcanvas = true;
|
||||||
|
html2canvas.log("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 {
|
||||||
|
html2canvas.log("html2canvas: Renderer: Can't track when flashcanvas is loaded");
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return func;
|
||||||
|
}
|
||||||
|
|
||||||
|
})(script, function(){
|
||||||
|
|
||||||
|
if (typeof window.FlashCanvas !== "undefined") {
|
||||||
|
html2canvas.log("html2canvas: Renderer: Flashcanvas initialized");
|
||||||
|
window.FlashCanvas.initElement( canvas );
|
||||||
|
|
||||||
|
canvasReadyToDraw = true;
|
||||||
|
if ( _createCalled !== false ) {
|
||||||
|
methods._create.apply( null, _createCalled );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
doc.body.appendChild( script );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
methods = {
|
||||||
|
_create: function( zStack, options, doc, queue, _html2canvas ) {
|
||||||
|
|
||||||
|
if ( !canvasReadyToDraw ) {
|
||||||
|
_createCalled = arguments;
|
||||||
|
return canvas;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
ctx.fillStyle = fstyle;
|
||||||
|
|
||||||
|
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 === "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]){
|
||||||
|
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'] );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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 methods;
|
||||||
|
|
||||||
|
};
|
@ -8,7 +8,7 @@
|
|||||||
(function(document, window) {
|
(function(document, window) {
|
||||||
var scrStart = '<script type="text/javascript" src="', scrEnd = '"></script>';
|
var scrStart = '<script type="text/javascript" src="', scrEnd = '"></script>';
|
||||||
document.write(scrStart + '../external/jquery-1.6.2.js' + scrEnd);
|
document.write(scrStart + '../external/jquery-1.6.2.js' + scrEnd);
|
||||||
var html2canvas = ['Core', 'Generate', 'Parse', 'Preload', 'Queue', 'Renderer', 'Util', 'plugins/jquery.plugin.html2canvas'], i;
|
var html2canvas = ['Core', 'Generate', 'Parse', 'Preload', 'Queue', 'Renderer', 'Util', 'renderers/Canvas', 'plugins/jquery.plugin.html2canvas'], i;
|
||||||
for (i = 0; i < html2canvas.length; ++i) {
|
for (i = 0; i < html2canvas.length; ++i) {
|
||||||
document.write(scrStart + '../src/' + html2canvas[i] + '.js' + scrEnd);
|
document.write(scrStart + '../src/' + html2canvas[i] + '.js' + scrEnd);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user