菜鸟进场,方圆十里,寸草不生
最近定制化一个app,需要显示wmf的文件,但是Android上无法对这种文件的直接显示,所以就需要对文件进行一个转换,网上对这方面的需求很少,所以简单的记录一下,就讲讲这里面的坑。
1、思路
首先,wmf是一种矢量图,而Android上说到矢量图想到什么呢?当然是svg图了,所以基本的思路就是将wmf转换为svg,然后再在Android上显示。
2、流程
(1)先通过jar包将wmf的图转化为svg,使用jar包:wmf2svg-0.9.6.jar
https://download.csdn.net/download/version1_0/10765431
使用代码:
/**
* @param file wmf文件的位置
* @param dest 转换出来的svg文件的保存位置
*/
private void convert(String file, String dest) throws Exception {
InputStream in = new FileInputStream(file);
WmfParser parser = new WmfParser();
final SvgGdi gdi = new SvgGdi(false);
parser.parse(in, gdi);
Document doc = gdi.getDocument();
OutputStream out = new FileOutputStream(dest);
if (dest.endsWith(".svgz")) {
out = new GZIPOutputStream(out);
}
output(doc, out);
}
private void output(Document doc, OutputStream out) throws Exception {
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer();
transformer.setOutputProperty(OutputKeys.METHOD, "xml");
transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, "-//W3C//DTD SVG 1.0//EN");
transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd");
transformer.transform(new DOMSource(doc), new StreamResult(out));
ByteArrayOutputStream bos = new ByteArrayOutputStream();
transformer.transform(new DOMSource(doc), new StreamResult(bos));
out.flush();
out.close();
}
备注:这里转换出来的文件在浏览器上已经可以访问了,但是在Android上不能访问。通过网上查询得知,这个转换出来的文件格式其实是svgz,这个svgz格式其实是svg的zip压缩包,但是这个压缩方式并不是普通的压缩方式,而是gzip方式压缩,需要解压。
(2)解压缩(这里附一个gzip格式压缩包的工具类)
public class GzipUtils {
public static final int BUFFER = 1024;
public static final String EXT = ".gz";
/**
* 数据压缩
*/
public static byte[] compress(byte[] data) throws Exception {
ByteArrayInputStream bais = new ByteArrayInputStream(data);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 压缩
compress(bais, baos);
byte[] output = baos.toByteArray();
baos.flush();
baos.close();
bais.close();
return output;
}
/**
* 文件压缩
*/
public static void compress(File file) throws Exception {
compress(file, true);
}
/**
* 文件压缩
*/
public static void compress(File file, boolean delete) throws Exception {
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream(file.getPath() + EXT);
compress(fis, fos);
fis.close();
fos.flush();
fos.close();
if (delete) {
file.delete();
}
}
/**
* 数据压缩
*/
public static void compress(InputStream is, OutputStream os) throws Exception {
GZIPOutputStream gos = new GZIPOutputStream(os);
int count;
byte data[] = new byte[BUFFER];
while ((count = is.read(data, 0, BUFFER)) != -1) {
gos.write(data, 0, count);
}
gos.finish();
gos.flush();
gos.close();
}
/**
* 文件压缩
*/
public static void compress(String path) throws Exception {
compress(path, true);
}
/**
* 文件压缩
*/
public static void compress(String path, boolean delete) throws Exception {
File file = new File(path);
compress(file, delete);
}
/**
* 文件压缩
*/
public static void compress(String inputFileName, String outputFileName) throws Exception {
FileInputStream inputFile = new FileInputStream(inputFileName);
FileOutputStream outputFile = new FileOutputStream(outputFileName);
compress(inputFile, outputFile);
inputFile.close();
outputFile.flush();
outputFile.close();
}
/**
* 数据解压缩
*/
public static byte[] decompress(byte[] data) throws Exception {
ByteArrayInputStream bais = new ByteArrayInputStream(data);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
// 解压缩
decompress(bais, baos);
data = baos.toByteArray();
baos.flush();
baos.close();
bais.close();
return data;
}
/**
* 文件解压缩
*/
public static void decompress(File file) throws Exception {
decompress(file, true, null);
}
/**
* 文件解压缩
*/
public static void decompress(File file, boolean delete, String outPath) throws Exception {
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = null;
if (outPath == null || outPath == "") {
fos = new FileOutputStream(file.getPath().replace(EXT, ""));
} else {
File files = new File(outPath);
//判断文件是否存在,不存在,则创建
if(!files.exists()){
files.mkdirs();
}
//文件输出流参数中,需要指定文件解压后的文件名,这里,用文件的原名称
fos = new FileOutputStream(outPath + File.separator + file.getName().replace(EXT, ""));
}
decompress(fis, fos);
fis.close();
fos.flush();
fos.close();
if (delete) {
file.delete();
}
}
/**
* 文件解压缩
*/
public static void decompress(String inputFileName, String outputFileName) throws Exception {
FileInputStream inputFile = new FileInputStream(inputFileName);
FileOutputStream outputFile = new FileOutputStream(outputFileName);
decompress(inputFile, outputFile);
inputFile.close();
outputFile.flush();
outputFile.close();
}
/**
* 数据解压缩
*/
public static void decompress(InputStream is, OutputStream os) throws Exception {
GZIPInputStream gis = new GZIPInputStream(is);
int count;
byte data[] = new byte[BUFFER];
while ((count = gis.read(data, 0, BUFFER)) != -1) {
os.write(data, 0, count);
}
gis.close();
}
/**
* 文件解压缩
*/
public static void decompress(String path) throws Exception {
decompress(path, true, null);
}
/**
* 文件解压缩(解压单个文件)
*/
public static void decompress(String path, boolean delete, String outPath) throws Exception {
File file = new File(path);
decompress(file, delete, outPath);
}
}
(3)、将svg图显示到Android上,目前网络上有直接显示svg图片的框架,而不需要通过Android studio自带的插件进行转换,这个框架就是:
//直接展示svg格式的图片
implementation 'com.pixplicity.sharp:library:1.1.0'
使用方式:
//展示到photoview
Sharp.loadFile(new File(file3) + ".1.svg").into(ivMap);
备注:到目前为止,可能有些svg图已经能够显示了,但是还有一些无法进行显示,原因是svg图里面可能带有style属性,而这个框架无法识别这个属性,就需要将这个属性里面的东西都设置到svg的文件中。(如果不理解的可以通过txt将svg打开,就知道什么原因了)
我这里写了一个,可能不是很规范,但能用吧,就先用着。
/**
* 将style文件放到
*/
private void setStyle(File file) {
if (!file.exists() && file.isDirectory()) {
return;
}
BufferedWriter bw = null;
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader(file));
File outFile = new File(file.getAbsolutePath() + ".1.svg");
bw = new BufferedWriter(new FileWriter(outFile));
//字符数组循环读取
String style = "";
boolean flag = false;
String str = null;
while ((str = br.readLine()) != null) {
bw.write(str + "\n");
if (str.indexOf("style") != -1) {
flag = !flag;
}
if (flag) {
style += str;
}
if (!flag && !TextUtils.isEmpty(style)) {
break;
}
}
Map map = new HashMap();
//去除里面的空格和换行
style = style.replaceAll("\n", "");
style = style.replaceAll(" ", "");
if (!TextUtils.isEmpty(style)) {
//切出所有的属性
String[] styles = style.split(">");
if (!TextUtils.isEmpty(styles[1])) {
String[] styles1 = styles[1].split("<");
if (!TextUtils.isEmpty(styles1[0])) {
//按.将所有的属性隔开
String[] styles2 = styles1[0].split("\\.");
for (int i = 0; i < styles2.length; i++) {
String data = styles2[i];
if (!TextUtils.isEmpty(data)) {
//按大括号切出属性值
String[] data1 = data.split("\\{");
String[] data2 = data1[1].split("\\}");
//转换属性的文件样式
String value = data2[0].replaceAll(":", "=\"");
value = value.replaceAll(";", "\" ");
map.put(data1[0], value);
}
}
}
}
}
//写出到磁盘
str = null;
while ((str = br.readLine()) != null) {
if (str.indexOf("class") != -1) {
//去掉以前的class属性标识
String[] str1 = str.split("\"");
String[] type = str1[1].split(" ");
str = str.replaceAll("class=\"", "");
for (int i = 0; i < type.length; i++) {
String style1 = map.get(type[i]);
if (!TextUtils.isEmpty(style1)) {
str = str.replaceAll(type[i] + "\"", style1);
str = str.replaceAll(type[i], style1);
}
}
}
bw.write(str + "\n");
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (bw != null) {
bw.close();
}
if (br != null) {
br.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
以上,wmf的文件就可以在Android上展示了。