Java 使用 batik 将 Svg 转为 Png 以及部署到Linux

357 阅读5分钟

这几天又在做 海报分享, 每次做都是头大,如果前端绘图 要写很多代码,可读性也不好 微信小程序的 canvas 对 SVG 的支持就像一个笑话 ,多端开发又要考虑各种设备的兼容, 最终卡在了 微信小程序的 canvas 上. 虽然小程序的 image支持svg 但是无法长安识别和保存. 最终决定使用后端绘制 海报图片 , 使用SVG 转Png 通过流输出给前端

下面展示需要用到的依赖

<dependency>
    <groupId>org.apache.xmlgraphics</groupId>
    <artifactId>batik-transcoder</artifactId>
    <version>1.17</version>
</dependency>
<!--https://mvnrepository.com/artifact/org.apache.xmlgraphics/batik-all -->
<dependency>
    <groupId>org.apache.xmlgraphics</groupId>
    <artifactId>batik-all</artifactId>
    <version>1.17</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.xmlgraphics/batik-codec -->
<dependency>
    <groupId>org.apache.xmlgraphics</groupId>
    <artifactId>batik-codec</artifactId>
    <version>1.17</version>
</dependency>
<!---->
<dependency>
    <groupId>org.apache.xmlgraphics</groupId>
    <artifactId>batik-svg-dom</artifactId>
    <version>1.17</version>
</dependency>
<dependency>
    <groupId>org.apache.xmlgraphics</groupId>
    <artifactId>batik-svgbrowser</artifactId>
    <version>1.17</version>
</dependency>
<dependency>
    <groupId>org.apache.xmlgraphics</groupId>
    <artifactId>batik-svggen</artifactId>
    <version>1.17</version>
</dependency>
<dependency>
    <groupId>org.apache.xmlgraphics</groupId>
    <artifactId>batik-svgpp</artifactId>
    <version>1.17</version>
</dependency>
<dependency>
    <groupId>org.apache.xmlgraphics</groupId>
    <artifactId>batik-svgrasterizer</artifactId>
    <version>1.17</version>
</dependency>
<dependency>
    <groupId>org.apache.xmlgraphics</groupId>
    <artifactId>batik-swing</artifactId>
    <version>1.17</version>
</dependency>
<dependency>
    <groupId>org.apache.xmlgraphics</groupId>
    <artifactId>batik-transcoder</artifactId>
    <version>1.17</version>
</dependency>
<dependency>
    <groupId>org.apache.xmlgraphics</groupId>
    <artifactId>batik-ttf2svg</artifactId>
    <version>1.17</version>
</dependency>
<dependency>
    <groupId>org.apache.xmlgraphics</groupId>
    <artifactId>batik-xml</artifactId>
    <version>1.17</version>
</dependency>

然后是绘制需要的海报以及分享码, 这个不难 ,我就以我自己绘制的为例, 这是一个 邀请卡片

<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 230 314.4" width="460" height="628.8">
	<style>
		text {  font-family: NSimSun,新宋体, 'Microsoft YaHei'; }
	</style>
	<rect rx="8" width="230" height="314.4" x="0" y="0" fill="#fff" />
	<svg x="8" y="8">
		<image xlink:href="data:image/png;base64,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"
			   width="18" height="18" />
		<text x="26" y="13.5" fill="#888888" font-size="11">公司名字</text>
		<text y="36" font-size="14">来自$NAME的分享</text>
	</svg>
	<svg x="8" y="56" width="214" height="214" version="1.1" viewBox="0 0 40 40" stroke="none">
		<rect width="100%" height="100%" fill="#FFFFFF" />
		$PATH </svg>
	<line x1="8" x2="222" y1="280" y2="280" stroke="#c9c9c9" stroke-dasharray="3 2" />
	<svg x="8" y="280">
		<image y="8" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAACqADAAQAAAABAAAACgAAAAA7eLj1AAAA2ElEQVQYGU2QPQrCQBCF3ZAmKcWz2Cp2dl7BnzMoJJ2QgGnt9Q42lgbsUukpbMQqP13i90IWdmB4M+89ZmbXRFHUjZwwxlzUdl23ceiRpwaxIDPKxhEbcdLE9UYwT5LkANYih6gHLldvhtWaJNOYCVcJrF4DPzIkAx+hv4mmDwxPz/OM7S3a1bZ3sWT1lkF3kf7wOne11kpbpWl6rKpqJo999Rlygqib9AsvoCjL8otpQX3zJRDzOI5PkDpc8cH8Bh9gCB/0Eymm5B4hkIt62bbtjhszmaT9Abd2YoeHof93AAAAAElFTkSuQmCC"
			   height="16" width="16" />
		<text x="24" y="21" font-size="14">二维码</text>
	</svg>
</svg>

需要注意 在windows上绘制 不会出现 字体兼容的问题,不过大多数的linux 没有内置字体 ,svg中如果包含有文字 一定要指定字体 记得加上去

<style>
		text {  font-family: NSimSun,新宋体, 'Microsoft YaHei'; }
</style> 

下面则是 服务端 java 通过 batik 将 SVG 转换为 Png


import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;



	@GetMapping(value = "universal-code")
	public void m通用码(String name, String code, HttpServletResponse response) 			throws WriterException, IOException, TranscoderException {
		String qrCodeSvgPath = UtilWeb.QRCodeSvgPath("如果你需要二维码", 2);
		//-> 将 字符串替换 替换 svg里面的文字 
                //-> svgString 就是 [邀请卡片] 里面的内容
		String svg = svgString.replace("$NAME", name) //
				.replace("$PATH", qrCodeSvgPath);

		TranscoderInput transcoderInput = new TranscoderInput(new StringReader(svg));
		TranscoderOutput transcoderOutput = new TranscoderOutput(response.getOutputStream());
		PNGTranscoder pngTranscoder = new PNGTranscoder();
		pngTranscoder.transcode(transcoderInput, transcoderOutput);
	}

注意: batik 中对图片的引用 必须有xmlns:xlink="http://www.w3.org/1999/xlink" 以及 image 标签 图片地址属性使用 xlink:href 而不是 href, 如果你能直接使用 href 可以告诉我, 我里面用的都是 base64 避免 batik 再去访问资源

这里我是直接输出给前端的 TranscoderInput和TranscoderOutput 还有不同的构造函数,会有适合你的

通过访问 universal-code?name=你好&code=222 就可以 得到这样一张图片

image.png

然后打包部署

Linux 需要安装字体 教程很多 我也是看的 linux如何安装中文字体库_linux font-CSDN博客

text { font-family: NSimSun,新宋体, 'Microsoft YaHei'; } 写的什么字体就安装什么字体,不然你会收获一堆 框框

启动时需要加上 -Djava.awt.headless=true 这个参数,linux 不会默认加上 就像这样 java -Djava.awt.headless=true -jar service.jar

到此就结束了 希望能够帮助到你