解析word公式的解决方案(office插入和wps插入不同的解决方案)
这几天在公司的项目有个需求就是数学公式的导入,而对于word来说,插入的公式xml格式,需要转换为mathML,借用插件MathJax来进行展示,而对于wps插入的公式来说,获取到的是一个wmf图片,wmf是无法在页面上进行展示的,所以思路就是将wmf转换为png图片. 这个在网上的资料有很多,是先转换为svg,再转换为png,但是我在实际操作过程中发现很多问题,就是公式的一些特殊符号展示不出来,所以在这总结下解决办法,最后有两种解决方案,一个是硬编码,一个是借助第三方来实现.
使用的是poi解析word
先说一下office插入的公式解决方案
思路就是读取出来的xml,先进行转换为mathML,然后直接在页面上展示就可以,直接代码实现:
// 进行转换的过程中需要借助这个文件,网上搜索就可以,或者使用everything这个软件全盘搜一下,一般来说本机安装office就会有这个文件,找到就可以
private static File stylesheet = new File("src/main/resources/OMML2MML.XSL");
private static TransformerFactory tFactory = TransformerFactory.newInstance();
private static StreamSource stylesource = new StreamSource(stylesheet);
/**
* 获取MathML
* @param ctomath
* @return
* @throws Exception
*/
static String getMathML(CTOMath ctomath) throws Exception {
Transformer transformer = tFactory.newTransformer(stylesource);
Node node = ctomath.getDomNode();
DOMSource source = new DOMSource(node);
StringWriter stringwriter = new StringWriter();
StreamResult result = new StreamResult(stringwriter);
transformer.setOutputProperty("omit-xml-declaration", "yes");
transformer.transform(source, result);
String mathML = stringwriter.toString();
stringwriter.close();
mathML = mathML.replaceAll("xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\"", "");
mathML = mathML.replaceAll("xmlns:mml", "xmlns");
mathML = mathML.replaceAll("mml:", "");
return mathML;
}
/**
* 返回公式的集合
* @param document
* @return
*/
public static Map<Integer,String> mml2Html(XWPFDocument document){
Map<Integer,String> result = new HashMap<>();
try{
//storing the found MathML in a AllayList of strings
List<String> mathMLList = new ArrayList<String>(16);
//getting the formulas out of all body elements
for (IBodyElement ibodyelement : document.getBodyElements()) {
if (ibodyelement.getElementType().equals(BodyElementType.PARAGRAPH)) {
XWPFParagraph paragraph = (XWPFParagraph)ibodyelement;
for (CTOMath ctomath : paragraph.getCTP().getOMathList()) {
mathMLList.add(getMathML(ctomath));
}
for (CTOMathPara ctomathpara : paragraph.getCTP().getOMathParaList()) {
for (CTOMath ctomath : ctomathpara.getOMathList()) {
mathMLList.add(getMathML(ctomath));
}
}
} else if (ibodyelement.getElementType().equals(BodyElementType.TABLE)) {
XWPFTable table = (XWPFTable)ibodyelement;
for (XWPFTableRow row : table.getRows()) {
for (XWPFTableCell cell : row.getTableCells()) {
for (XWPFParagraph paragraph : cell.getParagraphs()) {
for (CTOMath ctomath : paragraph.getCTP().getOMathList()) {
mathMLList.add(getMathML(ctomath));
}
for (CTOMathPara ctomathpara : paragraph.getCTP().getOMathParaList()) {
for (CTOMath ctomath : ctomathpara.getOMathList()) {
mathMLList.add(getMathML(ctomath));
}
}
}
}
}
}
}
document.close();
for (int i = 0; i < mathMLList.size(); i++) {
// 替换特殊符号(由于页面上无法直接展示特殊符号,所以需要进行替换,将特殊符号替换为html可以认识的标签(https://www.cnblogs.com/xinlvtian/p/8646683.html))
String s = mathMLList.get(i)
.replaceAll("±", "±")
.replaceAll("∑","∑");
s = "<math xmlns=\"http://www.w3.org/1998/Math/MathML\">" + s + "</math>";
result.put(i,s);
}
return result;
}catch (Exception e){
e.printStackTrace();
}
return result;
}
/**
* 获取所有的公式
* @param xwpfDocument
* @return
*/
public static Map<Integer,String> getFormulaMap(XWPFDocument xwpfDocument){
Map<Integer, String> result = new HashMap<>();
// 获取到公式的Map集合
Map<Integer, String> mml2Html = mml2Html(xwpfDocument);
Set<Map.Entry<Integer, String>> entries = mml2Html.entrySet();
// 遍历所有段落,获取所有包含公式的段落
List<XWPFParagraph> paragraphs = xwpfDocument.getParagraphs();
int j = 0;
for (int i = 0; i < paragraphs.size(); i++) {
XWPFParagraph xwpfParagraph = paragraphs.get(i);
CTP ctp = xwpfParagraph.getCTP();
String xmlText = ctp.xmlText();
if(xmlText.contains("<m:oMath>")){
StringBuilder sb = new StringBuilder();
sb.append(xwpfParagraph.getParagraphText());
sb.append(mml2Html.get(j++));
result.put(i,sb.toString());
}
}
return result;
}
public static void main(String[] args) throws Exception {
XWPFDocument xwpfDocument = new XWPFDocument(new FileInputStream("C:\\Users\\wz157\\Desktop\\题目批量导入模板 (1).docx"));
// 这个就能获取到所有公式了,Integer表示的是第几个公式,String表示公式转化后的mathML,借助mathJax可以在页面上进行展示
Map<Integer, String> formulaMap = getFormulaMap(xwpfDocument);
// 接下来就看自己公司的业务了,我们是将这个东西直接存入数据库,到时候展示的时候直接拿出来就可以了
// 前台展示的时候需要注意,将mathJax下载下来里面有实例,其实就是添加<script type="text/javascript"
src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">,就可以展示了,这个绝对是可行的,如果不可以请检查页面上的这个js文件是否引入正确.
}
上面就是office插入公式进行转换的解决方案,尤其注意后面的样式,一定要正确,就绝对没有问题,建议下载源码包,里面的test下有何mml的示例.
wps插入公式的解决方案
第一种,使用第三方,这个需要去官方先注册一下,获取到一个api key,网站是https://cloudconvert.com/,注册完成之后点击上面导航的API,进入页面点击API Console,就可以找到字节的apikey了,下面我使用自己的apikey作为实例.
这里只说转换,不说poi读取word,其实也很简单,获取对象,getAllPictures()方法,获取所有图片,使用picture.suggestFileExtension()获取图片后缀,看后缀是否是wmf结尾的就可以了.下面直接说转换.
// Create service object
// CloudConvertService service = new CloudConvertService("<api key>");
CloudConvertService service = new CloudConvertService("OtyvB1mgwMzVQsFYdN663Ue80fKXjrlR3D5T6Je1vqmHs93dkC1n8sWum6JHVnZx");
// Create conversion process
ConvertProcess process = service.startProcess("wmf", "png");
// Perform conversion
process.startConversion(new File("C:\\Users\\wz157\\Desktop\\1.wmf"));
// Wait for result
ProcessStatus status;
waitLoop: while (true) {
status = process.getStatus();
switch (status.step) {
case FINISHED: break waitLoop;
case ERROR: throw new RuntimeException(status.message);
}
// Be gentle
Thread.sleep(200);
}
// Download result
service.download(status.output.url, new File("C:\\\\Users\\\\wz157\\\\Desktop\\\\output.png"));
// Clean up
process.delete();
对了,首先要先引入依赖:
<dependency>
<groupId>org.aioobe.cloudconvert</groupId>
<artifactId>client</artifactId>
<version>1.1</version>
</dependency>
这就解决了,是不是很简单,但是这个因为访问的是国际网站,大家懂得,比较慢,但是也不是慢的不能接受,亲自实践,一张图片大概几秒的时间.
还有需要注意,如果使用过程出现NoSuch...Method,这个方法的出现只能证明jar包冲突,排除一下就可以.但是需要找到那个冲突,我在使用过程中和公司的父项目的jar冲突,所以直接将父项目中存在的jar排出了下,如下
<exclusions>
<exclusion>
<groupId>javax.ws.rs</groupId>
<artifactId>jsr311-api</artifactId>
</exclusion>
</exclusions>
第二种方案,就是硬编码,借助的是wmf2svg这个jar,这个需要版本是0.9.8,比较高的版本,这个需要注意.
/**
* 图片转化成base64字符串
*
* @param imgFile
* @return
*/
public static String GetImageStr(String imgFile) {// 将图片文件转化为字节数组字符串,并对其进行Base64编码处理
InputStream in = null;
byte[] data = null;
// 读取图片字节数组
try {
in = new FileInputStream(imgFile);
data = new byte[in.available()];
in.read(data);
in.close();
} catch (IOException e) {
e.printStackTrace();
}
// 对字节数组Base64编码
BASE64Encoder encoder = new BASE64Encoder();
return encoder.encode(data);// 返回Base64编码过的字节数组字符串
}
/**
* 将svg字符串转换为png
*
* @param svgCode svg代码
* @param pngFilePath 保存的路径
* @throws TranscoderException svg代码异常
* @throws IOException io错误
*/
public static void convertToPng(String svgCode, String pngFilePath) throws IOException,
TranscoderException {
File file = new File(pngFilePath);
FileOutputStream outputStream = null;
try {
file.createNewFile();
outputStream = new FileOutputStream(file);
convertToPng(svgCode, outputStream);
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 将svgCode转换成png文件,直接输出到流中
*
* @param svgCode svg代码
* @param outputStream 输出流
* @throws TranscoderException 异常
* @throws IOException io异常
*/
public static void convertToPng(String svgCode, OutputStream outputStream)
throws TranscoderException, IOException {
try {
// Base64解码
BASE64Decoder decoder = new BASE64Decoder();
byte[] bytes = decoder.decodeBuffer(svgCode);
for (int i = 0; i < bytes.length; ++i) {
if (bytes[i] < 0) {// 调整异常数据
bytes[i] += 256;
}
}
// 根据上面byte[]数组 生成 png 图片
PNGTranscoder t = new PNGTranscoder();
TranscoderInput input = new TranscoderInput(new ByteArrayInputStream(bytes));
TranscoderOutput output = new TranscoderOutput(outputStream);
t.transcode(input, output);
outputStream.flush();
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
// 尤其注意main方法,这里仅仅是作为演示,在我们项目中完全是使用流进行传递,二进制+img标签写入数据库的
public static void main(String[] args) throws IOException, TranscoderException {
String wmf = "C:\\Users\\wz157\\Desktop\\1.wmf";
String svg = "C:\\Users\\wz157\\Desktop\\222.svg";
// 这一步很重要
Main.main(new String[] {"-debug", "-replace-symbol-font", wmf, svg});
String strImg = GetImageStr(wmf);
// convertToPng(strImg, "C:\\Users\\wz157\\Desktop\\s.jpeg");
convertToPng(strImg, "C:\\Users\\wz157\\Desktop\\s.png");
}
加入依赖(应该就是下面的依赖):
<!-- wmf转码svg -->
<dependency>
<groupId>net.arnx</groupId>
<artifactId>wmf2svg</artifactId>
<version>0.9.8</version>
</dependency>
<!-- svg转码png -->
<dependency>
<groupId>org.codeartisans.thirdparties.swing</groupId>
<artifactId>batik-all</artifactId>
<version>1.8pre-r1084380</version>
</dependency>
<dependency>
<groupId>org.apache.xmlgraphics</groupId>
<artifactId>batik-transcoder</artifactId>
<version>1.9.1</version>
</dependency>
这个在使用过程中也可能出现jar包冲突,是因为低版本导致的,也是因为我们父项目中的版本是0.9.5,所以版本比较低,也出现了那个找不到方法的问题,一样的解决方案.
上面就是提供的word解析的方案,可以拿来直接使用,如果有问题或者哪没有弄通可以联系我(本人qq: 2585700076,微信是:wz15713598138),总结到此,一起加油
解析word公式的解决方案(office插入和wps插入不同的解决方案)的更多相关文章
- Java解析word,获取文档中图片位置
前言(背景介绍): Apache POI是Apache基金会下一个开源的项目,用来处理office系列的文档,能够创建和解析word.excel.ppt格式的文档. 其中对word文档的处理有两个技术 ...
- Java解析word文档
背景 在互联网教育行业,做内容相关的项目经常碰到的一个问题就是如何解析word文档. 因为系统如果无法智能的解析word,那么就只能通过其他方式手动录入word内容,效率低下,而且人工成本和录入出错率 ...
- php解析word,获得文档中的图片
背景 前段时间在写一个功能:用原生php将获得word中的内容并导入到网站系统中.因为文档中存在公式,图片,表格等,因此写的比较麻烦. 思路 大体思路是先将word中格式为doc的文档转化为docx, ...
- Apache-Tika解析Word文档
通常在使用爬虫时,爬取到网上的文章都是各式各样的格式处理起来比较麻烦,这里我们使用Apache-Tika来处理Word格式的文章,如下: package com.mengyao.tika.app; i ...
- VSTO 向office文档中插入内容
原文:VSTO 向office文档中插入内容 Word: Word.Selection sec = ThisAddIn.appWord.Selection; sec.Insert ...
- C#仪器数据文件解析-Word文件(doc、docx)
不少仪器数据报告输出为Word格式文件,同Excel文件,Word文件doc和docx的存储格式是不同的,相应的解析Word文件的方式也类似,主要有以下方式: 1.通过MS Word应用程序的DCOM ...
- word公式的使用
插入->公式->插入新公式 优点:可以表示一些特殊符号,而且word公式的字更好看. 方法: 1.Shift+Enter,公式转入下一行 2.选择内嵌或显示 3.选择性粘贴->粘贴成 ...
- latex转word公式 java (latextoword,latex_word,latex2word,latex_omml)
latex_word 主要目的: 给大家分享一个我的原创作品:latex转为word公式(omml)工具 [java] 此工具主要用于将含有latex公式的文本下载成word时,将latex转 ...
- WPF解析Word为图片
偶遇需要解析Word为单张图,此做 http://git.oschina.net/jiailiuyan/OfficeDecoder using System; using System.Collect ...
随机推荐
- Django Rest Framework源码剖析(八)-----视图与路由
一.简介 django rest framework 给我们带来了很多组件,除了认证.权限.序列化...其中一个重要组件就是视图,一般视图是和路由配合使用,这种方式给我们提供了更灵活的使用方法,对于使 ...
- 20155333 《网络对抗》 Exp7 网络欺诈防范
20155333 <网络对抗> Exp7 网络欺诈防范 基础问题 通常在什么场景下容易受到DNS spoof攻击? 公共网络 在日常生活工作中如何防范以上两种攻击方法? DNS欺骗攻击是很 ...
- POJ3267
从今天开始POJ里的一部分类型的题目就一般不放在一起写了 一个是太丑,格式麻烦,第二个是以后的题目难度都有所增大,因此一道题可能就要写蛮长 尤其是DP这一块,以前一直没好好学习,现在从基础的先开始吧 ...
- 新员工入门 - for测试
23456人员介绍 XXX 测试工作 [软件] Chrome 浏览器.jsonviewer.Firefox.FireBug HTTP协议与抓包 - fildder.wireshirk等 DB查询工具 ...
- 阿里云centos 安装禅道
下载 我的阿里云服务器系统是 centos6.8 64 位,下载的禅道版本是 Linux 64位一键安装包(适用于Linux 64位) 由于阿里云服务器没桌面,所以下载用不了浏览器,可考虑在本地下载后 ...
- Hadoop版本的选择问题
自从2013年下半年开始,hadoop的版本开始了快速的更新换代,这和通信和互联网行业(ICT)的发展是密切相关的.随着移动网络的和宽带网络的覆盖以及数据传输速率的提升,线上的数据有了爆炸式的增长.这 ...
- PAT甲题题解1098. Insertion or Heap Sort (25)-(插入排序和堆排序)
题目就是给两个序列,第一个是排序前的,第二个是排序中的,判断它是采用插入排序还是堆排序,并且输出下一次操作后的序列. 插入排序的特点就是,前面是从小到大排列的,后面就与原序列相同. 堆排序的特点就是, ...
- Java并发编程(详解wait(), notify(),sleep())
http://blog.csdn.net/luckyzhoustar/article/details/48179161
- linux第三章学习笔记
第三章 进程管理 进程是Unix操作系统抽象概念中最基本的一种. 进程管理是所有操作系统的心脏所在. 一.进程 1. 进程是处于执行期的程序.除了可执行程序代码,还包括打开的文件.挂起的信号.内核内部 ...
- Linux内核分析 实验三:跟踪分析Linux内核的启动过程
贺邦 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程 http://mooc.study.163.com/course/USTC-1000029000 一. 实验过程 ...