浏览代码

修改试卷解析代码

4228306 5 年之前
父节点
当前提交
9ef20e7a39

二进制
doc/fast6to7.docx


二进制
doc/fast6to7_knowledge.xlsx


+ 7 - 0
doc/op.sql

@@ -0,0 +1,7 @@
+delete from paper where id = 2;
+
+delete from question_option where qid in (select id from question where pid =2);
+
+delete from question where pid = 2;
+
+delete from ability_score where pid = 2;

二进制
doc/topic_picture.docx


二进制
image/aaa.emf


二进制
image/bbb.emf


+ 21 - 0
pom.xml

@@ -146,6 +146,27 @@
             <artifactId>minio</artifactId>
             <version>6.0.11</version>
         </dependency>
+        <!-- https://mvnrepository.com/artifact/org.freehep/freehep-graphicsio -->
+<!--        <dependency>-->
+<!--            <groupId>org.freehep</groupId>-->
+<!--            <artifactId>freehep-graphicsio</artifactId>-->
+<!--            <version>2.4</version>-->
+<!--        </dependency>-->
+        <!-- https://mvnrepository.com/artifact/org.freehep/freehep-graphicsio-emf -->
+        <dependency>
+            <groupId>org.freehep</groupId>
+            <artifactId>freehep-graphicsio-emf</artifactId>
+            <version>2.4</version>
+            <scope>test</scope>
+        </dependency>
+        <!-- https://mvnrepository.com/artifact/org.freehep/freehep-graphicsio-svg -->
+        <dependency>
+            <groupId>org.freehep</groupId>
+            <artifactId>freehep-graphicsio-svg</artifactId>
+            <version>2.4</version>
+            <scope>test</scope>
+        </dependency>
+
     </dependencies>
 
     <build>

+ 11 - 2
src/main/java/edu/math/diagnosis/config/Constants.java

@@ -23,8 +23,8 @@ public class Constants {
     public static final String TOPIC_QUESTION_TYPE = "题目类型";
 
     public static final int OPTION_NUMS = 5;
-    public static final int DEFAULT_HEIGHT = 300;
-    public static final int DEFAULT_WIDTH = 400;
+    public static final int DEFAULT_HEIGHT = 150;
+    public static final int DEFAULT_WIDTH = 200;
     public static final int MIN_HEIGHT = 150;
     public static final int MIN_WIDTH = 200;
     public static final int MAX_HEIGHT = 600;
@@ -98,4 +98,13 @@ public class Constants {
     public static final String OLD_PASS = "YX_OLD_PASS";
     public static final String NEW_PASS = "YX_NEW_PASS";
     public static final String DEFAULT_PASSWORD = "Admin123";
+
+    public static final String PICTURE_SIZE_SMALL = "Small";
+    public static final String PICTURE_SIZE_MIDDLE = "Middle";
+    public static final String PICTURE_SIZE_LARGE = "Large";
+
+    public static final int PICTURE_SMALL_SIZE = 200;
+    public static final int PICTURE_MIDDLE_SIZE = 400;
+    public static final int PICTURE_LARGE_SIZE = 800;
+
 }

+ 3 - 2
src/main/java/edu/math/diagnosis/controller/PaperController.java

@@ -79,8 +79,9 @@ public class PaperController {
     //    @PreAuthorize("hasRole('ROLE_ADMIN')")
     @ApiOperation(value = "上传试卷")
     @PostMapping("uploadPaper")
-    @ApiImplicitParam(name = "templateId", value = "试卷模板Id 默认1")
-    public Result uploadPaper(PaperVo paperVo, @RequestParam(defaultValue = "1") Long paperTemplateId,
+    @ApiImplicitParam(name = "paperTemplateId", value = "试卷模板Id 默认1")
+    public Result uploadPaper(PaperVo paperVo,
+                              @RequestParam(defaultValue = "1") Long paperTemplateId,
                               @RequestBody MultipartFile file) throws IOException {
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         FileCopyUtils.copy(file.getInputStream(), baos);

+ 12 - 0
src/main/java/edu/math/diagnosis/entity/PaperTemplate.java

@@ -48,6 +48,10 @@ public class PaperTemplate {
     @ApiModelProperty("选项正则匹配 默认为 ^[A-Z]\\.(.*) 匹配A. B. 直到 Z.")
     private String optionPattern;
 
+    @Column
+    @ApiModelProperty("图片正则匹配 默认为 #(Small|small|Middle|middle|Large|large)#")
+    private String picturePattern;
+
     @Column(nullable = false)
     @ApiModelProperty("答案 #Ans#")
     private String answer;
@@ -144,6 +148,14 @@ public class PaperTemplate {
         this.optionPattern = optionPattern;
     }
 
+    public String getPicturePattern() {
+        return picturePattern;
+    }
+
+    public void setPicturePattern(String picturePattern) {
+        this.picturePattern = picturePattern;
+    }
+
     public String getAnswer() {
         return answer;
     }

+ 10 - 0
src/main/java/edu/math/diagnosis/entity/Section.java

@@ -27,6 +27,8 @@ public class Section {
     @Column(nullable = false, columnDefinition = " int default 20")
     @ApiModelProperty("模块时间,默认20分钟")
     private Integer duration;
+    @Column(nullable = false,columnDefinition = " bit(1) default 0")
+    private Boolean hasMaterial;
     @Lob
     @Column
     @ApiModelProperty("背景材料")
@@ -79,6 +81,14 @@ public class Section {
         this.duration = duration;
     }
 
+    public Boolean getHasMaterial() {
+        return hasMaterial;
+    }
+
+    public void setHasMaterial(Boolean hasMaterial) {
+        this.hasMaterial = hasMaterial;
+    }
+
     public String getMaterial() {
         return material;
     }

+ 6 - 5
src/main/java/edu/math/diagnosis/model/PaperVo.java

@@ -14,7 +14,8 @@ public class PaperVo {
     private String sectionDurations;
     @ApiModelProperty("各模块休息时间,以','隔开,单位为分钟 2,2,2")
     private String sectionRests;
-    private String remark;
+    @ApiModelProperty("说明Id 1")
+    private Long remarkId;
     @ApiModelProperty("试卷类型Id 1")
     private Long typeId;
     @ApiModelProperty("科目类别Id 2")
@@ -60,12 +61,12 @@ public class PaperVo {
         this.sectionRests = sectionRests;
     }
 
-    public String getRemark() {
-        return remark;
+    public Long getRemarkId() {
+        return remarkId;
     }
 
-    public void setRemark(String remark) {
-        this.remark = remark;
+    public void setRemarkId(Long remarkId) {
+        this.remarkId = remarkId;
     }
 
     public Long getTypeId() {

+ 16 - 5
src/main/java/edu/math/diagnosis/service/PaperService.java

@@ -4,6 +4,7 @@ import edu.math.diagnosis.config.Constants;
 import edu.math.diagnosis.dao.OptionRepo;
 import edu.math.diagnosis.dao.PaperRepo;
 import edu.math.diagnosis.dao.QuestionRepo;
+import edu.math.diagnosis.dao.RemarkTemplateRepo;
 import edu.math.diagnosis.entity.*;
 import edu.math.diagnosis.model.PaperVo;
 import edu.math.diagnosis.model.Result;
@@ -55,6 +56,10 @@ public class PaperService {
 
     @Resource
     private PaperTemplateService paperTemplateService;
+
+    @Resource
+    private RemarkTemplateRepo remarkTemplateRepo;
+
     @Resource
     private WordService wordService;
 
@@ -222,6 +227,7 @@ public class PaperService {
     @Transactional(rollbackFor = Exception.class)
     public Result uploadPaper(PaperVo paperVo, Long templateId, String url, byte[] data) {
         Paper paper = init(paperVo, url);
+        paper.setRemark(remarkTemplateRepo.getOne(paperVo.getRemarkId()).getRemark());
         XWPFDocument document = WordUtil.open(data);
         PaperTemplate template = paperTemplateService.getOrDefault(templateId);
         if (template == null) {
@@ -244,9 +250,10 @@ public class PaperService {
         //TODO use parallel
 //        Result<Paper> paperResult = add(paper);
         return addWithQuestion(paper);
+//        return Result.ok(paper);
     }
 
-    private Map<String, List<XWPFParagraph>> initSections(Paper paper, String sectionPattern, String questionPattern, List<XWPFParagraph> paragraphs) {
+    private Map<String, List<XWPFParagraph>> initSections(Paper paper, String sectionPattern, String questionPattern, String picturePattern, List<XWPFParagraph> paragraphs) {
         //保证顺序
         Map<String, List<XWPFParagraph>> sections = new LinkedHashMap<>();
         String tag = "";
@@ -285,7 +292,7 @@ public class PaperService {
             //Session后面可能有背景材料,背景材料里面可能有图片和公式,这个放后面来处理
             if (betweenSectionAndQuestion) {
                 //解析背景材料的图片和公式
-                wordService.parsePicture(paragraph);
+                wordService.parsePicture(paragraph, picturePattern);
                 hasFormula = wordService.parseFormula(paragraph);
                 material.append("<p>").append(paragraph.getText()).append("</p>");
             }
@@ -304,13 +311,14 @@ public class PaperService {
     private void parsePaper(Paper paper, PaperTemplate template, XWPFDocument document) {
         String tagPattern = template.getSection();
         String questionPattern = template.getQuestion();
+        String picturePattern = template.getPicturePattern();
         List<XWPFParagraph> paragraphs = document.getParagraphs();
         Assert.notEmpty(paragraphs, "未检测到段落,请检查上传的文档");
         String name = paragraphs.get(0).getText();
         //TODO check name of paper
         parsePaperName(paper, name, template);
-        //获取模块
-        Map<String, List<XWPFParagraph>> sections = initSections(paper, tagPattern, questionPattern, paragraphs);
+        //获取模块,根据模块,给段落分组
+        Map<String, List<XWPFParagraph>> sections = initSections(paper, tagPattern, questionPattern, picturePattern, paragraphs);
         Assert.notEmpty(sections, "未检测到模块,请检查上传的文档");
 //        List<String> topics = paperTemplateService.getTopic(template);
         Map<String, String> topic = paperTemplateService.getMapTopic(template);
@@ -328,6 +336,7 @@ public class PaperService {
             List<XWPFParagraph> ps = sections.get(s);
 //            Section current = ss.stream().filter(section -> s.contains(section.getNumber().toString())).findFirst().orElse(null);
             Section current = sectionMap.get(s);
+            //根据题目标签,给题目分组
             Map<String, List<XWPFParagraph>> questions = initQuestions(current, questionPattern, ps);
             current.setStartNumber(currentNumber);
             List<Question> list = parseQuestions(questions, current, template, topic, abilities);
@@ -389,10 +398,11 @@ public class PaperService {
                 continue;
             }
             //下一个question
+            // questionPattern ^#[A-Z]#(.*)
             if (text.matches(questionPattern)) {
                 tag = text;
             }
-            logger.info("current tag is {},current text is {}", tag, text);
+            logger.info("initQuestions,current tag is {},current text is {}", tag, text);
             List<XWPFParagraph> list = questions.getOrDefault(tag, new ArrayList<>());
             list.add(paragraph);
             questions.put(tag, list);
@@ -413,6 +423,7 @@ public class PaperService {
         Section section = new Section();
         section.setStartNumber(Constants.DEFAULT_SECTION_START_NUMBER);
         section.setNumber(number);
+        section.setHasMaterial(StringUtils.isNotBlank(material));
         section.setMaterial(material);
         section.setDuration(Constants.DEFAULT_SECTION_DURATION);
         section.setRest(Constants.DEFAULT_SECTION_REST);

+ 79 - 38
src/main/java/edu/math/diagnosis/word/WordService.java

@@ -25,6 +25,8 @@ import javax.imageio.ImageIO;
 import java.awt.image.BufferedImage;
 import java.io.ByteArrayInputStream;
 import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
 @Service
@@ -64,7 +66,7 @@ public class WordService {
         logger.info("parsing question,pid={},section={},number={}", q.getPid(), q.getSection(), q.getNumber());
         Map<String, List<XWPFParagraph>> group = initGroup(ps, topic, template);
         //此次是否还需再处理一下?
-        parseQuestion(q, group.get(topic.get(Constants.TOPIC_QUESTION)), template.getOptionPattern());
+        parseQuestion(q, group.get(topic.get(Constants.TOPIC_QUESTION)), template.getOptionPattern(), template.getPicturePattern());
         parseAnswer(q, group.get(topic.get(Constants.TOPIC_ANSWER)));
         parseTag(q, group.get(topic.get(Constants.TOPIC_TAG)));
         parseAbility(q, group.get(topic.get(Constants.TOPIC_ABILITY)), abilities);
@@ -75,7 +77,7 @@ public class WordService {
     private void parseQuestion(Question q, Map<String, List<XWPFParagraph>> group) {
         logger.info("parsing question,pid={},section={},number={}", q.getPid(), q.getSection(), q.getNumber());
         String[] a = {"A1", "A2", "A3", "A4", "A5"};
-        parseQuestion(q, group.get(Constants.TOPIC_QUESTION), "^[A-Z]\\.(.*)");
+        parseQuestion(q, group.get(Constants.TOPIC_QUESTION), "^[A-Z]\\.(.*)", "^#(Small|Middle|Large)#");
         parseAnswer(q, group.get(Constants.TOPIC_ANSWER));
         parseTag(q, group.get(Constants.TOPIC_TAG));
         parseAbility(q, group.get(Constants.TOPIC_ABILITY), Arrays.asList(a));
@@ -84,29 +86,31 @@ public class WordService {
         logger.info("parse question finish,pid={},section={},number={}", q.getPid(), q.getSection(), q.getNumber());
     }
 
-    private void parseQuestion(Question question, List<XWPFParagraph> ps, String optionPattern) {
+    private void parseQuestion(Question question, List<XWPFParagraph> ps, String optionPattern, String picturePattern) {
         List<QuestionOption> options = new ArrayList<>();
         int i = 0;
         StringBuilder content = new StringBuilder();
         boolean hasFormula = false;
         for (XWPFParagraph p : ps) {
-            parsePicture(p);
+            parsePicture(p, picturePattern);
             //TODO 图片丢失
             hasFormula = parseFormula(p);
             String text = p.getText();
+            //清除掉#Small#
+            text = text.replaceAll(picturePattern, "");
             if (text.matches(optionPattern)) {
                 //匹配到选项,至少有2个字符
                 QuestionOption option = initOption(i++, text);
-                String optionNoContent = String.format("题号为%s的题目选项 %s 未检测到内容,题目内容为“%s”,请检查", question.getNumber(), text.charAt(0), content);
+                String optionNoContent = String.format("parseQuestion,题号为%s的题目选项 %s 未检测到内容,题目内容为“%s”,请检查", question.getNumber(), text.charAt(0), content);
                 Assert.hasText(option.getContent(), optionNoContent);
                 options.add(option);
             } else {
                 content.append("<p>").append(text).append("</p>");
             }
         }
-        String noContent = String.format("题号为 %s 的题目未检测到题干,题目内容为 “%s” ,请检查", question.getNumber(), content);
-        String noOptions = String.format("题号为 %s 的题目未检测到选项,题目内容为 “%s” ,请检查", question.getNumber(), content);
-        String lostOptions = String.format("题号为 %s 的题目检测到选项数量为 %s ,题目内容为 “%s” ,请检查", question.getNumber(), options.size(), content);
+        String noContent = String.format("parseQuestion,题号为 %s 的题目未检测到题干,题目内容为 “%s” ,请检查", question.getNumber(), content);
+        String noOptions = String.format("parseQuestion,题号为 %s 的题目未检测到选项,题目内容为 “%s” ,请检查", question.getNumber(), content);
+        String lostOptions = String.format("parseQuestion,题号为 %s 的题目检测到选项数量为 %s ,题目内容为 “%s” ,请检查", question.getNumber(), options.size(), content);
         Assert.hasText(content.toString(), noContent);
         Assert.notEmpty(options, noOptions);
         //TODO 选项数量可能不止5个?
@@ -145,11 +149,12 @@ public class WordService {
         Map<String, Double> json = new HashMap<>();
         //先手动设置1分
         //TODO 优化魔法值
-        json.put("A0", 1d);
-        AbilityScore a0 = new AbilityScore("A0", "", 2L, question.getPid(), 0L, 0d);
-        list.add(a0);
+//        json.put("A0", 1d);
+//        AbilityScore a0 = new AbilityScore("A0", "", 2L, question.getPid(), 0L, 0d);
+//        list.add(a0);
         for (XWPFParagraph p : ps) {
             String text = p.getText();
+            logger.info("parseAbility,section {} ,question number={},ability {} ", question.getSection(), question.getNumber(), text);
             String[] ss = text.split("=");
             String abilityCode = ss[0];
             double score = Double.parseDouble(ss[1]);
@@ -219,7 +224,13 @@ public class WordService {
             if (WordUtil.notContent(p, text)) {
                 continue;
             }
-            //如果是标签,继续循环
+            //如果是选项标签或者是图片标签
+            if (text.matches(template.getOptionPattern()) || text.matches(template.getPicturePattern())) {
+                List<XWPFParagraph> ps = map.get(template.getQuestion());
+                ps.add(p);
+                continue;
+            }
+            //如果是其他标签
             if (text.startsWith(template.getPrefix()) && text.endsWith(template.getSuffix())) {
                 tag = text;
                 continue;
@@ -229,7 +240,7 @@ public class WordService {
                 //把标签设置成问题标签
                 tag = template.getQuestion();
             }
-            logger.info("init Group, current Tag is {},current Text is {}", tag, text);
+            logger.info("initGroup, current Tag is {},current Text is {}", tag, text);
             List<XWPFParagraph> ps = map.get(tag);
             //标签不对
             if (ps == null) {
@@ -244,8 +255,8 @@ public class WordService {
     private QuestionOption initOption(int index, String content) {
         QuestionOption option = new QuestionOption();
         option.setOindex(index);
-        //去掉选项中的A.
-        option.setContent(content.substring(2));
+        //去掉选项中的#A#
+        option.setContent(content.substring(3));
         option.setCreatetime(new Date());
         option.setCorrect(false);
         return option;
@@ -255,9 +266,16 @@ public class WordService {
         return text.matches("^[A-Z]、(.*)");
     }
 
-    public void parsePicture(XWPFParagraph p) {
+    public void parsePicture(XWPFParagraph p, String picturePattern) {
         String text = p.getText();
-        logger.info("before parse run: " + text);
+        Matcher matcher = Pattern.compile(picturePattern).matcher(text);
+        if (!matcher.find()) {
+            logger.info("parsePicture,before parse run ,no picture: {}", text);
+            return;
+        }
+        String size = matcher.group().replaceAll("#", "");
+
+        logger.info("parsePicture,before parse run: " + text);
         List<XWPFRun> runs = p.getRuns();
         int i = 0;
         Map<Integer, String> insert = new HashMap<>();
@@ -265,31 +283,18 @@ public class WordService {
             List<XWPFPicture> pictures = run.getEmbeddedPictures();
             logger.debug("run pos " + (i++) + " embed picture size " + pictures.size());
 //            String img = "<img src=\"%s\" style=\"width: %spt;height: %spt\" />";
-            String img = "<img src=\"%s\" style=\"max-width: %spx\" />";
+            //图片水平居中
+            String img = "<p style=\"text-align:center\"><img src=\"%s\" style=\"max-width: %spx;center\" /></p>";
             if (CommonUtil.notEmpty(pictures)) {
+                //只处理第一张图片
                 XWPFPicture pp = pictures.get(0);
                 String pName = pp.getPictureData().getFileName();
                 //想办法加上长跟宽
                 String suffix = pName.substring(pName.lastIndexOf("."));
                 String saveName = CommonUtil.randomUUID() + suffix;
                 byte[] pData = pp.getPictureData().getData();
-                //给个默认长宽,因为有时图片会识别不到长宽
-                int width = Constants.DEFAULT_WIDTH, height = Constants.DEFAULT_HEIGHT;
-                try {
-                    BufferedImage image = ImageIO.read(new ByteArrayInputStream(pData));
-                    width = Math.min(image.getWidth(), Constants.MAX_WIDTH);
-                    //设置临界值
-//                    width = setBound(width, Constants.MIN_WIDTH, Constants.MAX_WIDTH);
-//                    if(width > Constants.MAX_WIDTH){
-//                        width = Constants.MAX_WIDTH;
-//                    }
-//                    height = image.getHeight();
-                    //设置临界值
-//                    height = setBound(height, Constants.MIN_HEIGHT, Constants.MAX_HEIGHT);
-                    logger.info("picture des is {},width is {},height is {}", pName, width, height);
-                } catch (Exception e) {
-                    logger.error("can't get width and height from picture, picture des is {},error message is {}", pName, e.getMessage());
-                }
+                int width = getWidth(pData);
+                width = setWidth(size, width);
                 //上传照片到阿里云,后续考虑不上传,存储到本地
 //                String url = aliyunFileService.putFile(pData, pName);
 //                String url = fileService.upload(pData, UploadProperties.IMAGE_PATH, saveName);
@@ -298,18 +303,54 @@ public class WordService {
 //                String url = "temp url";
 
                 insert.put(i, String.format(img, url, width));
-                logger.debug("picture url is {}, des is {} ", url, pp.getDescription());
+                logger.info("picture url is {}, des is {} ", url, pp.getDescription());
             }
         }
         insert.forEach((k, v) -> {
             XWPFRun r = p.insertNewRun(k);
             r.setText(v);
         });
-        logger.debug("after parse run: " + p.getText());
+
+        logger.info("after parse run: " + p.getText());
+    }
+
+    private int setWidth(String size, int width) {
+        switch (size) {
+            case Constants.PICTURE_SIZE_SMALL:
+                width = setBound(width, 0, Constants.PICTURE_SMALL_SIZE);
+                break;
+            case Constants.PICTURE_SIZE_MIDDLE:
+                width = setBound(width, 0, Constants.PICTURE_MIDDLE_SIZE);
+                break;
+            case Constants.PICTURE_SIZE_LARGE:
+                width = setBound(width, 0, Constants.PICTURE_LARGE_SIZE);
+        }
+        return width;
+    }
+
+    private int getWidth(byte[] pData) {
+        //给个默认长宽,因为有时图片会识别不到长宽
+        int width = Constants.DEFAULT_WIDTH, height = Constants.DEFAULT_HEIGHT;
+        try {
+            BufferedImage image = ImageIO.read(new ByteArrayInputStream(pData));
+            width = Math.min(image.getWidth(), Constants.MAX_WIDTH);
+            //设置临界值
+//                    width = setBound(width, Constants.MIN_WIDTH, Constants.MAX_WIDTH);
+//                    if(width > Constants.MAX_WIDTH){
+//                        width = Constants.MAX_WIDTH;
+//                    }
+//                    height = image.getHeight();
+            //设置临界值
+//                    height = setBound(height, Constants.MIN_HEIGHT, Constants.MAX_HEIGHT);
+            logger.info("picture width is {},height is {}", width, height);
+        } catch (Exception e) {
+            logger.error("can't get width and height from picture, picture error message is {}", e.getMessage());
+        }
+        return width;
     }
 
     private int setBound(int bound, int min, int max) {
-        return bound < min ? min : (bound > max ? max : bound);
+        return bound < min ? min : (Math.min(bound, max));
     }
 
     public boolean parseFormula(XWPFParagraph p) {

+ 18 - 5
src/main/java/edu/math/diagnosis/word/WordUtil.java

@@ -135,15 +135,28 @@ public class WordUtil {
         }
     }
 
-    public static boolean notContent(XWPFParagraph paragraph, String text) {
-        boolean notPicture = true;
+    public static boolean hasContent(XWPFParagraph paragraph, String text) {
+        if (StringUtils.isNotBlank(text)) {
+            return true;
+        }
         for (XWPFRun run : paragraph.getRuns()) {
             if (run.getEmbeddedPictures().size() > 0) {
-                notPicture = false;
+                return true;
             }
         }
-        boolean notMathML = CommonUtil.isEmpty(paragraph.getCTP().getOMathList());
-        return StringUtils.isBlank(text) && notPicture && notMathML;
+        return paragraph.getCTP().getOMathList().size() > 0;
+    }
+
+    public static boolean notContent(XWPFParagraph paragraph, String text) {
+        return !hasContent(paragraph, text);
+//        boolean notPicture = true;
+//        for (XWPFRun run : paragraph.getRuns()) {
+//            if (run.getEmbeddedPictures().size() > 0) {
+//                notPicture = false;
+//            }
+//        }
+//        boolean notMathML = CommonUtil.isEmpty(paragraph.getCTP().getOMathList());
+//        return StringUtils.isBlank(text) && notPicture && notMathML;
     }
 
     /**

+ 2 - 2
src/main/resources/application.properties

@@ -5,8 +5,8 @@ logging.file=log/log.log
 #logging.pattern.file= %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
 
 spring.servlet.multipart.enabled=true
-spring.servlet.multipart.max-file-size=10MB
-spring.servlet.multipart.max-request-size=10MB
+spring.servlet.multipart.max-file-size=50MB
+spring.servlet.multipart.max-request-size=50MB
 server.servlet.session.timeout=36000
 
 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

+ 93 - 0
src/test/java/edu/math/diagnosis/service/EmfToSVG.java

@@ -0,0 +1,93 @@
+package edu.math.diagnosis.service;
+
+import org.freehep.graphicsbase.util.export.ExportFileType;
+import org.freehep.graphicsio.ImageConstants;
+import org.freehep.graphicsio.emf.EMFConverter;
+import org.freehep.graphicsio.emf.EMFInputStream;
+import org.freehep.graphicsio.emf.EMFPanel;
+import org.freehep.graphicsio.emf.EMFRenderer;
+import org.freehep.graphicsio.svg.SVGGraphics2D;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.List;
+import java.util.Properties;
+
+public class EmfToSVG extends EMFConverter {
+
+    public static void main(String[] args) {
+//        String[] file = new String[2];
+//        file[0] = "D:\\input.emf";
+//
+//        if (file == null || file.length == 0 || file[0] == null || file[0].length() == 0) {
+//            System.out.println("usage: EMF2SVG imput.emf [output.svg]");
+//            return;
+//        }
+//        export(ImageConstants.SVG, file[0], file.length > 1 ? file[1] : null);
+        export(ImageConstants.SVG,"image/aaa.emf","D:\\result.svg");
+    }
+
+    protected static void export(String type, String srcFileName, String destFileName) {
+        try {
+            List<ExportFileType> exportFileTypes = ExportFileType.getExportFileTypes(type);
+            if (exportFileTypes == null || exportFileTypes.size() == 0) {
+                System.out.println(
+                        type + " library is not available. check your classpath!");
+                return;
+            }
+
+            ExportFileType exportFileType = (ExportFileType) exportFileTypes.get(0);
+
+            // read the EMF file
+            EMFRenderer emfRenderer = new EMFRenderer(
+                    new EMFInputStream(
+                            new FileInputStream(srcFileName)));
+
+            // create the destFileName,
+            // replace or add the extension to the destFileName
+            if (destFileName == null || destFileName.length() == 0) {
+                // index of the beginning of the extension
+                int lastPointIndex = srcFileName.lastIndexOf(".");
+
+                // to be sure that the point separates an extension
+                // and is not part of a directory name
+                int lastSeparator1Index = srcFileName.lastIndexOf("/");
+                int lastSeparator2Index = srcFileName.lastIndexOf("\\");
+
+                if (lastSeparator1Index > lastPointIndex ||
+                        lastSeparator2Index > lastPointIndex) {
+                    destFileName = srcFileName + ".";
+                } else if (lastPointIndex > -1) {
+                    destFileName = srcFileName.substring(
+                            0, lastPointIndex + 1);
+                }
+
+                // add the extension
+                destFileName += type.toLowerCase();
+            }
+
+            // TODO there is no possibility to use Constants of base class!
+            /* create SVG properties*/
+            Properties p = new Properties();
+            p.put(SVGGraphics2D.EMBED_FONTS, Boolean.toString(false));
+            p.put(SVGGraphics2D.CLIP, Boolean.toString(true));
+            p.put(SVGGraphics2D.COMPRESS, Boolean.toString(false));
+            p.put(SVGGraphics2D.TEXT_AS_SHAPES, Boolean.toString(false));
+            p.put(SVGGraphics2D.FOR, "Freehep EMF2SVG");
+            p.put(SVGGraphics2D.TITLE, srcFileName);
+
+            EMFPanel emfPanel = new EMFPanel();
+            emfPanel.setRenderer(emfRenderer);
+
+            // TODO why uses this classes components?!
+            exportFileType.exportToFile(
+                    new File(destFileName),
+                    emfPanel,
+                    emfPanel,
+                    p,
+                    "Freehep EMF converter");
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}

+ 148 - 3
src/test/java/edu/math/diagnosis/service/WordServiceTest.java

@@ -1,10 +1,12 @@
 package edu.math.diagnosis.service;
 
+import edu.math.diagnosis.config.Constants;
 import edu.math.diagnosis.util.CommonUtil;
 import edu.math.diagnosis.word.WordUtil;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.poi.xwpf.usermodel.XWPFDocument;
 import org.apache.poi.xwpf.usermodel.XWPFParagraph;
+import org.apache.poi.xwpf.usermodel.XWPFPicture;
 import org.apache.poi.xwpf.usermodel.XWPFRun;
 import org.apache.xmlbeans.SchemaType;
 import org.apache.xmlbeans.XmlCursor;
@@ -12,18 +14,28 @@ import org.apache.xmlbeans.XmlObject;
 import org.apache.xmlbeans.impl.values.TypeStore;
 import org.apache.xmlbeans.impl.values.XmlAnyTypeImpl;
 import org.apache.xmlbeans.impl.values.XmlComplexContentImpl;
+import org.freehep.graphicsio.emf.EMF2SVG;
+import org.freehep.graphicsio.emf.EMFConverter;
+import org.freehep.graphicsio.emf.EMFInputStream;
+import org.freehep.graphicsio.emf.EMFRenderer;
 import org.junit.Test;
 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDrawing;
 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTP;
 import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTPicture;
 import org.openxmlformats.schemas.wordprocessingml.x2006.main.impl.CTRImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
+import javax.imageio.ImageIO;
+import javax.imageio.stream.ImageOutputStream;
+import javax.swing.*;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.*;
 import java.util.*;
+import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
@@ -31,6 +43,8 @@ import java.util.stream.Collectors;
 
 public class WordServiceTest {
 
+    private static final Logger logger = LoggerFactory.getLogger(WordServiceTest.class);
+
     @Test
     public void test() {
         String t = "A、你好啊";
@@ -210,4 +224,135 @@ public class WordServiceTest {
 //        });
 
     }
+
+    @Test
+    public void parsePicture() {
+        String pattern = "^#(Small|Middle|Large)#";
+        XWPFDocument document = WordUtil.open(new File("doc/topic_picture.docx"));
+        XWPFParagraph paragraph = document.getParagraphs().get(0);
+        String text = paragraph.getText();
+        Matcher matcher = Pattern.compile(pattern).matcher(text);
+        String size="";
+        if(matcher.find()){
+            logger.info(matcher.group());
+            size = matcher.group().replaceAll("#","");
+        }
+        System.out.println(paragraph.getText());
+        List<XWPFRun> runs = paragraph.getRuns();
+        int i = 0;
+        Map<Integer, String> insert = new HashMap<>();
+        for (XWPFRun run : runs) {
+            List<XWPFPicture> pictures = run.getEmbeddedPictures();
+            logger.debug("run pos " + (i++) + " embed picture size " + pictures.size());
+            if (CommonUtil.notEmpty(pictures)) {
+                XWPFPicture pp = pictures.get(0);
+                String pName = pp.getPictureData().getFileName();
+                logger.info("pName {}", pName);
+                byte[] pData = pp.getPictureData().getData();
+                try {
+                    BufferedImage image = ImageIO.read(new ByteArrayInputStream(pData));
+                    if (image != null) {
+                        logger.info("picture des is {},width is {},height is {}", pName, image.getWidth(), image.getHeight());
+                    }
+                } catch (Exception e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+    }
+
+
+    private int setBound(int bound, int min, int max) {
+        return bound < min ? min : (Math.min(bound, max));
+    }
+
+    @Test
+    public void boundTest(){
+        int width1 = 100;
+        int width2 = 200;
+        int width3 = 300;
+        int width4 = 500;
+        System.out.println(setWidth("Large",width1));
+        System.out.println(setWidth("Large",width2));
+        System.out.println(setWidth("Large",width3));
+        System.out.println(setWidth("Large",width4));
+        System.out.println(setWidth("Middle",width3));
+        System.out.println(setWidth("Small",width4));
+    }
+
+    private int setWidth(String size, int width) {
+        switch (size) {
+            case Constants.PICTURE_SIZE_SMALL:
+                width = setBound(width, 0, Constants.PICTURE_SMALL_SIZE);
+                break;
+            case Constants.PICTURE_SIZE_MIDDLE:
+                width = setBound(width, 0, Constants.PICTURE_MIDDLE_SIZE);
+                break;
+            case Constants.PICTURE_SIZE_LARGE:
+                width = setBound(width, 0, Constants.PICTURE_LARGE_SIZE);
+        }
+        return width;
+    }
+
+    @Test
+    public void optionTest(){
+        String pattern = "^#[A-Z]#(.*)";
+        System.out.println("#A#1234".matches(pattern));
+//        EMFConverter
+    }
+
+    @Test
+    public void testEmf() throws Exception{
+        EMFInputStream inputStream = new EMFInputStream(new FileInputStream("image/bbb.emf"),
+                EMFInputStream.DEFAULT_VERSION);
+        System.out.println("height = " + inputStream.readHeader().getBounds().getHeight());
+        System.out.println("width = " + inputStream.readHeader().getBounds().getWidth());
+//        EMFConverter
+        EMFRenderer emfRenderer = new EMFRenderer(inputStream);
+        final int width = (int)inputStream.readHeader().getBounds().getWidth();
+        final int height = (int)inputStream.readHeader().getBounds().getHeight();
+        System.out.println("width = " + width + " and height = " + height);
+        final BufferedImage result = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+        Graphics2D g2 = (Graphics2D)result.createGraphics();
+        emfRenderer.paint(g2);
+//        emfRenderer.drawImage(result,0,0,width,height);
+
+//        ByteArrayOutputStream  baos = new ByteArrayOutputStream();
+//创建ImageOutputStream流
+//        ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(baos);
+//将二进制数据写进ByteArrayOutputStream
+//        ImageIO.write(result, "png", imageOutputStream);
+        // write it as png/jpg/gif, up to you!!!
+        File outputfile = new File("D:\\result.png");
+        ImageIO.write(result, "png", outputfile);
+
+//        JPanel resultPanel = new JPanel() {
+//            /**
+//             *
+//             */
+//            private static final long serialVersionUID = 1L;
+//
+//            public void paintComponent(Graphics g) {
+//                super.paintChildren(g);
+//                Graphics2D g2 = (Graphics2D)g;
+//                g2.drawImage(result, 0, 0, width, height, null);
+//            }
+//        };
+//        JFrame ui = new JFrame("EMF Reader");
+//        ui.getContentPane().setLayout(new BorderLayout());
+//        ui.getContentPane().add(resultPanel, BorderLayout.CENTER);
+//        ui.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
+//        ui.setSize(new Dimension(width+20, height+40));
+//        ui.setVisible(true);
+//        System.in.read();
+    }
+
+    @Test
+    public void emfTest2() throws Exception{
+        EMFInputStream inputStream = new EMFInputStream(new FileInputStream("image/bbb.emf"),
+                EMFInputStream.DEFAULT_VERSION);
+        System.out.println("height = " + inputStream.readHeader().getBounds().getHeight());
+        System.out.println("width = " + inputStream.readHeader().getBounds().getWidth());
+        EMF2SVG.main(new String[]{"image/aaa.emf","D:\\result.svg"});
+    }
 }