将SVG转换为带有样式的PNG

时间:2018-04-05 07:09:22

标签: javascript svg

我有来自数据库的数据,该数据库使用NVD3绘制图形。然后我想用dompdf来编写PDF报告页面。似乎"基本的SVG支持" dompdf对我的条形图不起作用。所以我想我会将SVG转换为PNG fisrt。

这个答案适用于将SVG显示为PNG而不带样式:https://stackoverflow.com/a/19269812

代码:

var el = $($('svg')[0]);
var svgMarkup = '<svg xmlns="http://www.w3.org/2000/svg"'
+ ' class="'  + el.attr('class') +'"'
+ ' width="'  + el.attr('width') +'"'
+ ' height="' + el.attr('height') +'"'
+ '>'
+ $('svg')[0].innerHTML.toString()+'</svg>';
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var DOMURL = this.URL || this.webkitURL || this;
var img = new Image();
var svg = new Blob([svgMarkup], {type: "image/svg+xml;charset=utf-8"});
var url = DOMURL.createObjectURL(svg);
img.onload = function() {
    ctx.drawImage(img, 0, 0);
    alert('ok');
    DOMURL.revokeObjectURL(url);
};
img.src = url;

在解决样式问题的同一问题上还有另一个答案,但我无法在同一屏幕上以正确的尺寸打开图像,即无需打开新标签(即使这样,图像也会被裁剪) )。 https://stackoverflow.com/a/38085847

代码:

var style = "\n";
var requiredSheets = ['phylogram_d3.css', 'open_sans.css']; // list of required CSS
for (var i=0; i<document.styleSheets.length; i++) {
    var sheet = document.styleSheets[i];
    if (sheet.href) {
        var sheetName = sheet.href.split('/').pop();
        if (requiredSheets.indexOf(sheetName) != -1) {
            var rules = sheet.rules;
            if (rules) {
                for (var j=0; j<rules.length; j++) {
                    style += (rules[j].cssText + '\n');
                }
            }
        }
    }
}

var svg = d3.select("svg"),
    img = new Image(),
    serializer = new XMLSerializer(),

// prepend style to svg
svg.insert('defs',":first-child")
d3.select("svg defs")
    .append('style')
    .attr('type','text/css')
    .html(style);


// generate IMG in new tab
var svgStr = serializer.serializeToString(svg.node());
img.src = 'data:image/svg+xml;base64,'+window.btoa(unescape(encodeURIComponent(svgStr)));
window.open().document.write('<img src="' + img.src + '"/>');

因此,使用Javascript,如何将SVG转换为PNG?我尝试了两者的组合,但我认为我的问题是第二个代码段中使用的d3选择器与第一个代码中使用的SVG标记方法有太大不同:

   var style = "\n";
    var requiredSheets = ['default-blue-white.css']; // list of required CSS
    for (var i=0; i<document.styleSheets.length; i++) {
        var sheet = document.styleSheets[i];
        if (sheet.href) {
            var sheetName = sheet.href.split('/').pop();
            if (requiredSheets.indexOf(sheetName) != -1) {
                var rules = sheet.rules;
                if (rules) {
                    for (var j=0; j<rules.length; j++) {
                        style += (rules[j].cssText + '\n');
                    }
                }
            }
        }
    }


    var svgX = d3.select("svg");

    // prepend style to svg
    svgX.insert('defs',":first-child");
    d3.select("svg defs")
        .append('style')
        .attr('type','text/css')
        .html(style);



    var el = $($('svg')[0]);
    var svgMarkup = '<svg xmlns="http://www.w3.org/2000/svg"'
        + ' class="'  + el.attr('class') +'"'
        + ' width="'  + el.attr('width') +'"'
        + ' height="' + el.attr('height') +'"'
        + '>'
        + $('svg')[0].innerHTML.toString()+'</svg>';
    var canvas = document.getElementById("canvas");
    var ctx = canvas.getContext("2d");
    var DOMURL = this.URL || this.webkitURL || this;
    var img = new Image();
    var svg = new Blob([svgMarkup], {type: "image/svg+xml;charset=utf-8"});
    var url = DOMURL.createObjectURL(svg);
    img.onload = function() {
        ctx.drawImage(img, 0, 0);
        alert('ok');
        DOMURL.revokeObjectURL(url);
    };
    img.src = url;

1 个答案:

答案 0 :(得分:0)

通过拼凑其属性来生成<svg>实在太天真了,正如您从裁剪和假大小中看到的那样。

通过数据URL进行访问是一种可行的方法,但不要在新窗口中打开它(它将是SVG图像,而不是PNG),而是将其写入画布。

不要使用d3.js selection.html()将样式表插入DOM,而是使用普通的Javascript document.createCDATASection()element.appendChild()来避免使用无效的XML。

以下内容将<svg>替换为<canvas>,其大小与浏览器中呈现的大小相同。

var styleRules = [];
var requiredSheets = [...]; // list of required CSS files
for (var sheet of document.styleSheet)) {
    if (sheet.href) {
        var sheetName = sheet.href.split('/').pop();
        if (requiredSheets.indexOf(sheetName) != -1) {
            var rules = Array.from(sheet.cssRules).map(rule => rule.cssText);
            styleRules = styleRules.concat(rules);
        }
    }
}
var styleText = styleRules.join(' ');
var styleNode = document.createCDATASection(styleRules);

var svg = d3.select("svg"),
    img = new Image(),
    serializer = new XMLSerializer(),

// prepend style to svg
svg.insert('defs',":first-child")
var styleEl = d3.select("svg defs")
    .append('style')
    .attr('type','text/css');

styleEl.node().appendChild(styleNode);

var svgStr = serializer.serializeToString(svg.node());
img.src = 'data:image/svg+xml;base64,'+window.btoa(unescape(encodeURIComponent(svgStr)));

var bbox = svg.getBoundingClientRect();

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

canvas.width = bbox.width;
canvas.height = bbox.height;
canvas.getContext("2d").drawImage(img,0,0,bbox.width,bbox.width);

canvas.parentNode.replaceChild(canvas, svg);