借助batik实现svg的渲染,并输出jpg/png图片,通过实际测试这个接口的性能不是特别好,但常规的使用还ok
jar包引入,请注意使用最新的版本
<!-- https://mvnrepository.com/artifact/com.github.liuyueyi.media/svg-plugin -->
<dependency>
<groupId>com.github.liuyueyi.media</groupId>
<artifactId>svg-core</artifactId>
</dependency>
直接将svg文件渲染为图片
public void testPng(){
BufferedImage img=SvgRenderWrapper.of("test.svg")
.setType(RenderType.JPG) // 默认输出图片为png格式,因此当输出png时,可以省略这个参数设置
.asImg();
System.out.println("---");
}
svg传参
of的传参可以是svg的文件地址(本地的绝对路径、相对路径或者网络url均可), 也可以是svg文本
支持四种输出方式
- 输出图片: asImg()
- 输出流: asStream()
- 输出字节: asBytes()
- 输出文件: asFile(fileName)
- 输出文件时,会自动根据文件名后缀,来设置渲染图片类型,如 save.jpg 表示将svg渲染为jpg格式图片
- 输出文件时,若指定文件的父目录不存在,会递归的创建父目录,无需担心文件不存在的异常
渲染类型
当前支持将svg渲染为jpg, png, tiff 3种格式图片
- png:
.setType(RenderType.PNG)
- jpg:
.setType(RenderType.JPG)
- tiff:
.setType(RenderType.TIFF)
说明,当希望渲染图片为tiff格式时,对于jdk8及之下的版本,由于jdk本身不支持tiff图片,因此需要使用第三方插件来适配,所以请在pom中额外添加依赖
<!-- https://mvnrepository.com/artifact/com.twelvemonkeys.imageio/imageio-tiff -->
<dependency>
<groupId>com.twelvemonkeys.imageio</groupId>
<artifactId>imageio-tiff</artifactId>
<version>3.9.4</version>
</dependency>
模板渲染主要是指svg定义了一套样式模板,其中的部分元素可以根据传参进行替换,从而实现复用的效果
下面是一个模板的使用case
public void testRenderSvgTemplate() {
String svg = "<svg width=\"480\" height=\"855\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n" +
" <!-- Created with Method Draw - http://github.com/duopixel/Method-Draw/ -->\n" +
" <defs>\n" +
" <filter id=\"svg_2_blur\">\n" +
" <feGaussianBlur stdDeviation=\"0.1\" in=\"SourceGraphic\"/>\n" +
" </filter>\n" +
" </defs>\n" +
" <g>\n" +
" <title>background</title>\n" +
" <rect fill=\"#fff\" id=\"canvas_background\" height=\"857\" width=\"482\" y=\"-1\" x=\"-1\"/>\n" +
" <g display=\"none\" overflow=\"visible\" y=\"0\" x=\"0\" height=\"100%\" width=\"100%\" id=\"canvasGrid\">\n" +
" <rect fill=\"url(#gridpattern)\" stroke-width=\"0\" y=\"0\" x=\"0\" height=\"100%\" width=\"100%\"/>\n" +
" </g>\n" +
" </g>\n" +
" <g>\n" +
" <text x=\"100\" y=\"55\" fill=\"red\" style=\"outline: 10px solid blue; font-size:2em; overflow; visible\">I love SVG</text>\n" +
" <text x=\"22\" y=\"40\">Text Behind Shape</text>\n" +
"\n" +
" <circle cx=\"50\" cy=\"50\" r=\"25\"\n" +
" style=\"stroke: none; fill: #0000ff;\n" +
" fill-opacity: 0.3; \" />\n" +
" <circle cx=\"120\" cy=\"50\" r=\"25\"\n" +
" style=\"stroke: none; fill: #0000ff;\n" +
" fill-opacity: 0.7; \" />\n" +
"\n" +
"\n" +
" <title>Layer 1</title>\n" +
" <image xlink:href=\"http://s2.mogucdn.com/mlcdn/c45406/170418_68lkjddg3bll08h9c9bk0d8ihkffi_800x1200.jpg_468x468.jpg\" id=\"svg_1\" height=\"855\" width=\"480\" y=\"-1\" x=\"1\"/>\n" +
" <text style=\"cursor: move;\" filter=\"url(#svg_2_blur)\" opacity=\"0.75\" stroke=\"#000\" xml:space=\"preserve\" text-anchor=\"start\" font-family=\"Euphoria, sans-serif\" font-size=\"35\" id=\"svg_2\" y=\"375.33555\" x=\"160.49442\" stroke-width=\"0\" fill=\"#000000\">¥1314.00</text>\n" +
" <text xml:space=\"preserve\" text-anchor=\"start\" font-family=\"Euphoria, sans-serif\" font-size=\"18\" id=\"svg_3\" y=\"827\" x=\"208.5\" stroke-width=\"0\" fill=\"#999999\">2017-01-28 11:02:01</text>\n" +
" </g>\n" +
"</svg>";
SvgRenderWrapper.of(svg)
.addParams("svg_2", "当前金额: ¥1314.00")
.addParams("svg_3", "当前时间: " + LocalDateTime.now())
.setCacheEnable(true) // 表示开启缓存,对于模板渲染的case,可以有效提高渲染效率
.asFile("/tmp/i1.tiff");
System.out.println("渲染完成");
SvgRenderWrapper.of(svg)
.addParams("svg_2", "金额: ¥520.00")
// svgContent 表示替换标签内容值; 后面的 fill: #ff0000 表示替换标签的属性值
.addParams("svg_3", newMap("svgContent", "当前时间: " + LocalDateTime.now(), "fill", "#ff0000"))
// 对于image标签,直接传图片地址即可
.addParams("svg_1", "https://spring.hhui.top/spring-blog/imgs/221026/logo.jpg")
.asFile("/tmp/i2.tiff");
System.out.println("替换属性渲染完成");
}
模板传参
当前仅支持根据标签id来实现参数替换,对于使用name的传参替换有bug,因此暂不提供,详情参看 * 图片合成支持的前世今生 - 一灰灰Blog
两种类型的参数替换
一个实例传参如下,表示需要替换 id=svg_3 标签的正文内容和fill属性
{
"svg_3": {
"svgContent": "替换后的内容",
"fill": "#ff0000"
}
}
- 标签正文内容替换:主要替换的是
<text id="svg_3">[这里是被替换内容]</tag>
中两个标签内的文本,更新为替换后的内容
- 标签属性替换:替换的标签的属性,如
<text fill="#999999">正文</text>
替换这个元素中的颜色属性,更新为fill="#ff0000
渲染之后输出图片为:
正文替换 | 正文 + 属性替换 |
---|---|
请注意上面两张图的差别
- 价格
- 图片
- 时间及颜色
缓存提效
对于模板渲染的方式,可以搭配cacheEnable
参数来使用;这个表示是否需要缓存svg模板转换后的Document结构
默认规则:
- 当param传参非空时,开启缓存
- 当param传参为空时,关闭缓存
主动设置的cacheEnable的优先级最高,会覆盖默认的规则
默认最多只缓存100个模板对象;可以通过 setCacheSize()
来更新缓存大小
以下是 3.0.0 及之前的版本使用姿势,最新版本做了较大改动,两者使用姿势并不通用,强烈推荐使用最新版本
对外暴露的一个封装类: SvgRenderWrapper
,一般的使用姿势是接受两个参数,这里需要额外说明
/**
* 将SVG转换成PNG
*
* @param path 可以是http开头的SVG文件路径;可以是<svg开头的纯svg内容
* @param paramMap 变更参数键值对,key为svg元素Id value为替换内容
* @throws TranscoderException
* @throws IOException
*/
public static BufferedImage convertToJpegAsImg(String path,Map<String, Object> paramMap);
- path: svg的文本内容;或者http地址对应的svg模板
- paramMap: 则表示替换的参数
说明
- 考虑到某些svg模板是通用的,只是部分图片或文字有些微的区别,所有通过paramMap来实现对svg内容的替换,目前只支持根据id进行替换
- 为了提升性能,内部对svg的模板进行了缓存,提升将svg模板解析为document对象的性能开销;而允许这么做的原因,就是document对象提供了深拷贝的接口
这个的具体使用比较简单,主要是svg模板的使用,友情贡献一个个人名片生成的svg模板
<svg width="610" height="240" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<style type="text/css">
text {
text-anchor: middle;
}
#title {
font-size: 20px;
stroke-width: 2px;
stroke: #aaa;
fill: #abc;
}
#title2 {
font-size: 15px;
stroke: #345;
fill: #abc;
}
#name {
font-size: 18px;
fill: #333;
display: block;
}
#ownDesc {
fill: #bbb;
font-size: 14px;
}
#qrDesc {
fill: #999;
font-size: 12px;
}
.bgcolor {
fill: #fff;
}
</style>
<rect class='bgcolor' x='0' y='0' height='100%' width='100%'></rect>
<rect class='bgcolor' style="stroke:#e6e6e6;stroke-width:2" id="canvas_background" height="220" width="96%" y="10"
x="2%"></rect>
<rect class='bgcolor' x='33%' y='0' height='30' width='33%'/>
<text y="16" x="50%" id="title" lengthAdjust='spacing' rotate="5" textLength='33%'>一灰灰Blog</text>
<svg width="270" height="230">
<image y="45" height="90" width="62%"
xlink:href="http://image.uc.cn/o/wemedia/s/upload/2017/39c53604fe3587a4876396cf3785b801x200x200x13.png"
id="logo">
</image>
<text x="205" y="72" id='name'>一灰灰Blog</text>
<text>
<tspan y="100" x="200" font-size="13px" fill="#567">
qq: 3302797840
</tspan>
<tspan y="120" x="198" font-size="13px" fill="#567">
sina: 一灰灰blog
</tspan>
<tspan y="140" x="198" font-size="13px" fill="#567">
osc: 小灰灰Blog
</tspan>
</text>
<text y="170" x="50%" id='ownDesc'>
<tspan y="170" x="50%">
码农界新人,Java搬运工一枚
</tspan>
<tspan y="190" x="50%">
不定时分享个人学习收获
</tspan>
</text>
</svg>
<line x1="260" y1="40" x2="240" y2="200" style="stroke:#e6e6e6;stroke-width:1"/>
<svg width="150" height="230" x="270">
<image y="30" width="100%" height="160"
xlink:href="https://static.oschina.net/uploads/img/201707/09205944_0PzS.jpg" id="qrCode">
</image>
<text y="200" x="50%" id="qrDesc">
小灰灰Blog微信公众号
</text>
</svg>
<line x1="425" y1="40" x2="425" y2="200" style="stroke:#e6e600;stroke-width:1"/>
<svg width="150" height="230" x="430">
<image y="30" width="100%" height="160"
xlink:href="http://s17.mogucdn.com/mlcdn/c45406/180209_3i75g6a8fbb9i9j6ked54ka8ggikh_500x500.png"
id="qrCode">
</image>
<text y="200" x="50%" style="font-size:12px;fill:#E02222">
一灰灰Blog 个人博客
</text>
</svg>
<rect class='bgcolor' x='22%' y='220' height='30' width='56%'/>
<text y="234" x="146" fill="#aaa"> [ -</text>
<text y="234" x="464" fill="#aaa"> - ]</text>
<text y="235" x="50%" id="title2" lengthAdjust='spacing' textLength='60%'>获取技术干货,共同学习成长</text>
</svg>
输出结果如下: