当前位置: 首页 > 面试题库 >

使用已应用的图像作为SVG元素的背景将SVG转换为PNG

杨豪
2023-03-14
问题内容

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


问题答案:

是的,有:将svg附加到文档中,并将所有包含的图像编码为dataURIs。

我正在编写一个脚本来执行此操作,还编写了一些其他内容,例如包括外部样式表以及toDataURL失败的其他修复方法(例如,通过xlink:hrefattribute或引用的外部元素<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()函数可以编写为:

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附加到文档中(通过xhr或到<iframe><object>元素中),并且必须确保所有资源都 符合CORS要求(或来自同一域)才能获得这些资源呈现。

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

    var href = image.getAttributeNS(xlinkNS, 'href');

    // really weird bug that appeared since this answer was first posted

    // we need to force a no-cached request for the crossOrigin be applied

    img.src = href + (href.indexOf('?') > -1 ? + '&1': '?1');

  };



  // 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;

};

window.onload = 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,并将其设置为背景图像,但我得到了错误: TypeError:无法将符号值转换为字符串 SVG组件代码: 容器组件代码: 我正在使用开箱即用的创建-反应-应用程序。 我也尝试过不使用样式组件和使用内联样式,但没有成功。 在这种情况下,是否可以使用SVG作为背景图像,而SVG是一个组件?

  • 问题内容: 是否可以为SVG 元素设置a ? 例如,如果设置了element ,则CSS样式有效,但都不起作用。 问题答案: 您可以通过将背景变成图案来实现: 根据您的图像调整宽度和高度,然后从这样的路径中引用它:

  • 我想为整个SVG文档设置一个默认背景色,例如红色。 上面的解决方案是可行的,但不幸的是style属性的background属性不是标准属性:http://www.w3.org/tr/SVG/styling.html#svgstylingproperties,因此在使用SVG Cleaner进行清理的过程中会将其删除。 这个底色有没有另外一种申报方式?

  • 问题内容: 如何以编程方式将SVG文件转换为PDF?(在生成PDF之前,我需要在某些方面进行更改,因此仅使用工具进行预转换就不够了。) 理想情况下,使用Java但Perl或PHP也可以。 显然,我基本上是在考虑使用Java的Apache FOP和Batik。但是,无论我搜索多长时间,都无法找到有关该操作方法的简单介绍。诸如SVGConverter之类的内容具有“为能够转换部分或全部GraphicC

  • 问题内容: 是否可以通过 对SVG元素 进行 3D转换 来实现透视? 我说的是与《星球大战》首部作品的3d透视图相似的事物。这是一个使用 CSS3 3d转换达到预期效果的jsfiddle: __ 问题答案: 2018年11月更新: 在最新的chrome和Firefox中可以测试该问题的片段。尽管对svg元素的3d转换的支持不是很广泛,但是浏览器正在越来越多地实现它。 来源答案: SVG元素不支持3

  • 问题内容: 我是Java新手,目前正在创建带有图形的游戏。我有从扩展的此类。在本课程中,我有很多需要图像作为背景的。据我所知,为了能够在JPanel中绘制图像,我需要从JPanel扩展一个单独的类,并且该类的方法可以完成工作。但是我不想为每个类创建单独的类,我的类太多了。而且我只关心背景。我怎样才能做到这一点?带有匿名内部类吗?怎么样? 为了更好地理解,我提供了一些代码: 问题答案: 为什么不制作