使用<canvas>将非常大的SVG转换为PNG

13

我正在尝试将一个非常大的SVG(数据URL大约为750000-1000000个字符)通过将其数据URL传递到图像和画布中来转换为PNG,但是图像只加载了SVG的1/4。

创建方法如下:

var svg_xml = (new XMLSerializer()).serializeToString(svg),
    url = 'data:image/svg+xml;base64,' + btoa(svg_xml);

var img = new Image();
img.width = 730;
img.height = 300;
img.onload = function(){
    var canvas = document.create('canvas');
    canvas.width = 730;
    canvas.height = 300;

    var ctx = canvas.getContext('2d');
    ctx.drawImage(img, 0, 0, 730, 300);

    callbackFn(canvas.toDataURL('image/png');
}
img.src = url

编辑

我尝试使用canvg绘制SVG,但生成的DataURL导致图像为空白:

var svg_xml = (new XMLSerializer()).serializeToString(svg);
var canvas = document.createElement('canvas');
canvas.width = 730;
canvas.height = 300;

var ctx = canvas.getContext('2d');
ctx.drawSvg(svg_xml, 0, 0, 730, 300);
callbackFn(canvas.toDataURL('image/png');

我使用的方法有什么问题吗?

进一步编辑

我现在相当确信这是画布未能绘制整个图像,因为我尝试实施Blob解决方案以达到相同的效果:

var svg_xml = (new XMLSerializer()).serializeToString(svg),
    blob = new Blob([svg_xml], {type:'image/svg+xml;charset=utf-8'}),
    url = window.URL.createObjectURL(blob);

var img = new Image();
img.width = 730;
img.height = 300;
img.onload = function(){
    var canvas = document.create('canvas');
    canvas.width = 730;
    canvas.height = 300;

    var ctx = canvas.getContext('2d');
    ctx.drawImage(img, 0, 0, 730, 300);

    window.URL.revokeObjectURL(url);
    callbackFn(canvas.toDataURL('image/png');
}
img.src = url   

图片再次正常加载,访问URL(在被撤销之前)也能正常显示图片。

画布数据URL的长度不一致,因此我认为这不是达到最大值的原因,有没有办法检测画布大小?该应用程序仅支持Chrome和FireFox。


2
@somethinghere new Imagenew Image() 都是有效的,如果您没有传递任何参数,可以省略括号。 - Jim Jones
1
@spencerkillen 不错,我从来没有想过省略括号。虽然两种方式都是有效的,但我的直觉更喜欢加上括号,因为它们看起来像是在执行某些操作,而不仅仅是声明。但好知道,谢谢! - somethinghere
1
@matts1189 在SVG XML中的宽度/高度设置是什么?即在此节点中:<svg xmlns="http://www.w3.org/2000/svg" width="200" height="200"> - Don Rhummy
此外,对于您的CSS,请尝试将完整的CSS样式表附加到您的SVG文档,而不是将每个规则应用于每个节点内联。 - Kaiido
请检查我的fiddle(http://jsfiddle.net/vyLtxgh4/1/),它可以工作。为了更好地帮助您,我需要您的SVG文件。 有关详细信息,请参阅此教程(http://it-supernova.com/convert-svg-to-png-using-canvas/)。 - Khalid Hussain
显示剩余14条评论
1个回答

3

这里是可运行的示例。

HTML:

    <div>
        <svg xmlns="http://www.w3.org/2000/svg"
              width="526" height="233">
          <rect x="13" y="14" width="500" height="200" rx="50" ry="100"
              fill="none" stroke="blue" stroke-width="10" />
        </svg>
        <a id='imgId'>Save</a>
    </div>
    <canvas></canvas>

JavaScript:

var svg = document.getElementsByTagName('svg')[0];
var svg_xml = (new XMLSerializer()).serializeToString(svg),
    blob = new Blob([svg_xml], {type:'image/svg+xml;charset=utf-8'}),
    url = window.URL.createObjectURL(blob);

var img = new Image();
img.width = 730;
img.height = 300;
img.onload = function(){
    var canvas = document.createElement('canvas');
    canvas.width = 730;
    canvas.height = 300;

    var ctx = canvas.getContext('2d');
    ctx.drawImage(img, 0, 0, 730, 300);

    window.URL.revokeObjectURL(url);
    var canvasdata = canvas.toDataURL('image/png');
    var a = document.getElementById('imgId');
    a.download = "export_" + Date.now() + ".png";
    a.href=canvasdata;   
}
img.src = url

您的问题:

为什么图像只加载了SVG的1/4?

回答:

只需遵循以下规则:

  1. <rect/>x + <rect/>width<svg/>width
  2. <rect/>y + <rect/>height<svg/>height

例如:

<svg xmlns="http://www.w3.org/2000/svg" width="500" height="200">
     <rect x="10" y="10" width="550" height="250" rx="50" ry="100"
                  fill="none" stroke="blue" stroke-width="10" />
</svg>

在这里,<rect/>x = 10<rect/>的宽度为550<svg>的宽度为500

所以,10+550>500

在这种情况下,图像将被部分渲染。

希望这可以解决您的问题。


但是在这种情况下,渲染的原始SVG也会被裁剪吗? - Kaiido
检查我的示例代码,并更改 xwidth 的值...... 这将帮助你可视化结果。 - Khalid Hussain
如果那个评论是针对我的,请注意我不是原帖作者。我也没有访问犯罪SVG文件的权限,而且我在两个月前就已经要求了。现在针对你的回答发表评论,我把它变成了一个问题,但实际上它是一个修辞问题。我知道如果你的假设是正确的,那么这张图片就不会“正常加载并且在URL(在撤销之前)显示图片也很好。” 它将像在画布上绘制时一样被裁剪。使用您的小例子 - Kaiido

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接