This commit is contained in:
Niklas von Hertzen
2012-03-08 11:35:12 +02:00
5 changed files with 469 additions and 154 deletions

View File

@ -2,128 +2,241 @@
html2canvas @VERSION@ <http://html2canvas.hertzen.com>
Copyright (c) 2011 Niklas von Hertzen. All rights reserved.
http://www.twitter.com/niklasvh
Contributor(s):
Niklas von Hertzen <http://www.twitter.com/niklasvh>
André Fiedler <http://www.twitter.com/sonnenkiste>
Released under MIT License
*/
(function(){
_html2canvas.Generate = {};
var reGradients = [
/^(-webkit-linear-gradient)\(([a-z\s]+)([\w\d\.\s,%\(\)]+)\)$/,
/^(-o-linear-gradient)\(([a-z\s]+)([\w\d\.\s,%\(\)]+)\)$/,
/^(-webkit-gradient)\((linear|radial),\s((?:\d{1,3}%?)\s(?:\d{1,3}%?),\s(?:\d{1,3}%?)\s(?:\d{1,3}%?))([\w\d\.\s,%\(\)-]+)\)$/,
/^(-moz-linear-gradient)\(((?:\d{1,3}%?)\s(?:\d{1,3}%?))([\w\d\.\s,%\(\)]+)\)$/
];
/*
* TODO: Add IE10 vendor prefix (-ms) support
* TODO: Add W3C gradient (linear-gradient) support
* TODO: Add radial gradient parsing
* TODO: Maybe some RegExp optimizations are possible ;o)
*/
_html2canvas.Generate.parseGradient = function(css, bounds) {
var gradient, i, len = reGradients.length, m1, stop, m2, m2Len, step, m3;
for(i = 0; i < len; i+=1){
m1 = css.match(reGradients[i]);
if(m1) break;
}
if(m1) {
switch(m1[1]) {
case '-webkit-linear-gradient':
case '-o-linear-gradient':
gradient = {
type: 'linear',
x0: null,
y0: null,
x1: null,
y1: null,
colorStops: []
};
// get coordinates
m2 = m1[2].match(/\w+/g);
if(m2){
m2Len = m2.length;
for(i = 0; i < m2Len; i+=1){
switch(m2[i]) {
case 'top':
gradient.y0 = 0;
gradient.y1 = bounds.height;
break;
case 'right':
gradient.x0 = bounds.width;
gradient.x1 = 0;
break;
case 'bottom':
gradient.y0 = bounds.height;
gradient.y1 = 0;
break;
case 'left':
gradient.x0 = 0;
gradient.x1 = bounds.width;
break;
}
}
}
if(gradient.x0 === null && gradient.x1 === null){ // center
gradient.x0 = gradient.x1 = bounds.width / 2;
}
if(gradient.y0 === null && gradient.y1 === null){ // center
gradient.y0 = gradient.y1 = bounds.height / 2;
}
// get colors and stops
m2 = m1[3].match(/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\)(?:\s\d{1,3}(?:%|px))?)+/g);
if(m2){
m2Len = m2.length;
step = 1 / Math.max(m2Len - 1, 1);
for(i = 0; i < m2Len; i+=1){
m3 = m2[i].match(/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\))\s*(\d{1,3})?(%|px)?/);
if(m3[2]){
stop = parseFloat(m3[2]);
if(m3[3] === '%'){
stop /= 100;
} else { // px - stupid opera
stop /= bounds.width;
}
} else {
stop = i * step;
}
gradient.colorStops.push({
color: m3[1],
stop: stop
});
}
}
break;
case '-webkit-gradient':
gradient = {
type: m1[2],
x0: 0,
y0: 0,
x1: 0,
y1: 0,
colorStops: []
};
// get coordinates
m2 = m1[3].match(/(\d{1,3})%?\s(\d{1,3})%?,\s(\d{1,3})%?\s(\d{1,3})%?/);
if(m2){
gradient.x0 = (m2[1] * bounds.width) / 100;
gradient.y0 = (m2[2] * bounds.height) / 100;
gradient.x1 = (m2[3] * bounds.width) / 100;
gradient.y1 = (m2[4] * bounds.height) / 100;
}
// get colors and stops
m2 = m1[4].match(/((?:from|to|color-stop)\((?:[0-9\.]+,\s)?(?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\)\))+/g);
if(m2){
m2Len = m2.length;
for(i = 0; i < m2Len; i+=1){
m3 = m2[i].match(/(from|to|color-stop)\(([0-9\.]+)?(?:,\s)?((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\))\)/);
stop = parseFloat(m3[2]);
if(m3[1] === 'from') stop = 0.0;
if(m3[1] === 'to') stop = 1.0;
gradient.colorStops.push({
color: m3[3],
stop: stop
});
}
}
break;
case '-moz-linear-gradient':
gradient = {
type: 'linear',
x0: 0,
y0: 0,
x1: 0,
y1: 0,
colorStops: []
};
// get coordinates
m2 = m1[2].match(/(\d{1,3})%?\s(\d{1,3})%?/);
// m2[1] == 0% -> left
// m2[1] == 50% -> center
// m2[1] == 100% -> right
// m2[2] == 0% -> top
// m2[2] == 50% -> center
// m2[2] == 100% -> bottom
if(m2){
gradient.x0 = (m2[1] * bounds.width) / 100;
gradient.y0 = (m2[2] * bounds.height) / 100;
gradient.x1 = bounds.width - gradient.x0;
gradient.y1 = bounds.height - gradient.y0;
}
// get colors and stops
m2 = m1[3].match(/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\)(?:\s\d{1,3}%)?)+/g);
if(m2){
m2Len = m2.length;
step = 1 / Math.max(m2Len - 1, 1);
for(i = 0; i < m2Len; i+=1){
m3 = m2[i].match(/((?:rgb|rgba)\(\d{1,3},\s\d{1,3},\s\d{1,3}(?:,\s[0-9\.]+)?\))\s*(\d{1,3})?(%)?/);
if(m3[2]){
stop = parseFloat(m3[2]);
if(m3[3]){ // percentage
stop /= 100;
}
} else {
stop = i * step;
}
gradient.colorStops.push({
color: m3[1],
stop: stop
});
}
}
break;
}
}
return gradient;
};
_html2canvas.Generate.Gradient = function(src, bounds) {
var canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d'),
tmp,
p0 = 0,
p1 = 0,
p2 = 0,
p3 = 0,
steps = [],
position,
i,
len,
lingrad,
increment,
p,
img;
gradient, lingrad, i, len, img;
canvas.width = bounds.width;
canvas.height = bounds.height;
gradient = _html2canvas.Generate.parseGradient(src, bounds);
function getColors(input) {
var j = -1,
color = '',
chr;
while( j++ < input.length ) {
chr = input.charAt( j );
if (chr === ')') {
color += chr;
steps.push( color );
color = '';
j = input.indexOf(",", j) + 1;
if (j === 0) {
break;
}
// while (j++ < input.length && input.charAt( j ) !== ',') {}
} else {
color += chr;
}
}
}
if ( (tmp = src.match(/-webkit-linear-gradient\((.*)\)/)) !== null ) {
position = tmp[1].split( ",", 1 )[0];
getColors( tmp[1].substr( position.length + 2 ) );
position = position.split(' ');
for ( p = 0, len = position.length; p < len; p+=1 ) {
switch( position[ p ] ) {
case 'top':
p3 = bounds.height;
break;
case 'right':
p0 = bounds.width;
break;
case 'bottom':
p1 = bounds.height;
break;
case 'left':
p2 = bounds.width;
break;
}
}
} else if ( (tmp = src.match(/-webkit-gradient\(linear, (\d+)[%]{0,1} (\d+)[%]{0,1}, (\d+)[%]{0,1} (\d+)[%]{0,1}, from\((.*)\), to\((.*)\)\)/)) !== null ) {
p0 = (tmp[1] * bounds.width) / 100;
p1 = (tmp[2] * bounds.height) / 100;
p2 = (tmp[3] * bounds.width) / 100;
p3 = (tmp[4] * bounds.height) / 100;
steps.push(tmp[5]);
steps.push(tmp[6]);
} else if ( (tmp = src.match(/-moz-linear-gradient\((\d+)[%]{0,1} (\d+)[%]{0,1}, (.*)\)/)) !== null ) {
p0 = (tmp[1] * bounds.width) / 100;
p1 = (tmp[2] * bounds.width) / 100;
p2 = bounds.width - p0;
p3 = bounds.height - p1;
getColors( tmp[3] );
} else {
return;
}
lingrad = ctx.createLinearGradient( p0, p1, p2, p3 );
increment = 1 / (steps.length - 1);
for (i = 0, len = steps.length; i < len; i+=1) {
try {
lingrad.addColorStop(increment * i, steps[i]);
}
catch(e) {
h2clog(['failed to add color stop: ', e, '; tried to add: ', steps[i], '; stop: ', i, '; in: ', src]);
}
}
ctx.fillStyle = lingrad;
// draw shapes
ctx.fillRect(0, 0, bounds.width,bounds.height);
img = new Image();
img.src = canvas.toDataURL();
if(gradient && gradient.type === 'linear'){
lingrad = ctx.createLinearGradient(gradient.x0, gradient.y0, gradient.x1, gradient.y1);
for (i = 0, len = gradient.colorStops.length; i < len; i+=1) {
try {
lingrad.addColorStop(gradient.colorStops[i].stop, gradient.colorStops[i].color);
}
catch(e) {
h2clog(['failed to add color stop: ', e, '; tried to add: ', gradient.colorStops[i], '; stop: ', i, '; in: ', src]);
}
}
ctx.fillStyle = lingrad;
ctx.fillRect(0, 0, bounds.width, bounds.height);
img.src = canvas.toDataURL();
} else if(gradient && gradient.type === 'radial'){
// TODO: implement radial gradient generation
h2clog('No radial gradient support implemented');
}
return img;
};
_html2canvas.Generate.ListAlpha = function(number) {
@ -160,3 +273,5 @@ _html2canvas.Generate.ListRoman = function(number) {
return roman;
};
})();