Selaa lähdekoodia

svg图片导出word报错

xiatian 2 kuukautta sitten
vanhempi
commit
4843724916

+ 5 - 0
examcloud-core-questions-base/pom.xml

@@ -12,6 +12,11 @@
     </parent>
 
     <dependencies>
+	    <dependency>
+			<groupId>org.w3c</groupId>
+			<artifactId>dom</artifactId>
+			<version>2.3.0-jaxb-1.0.6</version>
+		</dependency>
         <dependency>
             <groupId>cn.com.qmth.examcloud</groupId>
             <artifactId>examcloud-support</artifactId>

+ 185 - 137
examcloud-core-questions-service/src/main/java/cn/com/qmth/examcloud/core/questions/service/util/ExportPaperUtil.java

@@ -9,6 +9,7 @@ import java.io.StringWriter;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.ArrayList;
+import java.util.Base64;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -16,8 +17,9 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import javax.imageio.ImageIO;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
 
-import cn.com.qmth.examcloud.support.util.FileUtil;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang.StringEscapeUtils;
 import org.apache.commons.lang3.StringUtils;
@@ -45,17 +47,19 @@ import cn.com.qmth.examcloud.core.questions.dao.entity.Question;
 import cn.com.qmth.examcloud.core.questions.service.bean.dto.PaperDetailExp;
 import cn.com.qmth.examcloud.core.questions.service.bean.dto.PaperDetailUnitExp;
 import cn.com.qmth.examcloud.core.questions.service.bean.dto.PaperExp;
+import cn.com.qmth.examcloud.support.util.FileUtil;
 import freemarker.template.Configuration;
 import freemarker.template.Template;
 import sun.misc.BASE64Decoder;
 
+@SuppressWarnings("restriction")
 public class ExportPaperUtil {
 
     private static final Logger log = LoggerFactory.getLogger(ExportPaperUtil.class);
-    
-    private static final String docxBasePath=FileDisposeUtil.getDocxBasePath();
-    
-    private static final int docImageSzie=12700;
+
+    private static final String docxBasePath = FileDisposeUtil.getDocxBasePath();
+
+    private static final int docImageSzie = 12700;
 
     private static final String DOCX_SUFFIX = ".docx";
 
@@ -68,7 +72,7 @@ public class ExportPaperUtil {
     public static final String ELEMENT_TYPE_TEXT = "text";
 
     public static final String ELEMENT_TYPE_IMG = "image";
-    
+
     public static final String ELEMENT_TYPE_DOCTAG = "doctag";
 
     private static final String ENCODING = "UTF-8";
@@ -76,7 +80,7 @@ public class ExportPaperUtil {
     private static Configuration config;
 
     private static Template docSection;
-    
+
     private static Template examReamarkDocument;
 
     private static Template questionSection;
@@ -106,15 +110,16 @@ public class ExportPaperUtil {
             document = config.getTemplate("document.ftl", ENCODING);
             documentRel = config.getTemplate("document_rel.ftl", ENCODING);
             paperQuesOps = config.getTemplate("question_options.ftl", ENCODING);
-            docSection=config.getTemplate("doc_section.ftl", ENCODING);
-            examReamarkDocument=config.getTemplate("exam_reamark_document.ftl", ENCODING);
+            docSection = config.getTemplate("doc_section.ftl", ENCODING);
+            examReamarkDocument = config.getTemplate("exam_reamark_document.ftl", ENCODING);
         } catch (IOException e) {
             log.error(e.getMessage(), e);
         }
     }
-    //考试说明word文件
-    public static File createExamRemarkDocFile(File directory,String fileName,String html) throws IOException {
-     // doc固定源文件目录
+
+    // 考试说明word文件
+    public static File createExamRemarkDocFile(File directory, String fileName, String html) throws IOException {
+        // doc固定源文件目录
         File docxDir = new File(docxBasePath);
         // 将要生成的doc源文件目录
         File docxTargetDir = new File(directory.getAbsolutePath() + "/docx/");
@@ -134,9 +139,10 @@ public class ExportPaperUtil {
         FileUtils.deleteDirectory(docxTargetDir);
         return docfile;
     }
+
     private static void disposeExamRemark(File docxTargetDir, String html) throws IOException {
         ExportTempDataDto dto = new ExportTempDataDto();
-        List<JSection> slist=null;
+        List<JSection> slist = null;
         if (StringUtils.isNotBlank(html)) {
             slist = getSections(html);
             if (slist != null && slist.size() > 0) {
@@ -152,6 +158,7 @@ public class ExportPaperUtil {
         // image file
         writeImage(docxTargetDir, dto);
     }
+
     private static void writeExamRemarkDocument(File docxTargetDir, List<JSection> slist) throws IOException {
         StringWriter result = null;
         try {
@@ -165,6 +172,7 @@ public class ExportPaperUtil {
         File file = new File(docxTargetDir.getAbsolutePath() + "/word/document.xml");
         FileUtils.writeStringToFile(file, result.toString(), "utf-8");
     }
+
     // 考试试卷
     public static File createPaperDocFile(Long rootOrgId, PaperExp paperExp, File directory, String paperfileName,
             ExportTemplateType templateType) throws Exception {
@@ -204,7 +212,7 @@ public class ExportPaperUtil {
                 }
             }
         }
-        
+
         // header
         writePaperHeader(docxTargetDir, paperExp.getCourseName(), docxTemplate);
         // content-type
@@ -216,11 +224,11 @@ public class ExportPaperUtil {
         // image file
         writeImage(docxTargetDir, dto);
     }
-    
+
     private static void writePaperHeader(File docxTargetDir, String courseName, DocxTemplateBean docxTemplate)
             throws IOException {
-        Template head=docxTemplate.getHeader();
-        if(head==null) {
+        Template head = docxTemplate.getHeader();
+        if (head == null) {
             return;
         }
         Map<String, Object> map = new HashMap<String, Object>();
@@ -295,7 +303,7 @@ public class ExportPaperUtil {
     }
 
     // 原始试卷
-    public static File createOriginPaperDocFile(PaperExp paperExp, File directory) throws IOException{
+    public static File createOriginPaperDocFile(PaperExp paperExp, File directory) throws IOException {
         // doc固定源文件目录
         File docxDir = new File(docxBasePath);
         // 将要生成的doc源文件目录
@@ -319,7 +327,6 @@ public class ExportPaperUtil {
 
     }
 
-
     private static List<JSection> getSections(String html) {
         return getSections(html, false);
     }
@@ -349,13 +356,13 @@ public class ExportPaperUtil {
         return ss;
 
     }
-    
-    private static List<JSection> getEmptySections(){
-    	List<JSection> ss = new ArrayList<JSection>();
-    	JSection s = new JSection();
+
+    private static List<JSection> getEmptySections() {
+        List<JSection> ss = new ArrayList<JSection>();
+        JSection s = new JSection();
         List<SectionElement> ses = new ArrayList<SectionElement>();
         s.setElements(ses);
-        SectionElement se=new SectionElement();
+        SectionElement se = new SectionElement();
         se.setType(ELEMENT_TYPE_TEXT);
         se.setValue("");
         ses.add(se);
@@ -370,18 +377,19 @@ public class ExportPaperUtil {
             }
         } else {
             if (ce instanceof TextNode) {
-            	SectionElement se = new SectionElement();
+                SectionElement se = new SectionElement();
                 TextNode tn = (TextNode) ce;
                 se.setType(ELEMENT_TYPE_TEXT);
                 String text = tn.text();
                 if (diposeFillBlank) {
                     text = text.replaceAll("###", "______").replaceAll("##", "______");
                 }
-                text = text.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\u0000", " ");
+                text = text.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;")
+                        .replaceAll("\u0000", " ");
                 se.setValue(text);
                 ses.add(se);
             } else if (ce instanceof Element) {
-            	SectionElement se = new SectionElement();
+                SectionElement se = new SectionElement();
                 if ("img".equals(ce.nodeName())) {
                     se.setType(ELEMENT_TYPE_IMG);
                     se.setValue(ce.attr("src"));
@@ -403,29 +411,29 @@ public class ExportPaperUtil {
         int n = 0;
         String str = ce.attr("width");
         if (StringUtils.isNotBlank(str)) {
-        	String sizeStr = str.replace("px", "");
-        	if (StringUtils.isNotBlank(sizeStr)) {
-        		try {
-	        		return Integer.valueOf(sizeStr.trim()) * docImageSzie;
-	        	} catch (NumberFormatException e) {
-					log.warn("image width value is invalid");
-					return 0;
-				}
-        	}
+            String sizeStr = str.replace("px", "");
+            if (StringUtils.isNotBlank(sizeStr)) {
+                try {
+                    return Integer.valueOf(sizeStr.trim()) * docImageSzie;
+                } catch (NumberFormatException e) {
+                    log.warn("image width value is invalid");
+                    return 0;
+                }
+            }
         }
         String style = ce.attr("style");
         if (StringUtils.isNotBlank(style)) {
             Matcher m = widthRex.matcher(style);
             if (m.find()) {
-            	String size=m.group(1).trim();
-            	if(StringUtils.isNotBlank(size)) {
-            		try {
-	            		return Integer.valueOf(size) * docImageSzie;
-	            	} catch (NumberFormatException e) {
-						log.warn("image style width value is invalid");
-						return 0;
-					}
-            	}
+                String size = m.group(1).trim();
+                if (StringUtils.isNotBlank(size)) {
+                    try {
+                        return Integer.valueOf(size) * docImageSzie;
+                    } catch (NumberFormatException e) {
+                        log.warn("image style width value is invalid");
+                        return 0;
+                    }
+                }
             }
         }
         return n;
@@ -435,29 +443,29 @@ public class ExportPaperUtil {
         int n = 0;
         String str = ce.attr("height");
         if (StringUtils.isNotBlank(str)) {
-        	String sizeStr = str.replace("px", "");
-        	if (StringUtils.isNotBlank(sizeStr)) {
-        		try {
-					return Integer.valueOf(sizeStr.trim()) * docImageSzie;
-				} catch (NumberFormatException e) {
-					log.error("image height value is invalid");
-					return 0;
-				}
-        	}
+            String sizeStr = str.replace("px", "");
+            if (StringUtils.isNotBlank(sizeStr)) {
+                try {
+                    return Integer.valueOf(sizeStr.trim()) * docImageSzie;
+                } catch (NumberFormatException e) {
+                    log.error("image height value is invalid");
+                    return 0;
+                }
+            }
         }
         String style = ce.attr("style");
         if (StringUtils.isNotBlank(style)) {
             Matcher m = heightRex.matcher(style);
             if (m.find()) {
-            	String size=m.group(1).trim();
-            	if(StringUtils.isNotBlank(size)) {
-            		try {
-	            		return Integer.valueOf(size) * docImageSzie;
-	            	} catch (NumberFormatException e) {
-						log.error("image style height value is invalid");
-						return 0;
-					}
-            	}
+                String size = m.group(1).trim();
+                if (StringUtils.isNotBlank(size)) {
+                    try {
+                        return Integer.valueOf(size) * docImageSzie;
+                    } catch (NumberFormatException e) {
+                        log.error("image style height value is invalid");
+                        return 0;
+                    }
+                }
             }
         }
         return n;
@@ -492,13 +500,13 @@ public class ExportPaperUtil {
                     + se.getParam().getType());
             String src = se.getValue();
             if (src.contains("data:image")) {
-                //base64图片
-            	src = src.substring(src.indexOf(",") + 1);
+                // base64图片
+                src = src.substring(src.indexOf(",") + 1);
                 BASE64Decoder decoder = new BASE64Decoder();
                 byte[] bytes = decoder.decodeBuffer(src);
                 FileUtils.writeByteArrayToFile(file, bytes);
-            }else {
-                //网络图片URL
+            } else {
+                // 网络图片URL
                 FileUtil.saveUrlAs(src, file);
             }
         }
@@ -546,12 +554,12 @@ public class ExportPaperUtil {
 
     private static void disposeQuestion(Question qes, ExportTempDataDto dto) {
         if (qes != null) {
-            //处理题干
-            List<JSection> slist1 = getSections(qes.getQuesBody(),false);
-            if (slist1 == null||slist1.size()==0) {
-                slist1=new ArrayList<JSection>();
-                JSection sec=new JSection();
-                List<SectionElement> ses=new ArrayList<SectionElement>();
+            // 处理题干
+            List<JSection> slist1 = getSections(qes.getQuesBody(), false);
+            if (slist1 == null || slist1.size() == 0) {
+                slist1 = new ArrayList<JSection>();
+                JSection sec = new JSection();
+                List<SectionElement> ses = new ArrayList<SectionElement>();
                 sec.setElements(ses);
                 slist1.add(sec);
             }
@@ -565,7 +573,7 @@ public class ExportPaperUtil {
             htmlToDoc(slist1, dto);
             qes.setQuesBodyWord(getQuestionDoc(slist1));
 
-            //处理选项
+            // 处理选项
             if (qes.getQuesOptions() != null && qes.getQuesOptions().size() > 0) {
                 int index = 0;
                 for (QuesOption qo : qes.getQuesOptions()) {
@@ -582,13 +590,13 @@ public class ExportPaperUtil {
 
                 }
             }
-            
-            //处理答案
+
+            // 处理答案
             List<JSection> slist3 = getSections(qes.getQuesAnswer());
-            if (slist3 == null||slist3.size()==0) {
-                slist3=new ArrayList<JSection>();
-                JSection sec=new JSection();
-                List<SectionElement> ses=new ArrayList<SectionElement>();
+            if (slist3 == null || slist3.size() == 0) {
+                slist3 = new ArrayList<JSection>();
+                JSection sec = new JSection();
+                List<SectionElement> ses = new ArrayList<SectionElement>();
                 sec.setElements(ses);
                 slist3.add(sec);
             }
@@ -615,19 +623,19 @@ public class ExportPaperUtil {
                 paperExp.setExamRemarkWord(getSectionDoc(slist));
             }
         }
-        if(paperExp.getExamRemarkWord()==null) {
+        if (paperExp.getExamRemarkWord() == null) {
             paperExp.setExamRemarkWord("");
         }
     }
 
     private static void disposePaperQuestion(Question qes, ExportTempDataDto dto) {
         if (qes != null) {
-            //处理题干
-            List<JSection> slist1 = getSections(qes.getQuesBody(),true);
-            if (slist1 == null||slist1.size()==0) {
-                slist1=new ArrayList<JSection>();
-                JSection sec=new JSection();
-                List<SectionElement> ses=new ArrayList<SectionElement>();
+            // 处理题干
+            List<JSection> slist1 = getSections(qes.getQuesBody(), true);
+            if (slist1 == null || slist1.size() == 0) {
+                slist1 = new ArrayList<JSection>();
+                JSection sec = new JSection();
+                List<SectionElement> ses = new ArrayList<SectionElement>();
                 sec.setElements(ses);
                 slist1.add(sec);
             }
@@ -641,7 +649,7 @@ public class ExportPaperUtil {
             htmlToDoc(slist1, dto);
             qes.setQuesBodyWord(getQuestionDoc(slist1));
 
-            //处理选项
+            // 处理选项
             if (qes.getQuesOptions() != null && qes.getQuesOptions().size() > 0) {
                 int index = 0;
                 JOptionDto joDto = new JOptionDto();
@@ -664,14 +672,14 @@ public class ExportPaperUtil {
                 disposeQuesOptions(joDto);// 处理选项列数
                 qes.setQuesOptionsWord(getPaperQuestionDoc(joDto.getOptions()));
             }
-            
-            //处理答案
+
+            // 处理答案
             if (qes.getSubQuestions() == null || qes.getSubQuestions().size() == 0) {// 套题不加答案及序号
                 List<JSection> slist3 = getSections(qes.getQuesAnswer());
-                if (slist3 == null||slist3.size()==0) {
-                    slist3=new ArrayList<JSection>();
-                    JSection sec=new JSection();
-                    List<SectionElement> ses=new ArrayList<SectionElement>();
+                if (slist3 == null || slist3.size() == 0) {
+                    slist3 = new ArrayList<JSection>();
+                    JSection sec = new JSection();
+                    List<SectionElement> ses = new ArrayList<SectionElement>();
                     sec.setElements(ses);
                     slist3.add(sec);
                 }
@@ -683,7 +691,6 @@ public class ExportPaperUtil {
                 htmlToDoc(slist3, dto);
                 qes.setQuesAnswerWord(getQuestionDoc(slist3));
             }
-            
 
             if (qes.getSubQuestions() != null && qes.getSubQuestions().size() > 0) {
                 for (Question sunqes : qes.getSubQuestions()) {
@@ -765,18 +772,20 @@ public class ExportPaperUtil {
             }
         }
     }
+
     private static String getImageType(String src) {
-    	if(src.contains("data:image")) {
-    		return src.substring(11, src.indexOf(";"));
-    	}else {
-    		try {
-				URL url=new URL(src);
-				return url.getPath().substring(url.getPath().lastIndexOf(".")+1);
-			} catch (MalformedURLException e) {
-				throw new StatusException("1000", "图片链接格式错误:"+src);
-			}
-    	}
+        if (src.contains("data:image")) {
+            return src.substring(11, src.indexOf(";"));
+        } else {
+            try {
+                URL url = new URL(src);
+                return url.getPath().substring(url.getPath().lastIndexOf(".") + 1);
+            } catch (MalformedURLException e) {
+                throw new StatusException("1000", "图片链接格式错误:" + src);
+            }
+        }
     }
+
     private static String getSectionDoc(List<JSection> sections) {
         Map<String, Object> map = new HashMap<String, Object>();
         map.put("sections", sections);
@@ -815,40 +824,79 @@ public class ExportPaperUtil {
             throw new ExamCloudRuntimeException(e);
         }
     }
-    
-    
-    private static void setImageSize(SectionElement imageEle,Node ce) {
-    	int width=getWidth(ce);
-    	int height=getHeight(ce);
-    	if(width<100||height<100) {
-    		String base64=imageEle.getValue();
-    		if (base64.contains("data:image")) {
-                base64 = base64.substring(base64.indexOf(",") + 1);
-            }
-            BASE64Decoder decoder = new BASE64Decoder();
-    		
-    		InputStream is = null;
-            try {
-            	byte[] bytes = decoder.decodeBuffer(base64);
-                is = new ByteArrayInputStream(bytes);
-                BufferedImage image = ImageIO.read(is);
-                width=image.getWidth()* docImageSzie;
-                height=image.getHeight()* docImageSzie;
-            }catch (IOException e) {
-            	log.error(e.getMessage(), e);
-            } finally {
-                if (is != null) {
+
+    private static void setImageSize(SectionElement imageEle, Node ce) {
+        int width = getWidth(ce);
+        int height = getHeight(ce);
+        if (width < 100 || height < 100) {
+            String base64 = imageEle.getValue();
+            if (base64.contains("data:image")) {
+                String[] ss = base64.split(",");
+                if (ss[0].toLowerCase().contains("image/svg")) {
+                    try {
+                        // Step 1: Base64解码
+                        byte[] decodedBytes = Base64.getDecoder().decode(ss[1]);
+                        InputStream inputStream = new ByteArrayInputStream(decodedBytes);
+
+                        // Step 2: 解析SVG数据
+                        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+                        DocumentBuilder builder = factory.newDocumentBuilder();
+                        org.w3c.dom.Document document = builder.parse(inputStream);
+                        document.getDocumentElement().normalize();
+
+                        // Step 3: 提取宽高信息
+                        org.w3c.dom.Element svgElement = document.getDocumentElement();
+                        String widthStr = svgElement.getAttribute("width");
+                        String heightStr = svgElement.getAttribute("height");
+
+                        if (widthStr.isEmpty() || heightStr.isEmpty()) {
+                            // 如果没有宽高,尝试从viewBox中获取
+                            String viewBox = svgElement.getAttribute("viewBox");
+                            if (!viewBox.isEmpty()) {
+                                String[] viewBoxValues = viewBox.split(" ");
+                                if (viewBoxValues.length == 4) {
+                                    widthStr = viewBoxValues[2];
+                                    heightStr = viewBoxValues[3];
+                                }
+                            }
+                        }
+
+                        double w = Double.valueOf(widthStr.replace("ex", ""));
+                        double h = Double.valueOf(heightStr.replace("ex", ""));
+                        // ex转px参照16px的字体大小,x视为0.6倍
+                        width = (int) (w * 0.6 * 16) * docImageSzie;
+                        height = (int) (h * 0.6 * 16) * docImageSzie;
+
+                    } catch (Exception e) {
+                        throw new StatusException("500", e.getMessage(), e);
+                    }
+                } else {
+                    base64 = ss[1];
+                    BASE64Decoder decoder = new BASE64Decoder();
+
+                    InputStream is = null;
                     try {
-						is.close();
-					} catch (IOException e) {
-						log.error(e.getMessage(), e);
-					}
+                        byte[] bytes = decoder.decodeBuffer(base64);
+                        is = new ByteArrayInputStream(bytes);
+                        BufferedImage image = ImageIO.read(is);
+                        width = image.getWidth() * docImageSzie;
+                        height = image.getHeight() * docImageSzie;
+                    } catch (IOException e) {
+                        log.error(e.getMessage(), e);
+                    } finally {
+                        if (is != null) {
+                            try {
+                                is.close();
+                            } catch (IOException e) {
+                            }
+                        }
+                    }
                 }
             }
-    	}
-    	imageEle.getParam().setHeight(height);
-    	imageEle.getParam().setWidth(width);
-		
-	}
+        }
+        imageEle.getParam().setHeight(height);
+        imageEle.getParam().setWidth(width);
+
+    }
 
 }