简体   繁体   English

将SVG转换为PNG时裁剪的图像

[英]Image cropped while converting SVG to PNG

While saving an SVG to PNG, the image saved contains only the SVG rendered in the viewbox/window. 将SVG保存为PNG时,保存的图像仅包含在视图框/窗口中呈现的SVG。 How can one save a large PNG, containing the whole SVG? 如何保存包含整个SVG的大型PNG?

// SVG element and XML string.
var svg = document.querySelector('svg');
var svgData = new XMLSerializer().serializeToString(svg);

// Canvas to hold the image.
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');

// Canvas size = SVG size.
var svgSize = svg.getBoundingClientRect();
canvas.width = svgSize.width;
canvas.height = svgSize.height;

// Image element appended with data.
var img = document.createElement('img');
img.setAttribute('src', 'data:image/svg+xml;base64,' + btoa(svgData));

img.onload = function() {
    // Draw image on canvas and convert to URL.
    context.drawImage(img,0,0);
    console.log(canvas.toDataURL('image/png'));
};

Instead of: 代替:

var svgSize = svg.getBoundingClientRect();

Use: 采用:

var svgSize = svg.viewBox.baseVal;

This will get you the true dimensions of the viewBox. 这将为您提供viewBox的真实尺寸。

REFERENCE 参考

https://stackoverflow.com/a/7682976/2813224 https://stackoverflow.com/a/7682976/2813224

SNIPPET SNIPPET

 // SVG element and XML string. var svg = document.querySelector('svg'); var svgData = new XMLSerializer().serializeToString(svg); // Canvas to hold the image. var canvas = document.createElement('canvas'); var context = canvas.getContext('2d'); // Canvas size = SVG size. var svgSize = svg.viewBox.baseVal; canvas.width = svgSize.width; canvas.height = svgSize.height; // Image element appended with data. var img = document.createElement('img'); img.setAttribute('src', 'data:image/svg+xml;base64,' + btoa(svgData)); img.onload = function() { // Draw image on canvas and convert to URL. context.drawImage(img,0,0); console.log(canvas.toDataURL('image/png')); }; 
 <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" width="64px" height="64px" viewBox="-0.5 0.5 64 64" enable-background="new -0.5 0.5 64 64" xml:space="preserve"> <g> <circle fill="#FFFFFF" cx="31.325" cy="32.873" r="30.096"/> <path id="text2809_1_" d="M31.5,14.08c-10.565,0-13.222,9.969-13.222,18.42c0,8.452,2.656,18.42,13.222,18.42 c10.564,0,13.221-9.968,13.221-18.42C44.721,24.049,42.064,14.08,31.5,14.08z M31.5,21.026c0.429,0,0.82,0.066,1.188,0.157 c0.761,0.656,1.133,1.561,0.403,2.823l-7.036,12.93c-0.216-1.636-0.247-3.24-0.247-4.437C25.808,28.777,26.066,21.026,31.5,21.026z M36.766,26.987c0.373,1.984,0.426,4.056,0.426,5.513c0,3.723-0.258,11.475-5.69,11.475c-0.428,0-0.822-0.045-1.188-0.136 c-0.07-0.021-0.134-0.043-0.202-0.067c-0.112-0.032-0.23-0.068-0.336-0.11c-1.21-0.515-1.972-1.446-0.874-3.093L36.766,26.987z"/> <path id="path2815_1_" d="M31.433,0.5c-8.877,0-16.359,3.09-22.454,9.3c-3.087,3.087-5.443,6.607-7.082,10.532 C0.297,24.219-0.5,28.271-0.5,32.5c0,4.268,0.797,8.32,2.397,12.168c1.6,3.85,3.921,7.312,6.969,10.396 c3.085,3.049,6.549,5.399,10.398,7.037c3.886,1.602,7.939,2.398,12.169,2.398c4.229,0,8.34-0.826,12.303-2.465 c3.962-1.639,7.496-3.994,10.621-7.081c3.011-2.933,5.289-6.297,6.812-10.106C62.73,41,63.5,36.883,63.5,32.5 c0-4.343-0.77-8.454-2.33-12.303c-1.562-3.885-3.848-7.32-6.857-10.33C48.025,3.619,40.385,0.5,31.433,0.5z M31.567,6.259 c7.238,0,13.412,2.566,18.554,7.709c2.477,2.477,4.375,5.31,5.67,8.471c1.296,3.162,1.949,6.518,1.949,10.061 c0,7.354-2.516,13.454-7.506,18.33c-2.592,2.516-5.502,4.447-8.74,5.781c-3.2,1.334-6.498,1.994-9.927,1.994 c-3.468,0-6.788-0.653-9.949-1.948c-3.163-1.334-6.001-3.238-8.516-5.716c-2.515-2.514-4.455-5.353-5.826-8.516 c-1.333-3.199-2.017-6.498-2.017-9.927c0-3.467,0.684-6.787,2.017-9.949c1.371-3.2,3.312-6.074,5.826-8.628 C18.092,8.818,24.252,6.259,31.567,6.259z"/> </g> </svg> 

This is because you are setting your canvas size to your rendered svg ones. 这是因为您将画布大小设置为渲染的svg。 In your CSS, you probably do resize your svg, which results in a difference between it's computed size and it's natural one. 在CSS中,您可能确实需要调整svg的大小,从而导致其计算出的大小与自然大小之间存在差异。
By default, drawImage(img, dx, dy, dWidth, dHeight) will use the source's width and height as destinationWidth and destinationHeight if these parameters are not passed. 默认情况下,如果未传递这些参数, drawImage(img, dx, dy, dWidth, dHeight)将使用源的宽度和高度作为destinationWidth和destinationHeight。

You can check this example showing the same behavior with a raster image : 您可以检查此示例以光栅图像显示相同的行为:

 window.onload = function(){ var canvas = document.createElement('canvas'); var context = canvas.getContext('2d'); var svgSize = inDoc.getBoundingClientRect(); canvas.width = svgSize.width; canvas.height = svgSize.height; var img = document.createElement('img'); img.setAttribute('src', inDoc.src); img.onload = function() { context.drawImage(img,0,0); document.body.appendChild(canvas); }; } 
 img{ width: 64px; height: 64px} 
 <img id="inDoc" src="http://lorempixel.com/128/128"/> 

And here is a little graphic showing what's happening. 这是一个小图形,显示正在发生的事情。

SVGElement大小与img.svg大小的说明

So the solution is just to set your canvas' width and height properties to your img 's ones, just like you would do with any other source : 因此,解决方案就是将画布的widthheight属性设置为img的属性,就像对其他任何源一样:

img.onload = function(){
    canvas.width = this.width;
    canvas.height = this.height;
    ctx.drawImage(this, 0,0);
    }

and if you want to include some scaling factor : 以及是否要包含一些缩放因子:

img.onload = function(){
    canvas.width = this.width * scale;
    canvas.height = this.height * scale;
    ctx.drawImage(this, 0,0, canvas.width, canvas.height);
    }

Now, one not related to your actual code but still huge difference between raster images and svg images is that svg width and height can be set to relative units (like % ). 现在, 与您的实际代码无关,光栅图像和svg图像之间仍然存在巨大差异,那就是svg的widthheight可以设置为相对单位(例如% )。
Browsers have no direct clue about what it's relative to. 浏览器没有直接的线索。 ( Chrome does a guess, I don't know how, others won't render your image ). Chrome会猜测,我不知道如何,其他人不会渲染您的图像 )。

So you need to check for this before exporting to a dataURI : 因此,您需要在导出到dataURI之前进行检查:

var absoluteUnits = [1,5,6,7,8,9,10];
if (absoluteUnits.indexOf(svg.width.baseVal.unitType)<0) {
    svg.setAttribute('width', aboluteWidth);
    }
if (absoluteUnits.indexOf(svg.height.baseVal.unitType)<0) {
    svg.setAttribute('height', aboluteHeight);
    }

Here absoluteWidth and absoluteHeight can be the results of svg.getBoundingClientRect() . 在这里, absoluteWidthabsoluteHeight可以是svg.getBoundingClientRect()的结果。

Also note that IE9 won't be able to show the img.width and img.height values, so you've got to make a special case for it... ... but since you should have already checked for the absoluteSize, this should not be a problem : 另请注意,IE9无法显示img.widthimg.height值,因此您必须为其设置一个特殊情况... ...但是,由于您应该已经检查了absoluteSize,这应该不是问题:

 var svg = document.querySelector('svg'); // we'll use a copy to not modify the svg in the document var copy = svg.cloneNode(true); var absoluteWidth, absoluteHeight, BBox; var absoluteUnits = [1,5,6,7,8,9,10]; if (absoluteUnits.indexOf(svg.width.baseVal.unitType)<0) { BBox = svg.getBoundingClientRect(); absoluteWidth = BBox.width copy.setAttribute('width', absoluteWidth); } else{ absoluteWidth = svg.getAttribute('width'); } if (absoluteUnits.indexOf(svg.height.baseVal.unitType)<0) { if(!BBox){ BBox = svg.getBoundingClientRect(); } absoluteHeight = BBox.height; copy.setAttribute('height', absoluteHeight) } else{ absoluteHeight = svg.getAttribute('height'); } var svgData = new XMLSerializer().serializeToString(copy); var canvas = document.createElement('canvas'); var context = canvas.getContext('2d'); var img = document.createElement('img'); img.setAttribute('src', 'data:image/svg+xml;base64,' + btoa(svgData)); img.onload = function() { // here you set your canvas width and height canvas.width = this.width || absoluteWidth; canvas.height = this.height || absoluteHeight; context.drawImage(img,0,0); document.body.appendChild(canvas); }; 
 svg{width: 64px; height:64px; border: 1px solid green;} canvas{border: 1px solid blue;} 
 <svg width="128px" height="128px" viewBox="0 0 128 128"> <rect x="20" y="20" width="84" height="84"/> </svg> 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM