如何将svgcanvas保存到本地文件系统

有一种方法可以让用户在使用浏览器在javascript svgcanvas上创buildvectorgraphics后,将该文件下载到本地文件系统中?

SVG对我来说是一个全新的领域,所以如果我的措辞不准确,请耐心等待。

使用常规的“保存”浏览器命令可能是可能的,但它不会保存SVGcanvas,它将保存整个页面。

我相信你最好的select是使用AJAX,并将整个SVG XML数据作为POST数据发送到服务器脚本,然后让这个脚本只发送带有头Content-Disposition: attachment; filename=yourfile.svg的POST数据Content-Disposition: attachment; filename=yourfile.svg Content-Disposition: attachment; filename=yourfile.svg

(在PHP中,您可以使用file_get_contents('php://input')获取原始POST内容。)

您可以避免往返于服务器。

Base64编码你的SVG XML。

然后生成该数据的链接。 用户可以右键点击保存在本地。

 // This example was created using Protovis & jQuery // Base64 provided by http://www.webtoolkit.info/javascript-base64.html // Modern web browsers have a builtin function to this as well 'btoa' function encode_as_img_and_link(){ // Add some critical information $("svg").attr({ version: '1.1' , xmlns:"http://www.w3.org/2000/svg"}); var svg = $("#chart-canvas").html(); var b64 = Base64.encode(svg); // or use btoa if supported // Works in recent Webkit(Chrome) $("body").append($("<img src='data:image/svg+xml;base64,\n"+b64+"' alt='file.svg'/>")); // Works in Firefox 3.6 and Webit and possibly any browser which supports the data-uri $("body").append($("<a href-lang='image/svg+xml' href='data:image/svg+xml;base64,\n"+b64+"' title='file.svg'>Download</a>")); } 

img标签在Webkit中工作,链接在Webkit和Firefox中工作,并且可以在任何支持data-uri浏览器中工作

不需要做base64编码 – 你可以在其中创build一个包含原始SVG代码的链接。 下面是The_Who的答案中的一个修改的函数encode_as_img_and_link():

 function img_and_link() { $('body').append( $('<a>') .attr('href-lang', 'image/svg+xml') .attr('href', 'data:image/svg+xml;utf8,' + unescape($('svg')[0].outerHTML)) .text('Download') ); } 

使用FileSaver.js

 saveAs(new Blob([SVG_DATA_HERE], {type:"application/svg+xml"}), "name.svg") 

用Eli Gray的FileSaver ,我得到了它的工作(铬):

 bb = new window.WebKitBlobBuilder; var svg = $('#designpanel').svg('get'); bb.append(svg.toSVG()); var blob = bb.getBlob("application/svg+xml;charset=" + svg.characterSet); saveAs(blob,"name.svg"); 

SVG来自keith woods jquery的svg。

Html Rocks 1

Html Rocks 2

  // save SVG $('#SVGsave').click(function(){ var a = document.createElement('a'); a.href = 'data:image/svg+xml;utf8,' + unescape($('#SVG')[0].outerHTML); a.download = 'plot.svg'; a.target = '_blank'; document.body.appendChild(a); a.click(); document.body.removeChild(a); }); 

我最近发现这个Chrome插件http://nytimes.github.io/svg-crowbar/ 。 这对我的需求来说有点儿缺陷,但本质上是有效的。

之前我曾经提出过一个类似于接受的答案的解决scheme,它涉及一个服务器端的脚本,但是这个脚本很长,而且所有的样式都必须内联在标记中。 撬杠似乎为你照顾,这是很好的。

我回答了这个话题,尽pipe已经过了几年了,因为最近Web浏览器在支持SVG和其他相关行为方面的融合已经引起了对SVG的兴趣,并且允许对这个问题进行“普遍”的回答。 实际上zneak的方法是正确的,但在我看来,简洁(即花了我一段时间才能为自己工作)。 我也认为他对AJAX的引用是不必要的,或者不是我通过AJAX(=使用XMLHttpRequest)所理解的。 因此,我将使用纯JavaScript(即没有JQuery或任何其他库)提供更详细的答案,并为Java,Perl和PHP提供服务器代码。

(1)在你的HTML页面中的(dynamic生成的)SVG内容包含在一个具有唯一ID的div中,例如

<div id="svg"><svg...>SVG content</svg></div>

(2)包含一个button来调用JavaScript函数,例如

<button onclick="sendSVG();">Save as SVG File</button>

(3)包含您的button标记中指定的JavaScript函数:

 function sendSVG() { var svgText = document.getElementById('svg').innerHTML; var form = document.createElement("form"); form.setAttribute("method", "post"); form.setAttribute("action", "http://path-to-your-server-app"); form.setAttribute("accept-charset", "UTF-8"); var hiddenSVGField = document.createElement("input"); hiddenSVGField.setAttribute("type", "hidden"); hiddenSVGField.setAttribute("name", "svgText"); hiddenSVGField.setAttribute("value", svgText); form.appendChild(hiddenSVGField); document.body.appendChild(form); form.submit(); } 

(4)编写一个服务器应用程序来接受你的SVGtext发布请求,并使用Content-Disposition作为image / svg + xml返回来指定一个附件。 提供三种语言的工作代码,虽然我不是一个Perl程序员,并从来没有用过愤怒的PHP。

Java Servlet

 public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String svgText = (String) request.getParameter("svgText"); response.setContentType("image/svg+xml"); response.addHeader("Content-Disposition", "attachment; filename=\"image.svg\""); PrintWriter out = response.getWriter(); out.println(svgText); } 

Perl CGI

 use CGI qw(:standard); my $svgText = param('svgText'); print header(-type => "image/svg+xml", -content_disposition => "attachment; filename=image.svg"); print $svgText; 

PHP

 <?php $svgText = $_POST['svgText']; header('Content-type: image/svg+xml'); header('Content-Disposition: attachment; filename="image.svg"'); print "$svgText"; ?> 

我在这里使用了一个硬编码的名字(image.svg),但是实际上我从页面中产生了一个dynamic内容的描述document.getElementById('graphName').textContent再次使用一个div和一个ID, document.getElementById('graphName').textContent )。

这已经在Mac Safari 9,Firefox 42,Chrome 47,Opera 34,Windows 7 / IE 11和Windows10 / Edge上进行了testing,每种情况下都会下载svg文件或者提示下载。 生成的文件将打开,例如Adobe Illustrator或您设置为打开svg文件的任何其他应用程序。

一个真实世界的例子(如果你考虑学术研究的真实世界)在基因部分http://flyatlas.gla.ac.uk/MidgutAtlas/index.html

是的,这是可能的。 使用jquery.svg http://keith-wood.name/svgRef.html并使用函数svg.toSVG()(在提交时写入隐藏字段)发布svg xml数据。 使用imagemagick(convert image.svg image.png)将php保存并转换为光栅,然后使用头文件(“Content-Type:application / octet-stream”)强制文件下载并读取图像文件。

最兼容的方式将是一个往返服务器。 您也可以在某些浏览器中使用data:URI 。

你不能用JavaScript保存任何东西到本地文件系统,你应该做的是将canvas的内容发送到服务器,并让用户下载并保存。

回答我自己的问题:

另一种可能性虽然不是最好的,但在网页上显示序列化的内容并让用户select,复制和粘贴。 这在调查eli灰色的解答以后。

我也许发现了一个更好的方法,不要强迫用户按右键“保存图像为”。 只需要将canvas的base64代码绘制到链接的href中并修改它就可以自动启动下载。 我不知道它的通用浏览器兼容,但它应该与主/新浏览器。

 var canvas = document.getElementById('your-canvas'); if (canvas.getContext) { var C = canvas.getContext('2d'); } $('#your-canvas').mousedown(function(event) { // feel free to choose your event ;) // just for example // var OFFSET = $(this).offset(); // var x = event.pageX - OFFSET.left; // var y = event.pageY - OFFSET.top; // standard data to url var imgdata = canvas.toDataURL('image/png'); // modify the dataUrl so the browser starts downloading it instead of just showing it var newdata = imgdata.replace(/^data:image\/png/,'data:application/octet-stream'); // give the link the values it needs $('a.linkwithnewattr').attr('download','your_pic_name.png').attr('href',newdata); }); 

随意包围任何你想要的东西,希望有所帮助

 $(document).ready(function(){ $("#btnDownload").click(function(){ var $container = $('#svg-container'), // Canvg requires trimmed content content = $container.html().trim(), canvas = document.getElementById('svg-canvas'); // Draw svg on canvas canvg(canvas, content); $container.hide(); // Change img be SVG representation var theImage = canvas.toDataURL('image/jpeg'); var a = document.createElement('a'); a.href = theImage; // xhr.response es un blob file a.target = '_blank'; a.download = 'prueba'; // nombre del archivo. a.style.display = 'none'; document.body.appendChild(a); a.click(); delete a; });//fin function });// fin 
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <script type="text/javascript" src="http://canvg.googlecode.com/svn/trunk/rgbcolor.js"></script> <script type="text/javascript" src="http://canvg.googlecode.com/svn/trunk/canvg.js"></script> <input id="svgData" name="svgData" type="hidden"/> <input id="btnDownload" type="button" value="Descargar"/> <div id='svg-container'> <svg xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" style="font-family:'lucida grande', 'lucida sans unicode', arial, helvetica, sans-serif;font-size:12px;" xmlns="http://www.w3.org/2000/svg" width="600" height="400"><desc>Created with Highcharts 4.0.4</desc><defs><clipPath id="highcharts-5"><rect x="-75" y="-75" width="750" height="550"></rect></clipPath></defs><rect x="0" y="0" width="600" height="400" strokeWidth="0" fill="#FFFFFF" class=" highcharts-background"></rect><g style="stroke:rgba(255,255,255,0);"><path fill="rgb(255,255,255)" fill-opacity="0" d="M 59 79 L 460 61 L 456 287 L 65 330 Z" stroke-linejoin="round"></path><path fill="rgb(255,255,255)" fill-opacity="0" d="M 65 330 L 456 287 L 456 286 L 65 330 Z" stroke-linejoin="round"></path><path fill="rgb(230,230,230)" fill-opacity="0" d="M 0 0" stroke-linejoin="round"></path></g><g style="stroke:rgba(255,255,255,0);"><path fill="rgb(255,255,255)" fill-opacity="0" d="M 495 66 L 496 66 L 490 300 L 490 301 Z" stroke-linejoin="round"></path><path fill="rgb(230,230,230)" fill-opacity="0" d="M 495 66 L 460 61 L 455 287 L 490 301 Z" stroke-linejoin="round"></path><path fill="rgb(255,255,255)" fill-opacity="0" d="M 495 66 L 460 61 L 460 61 L 496 66 Z" stroke-linejoin="round"></path></g><g style="stroke:rgba(255,255,255,0);"><path fill="rgb(255,255,255)" fill-opacity="0" d="M 88 345 L 490 300 L 490 300 L 88 346 Z" stroke-linejoin="round"></path><path fill="rgb(255,255,255)" fill-opacity="0" d="M 88 346 L 490 300 L 457 287 L 65 330 Z" stroke-linejoin="round"></path><path fill="rgb(230,230,230)" fill-opacity="0" d="M 88 345 L 65 329 L 65 330 L 88 346 Z" stroke-linejoin="round"></path></g><g class="highcharts-grid" ><path fill="none" d="M 146 75 L 146 75 L 150 320 L 175 336" stroke="#C0C0C0" stroke-width="1" opacity="1"></path><path fill="none" d="M 189 73 L 189 73 L 191 316 L 217 331" stroke="#C0C0C0" stroke-width="1" opacity="1"></path><path fill="none" d="M 230 71 L 230 71 L 232 311 L 259 326" stroke="#C0C0C0" stroke-width="1" opacity="1"></path><path fill="none" d="M 271 69 L 271 69 L 271 307 L 300 322" stroke="#C0C0C0" stroke-width="1" opacity="1"></path><path fill="none" d="M 310 67 L 310 67 L 310 302 L 339 317" stroke="#C0C0C0" stroke-width="1" opacity="1"></path><path fill="none" d="M 349 66 L 349 66 L 348 298 L 378 313" stroke="#C0C0C0" stroke-width="1" opacity="1"></path><path fill="none" d="M 387 64 L 387 64 L 385 294 L 416 308" stroke="#C0C0C0" stroke-width="1" opacity="1"></path><path fill="none" d="M 424 62 L 424 62 L 421 290 L 454 304" stroke="#C0C0C0" stroke-width="1" opacity="1"></path><path fill="none" d="M 461 61 L 461 61 L 457 286 L 491 300" stroke="#C0C0C0" stroke-width="1" opacity="1"></path><path fill="none" d="M 103 77 L 103 77 L 108 325 L 131 341" stroke="#C0C0C0" stroke-width="1" opacity="1"></path><path fill="none" d="M 59 79 L 59 79 L 65 329 L 87 345" stroke="#C0C0C0" stroke-width="1" opacity="1"></path></g><g class="highcharts-grid" ><path fill="none" d="M 59 78 L 59 78 L 461 60 L 496 66" stroke="#C0C0C0" stroke-width="1" opacity="1"></path><path fill="none" d="M 61 144 L 61 144 L 460 119 L 494 127" stroke="#C0C0C0" stroke-width="1" opacity="1"></path><path fill="none" d="M 62 206 L 62 206 L 459 175 L 493 185" stroke="#C0C0C0" stroke-width="1" opacity="1"></path><path fill="none" d="M 64 269 L 64 269 L 458 232 L 492 243" stroke="#C0C0C0" stroke-width="1" opacity="1"></path><path fill="none" d="M 65 330 L 65 330 L 457 286 L 490 300" stroke="#C0C0C0" stroke-width="1" opacity="1"></path></g><g class="highcharts-axis" ><path fill="none" d="M 75 325.5 L 525 325.5" stroke="#C0D0E0" stroke-width="1" visibility="hidden"></path></g><g class="highcharts-axis" ><text x="556.96875" text-anchor="middle" transform="translate(0,0) rotate(90 556.96875 200)" class=" highcharts-yaxis-title" style="color:#707070;fill:#707070;" visibility="visible" y="200">Values</text></g><g class="highcharts-series-group" ><g class="highcharts-series" visibility="visible" transform="translate(75,75) scale(1 1)" clip-path="url(#highcharts-5)"><gr="0" stroke="#7cb5ec" stroke-width="1"><path fill="#7cb5ec" d="M 390 141 L 408 139 L 406 226 L 388 228 Z" stroke-linejoin="round"></path><path fill="rgb(99,156,211)" fill-opacity="1" d="M 390 141 L 378 137 L 376 223 L 388 228 Z" stroke-linejoin="round"></path><path fill="rgb(149,206,255)" fill-opacity="1" d="M 390 141 L 378 137 L 395 136 L 408 139 Z" stroke-linejoin="round"></path></g><gr="0" stroke="#7cb5ec" stroke-width="1"><path fill="#7cb5ec" d="M 353 56 L 372 54 L 369 230 L 351 232 Z" stroke-linejoin="round"></path><path fill="rgb(99,156,211)" fill-opacity="1" d="M 353 56 L 342 53 L 339 227 L 351 232 Z" stroke-linejoin="round"></path><path fill="rgb(149,206,255)" fill-opacity="1" d="M 353 56 L 342 53 L 360 52 L 372 54 Z" stroke-linejoin="round"></path></g><gr="0" stroke="#7cb5ec" stroke-width="1"><path fill="#7cb5ec" d="M 314 118 L 333 117 L 332 235 L 313 237 Z" stroke-linejoin="round"></path><path fill="rgb(99,156,211)" fill-opacity="1" d="M 314 118 L 303 114 L 302 231 L 313 237 Z" stroke-linejoin="round"></path><path fill="rgb(149,206,255)" fill-opacity="1" d="M 314 118 L 303 114 L 322 113 L 333 117 Z" stroke-linejoin="round"></path></g><gr="0" stroke="#7cb5ec" stroke-width="1"><path fill="#7cb5ec" d="M 275 212 L 294 210 L 293 239 L 274 241 Z" stroke-linejoin="round"></path><path fill="rgb(149,206,255)" fill-opacity="1" d="M 275 212 L 264 207 L 283 205 L 294 210 Z" stroke-linejoin="round"></path><path fill="rgb(99,156,211)" fill-opacity="1" d="M 275 212 L 264 207 L 264 236 L 274 241 Z" stroke-linejoin="round"></path></g><gr="0" stroke="#7cb5ec" stroke-width="1"><path fill="#7cb5ec" d="M 235 94 L 255 93 L 254 243 L 235 246 Z" stroke-linejoin="round"></path><path fill="rgb(99,156,211)" fill-opacity="1" d="M 235 94 L 224 90 L 224 240 L 235 246 Z" stroke-linejoin="round"></path><path fill="rgb(149,206,255)" fill-opacity="1" d="M 235 94 L 224 90 L 244 89 L 255 93 Z" stroke-linejoin="round"></path></g><gr="0" stroke="#7cb5ec" stroke-width="1"><path fill="#7cb5ec" d="M 194 250 L 214 248 L 214 248 L 194 250 Z" stroke-linejoin="round"></path><path fill="rgb(149,206,255)" fill-opacity="1" d="M 194 250 L 184 245 L 204 243 L 214 248 Z" stroke-linejoin="round"></path><path fill="rgb(99,156,211)" fill-opacity="1" d="M 194 250 L 184 245 L 184 245 L 194 250 Z" stroke-linejoin="round"></path></g><gr="0" stroke="#7cb5ec" stroke-width="1"><path fill="#7cb5ec" d="M 152 131 L 173 130 L 173 253 L 153 255 Z" stroke-linejoin="round"></path><path fill="rgb(99,156,211)" fill-opacity="1" d="M 152 131 L 142 127 L 143 249 L 153 255 Z" stroke-linejoin="round"></path><path fill="rgb(149,206,255)" fill-opacity="1" d="M 152 131 L 142 127 L 163 126 L 173 130 Z" stroke-linejoin="round"></path></g><gr="0" stroke="#7cb5ec" stroke-width="1"><path fill="#7cb5ec" d="M 66 170 L 88 168 L 89 262 L 68 264 Z" stroke-linejoin="round"></path><path fill="rgb(99,156,211)" fill-opacity="1" d="M 66 170 L 57 165 L 59 259 L 68 264 Z" stroke-linejoin="round"></path><path fill="rgb(149,206,255)" fill-opacity="1" d="M 66 170 L 57 165 L 79 163 L 88 168 Z" stroke-linejoin="round"></path></g><gr="0" stroke="#7cb5ec" stroke-width="1"><path fill="#7cb5ec" d="M 23 206 L 44 204 L 45 267 L 24 269 Z" stroke-linejoin="round"></path><path fill="rgb(99,156,211)" fill-opacity="1" d="M 23 206 L 14 201 L 15 264 L 24 269 Z" stroke-linejoin="round"></path><path fill="rgb(149,206,255)" fill-opacity="1" d="M 23 206 L 14 201 L 36 199 L 44 204 Z" stroke-linejoin="round"></path></g></g><g class="highcharts-markers" visibility="visible" transform="translate(75,75) scale(1 1)" clip-path="none"></g></g><text x="300" text-anchor="middle" class="highcharts-title" style="color:#333333;font-size:18px;fill:#333333;width:536px;" y="25"><tspan>3D chart with null values</tspan></text><text x="300" text-anchor="middle" class="highcharts-subtitle" style="color:#555555;fill:#555555;width:536px;" y="53"><tspan>Notice the difference between a 0 value and a null point</tspan></text><g class="highcharts-legend" transform="translate(270,364)"><g ><g><g class="highcharts-legend-item" transform="translate(8,3)"><text x="21" style="color:#333333;font-size:12px;font-weight:bold;cursor:pointer;fill:#333333;" text-anchor="start" y="15">Sales</text><rect x="0" y="4" width="16" height="12" fill="#7cb5ec"></rect></g></g></g></g><g class="highcharts-axis-labels highcharts-xaxis-labels" ><text x="110" text-anchor="middle" style="width:25px;color:#606060;cursor:default;font-size:11px;fill:#606060;" y="363" z="-59" opacity="1">Jan</text><text x="154" text-anchor="middle" style="width:25px;color:#606060;cursor:default;font-size:11px;fill:#606060;" y="358" z="-40" opacity="1">Feb</text><text x="197" text-anchor="middle" style="width:25px;color:#606060;cursor:default;font-size:11px;fill:#606060;" y="353" z="-22" opacity="1">Mar</text><text x="239" text-anchor="middle" style="width:25px;color:#606060;cursor:default;font-size:11px;fill:#606060;" y="348" z="-3" opacity="1">Apr</text><text x="280" text-anchor="middle" style="width:25px;color:#606060;cursor:default;font-size:11px;fill:#606060;" y="343" z="16" opacity="1">May</text><text x="320" text-anchor="middle" style="width:25px;color:#606060;cursor:default;font-size:11px;fill:#606060;" y="338" z="35" opacity="1">Jun</text><text x="359" text-anchor="middle" style="width:25px;color:#606060;cursor:default;font-size:11px;fill:#606060;" y="334" z="53" opacity="1">Jul</text><text x="398" text-anchor="middle" style="width:25px;color:#606060;cursor:default;font-size:11px;fill:#606060;" y="329" z="72" opacity="1">Aug</text><text x="435" text-anchor="middle" style="width:25px;color:#606060;cursor:default;font-size:11px;fill:#606060;" y="324" z="91" opacity="1">Sep</text><text x="472" text-anchor="middle" style="width:25px;color:#606060;cursor:default;font-size:11px;fill:#606060;" y="320" z="109" opacity="1">Oct</text></g><g class="highcharts-axis-labels highcharts-yaxis-labels" ><text x="502" text-anchor="start" style="width:55px;color:#606060;cursor:default;font-size:11px;fill:#606060;" y="301" z="122" opacity="1">0</text><text x="504" text-anchor="start" style="width:55px;color:#606060;cursor:default;font-size:11px;fill:#606060;" y="244" z="111" opacity="1">2</text><text x="505" text-anchor="start" style="width:55px;color:#606060;cursor:default;font-size:11px;fill:#606060;" y="187" z="100" opacity="1">4</text><text x="506" text-anchor="start" style="width:55px;color:#606060;cursor:default;font-size:11px;fill:#606060;" y="128" z="90" opacity="1">6</text><text x="508" text-anchor="start" style="width:55px;color:#606060;cursor:default;font-size:11px;fill:#606060;" y="69" z="79" opacity="1">8</text></g><g class="highcharts-tooltip" style="cursor:default;padding:0;white-space:nowrap;" transform="translate(0,-9999)"><path fill="none" d="M 3 0 L 13 0 C 16 0 16 0 16 3 L 16 13 C 16 16 16 16 13 16 L 3 16 C 0 16 0 16 0 13 L 0 3 C 0 0 0 0 3 0" stroke="black" stroke-opacity="0.049999999999999996" stroke-width="5" transform="translate(1, 1)"></path><path fill="none" d="M 3 0 L 13 0 C 16 0 16 0 16 3 L 16 13 C 16 16 16 16 13 16 L 3 16 C 0 16 0 16 0 13 L 0 3 C 0 0 0 0 3 0" stroke="black" stroke-opacity="0.09999999999999999" stroke-width="3" transform="translate(1, 1)"></path><path fill="none" d="M 3 0 L 13 0 C 16 0 16 0 16 3 L 16 13 C 16 16 16 16 13 16 L 3 16 C 0 16 0 16 0 13 L 0 3 C 0 0 0 0 3 0" stroke="black" stroke-opacity="0.15" stroke-width="1" transform="translate(1, 1)"></path><path fill="rgb(249, 249, 249)" fill-opacity=" .85" d="M 3 0 L 13 0 C 16 0 16 0 16 3 L 16 13 C 16 16 16 16 13 16 L 3 16 C 0 16 0 16 0 13 L 0 3 C 0 0 0 0 3 0"></path><text x="8" style="font-size:12px;color:#333333;fill:#333333;" y="21"></text></g><text x="590" text-anchor="end" style="cursor:pointer;color:#909090;font-size:9px;fill:#909090;" y="395">Highcharts.com</text></svg> </div> <section> <canvas id="svg-canvas"></canvas> </section> 

我提出了一个干净的/可用的小书签。

它会在页面上的每个内联<svg>旁边放置一个唯一的链接。

https://codepen.io/corysimmons/pen/vybzqV

希望它可以帮助别人。

根本不需要做任何编程。 有人们已经build立了在线应用程序,包括可定义的参数,如尺寸,分辨率,输出格式等。

这是一个更好的在线图像转换应用程序,我find了svg-> jpeg。 http://image.online-convert.com/convert-to-jpg