Canvas与Svg互转
本文主要以两个库canvg和canvas2svg为例。尝试探寻Svg与Canvas如何实现互转,以及上述两个库的可用性问题。
简单尝试
Svg转Canvas
以一个简单的静态svg图表作为案例,采用canvg转为canvas结果如下图所示。其中最顶部的装饰线条不见了,具体原因我们稍后再分析。

Canvas转Svg
原本的期望为将上述转化完的canvas在由canvas2svg转回svg执行报错Attempted to apply path command to node g。说明canvg在渲染过程中可能存在某些问题导致绘图操作不能被canvas2svg识别。接下来将以canvas2svg的示例demo绘制探究其绘制原理。

小结
Svg转Canvas直接基于canvg来转可能会有些错误(另外,直接基于canvg做svg导出可能会遇到svg中引用的class、图片等资源不生效的问题,需要先将class的样式解析成svg标签中的属性,这里不做展开,详情见saveSvgAsPng)。
canvas转svg是通过记录canvas绘图操作,解析操作、基于svg渲染器渲染的方式来实现的。在没有canvas的context或者说在没有canvas的操作记录的情况下canvas转svg就会退化成位图转矢量图。由于位图和矢量图存储信息方式的不同,几乎不存在不失真的情况话做转换。另外的确存在一些基于图像识别、图像追踪的位图转矢量图方案,详情见[附录](# 附录)。目前未发现基于NPM生态的位图转矢量图方案。
Svg转Canvas具体实现
canvg实现svg转canvas的方案为将svg文件根据标签实别为一个一个单独的元素,每个的元素会有对应的渲染方法。
1 | render(ctx: RenderingContext2D) { |
例:绘制圆形
1 | export default class CircleElement extends PathElement { |
以上,从原理分析canvg根据svg绘制canvas的方案为解析svg标签及样式、根据根据解析结果调用对应的canvas绘制对应的元素。至于上文顶部的装饰线条不见的问题,暂时当作普通bug不做深究。
Canvas转Svg具体实现
canvas2svg实现canvas转svg的方案为重写canvasAPI在绘制canvas的同时绘制svg。
canvas2svg源码,示例代码:
1 | /** |
结论
实现方案
canvg实现svg转canvas的方案为将svg文件根据标签实别为一个一个单独的元素,每个的元素会有对应的渲染方法。
canvas2svg实现canvas转svg的方案为重写canvasAPI在绘制canvas的同时绘制svg。
本质上均为从svg标签、canvasAPI入手在绘制canvas或svg的同时记录操作,做镜像绘制。
互转可行性
由于svg是根据标签自解释的,所以可以实现由svg文件转png文件这种操作。但canvas绘制完毕之后会丢失context即丢失操作步骤,而且基于位图的数据存储方式无法通过简单的方式直接转换为svg。
上述两库可用性
canvg可用,但仍有bug,canvas2svg未做深入分析,理应可用,需基于canvas context。另:zRender提供类似解决方案,同时对canvasAPI做了一层封装。
附录
adobe illustrator 的png to svg演示视频。这种实现方式应该为基于图像追踪的元素实别,会将一些色值相同的块实别成具体的元素。
项目示例:canvas-svg
参考 & 引用
https://elearning.adobe.com/2020/02/convert-your-png-to-svg-images/
https://github.com/canvg/canvg
https://github.com/exupero/saveSvgAsPng
android - Bitmap to SVG Programmatically conversion - Stack Overflow
How to make or convert png to SVG file in Illustrator - Quora