将svg转换为png时如何包含CSS样式
我创建了一个简单的 SVG 元素,在单击按钮时会下载到 png,我的解决方案类似于 这里
i've created a simple SVG elment that get dowbloaded to png when clicking on a button, my solution is similiar to here
基本思路是:
1.svg 到画布
2.canvas转dataUrl
3.触发从dataUrl下载
The basic idea is:
1.svg to canvas
2.canvas to dataUrl
3.trigger download from dataUrl
问题是在下载 png 文件时,它不包含应用于 svg 的 css 样式我的解决结果
注意 - 我知道通过在元素上移动样式内联"(如 here 或通过挖掘 DOM 树并使用 getComputedStyle(element,null); 的递归解决方案
NOTICE - I know there is a workingaround solution by moving the styles "inline" on the elements like here or the recursive solution by digging the DOM tree and using getComputedStyle(element,null);
问题:
1.这个问题的真正原因和解决方案是什么.
(与GPU加速有关吗?)
2.如何在使用带有 Fontface 的自定义字体时仍然克服这个问题
<button id="btn">svg to png</button>
<svg id="svg" width="200" height="200">
<circle cx="50" cy="50" r="30" />
<text class="svgTxt" x="0" y="100">Hen's SVG Image</text>
</svg>
<canvas id="canvas" width="200" height="200"></canvas>
我的 CSS:
/*adding exo2 font*/
@font-face {
font-family: 'exo_2black';
src: url('./exo2font/Exo2-Black-webfont.eot');
src: url('./exo2font/Exo2-Black-webfont.eot?#iefix') format('embedded-opentype'),
url('./exo2font/Exo2-Black-webfont.woff') format('woff'),
url('./exo2font/Exo2-Black-webfont.ttf') format('truetype'),
url('./exo2font/Exo2-Black-webfont.svg#exo_2black') format('svg');
font-weight: normal;
font-style: normal;
}
/*change circle color depends on window size*/
@media screen and (min-width: 480px) {
svg circle {
fill: lightgreen;
}
}
/*style on the svg text*/
.svgTxt{
font-family: 'exo_2black';
font-size: 30px;
fill: red;
}
我的代码:
//reference to elements
var btn = document.querySelector('#btn');
var svg = document.getElementById('svg');
var svgTexts = svg.getElementsByTagName('text');
var canvas = document.getElementById('canvas');
//Style definitions for svg elements defined in stylesheets are not applied to the generated canvas. This can be patched by adding style definitions to the svg elements before calling canvg.
//3.trigger download from dataUrl
function triggerDownload(imgURI) {
var evt = new MouseEvent('click', {
view: window,
bubbles: false,
cancelable: true
});
var a = document.createElement('a');
a.setAttribute('download', 'hen_saved_image.png');
a.setAttribute('href', imgURI);
a.setAttribute('target', '_blank');
a.dispatchEvent(evt);
}
//btn click event
btn.addEventListener('click', function () {
// 1.svg to canvas
var ctx = canvas.getContext('2d');
var data = (new XMLSerializer()).serializeToString(svg);//serialize the svg element to string
var DOMURL = window.URL || window.webkitURL || window;
var img = new Image();
var svgBlob = new Blob([data], { type: 'image/svg+xml;charset=utf-8' });//A blob object represents a chuck of bytes that holds data of a file.
var url = DOMURL.createObjectURL(svgBlob);//creates a DOMString containing an URL representing the object given in paramete
$('svg').append(deletedSVGText);
img.onload = function () {
ctx.drawImage(img, 0, 0);
DOMURL.revokeObjectURL(url);
// 2.canvas to dataUrl
var imgURI = canvas
.toDataURL('image/png')
.replace('image/png', 'image/octet-stream');// returns a data URI containing a representation of the image in the format specified by the type parameter
triggerDownload(imgURI);
};
img.src = url;
});
推荐答案
问题一(上半场): 真正的原因是什么(到底GPU加速是否相关?)
不,GPU 加速与此无关.
最广泛的原因是隐私.
No, GPU acceleration has nothing to do with it.
The broadest reason is privacy.
要使用 drawImage
绘制 svg,您必须将 svg 作为外部文档加载到 <img>
标记内.SVG 可以是一种用于资源加载的非常复杂的图像格式(它实际上可以需要任何 HTML 文档可能需要的任何类型的资源).因此,规范中已声明与 元素或
或类似的安全性相同的安全性应适用于
<;img>
内容更严格:
To draw your svg with drawImage
you have to load your svg as an external document inside an <img>
tag. SVG can be quite a complex image format for resources loading (it can literally require any kind of resource that could be required by any HTML document). Thus, it has been stated in specs that the same security as the one for <iframe>
elements or <object>
or similar ones should apply to <img>
content and even stricter :
<img>
内容不能需要任何外部资源,也不能访问主文档.
<img>
content can not require any external resources, nor access to the main document.
问题 1(下半场):以及这个问题的解决方案
您指出了一些已经回答它的 SO 问题,您也可以在创建从中一滴.这里的愚蠢实现
You pointed to some SO questions already answering it, you could also just include all the stylesheets from the main document inside a <style>
tag inside your parsed svg Node, before you do create the Blob from it. dumb implementation here
问题 2: 在使用带有 Fontface 的自定义字体时,我如何克服这个问题"
对于外部资源,您必须将其编码为 dataURI,并在创建 Blob 之前将其包含在您的 svg 节点中.特别是对于字体,您需要在 <style>
元素中设置 font-face
属性.
For external resources, you have to encode it as dataURI, and include it in your svg node before you create the Blob. For font in particular, you'd set a font-face
property in a <style>
element.
所以最后,你的 svg 会有类似的东西
So at the end, your svg would have something like
<defs>
<style>
/* all your parsed styles in here */
@font-face {
font-family: foo;
src: url('data:application/font-woff;charset=utf-8;base64,...')
}
</style>
</defs>
在您提取其标记之前就在其本身.
in itself before you do extract its markup.
相关文章