added support for font-metrics, to find baseline information for text (text-decoration:underline)

This commit is contained in:
Niklas von Hertzen 2011-07-16 22:35:06 +03:00
parent d1626c546b
commit ba0306af49
4 changed files with 195 additions and 44 deletions

View File

@ -56,6 +56,7 @@ function html2canvas(el, userOptions) {
image;
this.imagesLoaded = 0;
this.images = [];
this.fontData = [];
this.ignoreElements = "IFRAME|OBJECT|PARAM";
@ -581,10 +582,7 @@ html2canvas.prototype.preloadImage = function(src){
html2canvas.prototype.newText = function(el,textNode){
var family = this.getCSS(el,"font-family");
var size = this.getCSS(el,"font-size");
var color = this.getCSS(el,"color");
@ -608,15 +606,17 @@ html2canvas.prototype.newText = function(el,textNode){
break;
}
if (text_decoration!="none"){
var metrics = this.fontMetrics(family,size);
}
this.ctx.font = bold+" "+font_style+" "+size+" "+family;
this.ctx.fillStyle = color;
var oldTextNode = textNode;
for(var c=0;c<text.length;c++){
var newTextNode = oldTextNode.splitText(1);
@ -656,16 +656,16 @@ html2canvas.prototype.newText = function(el,textNode){
switch(text_decoration) {
case "underline":
// guesstimate the y-position of the line
// TODO try and find a more accurate way to find the baseline of the text
this.newRect(bounds.left,Math.round(bounds.bottom-(bounds.height/7)),bounds.width,1,color);
// Draws a line at the baseline of the font
// TODO As some browsers display the line as more than 1px if the font-size is big, need to take that into account both in position and size
this.newRect(bounds.left,Math.round(bounds.top+metrics.baseline+metrics.lineWidth),bounds.width,1,color);
break;
case "overline":
this.newRect(bounds.left,bounds.top,bounds.width,1,color);
break;
case "line-through":
// TODO try and find exact position for line-through
this.newRect(bounds.left,Math.round(bounds.top+(bounds.height/2)),bounds.width,1,color);
this.newRect(bounds.left,Math.ceil(bounds.top+metrics.middle+metrics.lineWidth),bounds.width,1,color);
break;
}
@ -681,11 +681,85 @@ html2canvas.prototype.newText = function(el,textNode){
}
/*
* Function to find baseline for font with a specicic size
*/
html2canvas.prototype.fontMetrics = function(font,fontSize){
var findMetrics = this.fontData.indexOf(font+"-"+fontSize);
if (findMetrics>-1){
return this.fontData[findMetrics+1];
}
var container = document.createElement('div');
document.getElementsByTagName('body')[0].appendChild(container);
// jquery to speed this up, TODO remove jquery dependancy
$(container).css({
visibility:'hidden',
fontFamily:font,
fontSize:fontSize,
margin:0,
padding:0
});
var img = document.createElement('img');
img.src = "http://html2canvas.hertzen.com/images/8.jpg";
img.width = 1;
img.height = 1;
$(img).css({
margin:0,
padding:0
});
var span = document.createElement('span');
$(span).css({
fontFamily:font,
fontSize:fontSize,
margin:0,
padding:0
});
span.appendChild(document.createTextNode('Hidden Text'));
container.appendChild(span);
container.appendChild(img);
var baseline = (img.offsetTop-span.offsetTop)+1;
container.removeChild(span);
container.appendChild(document.createTextNode('Hidden Text'));
$(container).css('line-height','normal');
$(img).css("vertical-align","super");
var middle = (img.offsetTop-container.offsetTop)+1;
var metricsObj = {
baseline: baseline,
lineWidth: 1,
middle: middle
};
this.fontData.push(font+"-"+fontSize);
this.fontData.push(metricsObj);
$(container).remove();
return metricsObj;
}
/*
* Function to apply text-transform attribute to text
*/
* Function to apply text-transform attribute to text
*/
html2canvas.prototype.textTransform = function(text,transform){
switch(transform){
case "lowercase":

View File

@ -6,22 +6,25 @@
* Released under MIT License
*/
function html2canvas(a,b){this.opts=this.extendObj(b||{},{logging:!1,ready:function(a){document.body.appendChild(a)},renderViewport:!0});this.element=a;this.imagesLoaded=0;this.images=[];this.ignoreElements="IFRAME|OBJECT|PARAM";this.useRangeBounds=!1;if(document.createRange){var c=document.createRange();this.useRangeBounds=new Boolean(c.getBoundingClientRect)}this.init()}
function html2canvas(a,b){this.opts=this.extendObj(b||{},{logging:!1,ready:function(a){document.body.appendChild(a)},renderViewport:!0});this.element=a;this.imagesLoaded=0;this.images=[];this.fontData=[];this.ignoreElements="IFRAME|OBJECT|PARAM";this.useRangeBounds=!1;if(document.createRange){var c=document.createRange();this.useRangeBounds=new Boolean(c.getBoundingClientRect)}this.init()}
html2canvas.prototype.init=function(){var a=this;this.canvas=document.createElement("canvas");this.canvas.width=$(document).width();this.canvas.height=$(document).height()+10;if(this.canvas.getContext)this.ctx=this.canvas.getContext("2d");this.ctx?(this.ctx.textBaseline="bottom",this.log("Finding background images"),this.getImages(this.element),this.log("Finding images"),this.each(document.images,function(b,c){a.preloadImage(a.getAttr(c,"src"))}),this.images.length==0&&this.start()):this.log("Canvas not available")};
html2canvas.prototype.start=function(){if(this.images.length==0||this.imagesLoaded==this.images.length/2)this.log("Started parsing"),this.newElement(this.element),this.parseElement(this.element)};html2canvas.prototype.finish=function(){this.log("Finished rendering");if(this.opts.renderViewport){var a=document.createElement("canvas");a.getContext("2d");a.width=window.innerWidth;a.height=window.innerHeight}this.opts.ready(this.canvas)};
html2canvas.prototype.drawBackground=function(a,b){var c=this.getCSS(a,"background-image"),f=this.getCSS(a,"background-repeat");if(typeof c!="undefined"&&/^(1|none)$/.test(c)==!1){var c=this.backgroundImageUrl(c),d=this.loadImage(c),h=this.getBackgroundPosition(a,b,d);if(d)switch(f){case "repeat-x":this.drawbackgroundRepeatX(d,h,b.left,b.top,b.width,b.height);break;case "repeat-y":this.drawbackgroundRepeatY(d,h,b.left,b.top,b.width,b.height);break;case "no-repeat":this.drawBackgroundRepeat(d,h.left+
b.left,h.top+b.top,Math.min(b.width,d.width),Math.min(b.height,d.height),b.left,b.top);break;default:var g;h.top-=Math.ceil(h.top/d.height)*d.height;for(c=b.top+h.top;c<=b.height+b.top;)f=Math.min(d.height,b.height+b.top-c),f=Math.floor(c+d.height)>f+c?f+c-c:d.height,c<b.top?(g=b.top-c,c=b.top):g=0,this.drawbackgroundRepeatX(d,h,b.left,c,b.width,f),g>0&&(h.top+=g),c=Math.floor(c+d.height)-g}else this.log("Error loading background:"+c)}};
html2canvas.prototype.backgroundImageUrl=function(a){a.substr(0,5)=='url("'?(a=a.substr(5),a=a.substr(0,a.length-2)):(a=a.substr(4),a=a.substr(0,a.length-1));return a};html2canvas.prototype.getBackgroundPosition=function(a,b,c){var f=this.getCSS(a,"background-position").split(" "),d;f[0].indexOf("%")!=-1?(d=parseFloat(f[0])/100,a=b.width*d-c.width*d):a=parseInt(f[0],10);f[1].indexOf("%")!=-1?(d=parseFloat(f[1])/100,b=b.height*d-c.height*d):b=parseInt(f[1],10);return{top:b,left:a}};
html2canvas.prototype.drawbackgroundRepeatY=function(a,b,c,f,d,h){var g=Math.min(a.width,d),e;b.top-=Math.ceil(b.top/a.height)*a.height;for(e=f+b.top;e<=h+f;)d=Math.floor(e+a.height)>h+f?h+f-e:a.height,this.drawBackgroundRepeat(a,c+b.left,e,g,d,c,f),e=Math.floor(e+a.height)};
html2canvas.prototype.drawbackgroundRepeatX=function(a,b,c,f,d,h){var h=Math.min(a.height,h),g,e;b.left-=Math.ceil(b.left/a.width)*a.width;for(e=c+b.left;e<=d+c;)g=Math.floor(e+a.width)>d+c?d+c-e:a.width,this.drawBackgroundRepeat(a,e,f+b.top,g,h,c,f),e=Math.floor(e+a.width)};html2canvas.prototype.drawBackgroundRepeat=function(a,b,c,f,d,h,g){var e=0,i=0;h-b>0&&(e=h-b);g-c>0&&(i=g-c);this.ctx.drawImage(a,e,i,f-e,d-i,b+e,c+i,f-e,d-i)};
html2canvas.prototype.getBorderData=function(a){var b=[],c=this;this.each(["top","right","bottom","left"],function(f,d){b.push({width:parseInt(c.getCSS(a,"border-"+d+"-width"),10),color:c.getCSS(a,"border-"+d+"-color")})});return b};
html2canvas.prototype.newElement=function(a){var b=this.getBounds(a),c=b.left,f=b.top,d=b.width,h=b.height,g=this,b=this.getCSS(a,"background-color"),e=this.getBorderData(a);this.each(e,function(a,b){if(b.width>0){var j=c,k=f,l=d,m=h-e[2].width;switch(a){case 0:m=e[0].width;break;case 1:j=c+d-e[1].width;l=e[1].width;break;case 2:k=k+h-e[2].width;m=e[2].width;break;case 3:l=e[3].width}g.newRect(j,k,l,m,b.color)}});this.newRect(c+e[3].width,f+e[0].width,d-(e[1].width+e[3].width),h-(e[0].width+e[2].width),
b);this.drawBackground(a,{left:c+e[3].width,top:f+e[0].width,width:d-(e[1].width+e[3].width),height:h-(e[0].width+e[2].width)});a.nodeName=="IMG"&&((b=g.loadImage(g.getAttr(a,"src")))?this.ctx.drawImage(b,c+parseInt(g.getCSS(a,"padding-left"),10),f+parseInt(g.getCSS(a,"padding-top"),10)):this.log("Error loading <img>:"+g.getAttr(a,"src")))};html2canvas.prototype.printText=function(a,b,c){this.trim(a).length>0&&this.ctx.fillText(a,b,c)};
html2canvas.prototype.newRect=function(a,b,c,f,d){if(d!="transparent")this.ctx.fillStyle=d,this.ctx.fillRect(a,b,c,f)};html2canvas.prototype.getImages=function(a){var b=this;this.each($(a).contents(),function(a,f){RegExp("("+this.ignoreElements+")").test(f.nodeName)||b.getImages(f)});if(a.nodeType==1||typeof a.nodeType=="undefined")(a=this.getCSS(a,"background-image"))&&a!="1"&&a!="none"&&a.substring(0,7)!="-webkit"&&a.substring(0,4)!="-moz"&&this.preloadImage(this.backgroundImageUrl(a))};
html2canvas.prototype.drawBackground=function(a,b){var c=this.getCSS(a,"background-image"),e=this.getCSS(a,"background-repeat");if(typeof c!="undefined"&&/^(1|none)$/.test(c)==!1){var c=this.backgroundImageUrl(c),d=this.loadImage(c),h=this.getBackgroundPosition(a,b,d);if(d)switch(e){case "repeat-x":this.drawbackgroundRepeatX(d,h,b.left,b.top,b.width,b.height);break;case "repeat-y":this.drawbackgroundRepeatY(d,h,b.left,b.top,b.width,b.height);break;case "no-repeat":this.drawBackgroundRepeat(d,h.left+
b.left,h.top+b.top,Math.min(b.width,d.width),Math.min(b.height,d.height),b.left,b.top);break;default:var g;h.top-=Math.ceil(h.top/d.height)*d.height;for(c=b.top+h.top;c<=b.height+b.top;)e=Math.min(d.height,b.height+b.top-c),e=Math.floor(c+d.height)>e+c?e+c-c:d.height,c<b.top?(g=b.top-c,c=b.top):g=0,this.drawbackgroundRepeatX(d,h,b.left,c,b.width,e),g>0&&(h.top+=g),c=Math.floor(c+d.height)-g}else this.log("Error loading background:"+c)}};
html2canvas.prototype.backgroundImageUrl=function(a){a.substr(0,5)=='url("'?(a=a.substr(5),a=a.substr(0,a.length-2)):(a=a.substr(4),a=a.substr(0,a.length-1));return a};html2canvas.prototype.getBackgroundPosition=function(a,b,c){var e=this.getCSS(a,"background-position").split(" "),d;e[0].indexOf("%")!=-1?(d=parseFloat(e[0])/100,a=b.width*d-c.width*d):a=parseInt(e[0],10);e[1].indexOf("%")!=-1?(d=parseFloat(e[1])/100,b=b.height*d-c.height*d):b=parseInt(e[1],10);return{top:b,left:a}};
html2canvas.prototype.drawbackgroundRepeatY=function(a,b,c,e,d,h){var g=Math.min(a.width,d),f;b.top-=Math.ceil(b.top/a.height)*a.height;for(f=e+b.top;f<=h+e;)d=Math.floor(f+a.height)>h+e?h+e-f:a.height,this.drawBackgroundRepeat(a,c+b.left,f,g,d,c,e),f=Math.floor(f+a.height)};
html2canvas.prototype.drawbackgroundRepeatX=function(a,b,c,e,d,h){var h=Math.min(a.height,h),g,f;b.left-=Math.ceil(b.left/a.width)*a.width;for(f=c+b.left;f<=d+c;)g=Math.floor(f+a.width)>d+c?d+c-f:a.width,this.drawBackgroundRepeat(a,f,e+b.top,g,h,c,e),f=Math.floor(f+a.width)};html2canvas.prototype.drawBackgroundRepeat=function(a,b,c,e,d,h,g){var f=0,i=0;h-b>0&&(f=h-b);g-c>0&&(i=g-c);this.ctx.drawImage(a,f,i,e-f,d-i,b+f,c+i,e-f,d-i)};
html2canvas.prototype.getBorderData=function(a){var b=[],c=this;this.each(["top","right","bottom","left"],function(e,d){b.push({width:parseInt(c.getCSS(a,"border-"+d+"-width"),10),color:c.getCSS(a,"border-"+d+"-color")})});return b};
html2canvas.prototype.newElement=function(a){var b=this.getBounds(a),c=b.left,e=b.top,d=b.width,h=b.height,g=this,b=this.getCSS(a,"background-color"),f=this.getBorderData(a);this.each(f,function(a,b){if(b.width>0){var k=c,j=e,l=d,n=h-f[2].width;switch(a){case 0:n=f[0].width;break;case 1:k=c+d-f[1].width;l=f[1].width;break;case 2:j=j+h-f[2].width;n=f[2].width;break;case 3:l=f[3].width}g.newRect(k,j,l,n,b.color)}});this.newRect(c+f[3].width,e+f[0].width,d-(f[1].width+f[3].width),h-(f[0].width+f[2].width),
b);this.drawBackground(a,{left:c+f[3].width,top:e+f[0].width,width:d-(f[1].width+f[3].width),height:h-(f[0].width+f[2].width)});a.nodeName=="IMG"&&((b=g.loadImage(g.getAttr(a,"src")))?this.ctx.drawImage(b,c+parseInt(g.getCSS(a,"padding-left"),10),e+parseInt(g.getCSS(a,"padding-top"),10)):this.log("Error loading <img>:"+g.getAttr(a,"src")))};html2canvas.prototype.printText=function(a,b,c){this.trim(a).length>0&&this.ctx.fillText(a,b,c)};
html2canvas.prototype.newRect=function(a,b,c,e,d){if(d!="transparent")this.ctx.fillStyle=d,this.ctx.fillRect(a,b,c,e)};html2canvas.prototype.getImages=function(a){var b=this;this.each($(a).contents(),function(a,e){RegExp("("+this.ignoreElements+")").test(e.nodeName)||b.getImages(e)});if(a.nodeType==1||typeof a.nodeType=="undefined")(a=this.getCSS(a,"background-image"))&&a!="1"&&a!="none"&&a.substring(0,7)!="-webkit"&&a.substring(0,4)!="-moz"&&this.preloadImage(this.backgroundImageUrl(a))};
html2canvas.prototype.loadImage=function(a){a=this.images.indexOf(a);return a!=-1?this.images[a+1]:!1};html2canvas.prototype.preloadImage=function(a){if(this.images.indexOf(a)==-1){this.images.push(a);var b=new Image,c=this;$(b).load(function(){c.imagesLoaded++;c.start()});b.onerror=function(){c.images.splice(c.images.indexOf(b.src),2);c.imagesLoaded++;c.start()};b.src=a;this.images.push(b)}};
html2canvas.prototype.newText=function(a,b){var c=this.getCSS(a,"font-family"),f=this.getCSS(a,"font-size"),d=this.getCSS(a,"color"),h=this.getCSS(a,"font-weight"),g=this.getCSS(a,"font-style"),e=this.getCSS(a,"text-decoration");b.nodeValue=this.textTransform(b.nodeValue,this.getCSS(a,"text-transform"));var i=b.nodeValue;if(i.length>0){switch(h){case "401":h="bold"}this.ctx.font=h+" "+g+" "+f+" "+c;this.ctx.fillStyle=d;c=b;for(f=0;f<i.length;f++){h=c.splitText(1);if(this.useRangeBounds)document.createRange?
(g=document.createRange(),g.selectNode(c)):g=document.body.createTextRange(),g=g.getBoundingClientRect()?g.getBoundingClientRect():{};else{var n=c.parentNode,j=document.createElement("wrapper"),k=c.cloneNode(!0);j.appendChild(c.cloneNode(!0));n.replaceChild(j,c);g=this.getBounds(j);n.replaceChild(k,j)}this.printText(c.nodeValue,g.left,g.bottom);switch(e){case "underline":this.newRect(g.left,Math.round(g.bottom-g.height/7),g.width,1,d);break;case "overline":this.newRect(g.left,g.top,g.width,1,d);break;
case "line-through":this.newRect(g.left,Math.round(g.top+g.height/2),g.width,1,d)}c=h}}};html2canvas.prototype.textTransform=function(a,b){switch(b){case "lowercase":return a.toLowerCase();case "capitalize":return a.replace(/(^|\s|:|-|\(|\))([a-z])/g,function(a,b,d){return b+d.toUpperCase()});case "uppercase":return a.toUpperCase();default:return a}};html2canvas.prototype.trim=function(a){return a.replace(/^\s*/,"").replace(/\s*$/,"")};
html2canvas.prototype.parseElement=function(a){var b=this;this.each(a.children,function(a,f){b.parsing(f)});this.finish()};html2canvas.prototype.parsing=function(a){var b=this;if(!RegExp("("+this.ignoreElements+")").test(a.nodeName)){this.newElement(a);var c=$(a).contents();c.length==1?c[0].nodeType==1?this.parsing(c[0]):c[0].nodeType==3&&this.newText(a,c[0]):this.each(c,function(c,d){d.nodeType==1?b.parsing(d):d.nodeType==3&&b.newText(a,d)})}};html2canvas.prototype.log=function(){};
html2canvas.prototype.newText=function(a,b){var c=this.getCSS(a,"font-family"),e=this.getCSS(a,"font-size"),d=this.getCSS(a,"color"),h=this.getCSS(a,"font-weight"),g=this.getCSS(a,"font-style"),f=this.getCSS(a,"text-decoration");b.nodeValue=this.textTransform(b.nodeValue,this.getCSS(a,"text-transform"));var i=b.nodeValue;if(i.length>0){switch(h){case "401":h="bold"}if(f!="none")var m=this.fontMetrics(c,e);this.ctx.font=h+" "+g+" "+e+" "+c;this.ctx.fillStyle=d;c=b;for(e=0;e<i.length;e++){h=c.splitText(1);
if(this.useRangeBounds)document.createRange?(g=document.createRange(),g.selectNode(c)):g=document.body.createTextRange(),g=g.getBoundingClientRect()?g.getBoundingClientRect():{};else{var k=c.parentNode,j=document.createElement("wrapper"),l=c.cloneNode(!0);j.appendChild(c.cloneNode(!0));k.replaceChild(j,c);g=this.getBounds(j);k.replaceChild(l,j)}this.printText(c.nodeValue,g.left,g.bottom);switch(f){case "underline":this.newRect(g.left,Math.round(g.top+m.baseline+m.lineWidth),g.width,1,d);break;case "overline":this.newRect(g.left,
g.top,g.width,1,d);break;case "line-through":this.newRect(g.left,Math.ceil(g.top+m.middle+m.lineWidth),g.width,1,d)}c=h}}};
html2canvas.prototype.fontMetrics=function(a,b){var c=this.fontData.indexOf(a+"-"+b);if(c>-1)return this.fontData[c+1];c=document.createElement("div");document.getElementsByTagName("body")[0].appendChild(c);$(c).css({visibility:"hidden",fontFamily:a,fontSize:b,margin:0,padding:0});var e=document.createElement("img");e.src="http://html2canvas.hertzen.com/images/8.jpg";e.width=1;e.height=1;$(e).css({margin:0,padding:0});var d=document.createElement("span");$(d).css({fontFamily:a,fontSize:b,margin:0,
padding:0});d.appendChild(document.createTextNode("Hidden Text"));c.appendChild(d);c.appendChild(e);var h=e.offsetTop-d.offsetTop+1;c.removeChild(d);c.appendChild(document.createTextNode("Hidden Text"));$(c).css("line-height","normal");$(e).css("vertical-align","super");e={baseline:h,lineWidth:1,middle:e.offsetTop-c.offsetTop+1};this.fontData.push(a+"-"+b);this.fontData.push(e);$(c).remove();return e};
html2canvas.prototype.textTransform=function(a,b){switch(b){case "lowercase":return a.toLowerCase();case "capitalize":return a.replace(/(^|\s|:|-|\(|\))([a-z])/g,function(a,b,d){return b+d.toUpperCase()});case "uppercase":return a.toUpperCase();default:return a}};html2canvas.prototype.trim=function(a){return a.replace(/^\s*/,"").replace(/\s*$/,"")};html2canvas.prototype.parseElement=function(a){var b=this;this.each(a.children,function(a,e){b.parsing(e)});this.finish()};
html2canvas.prototype.parsing=function(a){var b=this;if(!RegExp("("+this.ignoreElements+")").test(a.nodeName)){this.newElement(a);var c=$(a).contents();c.length==1?c[0].nodeType==1?this.parsing(c[0]):c[0].nodeType==3&&this.newText(a,c[0]):this.each(c,function(c,d){d.nodeType==1?b.parsing(d):d.nodeType==3&&b.newText(a,d)})}};html2canvas.prototype.log=function(){};
html2canvas.prototype.getBounds=function(a){window.scroll(0,0);if(a.getBoundingClientRect)return a=a.getBoundingClientRect(),a.top=a.top,a.left=a.left,a;else{var b=$(a).offset();return{left:b.left+parseInt(this.getCSS(a,"border-left-width"),10),top:b.top+parseInt(this.getCSS(a,"border-top-width"),10),width:$(a).innerWidth(),height:$(a).innerHeight()}}};html2canvas.prototype.each=function(a,b){for(var b=b||function(){},c=0;c<a.length;c++)b(c,a[c])};html2canvas.prototype.getAttr=function(a,b){return a.getAttribute(b)};
html2canvas.prototype.extendObj=function(a,b){for(var c in a)b[c]=a[c];return b};html2canvas.prototype.getContents=function(a){return a.nodeName=="iframe"?a.contentDocument||a.contentWindow.document:a.childNodes};html2canvas.prototype.getCSS=function(a,b){return $(a).css(b)};

View File

@ -26,6 +26,7 @@ function html2canvas(el, userOptions) {
image;
this.imagesLoaded = 0;
this.images = [];
this.fontData = [];
this.ignoreElements = "IFRAME|OBJECT|PARAM";

View File

@ -1,9 +1,6 @@
html2canvas.prototype.newText = function(el,textNode){
var family = this.getCSS(el,"font-family");
var size = this.getCSS(el,"font-size");
var color = this.getCSS(el,"color");
@ -27,15 +24,17 @@ html2canvas.prototype.newText = function(el,textNode){
break;
}
if (text_decoration!="none"){
var metrics = this.fontMetrics(family,size);
}
this.ctx.font = bold+" "+font_style+" "+size+" "+family;
this.ctx.fillStyle = color;
var oldTextNode = textNode;
for(var c=0;c<text.length;c++){
var newTextNode = oldTextNode.splitText(1);
@ -75,16 +74,16 @@ html2canvas.prototype.newText = function(el,textNode){
switch(text_decoration) {
case "underline":
// guesstimate the y-position of the line
// TODO try and find a more accurate way to find the baseline of the text
this.newRect(bounds.left,Math.round(bounds.bottom-(bounds.height/7)),bounds.width,1,color);
// Draws a line at the baseline of the font
// TODO As some browsers display the line as more than 1px if the font-size is big, need to take that into account both in position and size
this.newRect(bounds.left,Math.round(bounds.top+metrics.baseline+metrics.lineWidth),bounds.width,1,color);
break;
case "overline":
this.newRect(bounds.left,bounds.top,bounds.width,1,color);
break;
case "line-through":
// TODO try and find exact position for line-through
this.newRect(bounds.left,Math.round(bounds.top+(bounds.height/2)),bounds.width,1,color);
this.newRect(bounds.left,Math.ceil(bounds.top+metrics.middle+metrics.lineWidth),bounds.width,1,color);
break;
}
@ -100,11 +99,85 @@ html2canvas.prototype.newText = function(el,textNode){
}
/*
* Function to find baseline for font with a specicic size
*/
html2canvas.prototype.fontMetrics = function(font,fontSize){
var findMetrics = this.fontData.indexOf(font+"-"+fontSize);
if (findMetrics>-1){
return this.fontData[findMetrics+1];
}
var container = document.createElement('div');
document.getElementsByTagName('body')[0].appendChild(container);
// jquery to speed this up, TODO remove jquery dependancy
$(container).css({
visibility:'hidden',
fontFamily:font,
fontSize:fontSize,
margin:0,
padding:0
});
var img = document.createElement('img');
img.src = "http://html2canvas.hertzen.com/images/8.jpg";
img.width = 1;
img.height = 1;
$(img).css({
margin:0,
padding:0
});
var span = document.createElement('span');
$(span).css({
fontFamily:font,
fontSize:fontSize,
margin:0,
padding:0
});
span.appendChild(document.createTextNode('Hidden Text'));
container.appendChild(span);
container.appendChild(img);
var baseline = (img.offsetTop-span.offsetTop)+1;
container.removeChild(span);
container.appendChild(document.createTextNode('Hidden Text'));
$(container).css('line-height','normal');
$(img).css("vertical-align","super");
var middle = (img.offsetTop-container.offsetTop)+1;
var metricsObj = {
baseline: baseline,
lineWidth: 1,
middle: middle
};
this.fontData.push(font+"-"+fontSize);
this.fontData.push(metricsObj);
$(container).remove();
return metricsObj;
}
/*
* Function to apply text-transform attribute to text
*/
* Function to apply text-transform attribute to text
*/
html2canvas.prototype.textTransform = function(text,transform){
switch(transform){
case "lowercase":