我们去年就在emojiall.com这个网站中大量使用svg格式的矢量图,包括各emoji图片厂商和平台提供的svg矢量图以及我们自己的排行榜、情绪分析等原创生成的svg图,有一些svg是直接把svg代码放置在页面的html中,最近把一部分svg代码从页面html中拿出来单独作为独立文件,用img标签放在原来页面的html中,这样方便Google的收录,但百度等搜索引擎不能识别、解析和收录svg图片,于是我们也把svg图片转为png保存。
这个svg转png的功能以前就了解过一些,主要有两种方式:
- 使用PHP的Imagick插件
- 用JS将svg转为canvas绘制png
我们使用了第一种方式,下面是代码:
/** * 函数:svg数据转png图片 * @param: svg数据 * @return: png图片 */ function svg_data_to_png($input) { $im = new Imagick(); $im->readImageBlob($input); $im->setImageFormat("png8"); header("Content-type: image/png"); echo $im->getImageBlob(); $im->clear(); $im->destroy(); }
下面是原始svg和转为png的对比:
svg图片:
png图片:
有一个坑:用上面的PHP方式转换后尺寸不合适,后来是通过修改原是svg图数据中的width和height来解决的。如果还有其它修改,也需要在转换png前进行修改。
另外,确实还有一些svg样式和特殊的语法在转换后的png中无法显示,也需要修改svg源码或者以后找其它办法解决。
2022年9月26日补充:上周自己编写了一个php程序,对apache日志进行统计,将耗时最长的一些访问列出,以发现性能瓶颈在什么地方,有针对性解决。该程序在www.emojiall.com网站所在的服务器上运行时,发现有一些svg转png的页面访问耗时长达几百秒,特别是生成1280x1280、1920x1920这种大尺寸png图片时更容易卡,今天进一步研究发现耗时几百秒的都是svg中带有所谓径向渐变标签的,例如:👎🏾 这个Emoji的Google SVG矢量图的源代码中包含:
<radialGradient id="e" cx="51.77" cy="27.401" r="87.039" gradientTransform="matrix(-.0021809 -1 -.7873 .001717 73.454 148.32)" gradientUnits="userSpaceOnUse"> <stop stop-color="#A56C43" offset=".6"/> <stop stop-color="#8D5738" offset="1"/> </radialGradient>
这其中的radialGradient就是径向渐变的标签,可以让svg的颜色变化更方便,但正是这个颜色渐变让Imagick的转换运算量大增,转为大尺寸的png图片需要几十甚至几百秒。使用正则表达式把cx / cy / r / gradientTransform / gradientUnits这些内容替换为空后,转换速度马上大幅提升,一秒内就可以转好。颜色信息不丢失,只是渐变效果丢失,还是可以接受的。👌
评论