您的位置:首页 > 其它

Itext操作word文档动态生成数学试卷及Latex转mathML公式处理方式

2018-01-26 11:32 591 查看

Itext操作word文档动态生成数学试卷及Latex转mathML公式处理方式

转发请注明出处,谢谢!

介绍: 我下这篇博客的时候所在的公司是一个关于中小学教育的公司,之所以写这篇博客,是因为公司有这样一个需求.刚开始做的时候,近乎看完了网上所有关于poi,Itext,Java2word等操作word文档的博客,但是网上关于这种类似的资料很少,更不要说数学latex,mathml公式生成word文档了,所以只能自己研究,用了两周时间,终于做出来了,所以决定认真的写好这篇博客,希望以后对有些人提供一些帮助.

需求: 学生在网上做题,可以自选考题然后生成考试试卷

需求实现过程: 熟悉了poi,Itext,Java2word等技术操作word后,最后决定用poi和Itext操作word文档的实现方式,itext操作word文档功能很齐全.相对poi操作cexel比较强大,可以实现简单的word操作.

博客介绍: 这篇博客主要讲怎么讲latex,mathml写入到word文档及数学试卷里面题目的一些格式,像word文档的页眉页脚,水印啊什么的都是简单的功能,网上也有很好的博客,我就不讲了.重要的是IText的实现方式,遇到的坑及解决办法等.

POI操作word文档生成数学试卷  --->
http://blog.csdn.net/qq_35834998/article/details/79235304
好,说了这么多,希望大家不要介意.现在切入正题: 先看下面的效果图

Itext生成的数学试卷文档: doc不可编辑公式,数据库存储的事latex公式,及公式图片 

例:latex公式: \[(\cfrac{x-y}{x+y}-\cfrac{x+y}{x-y})\div \cfrac{2x}{{{x}^{2}}y-{{y}^{3}}}\] 

图片: http://xxx/xxx.png


POI生成数学试卷文档: docx可编辑公式



基础开发环境: IDEA,java1.8,JPA,Itext,maven

第一步 : maven 依赖 Itext依赖

<!-- https://mvnrepository.com/artifact/com.lowagie/itext -->
<dependency>
<groupId>com.lowagie</groupId>
<artifactId>itext</artifactId>
<version>2.1.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.itextpdf/itext-asian -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.lowagie/itext-rtf -->
<dependency>
<groupId>com.lowagie</groupId>
<artifactId>itext-rtf</artifactId>
<version>2.1.7</version>
</dependency>

Latex转mathml公式依赖

<dependency>
<groupId>fmath</groupId>
<artifactId>fmath-mathml-java</artifactId>
<version>3.1</version>
</dependency>
<dependency>
<groupId>org.scilab.forge</groupId>
<artifactId>jlatexmath</artifactId>
<version>1.0.6</version>
</dependency>

第二步:

补充说明 : Itext生成试卷文档,文档中所有的公式都是以图片的形式写入===实现方式,将latex公司转换成图片后在写入相关位置

直接上代码 :

@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4j
public class WordControllerTest{

@Autowired
private QuesService quesService;  //查询数据库的service根据自己的改

private Pattern pattern = Pattern.compile("\\\\\\\\\\[(.*?)\\\\\\\\\\]");//

private  Pattern compile = Pattern.compile("\\p{Lower}");//正则
@Test
public void produceItextWord() throws Exception {
//调用wordStart方法,文档名称,生成路径
Document document = wordStart("初中数学试卷","E:\\题库文档\\test06\\word.doc");
//题干title段落
Paragraph paragraph = new Paragraph();
paragraph.setSpacingAfter(8);
//题目编号
int number = 0;
List<String> stringList = Arrays.asList( //考题的id
"01162767-2f7d-458d-8945-877a81fd3361",
"0040110f-2c26-4865-b999-c8754f5803e3");
for (String id : stringList ){
//去数据库查询,获取题目信息
Ques ques = quesService.getQuesFromId(id);
//调用titleGroup方法,题目类容段落处理
String[] titleSplit = titleGroup(++number, ques);
//按照顺序写入文档
for (int i = 0 ; i < titleSplit.length ; i++ ) {
Matcher mather = compile.matcher(titleSplit[i]);//匹配是否是公式
if (!mather.find()){
//paragraph.add(titleSplit[i]);
paragraph.add(new Phrase(titleSplit[i]));//不是,直接写入
}else{//是,接着写入图片
//调用latexImage方法将公式转换成图片,wordLocalImage方法处理图片,图片生成
Image img = wordLocalImage(latexImage(titleSplit[i],"E:\\题库文档\\test06\\"+ i +".png"));
paragraph.add(new Phrase(new Chunk(img, 0, 0, true)));
}
}
document.add(paragraph);//题干段落结束

//选项段落
paragraph = new Paragraph();
paragraph.setSpacingAfter(8);  //段落距离
//四个选项 例:\[-\cfrac{1}{2}\]|||\[\cfrac{1}{4}\]|||1|||\[\cfrac{25}{4}\]  以|||截取出四个选项
String[] split = ques.getOptions().split("\\|\\|\\|");
for (int i = 0 ; i < split.length ; i++ ) {
if (split[i].contains("http")){//判断选项是否是图片
//调用wordHttpImage方法,图片读取
Image img = wordHttpImage(chooseUrl(i,split));
//调用chooseTag方法,选择题标签文本添加
paragraph.add(chooseTag(i));
//文本带图片写入
paragraph.add(new Phrase(new Chunk(img, 0, 0, true)));
}else{//不是
//调用latexIamge方法,图片生成
Image img = wordLocalImage(latexImage(split[i],"E:\\题库文档\\test06\\"+ i +".png"));
//选择题标签文本添加
paragraph.add(chooseTag(i));
//文本带图片
paragraph.add(new Phrase(new Chunk(img,0,0,true)));
}
}
//添加选择题段落
document.add(paragraph);

//详解类容
paragraph = new Paragraph();
paragraph.setSpacingAfter(8);
//调用analysisSplit方法,题目类容段落
String[] analysisSplit = analysisGroup(ques);
//按照顺序写入文档
for (int i = 0 ; i < analysisSplit.length ; i++ ) {
Matcher mather = compile.matcher(analysisSplit[i]);
if (mather.find()){
//图片生成
Image img = wordLocalImage(latexImage(analysisSplit[i],"E:\\题库文档\\test06\\"+ i +".png"));
paragraph.add(new Phrase(new Chunk(img,0, 0, true)));
}else{
paragraph.add(new Phrase(analysisSplit[i]));
}
}
document.add(paragraph);
paragraph = new Paragraph();
}
// 关闭document
document.close();

}
}
/**
* 文档生成开始配置
* */
private Document wordStart(String wordTitle,String wordUrl) throws Exception {
// 创建word文档,并设置纸张的大小
Document document = new Document(PageSize.A4);
RtfWriter2.getInstance(document, new FileOutputStream(wordUrl));
// 打开document
document.open();
// 设置字体,字号,加粗,颜色
Font font = new Font(Font.NORMAL, 20, Font.BOLD, new Color(0, 0, 0));
// 设置新的段落,使其字体为font
Paragraph paragraph = new Paragraph(wordTitle, font);
// 设置段落居中,其中1为居中对齐,2为右对齐,3为左对齐
paragraph.setAlignment(1);
// 文档中加入该段落
document.add(paragraph);
//调用系统的“楷体”字体,设置该段落时楷体
//BaseFont bf = BaseFont.createFont("C:\\Windows\\Fonts\\simli.ttf",       BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
//font = new Font(bf, 16, Font.NORMAL, new Color(0, 0, 0));
return document;
}
/**
* 题干类容段落处理
* */
private String[] titleGroup(Integer number,Ques ques){
String title = number + "." + ques.getTitle();
//公式处理\[(\cfrac{x-y}{x+y}-\cfrac{x+y}{x-y})\div \cfrac{2x}{{{x}^{2}}y-{{y}^{3}}}\] 将\cfrac转换成\\,否者后面\cfrac转换成mathml其实转换的事cfrac,报错
title = title.replaceAll("\\\\","\\\\\\\\");
//\[  \]  latex其实是没有的,为了转换公式不出错需要去掉,把整个公式替换成@@@,再把去掉\[ \]的然后以@@@截取后,就是  文字-公式-文字-公式的数组形式,最后依次写入文档
String titleNot = title.replaceAll("\\\\\\\\\\[(.*?)\\\\\\\\\\]","@@@");
Matcher mather = pattern.matcher(title);
while (mather.find()){
String formula = mather.group(1);
titleNot = titleNot.replaceFirst("@@@", "@@"+formula+"@@");
}
String[] titleSplit = titleNot.split("@@");
return titleSplit;
}
/**
* latex公式转图片
* */
private String latexImage(String formulaStr,String path) throws IOException, BadElementException {
TeXFormula tf = new TeXFormula(formulaStr);
TeXIcon ti = tf.createTeXIcon(TeXConstants.STYLE_DISPLAY, 40);
BufferedImage bimg = new BufferedImage(ti.getIconWidth(), ti.getIconHeight(), BufferedImage.TYPE_4BYTE_ABGR);
Graphics2D g2d = bimg.createGraphics();
g2d.setColor(Color.white);
g2d.fillRect(0,0,ti.getIconWidth(),ti.getIconHeight());
JLabel jl = new JLabel();
jl.setForeground(new Color(0, 0, 0));
ti.paintIcon(jl, g2d, 0, 0);
File out = new File(path);
ImageIO.write(bimg, "png", out);
return path;
}
/**
* 文档线下图片获取
* */
private Image wordLocalImage(String imageUrl) throws Exception{
//声明图片
Image img = Image.getInstance(imageUrl);
//绝对大小设置
//img.scaleAbsolute(img.getWidth()/3,img.getHeight()/3);
//比例大小
img.scalePercent(30,30);
//图片位置坐标
img.setAbsolutePosition(0, 0);
//图片位置靠左并且文字绕图形显示| Image.TEXTWRAP ,图片背景Image.UNDERLYING
img.setAlignment(Image.LEFT | Image.TEXTWRAP);
return img;
}
/**
* 文档线上图片获取
* */
private Image wordHttpImage(String imageUrl) throws Exception{
//声明图片
Image img = Image.getInstance(new URL(imageUrl));
//img.scaleAbsolute(img.getWidth()/3, img.getHeight()/3);
img.scalePercent(50,50);
img.setAbsolutePosition(0, 0);
img.setAlignment(Image.BOTTOM | Image.TEXTWRAP);
return img;
}
/**
* 获取选择题选项标签
* */
private Phrase chooseTag(Integer i){
Phrase phrase = null;
if (i == 0){
phrase = new Phrase("A:");
}else if(i == 1){
phrase = new Phrase("        B:");
}else if(i == 2){
phrase = new Phrase("        C:");
}else{
phrase = new Phrase("        D:");
}
return phrase;
}
/**
* 详解类容段落处理
* */
private String[] analysisGroup(Ques ques){
String analysis = ques.getAnalysis();
//公式处理
analysis = analysis.replaceAll("\\\\","\\\\\\\\");

String analysisNot = analysis.replaceAll("\\\\\\\\\\[(.*?)\\\\\\\\\\]","@@@");
Matcher mather = pattern.matcher(analysis);
while (mather.find()){
String formula = mather.group(1);
analysisNot = analysisNot.replaceFirst("@@@", "@@"+formula+"@@");
}
String[] analysisSplit = analysisNot.split("@@");
return analysisSplit;
}


}

到此 : Itext生成的数学试卷文档结束

补充说明 : 如果是poi生成可编辑公式的数学试卷,将latex生成mathml公式写入文档的时候,博主用了很多latex转mathml的方法,但是没有找到一个是完善的,比如 如果是复杂的有关圆的公式都是转换不了的,解决办法 : 把latex转mathml失败的公式都把latex转图片写入到文档,这样呈现出可编辑公式和图片公式共存的文档.

如果在操作中遇到什么问题,可留言,博主会及时回答,给你意见及解决的办法,博客写得不好的地方,希望谅解!

如果需要POI生成数学试卷的方式,请关注博主,后续会更新.

如果觉得此博客对你有所帮助请打赏博主一元,微信扫码,无需加友,谢谢!

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: