html div 转换图片,Javascript – 将带有SVG的HTML div转换为图像

我想你正在处理一些svg到位图转换的边缘情况.

我不确定html2canvas使用哪种方法,但它肯定缺少这里的东西.

我编写了一个函数来处理一些在调用html2canvas之前可以使用的边缘情况,因为它能够毫无问题地绘制位图.

// without converting the svg to png

html2canvas(contentDiv, {

onrendered: function(can) {

dirty.appendChild(can);

}

});

// first convert your svg to png

exportInlineSVG(svg, function(data, canvas) {

svg.parentNode.replaceChild(canvas, svg);

// then call html2canvas

html2canvas(contentDiv, {

onrendered: function(can) {

can.id = 'canvas';

clean.appendChild(can);

}

});

})

function exportInlineSVG(svg, receiver, params, quality) {

if (!svg || !svg.nodeName || svg.nodeName !== 'svg') {

console.error('Wrong arguments : should be \n exportSVG(SVGElement, function([dataURL],[canvasElement]) || IMGElement || CanvasElement [, String_toDataURL_Params, Float_Params_quality])')

return;

}

var xlinkNS = "http://www.w3.org/1999/xlink";

var clone;

// This will convert an external image to a dataURL

var toDataURL = function(image) {

var img = new Image();

// CORS workaround, this won't work in IE<11

// If you are sure you don't need it, remove the next line and the double onerror handler

// First try with crossorigin set, it should fire an error if not needed

img.crossOrigin = 'Anonymous';

img.onload = function() {

// we should now be able to draw it without tainting the canvas

var canvas = document.createElement('canvas');

var bbox = image.getBBox();

canvas.width = bbox.width;

canvas.height = bbox.height;

// draw the loaded image

canvas.getContext('2d').drawImage(this, 0, 0, bbox.width, bbox.height);

// set our original 's href attribute to the dataURL of our canvas

image.setAttributeNS(xlinkNS, 'href', canvas.toDataURL());

// that was the last one

if (++encoded === total) exportDoc()

}

// No CORS set in the response

img.onerror = function() {

// save the src

var oldSrc = this.src;

// there is an other problem

this.onerror = function() {

console.warn('failed to load an image at : ', this.src);

if (--total === encoded && encoded > 0) exportDoc();

}

// remove the crossorigin attribute

this.removeAttribute('crossorigin');

// retry

this.src = '';

this.src = oldSrc;

}

// load our external image into our img

img.src = image.getAttributeNS(xlinkNS, 'href');

}

// The final function that will export our svgNode to our receiver

var exportDoc = function() {

// check if our svgNode has width and height properties set to absolute values

// otherwise, canvas won't be able to draw it

var bbox = svg.getBBox();

// avoid modifying the original one

clone = svg.cloneNode(true);

if (svg.width.baseVal.unitType !== 1) clone.setAttribute('width', bbox.width);

if (svg.height.baseVal.unitType !== 1) clone.setAttribute('height', bbox.height);

parseStyles();

// serialize our node

var svgData = (new XMLSerializer()).serializeToString(clone);

// remember to encode special chars

var svgURL = 'data:image/svg+xml; charset=utf8, ' + encodeURIComponent(svgData);

var svgImg = new Image();

svgImg.onload = function() {

// if we set a canvas as receiver, then use it

// otherwise create a new one

var canvas = (receiver && receiver.nodeName === 'CANVAS') ? receiver : document.createElement('canvas');

// IE11 doesn't set a width on svg images...

canvas.width = this.width || bbox.width;

canvas.height = this.height || bbox.height;

canvas.getContext('2d').drawImage(this, 0, 0, canvas.width, canvas.height);

// try to catch IE

try {

// if we set an as receiver

if (receiver.nodeName === 'IMG') {

// make the img looks like the svg

receiver.setAttribute('style', getSVGStyles(receiver));

receiver.src = canvas.toDataURL(params, quality);

} else {

// make the canvas looks like the canvas

canvas.setAttribute('style', getSVGStyles(canvas));

// a container element

if (receiver.appendChild && receiver !== canvas)

receiver.appendChild(canvas);

// if we set a function

else if (typeof receiver === 'function')

receiver(canvas.toDataURL(params, quality), canvas);

}

} catch (ie) {

console.warn("Your ~browser~ has tainted the canvas.\n The canvas is returned");

if (receiver.nodeName === 'IMG') receiver.parentNode.replaceChild(canvas, receiver);

else receiver(null, canvas);

}

}

svgImg.onerror = function(e) {

if (svg._cleanedNS) {

console.error("Couldn't export svg, please check that the svgElement passed is a valid svg document.");

return;

}

// Some non-standard NameSpaces can cause this issues

// This will remove them all

function cleanNS(el) {

var attr = el.attributes;

for (var i = 0; i < attr.length; i++) {

if (attr[i].name.indexOf(':') > -1) el.removeAttribute(attr[i].name)

}

}

cleanNS(svg);

for (var i = 0; i < svg.children.length; i++)

cleanNS(svg.children[i]);

svg._cleanedNS = true;

// retry the export

exportDoc();

}

svgImg.src = svgURL;

}

// ToDo : find a way to get only usefull rules

var parseStyles = function() {

var styleS = [],i;

// transform the live StyleSheetList to an array to avoid endless loop

for (i = 0; i < document.styleSheets.length; i++)

styleS.push(document.styleSheets[i]);

// Do we have a `` element already ?

var defs = clone.querySelector('defs') || document.createElementNS('http://www.w3.org/2000/svg', 'defs');

if (!defs.parentNode)

clone.insertBefore(defs, clone.firstElementChild);

// iterate through all document's stylesheets

for (i = 0; i < styleS.length; i++) {

var style = document.createElement('style');

var rules = styleS[i].cssRules,

l = rules.length;

for (var j = 0; j < l; j++)

style.innerHTML += rules[j].cssText + '\n';

defs.appendChild(style);

}

// small hack to avoid border and margins being applied inside the

var s = clone.style;

s.border = s.padding = s.margin = 0;

s.transform = 'initial';

}

var getSVGStyles = function(node) {

var dest = node.cloneNode(true);

svg.parentNode.insertBefore(dest, svg);

var dest_comp = getComputedStyle(dest);

var svg_comp = getComputedStyle(svg);

var mods = "";

for (var i = 0; i < svg_comp.length; i++) {

if (svg_comp[svg_comp[i]] !== dest_comp[svg_comp[i]])

mods += svg_comp[i] + ':' + svg_comp[svg_comp[i]] + ';';

}

svg.parentNode.removeChild(dest);

return mods;

}

var images = svg.querySelectorAll('image'),

total = images.length,

encoded = 0;

// Loop through all our elements

for (var i = 0; i < images.length; i++) {

// check if the image is external

if (images[i].getAttributeNS(xlinkNS, 'href').indexOf('data:image') < 0)

toDataURL(images[i]);

// else increment our counter

else if (++encoded === total) exportDoc()

}

// if there were no element

if (total === 0) exportDoc();

}

rect {

fill: blue;

transform: translate(35px) rotate(45deg);

}

div {

width: 250px;

display: inline-block

}

#svg {

border: 1px solid green;

}

#canvas { border: 1px solid red;}

Some html content

clean:
dirty :

注意 :

从这个问题开始,我开始编写一个完整的exportInlineSVG函数,你可以找到here.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值