SVG导出PNG
0
今天研究了一下把SVG导出PNG图片,东西不难就是有一些地方需要注意,我这里主要是吧IcoMoon
生成的字体导出图片。
首先准备工作
下载Apatch的batik,我这里用的是batik-1.7.1
这个版本。
准备好SVG数据
我这里是在IcoMoon导出来的webfont,非常不错的webfont工具,可以生成SVG文件,或者阿里妈妈也可以。
下面是一个SVG文件:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="图形" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="1024px" height="1024px" viewBox="0 0 1024 1024" enable-background="new 0 0 1024 1024" xml:space="preserve">
<path fill="#eb4f38" d="M76.8 287.712l0 169.984 279.552 184.32 69.632-134.144 175.104 137.216 71.68-135.168 176.128 132.096 95.232-141.312-3.072-222.208-134.144 154.624-184.32-134.144-68.608 137.216-184.32-129.024-77.824 132.096zM76.8-95.264l0 168.96 279.552 184.32 69.632-134.144 175.104 137.216 71.68-135.168 176.128 132.096 95.232-140.288-3.072-223.232-134.144 155.648-184.32-135.168-68.608 137.216-184.32-129.024-77.824 133.12z" transform="translate(0, 812) scale(1, -1)"/>
</svg>
这其实就是一个xml文件,好了我们开始来生成我们的PNG了。
下面直接先贴代码:
package com.acgist;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
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;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.xml.sax.SAXException;
/**
* 将svg转换为png格式的图片
*/
public abstract class SvgPngConverter {
// 颜色正则表达式
private static final String COLOR_REGEX = "#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})";
// 包含dtd的svg
// private static final String SVG_TMP = "<?xml version=\"1.0\" encoding=\"utf-8\"?><!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\" \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\"><svg version=\"1.1\" id=\"acgist\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0\" y=\"0\" width=\"0\" height=\"0\" viewBox=\"0 0 1024 1024\"><path fill=\"#000000\" d=\"\" transform=\"translate(0, 960) scale(1, -1)\" /></svg>";
// 不含dtd的svg
private static final String SVG_TMP = "<?xml version=\"1.0\" encoding=\"utf-8\"?><svg version=\"1.1\" id=\"acgist\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" x=\"0\" y=\"0\" width=\"0\" height=\"0\" viewBox=\"0 0 1024 1024\"><path fill=\"#000000\" d=\"\" transform=\"translate(0, 960) scale(1, -1)\" /></svg>";
/**
* 将svg字符串转换为png
*
* @param svg svg代码
* @param outputPath 保存的路径
*/
public static void convertToPng(String svg, String outputPath) {
if(StringUtils.isEmpty(svg) || StringUtils.isEmpty(outputPath))
return;
File file = new File(outputPath);
OutputStream outputStream = null;
try {
file.createNewFile();
outputStream = new FileOutputStream(file);
convertToPng(svg, outputStream);
} catch (IOException | TranscoderException e) {
e.printStackTrace();
} finally {
IOUtils.closeQuietly(outputStream);
}
}
/**
* 将svg转换成png文件,直接输出到流中
*
* @param svg svg代码
* @param outputStream 输出流
* @throws TranscoderException 异常
* @throws IOException io异常
*/
public static void convertToPng(String svg, OutputStream outputStream) throws TranscoderException, IOException {
if(StringUtils.isEmpty(svg) || outputStream == null)
return;
byte[] bytes = svg.getBytes("utf-8");
PNGTranscoder pngTranscoder = new PNGTranscoder();
TranscoderInput input = new TranscoderInput(new ByteArrayInputStream(bytes));
TranscoderOutput output = new TranscoderOutput(outputStream);
pngTranscoder.transcode(input, output);
outputStream.flush();
}
/**
* 生成svg
*
* @param svg svg模板
* @param data 数据
* @return svg
*/
public static String createSvg(String svg, String data) {
return createSvg(svg, data, null, null, null);
}
/**
* 生成svg
*
* @param svg svg模板
* @param data 数据
* @param width 生成宽度,默认:100
* @param height 生成高度,默认:100
* @param color 颜色,默认:#000000
* @return svg
*/
public static String createSvg(String svg, String data, Integer width, Integer height, String color) {
// SAXReader saxReader = new SAXReader();
//==================去掉dtd校验=======================//
// saxReader.setValidation(false);
// saxReader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
//==================去掉dtd校验=======================//
// Document document = saxReader.read(new InputSource(new ByteArrayInputStream(svg.getBytes())));
if(StringUtils.isEmpty(svg) || StringUtils.isEmpty(data))
return null;
if(width == null)
width = 100;
if(height == null)
height = 100;
if(StringUtils.isEmpty(color) || !color.matches(COLOR_REGEX))
color = "#000000";
Document document = null;
try {
document = DocumentHelper.parseText(svg);
} catch (DocumentException e) {
e.printStackTrace();
}
if(document == null)
return null;
Element root = document.getRootElement();
Attribute widthAttr = root.attribute("width");
if(widthAttr == null)
root.addAttribute("width", width.toString());
else
widthAttr.setText(width.toString());
Attribute heightAttr = root.attribute("height");
if(heightAttr == null)
root.addAttribute("height", height.toString());
else
heightAttr.setText(height.toString());
Element path = root.element("path");
Attribute colorAttr = path.attribute("fill");
if(colorAttr == null)
path.addAttribute("fill", color);
else
colorAttr.setText(color);
Attribute dAttr = path.attribute("d");
if(dAttr == null)
path.addAttribute("d", data);
else
dAttr.setText(data);
return root.asXML();
}
public static void main(String[] args) throws IOException, TranscoderException, DocumentException, SAXException {
String svg = createSvg(SVG_TMP, "M829.248 539.424c-13.984 146.016-135.552 260.576-285.248 260.576-115.808 0-214.944-68.736-260.672-167.36-13.76 4.352-28.096 7.36-43.296 7.36-79.52 0-144-64.512-144-144 0-15.808 3.168-30.752 7.872-44.928-61.856-36.064-103.872-102.24-103.872-179.008 0-114.88 93.12-208 208-208v-0.064l575.968 0.064c132.576 0 240 107.424 240 240 0 116.992-83.872 214.176-194.752 235.36zM784 128.064v-0.064h-575.968c-79.392 0.064-144 64.64-144 144.064 0 51.2 26.976 97.44 72.128 123.744 43.872 25.184 46.88 30.176 28.48 75.424-3.104 9.312-4.608 17.408-4.608 24.736 0 44.128 35.872 80 80 80 0 0 20.992 1.504 43.296-7.36 36.704-14.624 40.704-0.64 58.048 37.088 36.704 79.136 116.224 130.304 202.624 130.304 115.2 0 210.432-87.136 221.568-202.688 3.936-45.824 3.936-45.824 51.68-56.736 82.752-15.808 142.752-88.384 142.752-172.512 0-97.056-78.944-176-176-176z",
200, 200, "#CC0000");
convertToPng(svg, "e://svg.png");
}
}
下面讲几个非常重要的地方:
上面代码中的:viewBox=\"0 0 1024 1024\"
,这个属性注意了,最后两个值不是高和宽,而是你的SVG导出来时原画布的高和宽,后面的数据是在这个大小的画布上面的数据,如果大小对不上那么比例就不对了。
如下图是使用IcoMoon导出来的SVG,注意箭头部分:
后面又有transform=\"translate(0, 960) scale(1, -1)\"
这个属性,这个和CSS像是就是位移、旋转、放大这些属性了。
这里的960
,也是有讲究的,就是上图中font-face
这个节点的ascent
这个属性值,至于scale(1, -1)
这个是把图片上下翻转一下(主要是这个SVG不知道为什么生成出来是颠倒的,所以要在上下翻转一下才能正常,不知道为什么会这样)。
参考文章:http://www.w3cplus.com/html5/svg-transformations.html
在线SVG工具:http://www.zhangxinxu.com/sp/svg/
下面上效果:
这个是webfont在网页上面SVG:
下面是生成出来PNG: