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

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

扫描二维码关注公众号,回复: 451873 查看本文章


好,说了这么多,希望大家不要介意.现在切入正题: 先看下面的效果图


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生成数学试卷的方式,请关注博主,后续会更新.

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



猜你喜欢

转载自blog.csdn.net/qq_35834998/article/details/79170388