当前位置

使用PHP的Imagick将SVG转PNG

James Qi 在 2021年12月23日 - 12:10 提交

我们去年就在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中带有所谓径向渐变标签的,例如:👎🏾 这个EmojiGoogle 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这些内容替换为空后,转换速度马上大幅提升,一秒内就可以转好。颜色信息不丢失,只是渐变效果丢失,还是可以接受的。👌

自由标签:

添加新评论

Plain text

  • 不允许使用HTML标签。
  • 自动将网址与电子邮件地址转变为链接。
  • 自动断行和分段。