将SVG转换为PNG,并将应用的图像作为svg元素的背景 [英] Convert SVG to PNG with applied images as background to svg elements

查看:605
本文介绍了将SVG转换为PNG,并将应用的图像作为svg元素的背景的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个外部SVG文件,其中包含一些嵌入式图像标签模式。每当我使用 toDataURL()将此SVG转换为PNG时,生成的PNG图像不包含我作为模式应用于某些SVG路径的图像。有没有办法解决这个问题?

I have an external SVG file which contains some embedded image tags in pattern. Whenever I convert this SVG into PNG using toDataURL(), the generated PNG images does not contain the image I have applied as pattern to some SVG paths. Is there any way to solve this problem?

推荐答案

是的有:附加svg到您的文档, to dataURIs。

Yes there are : append the svg into your document and encode all the included images to dataURIs.

我在写一个脚本,这样做,还有一些其他的东西,如包括外部样式表和一些其他修复toDataURL将失败(例如外部元素引用 xlink:href 属性或< funciri> )。

I am writing a script that does this and also some other stuff like including external style-sheets and some other fix of where toDataURL will fail (e.g external elements referenced through xlink:href attribute or <funciri>).

解析图片内容:

function parseImages(){
    var xlinkNS = "http://www.w3.org/1999/xlink";
    var total, encoded;
    // convert an external bitmap 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');
            canvas.width = this.width;
            canvas.height = this.height;
            // draw the loaded image
            canvas.getContext('2d').drawImage(this, 0, 0);
            // set our <image>'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');
    };

    // get an external svg doc to data String
    var parseFromUrl = function(url, element){
        var xhr = new XMLHttpRequest();
        xhr.onload = function(){
            if(this.status === 200){
                var response = this.responseText || this.response;
                var dataUrl = 'data:image/svg+xml; charset=utf8, ' + encodeURIComponent(response);
                element.setAttributeNS(xlinkNS, 'href', dataUrl);
                if(++encoded === total) exportDoc();
                }
            // request failed with xhr, try as an <img>
            else{
                toDataURL(element);
                }
            };
        xhr.onerror = function(){toDataURL(element);};
        xhr.open('GET', url);
        xhr.send();
        };

    var images = svg.querySelectorAll('image');
    total = images.length;
    encoded = 0;

    // loop through all our <images> elements
    for (var i = 0; i < images.length; i++) {
        var href = images[i].getAttributeNS(xlinkNS, 'href');
        // check if the image is external
        if (href.indexOf('data:image') < 0){
            // if it points to another svg element
            if(href.indexOf('.svg') > 0){
                parseFromUrl(href, images[i]);
                }
            else // a pixel image
                toDataURL(images[i]);
            }
        // else increment our counter
        else if (++encoded === total) exportDoc();
    }
    // if there were no <image> element
    if (total === 0) exportDoc();
}

这里svgDoc被调用 svg

exportDoc()函数可以写成:

Here the svgDoc is called svg,
and the exportDoc() function could just be written as :

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.getBoundingClientRect();

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

    // serialize our node
    var svgData = (new XMLSerializer()).serializeToString(svg);
    // remember to encode special chars
    var svgURL = 'data:image/svg+xml; charset=utf8, ' + encodeURIComponent(svgData);

    var svgImg = new Image();

    svgImg.onload = function () {
        var canvas =  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(svgImg, 0, 0, canvas.width, canvas.height);
        doSomethingWith(canvas)
    };

    svgImg.src = svgURL;
};

但是,你必须先将svg附加到文档中< iframe> < object> 元素,并且您必须确保您的所有资源

But once again, you will have to append your svg into the document first (either through xhr or into an <iframe> or an <object> element, and you will have to be sure all your resources are CORS compliant (or from same domain) in order to get these rendered.

var svg = document.querySelector('svg');
var doSomethingWith = function(canvas){document.body.appendChild(canvas)};

   function parseImages(){
    	var xlinkNS = "http://www.w3.org/1999/xlink";
		var total, encoded;
		// convert an external bitmap 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');
				canvas.width = this.width;
				canvas.height = this.height;
				// draw the loaded image
				canvas.getContext('2d').drawImage(this, 0, 0);
				// set our <image>'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');
		};
		
		// get an external svg doc to data String
		var parseFromUrl = function(url, element){
			var xhr = new XMLHttpRequest();
			xhr.onload = function(){
				if(this.status === 200){
					var response = this.responseText || this.response;
					var dataUrl = 'data:image/svg+xml; charset=utf8, ' + encodeURIComponent(response);
					element.setAttributeNS(xlinkNS, 'href', dataUrl);
					if(++encoded === total) exportDoc();
					}
				// request failed with xhr, try as an <img>
				else{
					toDataURL(element);
					}
				};
			xhr.onerror = function(){toDataURL(element);};
			xhr.open('GET', url);
			xhr.send();
			};

		var images = svg.querySelectorAll('image');
		total = images.length;
		encoded = 0;

		// loop through all our <images> elements
		for (var i = 0; i < images.length; i++) {
			var href = images[i].getAttributeNS(xlinkNS, 'href');
			// check if the image is external
			if (href.indexOf('data:image') < 0){
				// if it points to another svg element
				if(href.indexOf('.svg') > 0){
					parseFromUrl(href, images[i]);
					}
				else // a pixel image
					toDataURL(images[i]);
				}
			// else increment our counter
			else if (++encoded === total) exportDoc();
		}
		// if there were no <image> element
		if (total === 0) exportDoc();
	}

	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.getBoundingClientRect();

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

		// serialize our node
		var svgData = (new XMLSerializer()).serializeToString(svg);
		// remember to encode special chars
		var svgURL = 'data:image/svg+xml; charset=utf8, ' + encodeURIComponent(svgData);

		var svgImg = new Image();

		svgImg.onload = function () {
            var canvas =  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(svgImg, 0, 0, canvas.width, canvas.height);
            doSomethingWith(canvas)
		};

		svgImg.src = svgURL;
	};
parseImages();

canvas{border: 1px solid green !important;}

    <svg width="200" height="200" xmlns="http://www.w3.org/2000/svg" version="1.1">
  <defs>

    <pattern id="Pattern" x="0" y="0" width=".25" height=".25">
      <image xlink:href="https://dl.dropboxusercontent.com/s/1alt1303g9zpemd/UFBxY.png" width="100" height="100"/>
    </pattern>

  </defs>

  <rect fill="url(#Pattern)" x="0" y="0" width="200" height="200"/>
</svg>

这篇关于将SVG转换为PNG,并将应用的图像作为svg元素的背景的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆