一行代码解决svg保存成png文件

先说下我的功能需求,大家看看和大家的是否相同,能否借鉴。
下面是我的整个的思路过程,如果想直接找解决方案,直接看方案三。

功能需求:

添加一个按钮,点击按钮时,将拓扑图保存为图片文件并导出。

就是将在svg画布上画的图,保存成图片并导出。

问题描述:

在svg画布上画的拓扑图,每个节点使用的是图片,将整个svg导出时,导出的图片文件上面不显示节点图片。如图1-1、1-2:

图1-1 svg画布画好的拓扑图

图1-2 导出的图片

我svg中绘制过程中,引入图片的代码如图1-3:


图1-3 svg节点引入图片

图片放在static下面,如图1-4:

图1-4 引入的图片存放位置

方案思路:

方案一:无须引入插件

首先是制造一个button,用的element的框架。
<el-button size = 'mini' type="primary" @click="saveSvgToPng" v-loading.fullscreen.lock="fullscreenLoading">导出图片</el-button>

然后写这个点击事件响应函数:

saveSvgToPng: function () {
        //采用直接转成canvas的方式
        let width = 1000;
        let height = 666;
        var serializer = new XMLSerializer();
        var source = '<?xml version="1.0" standalone="no"?>\r\n'+serializer.serializeToString(svg.node());
        var image = new Image();
        image.src = "data:image/svg+xml;charset=utf-8," + encodeURIComponent(source);
        var canvas = document.createElement("canvas");
        canvas.width = width;
        canvas.height = height;
        var context = canvas.getContext("2d")
        image.onload = function(){
          context.drawImage(image, 0, 0);

          var a = document.createElement("a");
          a.download = "aaaa.png";
          a.href = canvas.toDataURL('image/png');
          a.click();
        }
      },

导出内容如图1-2,未显示网元节点图片。未搞清楚原因,查了一些资料,好像是因为canvas画布被污染了,所以无法使用toDataURL这种方法了。而canvas画布被污染的原因好像是因为svg中网元节点图片跨域了,我现在有这个疑问:在static下面的图片,存在跨域问题吗,因为我导出的时候,并没有报出跨域的错误。

然后我又尝试了方案二:

方案二:使用插件html2canvas

按照官网步骤,引入html2canvas插件,修改html结构,将svg放入一个div内,并给div一个ref标签,便于引用,如图1-5.

图1-5 html结构

然后修改点击响应函数,代码如下:

函数1:

dataURLToBlob: function (dataurl) {
  var arr = dataurl.split(',');
  var mime = arr[0].match(/:(.*?);/)[1];
  var bstr = atob(arr[1]);
  var n = bstr.length;
  var u8arr = new Uint8Array(n);
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n);
  }
  return new Blob([u8arr], {type: mime})
},

单击响应函数2:

catchSvgToPng: function () {
        const _this = this
        let a = document.createElement('a');
        setTimeout(() => {
          // 此处用于解决截图不清晰问题,将生成的canvas放大,然后再填充到原有的容器中就会清晰
          const width = 1000;
          const height = 400;
          const canvas2 = document.createElement('canvas');
          const scale = 2;
          canvas2.width = width * scale;
          canvas2.height = height * scale;
          const context1 = canvas2.getContext('2d')
          if(context1) {
            context1.scale(scale, scale);
          }
          const opts = {
            scale,
            canvas: canvas2,
            // logging: true, //日志开关,便于查看html2canvas的内部执行流程
            width,
            height,
            // 【重要】开启跨域配置
            useCORS: true
          };
          html2canvas(_this.$refs.imageWrapper,opts).then((canvas) => {
            const context = canvas2.getContext('2d');
            if(context) {
              context.scale(2,2);
              context.mozImageSmoothingEnabled = false;
              context.webkitImageSmoothingEnabled = false;
              context.imageSmoothingEnabled = false;
            }
            // canvas转换成url,然后利用a标签的download属性,直接下载,绕过上传服务器再下载
//            _this.screenUrl = canvas.toDataURL()

//            var imgBlob = canvas.toDataURL('image/jpeg', 1.0); //将图片转为base64
//            imgBlob = imgBlob.toString().substring(imgBlob.indexOf(",") + 1);//截取base64以便上传
            let blob = _this.dataURLToBlob(canvas.toDataURL('image/jpeg', 1.0));
            a.setAttribute("href", URL.createObjectURL(blob));
            a.setAttribute("download", "xxxxxx.png");
            document.body.appendChild(a);
            a.click();
            URL.revokeObjectURL(blob);
            document.body.removeChild(a);
          });
        },1000)
      },

导出的图片如图1-6所示:


图1-6 html2canvas导出的图片

导出的图片依然无网元节点图片,已经按照网上查到的资料,对污染的canvas进行处理,不让canvas被污染,依然没有效果。现在不清楚是什么原因导致的导出的图片无节点图片,因此也不知如何解决。
这个问题到这里已经困扰了我将近一周之久,查了好多资料,试了又试,像一支无头苍蝇一样撞来撞去,毫无头绪。因为之前科学上网的软件到期了,一直没有续费,所以之前的查资料都是在百度上进行。
在这里!!!强烈建议大家科学上网!!!当我把软件续费以后,用谷歌重新试着查询之前的资料,发现之前尝试的一种插件,但苦于没有找到例子而不知道怎么使用,就一直未动。当我谷歌出使用流程以后,我抱着试一试的心态重新试了一下,这就是我的方案三。

方案二:使用插件saveSvgAsPng
废话不多说,上个官网网址,写的很清楚。
github:https://github.com/exupero/saveSvgAsPng
翻译版本:https://www.helplib.com/GitHub/article_110596
按照这上面的提示,一步步操作。
1.用npm把插件装上
npm install save-svg-as-png
2.在需要使用的vue文件中把js文件import进来
import saveSvg from 'save-svg-as-png';
3.对之前的按钮点击响应函数进行编写

saveSvgToPng: function () {
        //调研使用saveSvgAsPng 的方式
        saveSvg.saveSvgAsPng(document.getElementById("topologySvg"), "diagram.png",{height:800});
      },

官网上面给的例子直接使用的
saveSvgAsPng(document.getElementById("topologySvg"), "diagram.png")
但是这样的话,在我的vue框架下,是显示这个方法无效,所以需要使用前面import的文件名来进行调用。
我们调转这个函数,看下怎么回事。

out$.saveSvgAsPng = (el, name, options) => {
    requireDomNode(el);
    out$.svgAsPngUri(el, options || {}, uri => out$.download(name, uri));
  };

这个是引入插件中该方法的位置,很显然该方法需要三个参数,操作的元素、保存的文件名称以及一些参数。至于具体可以设置哪些参数来控制导出的png图片,官网给了一个清单,写的很清楚。比如我们想设置导出图片的宽度和高度为我们想要的值,就可以这么写:

saveSvg.saveSvgAsPng(document.getElementById("topologySvg"), "diagram.png",{height:800,width:1400});

至此,该功能就实现了,一行代码可以搞定的功能琢磨了一周多,以后一定要科学上网!!!百度真得往后稍稍。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,104评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,816评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,697评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,836评论 1 298
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,851评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,441评论 1 310
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,992评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,899评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,457评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,529评论 3 341
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,664评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,346评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,025评论 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,511评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,611评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,081评论 3 377
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,675评论 2 359

推荐阅读更多精彩内容