将嵌入式SVG就地转换为PNG

时间:2011-03-25 14:30:04

标签: html svg

我在使用SVG图像(从MathML转换)时从Docbook源生成HTML。这适用于某些可以解释SVG的浏览器,但对其他浏览器则无效。

我真正想要的是添加一个后处理步骤,将SVG“就地”(在HTML中)转换为PNG。

这样的事情:

<body>
    <svg xmlns="http://www.w3.org/2000/svg" version="1.1">
        <circle cx="50" cy="50" r="30" />
    </svg>
</body>

会无缝转换为:

<body>
    <img src="img0001.png" />
</body>

我会得到一个转换后的PNG。

有什么东西可以做到吗?

6 个答案:

答案 0 :(得分:40)

演示:http://phrogz.net/SVG/svg_to_png.xhtml

  1. 创建img并将其src设置为SVG。
  2. 创建HTML5画布并使用drawImage()将该图像绘制到画布上。
  3. 在画布上使用toDataURL()获取base64编码的PNG。
  4. 创建一个img并将其src设置为该数据URL。
  5. var mySVG    = document.querySelector('…'),      // Inline SVG element
        tgtImage = document.querySelector('…'),      // Where to draw the result
        can      = document.createElement('canvas'), // Not shown on page
        ctx      = can.getContext('2d'),
        loader   = new Image;                        // Not shown on page
    
    loader.width  = can.width  = tgtImage.width;
    loader.height = can.height = tgtImage.height;
    loader.onload = function(){
      ctx.drawImage( loader, 0, 0, loader.width, loader.height );
      tgtImage.src = can.toDataURL();
    };
    var svgAsXML = (new XMLSerializer).serializeToString( mySVG );
    loader.src = 'data:image/svg+xml,' + encodeURIComponent( svgAsXML );
    

    但是,这个答案(以及所有客户端唯一的解决方案)都要求浏览器支持SVG,这可能会使您无法满足您的特定需求。

    编辑:此答案假定SVG作为单独的URL提供。由于所描述的问题in this question我无法使用上述内容来处理执行该工作的同一文档中嵌入的SVG文档。

    编辑2 :Chrome和Firefox的改进克服了其他问题中描述的问题。对于Firefox,<svg>元素必须具有width="…" height="…"属性仍然存在限制,以允许将其绘制到画布。每当你向它绘制任何SVG时(无论来源如何),Safari目前都会污染整个画布,但that should change soon

答案 1 :(得分:4)

我在上周末遇到了这个问题,最后编写了一个简单的库来做或多或少的Phrogz描述的内容。它还硬编码目标SVG的样式,以避免渲染问题。希望下一个寻找方法的人可以简单地使用我的代码并继续进行更有趣的挑战!

P.S。我只在Chrome中测试了这个。

// Takes an SVG element as target
function svg_to_png_data(target) {
  var ctx, mycanvas, svg_data, img, child;

  // Flatten CSS styles into the SVG
  for (i = 0; i < target.childNodes.length; i++) {
    child = target.childNodes[i];
    var cssStyle = window.getComputedStyle(child);
    if(cssStyle){
       child.style.cssText = cssStyle.cssText;
    }
  }

  // Construct an SVG image
  svg_data = '<svg xmlns="http://www.w3.org/2000/svg" width="' + target.offsetWidth +
             '" height="' + target.offsetHeight + '">' + target.innerHTML + '</svg>';
  img = new Image();
  img.src = "data:image/svg+xml," + encodeURIComponent(svg_data);

  // Draw the SVG image to a canvas
  mycanvas = document.createElement('canvas');
  mycanvas.width = target.offsetWidth;
  mycanvas.height = target.offsetHeight;
  ctx = mycanvas.getContext("2d");
  ctx.drawImage(img, 0, 0);

  // Return the canvas's data
  return mycanvas.toDataURL("image/png");
}

// Takes an SVG element as target
function svg_to_png_replace(target) {
  var data, img;
  data = svg_to_png_data(target);
  img = new Image();
  img.src = data;
  target.parentNode.replaceChild(img, target);
}

答案 2 :(得分:3)

FOP和Batik

http://xmlgraphics.apache.org/fop/

http://xmlgraphics.apache.org/batik/

来自Apache的FOP整合了来自Apache的Batik。 Batik有一个SVG渲染工具,可以生成你的PNG。 FOP也是一种文档生成工具。

答案 3 :(得分:3)

我在上面使用了@Phrogz代码并制作了一个工作片段。但不确定mySVG.clientWidth是否适用于FF。它也可以在这里找到 - https://jsfiddle.net/LLjLpo05/

var mySVG = document.querySelector('#svblock'),        // Inline SVG element
    tgtImage = document.querySelector('#diagram_png'), // Where to draw the result
    can = document.createElement('canvas'), // Not shown on page
    ctx = can.getContext('2d'),
    loader = new Image; // Not shown on page

//loader.width  = can.width  = tgtImage.width = mySVG.getBBox().width;
//loader.height = can.height = tgtImage.height = mySVG.getBBox().height;

loader.width = can.width = tgtImage.width = mySVG.clientWidth;
loader.height = can.height = tgtImage.height = mySVG.clientHeight;

loader.onload = function() {
  ctx.drawImage(loader, 0, 0, loader.width, loader.height);
  tgtImage.src = can.toDataURL();
};
var svgAsXML = (new XMLSerializer).serializeToString(mySVG);
loader.src = 'data:image/svg+xml,' + encodeURIComponent(svgAsXML);
<div id="diagram_image">
  <svg id="svblock" xmlns="http://www.w3.org/2000/svg" xmlns:inkspace="http://www.inkscape.org/namespaces/inkscape" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 640 120">
    <defs id="defs_block">
      <filter height="1.504" id="filter_blur" inkspace:collect="always" width="1.1575" x="-0.07875" y="-0.252">
        <feGaussianBlur id="feGaussianBlur3780" inkspace:collect="always" stdDeviation="4.2" />
      </filter>
    </defs>
    <title>blockdiag</title>
    <desc/>
    <rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="67" y="46" />
    <rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="259" y="46" />
    <rect fill="rgb(0,0,0)" height="40" stroke="rgb(0,0,0)" style="filter:url(#filter_blur);opacity:0.7;fill-opacity:1" width="128" x="451" y="46" />
    <rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="64" y="40" />
    <text fill="rgb(0,0,0)" font-family="sans-serif" font-size="11" font-style="normal" font-weight="normal" text-anchor="middle" textLength="55" x="128" y="66">discovery</text>
    <rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="256" y="40" />
    <text fill="rgb(0,0,0)" font-family="sans-serif" font-size="11" font-style="normal" font-weight="normal" text-anchor="middle" textLength="55" x="320" y="66">execution</text>
    <rect fill="rgb(255,255,255)" height="40" stroke="rgb(0,0,0)" width="128" x="448" y="40" />
    <text fill="rgb(0,0,0)" font-family="sans-serif" font-size="11" font-style="normal" font-weight="normal" text-anchor="middle" textLength="55" x="512" y="66">reporting</text>
    <path d="M 192 60 L 248 60" fill="none" stroke="rgb(0,0,0)" />
    <polygon fill="rgb(0,0,0)" points="255,60 248,56 248,64 255,60" stroke="rgb(0,0,0)" />
    <path d="M 384 60 L 440 60" fill="none" stroke="rgb(0,0,0)" />
    <polygon fill="rgb(0,0,0)" points="447,60 440,56 440,64 447,60" stroke="rgb(0,0,0)" />
  </svg>
</div>

<img id="diagram_png" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4
//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" />

更新:重构一点 - https://jsfiddle.net/e4r8sk18/1/

UPDATE2 :重构为转换器类 - https://jsfiddle.net/07a93Lt6/5/

答案 4 :(得分:1)

如果你想纯粹在客户端进行,你需要两个步骤:

  1. 将SVG转换为Canvas(http://code.google.com/p/canvas-svg/或其他一些工具)
  2. 将Canvas转换为PNG(http://www.nihilogic.dk/labs/canvas2image/或其他一些工具)
  3. 这显然只适用于支持HTML5的浏览器。

答案 5 :(得分:1)

这个相当陈旧,但我找到了一个更简单的代码段,可以在现代浏览器中正确完成工作:https://gist.github.com/Caged/4649511