init: WordFileParse docx→HTML 解析服务(含 Word EQ 域公式修复)
服务:Spring Boot 3.2 + docx4j 8.3.9,POST /api/v3/server_office_file/file/parse
接受 .docx,返回 HTML(公式 → LaTeX,图片 → RustFS 外链)
公式支持三类来源:
- OMML(Word 2007+ 公式) → Python omml_mathml2latex
- MathType OLE 对象 → Ruby mathtype2mathml → MathML → LaTeX
- Word EQ 域(老教辅主力) → EqToLatexUtil(本次新增)
本次改动:
1. 新增 java-svc/.../core/EqToLatexUtil.java:
移植自 jby backend-services office-core,EQ 语法 → LaTeX
(\f→\dfrac、\r→\sqrt、\i→\int/\sum/\prod、\s→^{}/_{}、\b→\left\right、
\a→array、\x→\boxed/\overline、\o\al 堆叠、圈码、化学符号、极限、连等式)
品牌标记 JBYU* → WPU*,与采集端一致
2. CtoMathFinder:接上 EQ 分支(原为 not-ported 桩),域代码经
EqToLatexUtil.convert 转 LaTeX 写入 eqLatexMap(WPEQNUM 占位符)
3. WordParseUtil.dealPlaceholder:EQ 的 LaTeX 同样加 \( \) 包裹
(原先因 WPEQNUM 例外不加包裹,前端/MathJax 不渲染)
修前症状:教辅 Word 里分式/方程组/上下标整段丢失(如 {−1/3, 1} 变成 {-,1})
修后实测:46 份教辅 2908 处 EQ 域全部还原,公式总数 2954 处、零未包裹残留
安全:application.yml(含 RustFS 密钥)不入库,提供 application.yml.example;
OssService 的 @Value 默认密钥已清空
This commit is contained in:
112
java-src/utils/DigestUtil.java
Normal file
112
java-src/utils/DigestUtil.java
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*
|
||||
* Could not load the following classes:
|
||||
* com.jby.common.util.FileUtil
|
||||
* org.apache.commons.codec.binary.Hex
|
||||
* org.apache.commons.codec.digest.DigestUtils
|
||||
* org.apache.commons.lang3.StringUtils
|
||||
* org.slf4j.Logger
|
||||
* org.slf4j.LoggerFactory
|
||||
* org.springframework.stereotype.Component
|
||||
* org.springframework.web.multipart.MultipartFile
|
||||
*/
|
||||
package com.jby.officecore.utils;
|
||||
|
||||
import com.jby.common.util.FileUtil;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.MessageDigest;
|
||||
import org.apache.commons.codec.binary.Hex;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@Component
|
||||
public class DigestUtil {
|
||||
private static final Logger log = LoggerFactory.getLogger(DigestUtil.class);
|
||||
private static final String DIGEST_MD5 = "MD5";
|
||||
private static final String DIGEST_SHA1 = "SHA-1";
|
||||
|
||||
public static String getMd5(String str) {
|
||||
if (StringUtils.isBlank((CharSequence)str)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return DigestUtils.md5Hex((String)str);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("\u83b7\u53d6\u5b57\u7b26\u4e32MD5\u503c\u5f02\u5e38:{}", (Object)e.getMessage(), (Object)e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getFileMd5(String filePath) {
|
||||
File file = FileUtil.getFile((String)filePath);
|
||||
return DigestUtil.getFileMd5(FileUtil.getMultipartFile((String)file.getName(), (File)file));
|
||||
}
|
||||
|
||||
public static String getFileMd5(MultipartFile file) {
|
||||
return DigestUtil.getDigest(file, DIGEST_MD5);
|
||||
}
|
||||
|
||||
public static String getSha1(String str) {
|
||||
if (StringUtils.isBlank((CharSequence)str)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return DigestUtils.sha1Hex((String)str);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("\u83b7\u53d6\u5b57\u7b26\u4e32sha1\u503c\u5f02\u5e38:{}", (Object)e.getMessage(), (Object)e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static String getFileSha1(String filePath) {
|
||||
File file = FileUtil.getFile((String)filePath);
|
||||
return DigestUtil.getFileSha1(FileUtil.getMultipartFile((String)file.getName(), (File)file));
|
||||
}
|
||||
|
||||
public static String getFileSha1(MultipartFile file) {
|
||||
return DigestUtil.getDigest(file, DIGEST_SHA1);
|
||||
}
|
||||
|
||||
/*
|
||||
* WARNING - Removed try catching itself - possible behaviour change.
|
||||
*/
|
||||
private static String getDigest(MultipartFile file, String digest) {
|
||||
InputStream is = null;
|
||||
try {
|
||||
int length;
|
||||
MessageDigest messageDigest = MessageDigest.getInstance(digest);
|
||||
is = file.getInputStream();
|
||||
byte[] buffer = new byte[8192];
|
||||
while ((length = is.read(buffer)) != -1) {
|
||||
messageDigest.update(buffer, 0, length);
|
||||
}
|
||||
String string = new String(Hex.encodeHex((byte[])messageDigest.digest()));
|
||||
return string;
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("\u83b7\u53d6\u6458\u8981\u503c\u5f02\u5e38:{}", (Object)e.getMessage(), (Object)e);
|
||||
String string = null;
|
||||
return string;
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
if (is != null) {
|
||||
is.close();
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("close error");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1034
java-src/utils/EqToLatexUtil.java
Normal file
1034
java-src/utils/EqToLatexUtil.java
Normal file
File diff suppressed because it is too large
Load Diff
501
java-src/utils/LatexUtil.java
Normal file
501
java-src/utils/LatexUtil.java
Normal file
@@ -0,0 +1,501 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*
|
||||
* Could not load the following classes:
|
||||
* cn.hutool.core.thread.ThreadUtil
|
||||
* com.alibaba.fastjson.JSON
|
||||
* com.alibaba.fastjson.JSONObject
|
||||
* com.alibaba.fastjson.TypeReference
|
||||
* com.alibaba.fastjson.parser.Feature
|
||||
* com.fasterxml.jackson.databind.ObjectMapper
|
||||
* com.fasterxml.jackson.databind.SerializationFeature
|
||||
* com.jby.common.util.FileUtil
|
||||
* com.jby.common.util.HttpClientUtil
|
||||
* com.jby.common.util.UniqueUtil
|
||||
* fmath.conversion.ConvertFromLatexToMathML
|
||||
* fmath.conversion.ConvertFromMathMLToLatex
|
||||
* org.apache.commons.collections4.MapUtils
|
||||
* org.apache.commons.exec.CommandLine
|
||||
* org.apache.commons.exec.DefaultExecutor
|
||||
* org.apache.commons.exec.ExecuteStreamHandler
|
||||
* org.apache.commons.exec.PumpStreamHandler
|
||||
* org.apache.commons.lang3.StringUtils
|
||||
* org.scilab.forge.jlatexmath.TeXFormula
|
||||
* org.scilab.forge.jlatexmath.TeXIcon
|
||||
* org.slf4j.Logger
|
||||
* org.slf4j.LoggerFactory
|
||||
* org.springframework.beans.factory.annotation.Autowired
|
||||
* org.springframework.stereotype.Component
|
||||
*/
|
||||
package com.jby.officecore.utils;
|
||||
|
||||
import cn.hutool.core.thread.ThreadUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
import com.alibaba.fastjson.parser.Feature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.jby.common.util.FileUtil;
|
||||
import com.jby.common.util.HttpClientUtil;
|
||||
import com.jby.common.util.UniqueUtil;
|
||||
import com.jby.officecore.config.OfficeCoreConfig;
|
||||
import com.jby.officecore.domain.bo.LatexInfoBO;
|
||||
import com.jby.officecore.utils.MapUtil;
|
||||
import fmath.conversion.ConvertFromLatexToMathML;
|
||||
import fmath.conversion.ConvertFromMathMLToLatex;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Insets;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.JLabel;
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
import org.apache.commons.exec.CommandLine;
|
||||
import org.apache.commons.exec.DefaultExecutor;
|
||||
import org.apache.commons.exec.ExecuteStreamHandler;
|
||||
import org.apache.commons.exec.PumpStreamHandler;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.scilab.forge.jlatexmath.TeXFormula;
|
||||
import org.scilab.forge.jlatexmath.TeXIcon;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class LatexUtil {
|
||||
private static final Logger log = LoggerFactory.getLogger(LatexUtil.class);
|
||||
private static final String LATEX_PATTERN_STR = "\\$\\$(.*?)\\$\\$|\\\\\\((.*?)\\\\\\)";
|
||||
private static final Pattern LATEX_PATTERN = Pattern.compile("\\$\\$(.*?)\\$\\$|\\\\\\((.*?)\\\\\\)");
|
||||
private static final String LATEX_SELF_PATTERN_STR = "(?<=\\$\\$)(.*?)(?=\\$\\$)|(?<=\\\\\\()(.*?)(?=\\\\\\))";
|
||||
private static final Pattern LATEX_SELF_PATTERN = Pattern.compile("(?<=\\$\\$)(.*?)(?=\\$\\$)|(?<=\\\\\\()(.*?)(?=\\\\\\))");
|
||||
private static final Pattern CHINESE_PATTERN = Pattern.compile("[\u4e00-\u9fa5]");
|
||||
private static final String LATEX_REPLACE = "@@@";
|
||||
public static final String LATEX_SPLIT = "###";
|
||||
private static OfficeCoreConfig officeCoreConfig;
|
||||
private static final ObjectMapper MAPPER;
|
||||
|
||||
@Autowired
|
||||
public void setOfficeCoreConfig(OfficeCoreConfig officeCoreConfig) {
|
||||
LatexUtil.officeCoreConfig = officeCoreConfig;
|
||||
}
|
||||
|
||||
public static String dealLatexContent(String content, Map<String, LatexInfoBO> latexMap, Boolean newTransferVersion) {
|
||||
String result = content.replaceAll(LATEX_PATTERN_STR, LATEX_REPLACE);
|
||||
Matcher mather = LatexUtil.getLatexMatcher(content);
|
||||
while (mather.find()) {
|
||||
String latex = mather.group();
|
||||
String latexKey = "";
|
||||
if (StringUtils.isNotBlank((CharSequence)latex)) {
|
||||
String cleanLatex;
|
||||
Matcher matcher;
|
||||
latex = latex.replaceAll(" ", " ");
|
||||
latex = latex.replaceAll(">", ">");
|
||||
latex = latex.replaceAll("<", "<");
|
||||
latex = latex.replace("<br/>", "").replace("\\ ", "");
|
||||
if (Boolean.TRUE.equals(newTransferVersion)) {
|
||||
latexKey = latex.replaceAll(LATEX_SELF_PATTERN_STR, UniqueUtil.getUuid());
|
||||
matcher = LATEX_SELF_PATTERN.matcher(latex);
|
||||
if (matcher.find() && StringUtils.isNotBlank((CharSequence)(cleanLatex = matcher.group()))) {
|
||||
latex = cleanLatex;
|
||||
}
|
||||
} else {
|
||||
latex = LatexUtil.formatLatex(latex);
|
||||
latexKey = latex.replaceAll(LATEX_SELF_PATTERN_STR, UniqueUtil.getUuid());
|
||||
matcher = LATEX_SELF_PATTERN.matcher(latex);
|
||||
if (matcher.find() && StringUtils.isNotBlank((CharSequence)(cleanLatex = matcher.group()))) {
|
||||
latex = cleanLatex;
|
||||
}
|
||||
latex = LatexUtil.wrapLatexExpressionWithBraces(latex);
|
||||
}
|
||||
latexMap.put(latexKey, new LatexInfoBO().setLatexKey(latexKey).setLatex(latex));
|
||||
}
|
||||
result = StringUtils.replaceOnce((String)result, (String)LATEX_REPLACE, (String)(" ###" + latexKey + LATEX_SPLIT + " "));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static String wrapLatexExpressionWithBraces(String latex) {
|
||||
String[] simpleOperators;
|
||||
String[] limitsOperators;
|
||||
if (StringUtils.isBlank((CharSequence)latex)) {
|
||||
return latex;
|
||||
}
|
||||
latex = latex.replaceAll("\\\\xleftrightarrow\\[([^\\]]+)\\]\\{([^}]+)\\}", "\\\\underset{$1}{\\\\overset{$2}{\\\\longleftrightarrow}}");
|
||||
latex = latex.replaceAll("\\\\xrightleftharpoons\\[([^\\]]+)\\]\\{([^}]+)\\}", "\\\\underset{$1}{\\\\overset{$2}{\\\\mathop{\\\\rightleftharpoons }}}\\\\,");
|
||||
latex = latex.replaceAll("\\\\enclose\\{madruwb\\}\\{([^}]+)\\}", "\\\\left. \\{\\\\underline \\{$1\\}\\} \\\\right|");
|
||||
latex = latex.replaceAll("\\\\enclose\\{actuarial\\}\\{([^}]+)\\}", "\\\\left. \\{\\\\overline \\{$1\\}\\} \\\\right|");
|
||||
String[] operators = new String[]{"prod", "coprod", "sum", "int", "bigcap", "bigcup", "iint", "iiint", "oint"};
|
||||
for (String op : limitsOperators = new String[]{"prod", "coprod", "sum", "bigcap", "bigcup", "iint", "iiint", "oint"}) {
|
||||
latex = latex.replaceAll("(\\\\displaystyle\\\\" + op + "\\\\limits(?:\\s*_\\{[^}]*\\})?(?:\\s*\\^\\{[^}]*\\}|\\s*_\\{[^}]*\\})\\s*)([a-zA-Z0-9]+)(?![a-zA-Z0-9])", "$1{$2}");
|
||||
}
|
||||
for (String op : operators) {
|
||||
latex = latex.replaceAll("(\\\\displaystyle\\\\" + op + "(?:\\s*_\\{[^}]*\\})?(?:\\s*\\^\\{[^}]*\\}|\\s*_\\{[^}]*\\})\\s*)([a-zA-Z0-9]+)(?![a-zA-Z0-9])", "$1{$2}");
|
||||
}
|
||||
for (String op : simpleOperators = new String[]{"iint", "iiint", "oint"}) {
|
||||
latex = latex.replaceAll("(\\\\" + op + "\\s*_\\{[^}]*\\}\\s*)([a-zA-Z0-9]+)(?![a-zA-Z0-9])", "$1{$2}");
|
||||
}
|
||||
return latex;
|
||||
}
|
||||
|
||||
public static String formatLatex(String latex) {
|
||||
if (StringUtils.isBlank((CharSequence)latex)) {
|
||||
return latex;
|
||||
}
|
||||
StringBuilder latexBuilder = new StringBuilder();
|
||||
try {
|
||||
latex = latex.replace("leqslant", "leq");
|
||||
latex = latex.replace("geqslant", "geq");
|
||||
boolean inChinese = false;
|
||||
char[] cArray = latex.toCharArray();
|
||||
int n = cArray.length;
|
||||
for (int i = 0; i < n; ++i) {
|
||||
Character c = Character.valueOf(cArray[i]);
|
||||
Matcher chineseMatch = CHINESE_PATTERN.matcher(c.toString());
|
||||
if (chineseMatch.find()) {
|
||||
if (inChinese) {
|
||||
latexBuilder.append(c);
|
||||
continue;
|
||||
}
|
||||
latexBuilder.append("\\mbox{").append(c);
|
||||
inChinese = true;
|
||||
continue;
|
||||
}
|
||||
if (inChinese) {
|
||||
inChinese = false;
|
||||
latexBuilder.append("}");
|
||||
}
|
||||
latexBuilder.append(c);
|
||||
}
|
||||
if (inChinese) {
|
||||
latexBuilder.append("}");
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("formatLatex error, latex:{}, result:{}", new Object[]{latex, latexBuilder.toString(), e});
|
||||
}
|
||||
return latexBuilder.toString();
|
||||
}
|
||||
|
||||
public static void latexToImg(String latex, String path) {
|
||||
try {
|
||||
TeXFormula formula = new TeXFormula(latex);
|
||||
TeXIcon icon = formula.createTeXIcon(0, 40.0f);
|
||||
icon.setInsets(new Insets(5, 5, 5, 5));
|
||||
BufferedImage bImg = new BufferedImage(icon.getIconWidth(), icon.getIconHeight(), 6);
|
||||
Graphics2D g2d = bImg.createGraphics();
|
||||
g2d.setColor(Color.white);
|
||||
g2d.fillRect(0, 0, icon.getIconWidth(), icon.getIconHeight());
|
||||
JLabel jl = new JLabel();
|
||||
jl.setForeground(new Color(0, 0, 0));
|
||||
icon.paintIcon((java.awt.Component)jl, (Graphics)g2d, 0, 0);
|
||||
File out = FileUtil.getFile((String)path);
|
||||
ImageIO.write((RenderedImage)bImg, "png", out);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("latexToImg error\uff1alatex={}, path={}, ", new Object[]{latex, path, e});
|
||||
}
|
||||
}
|
||||
|
||||
public static void latexToMathML(Map<String, LatexInfoBO> latexMap) {
|
||||
Collection<Map<String, LatexInfoBO>> maps = MapUtil.splitMap(latexMap, 500);
|
||||
HashMap convertMap = new HashMap();
|
||||
maps.forEach(map -> {
|
||||
if (MapUtils.isEmpty((Map)map)) {
|
||||
return;
|
||||
}
|
||||
HashMap convertParam = new HashMap();
|
||||
String result = null;
|
||||
try {
|
||||
HashMap param = new HashMap();
|
||||
map.values().forEach(info -> param.put(info.getLatexKey(), info.getLatex()));
|
||||
convertParam.put("latex", param);
|
||||
long ts = System.currentTimeMillis();
|
||||
result = HttpClientUtil.doPost((String)officeCoreConfig.getForeLatexToMathMlApi(), (String)JSON.toJSONString(convertParam));
|
||||
log.info("latex\u8f6cmathML\u8c03\u7528python\u63a5\u53e3\u6210\u529f, \u8017\u65f6\uff1a{}\u6beb\u79d2", (Object)(System.currentTimeMillis() - ts));
|
||||
Map convertResult = (Map)HttpClientUtil.parseResult((String)result, (TypeReference)new TypeReference<Map<String, String>>(){});
|
||||
if (MapUtils.isNotEmpty((Map)convertResult)) {
|
||||
convertMap.putAll(convertResult);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("latex\u8f6cmathML\u8c03\u7528python\u63a5\u53e3\u5f02\u5e38, param:{}, result:{}", new Object[]{JSON.toJSONString(convertParam), result, e});
|
||||
}
|
||||
});
|
||||
latexMap.values().forEach(info -> {
|
||||
String mathMl = (String)convertMap.get(info.getLatexKey());
|
||||
if (StringUtils.isBlank((CharSequence)mathMl)) {
|
||||
try {
|
||||
mathMl = LatexUtil.convertFromLatexToMathML(info.getLatex());
|
||||
log.info("latex\u8f6cmathML\u672c\u5730\u8f6c\u6362,latex:{}", (Object)info.getLatex());
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("latex\u8f6cmathML\u672c\u5730\u8f6c\u6362\u5f02\u5e38, info:{}", (Object)JSON.toJSONString((Object)info), (Object)e);
|
||||
}
|
||||
}
|
||||
if (StringUtils.isNotBlank((CharSequence)mathMl)) {
|
||||
mathMl = mathMl.replaceAll("(?i)⟂", "⊥");
|
||||
}
|
||||
info.setMathMl(mathMl);
|
||||
});
|
||||
}
|
||||
|
||||
private static String convertFromLatexToMathML(String latex) {
|
||||
String mathMl = ConvertFromLatexToMathML.convertToMathML((String)latex);
|
||||
mathMl = mathMl.replace("\n", "").replaceFirst("<math", "<math xmlns=\"http://www.w3.org/1998/Math/MathML\" ").replace("∗", "\u2217").replace("∴", "\u2234").replace("∝", "\u221d").replace("≈", "\u2248").replace("≠", "\u2260").replace("∋", "\u220b").replace("∈", "\u2208").replace("∉", "\u2209").replace("α", "\u03b1").replace("β", "\u03b2").replace("γ", "\u03b3").replace("δ", "\u03b4").replace("ϵ", "\u03b5").replace("ε", "\u03f5").replace("ζ", "\u03b6").replace("η", "\u03b7").replace("θ", "\u03b8").replace("ϑ", "\u03d1").replace("ι", "\u03b9").replace("κ", "\u03ba").replace("λ", "\u03bb").replace("μ", "\u03bc").replace("ν", "\u03bd").replace("ρ", "\u03c1").replace("σ", "\u03c3").replace("φ", "\u03d5").replace("ϕ", "\u03c6").replace("ω", "\u03c9").replace("Λ", "\u039b").replace("Σ", "\u03a3").replace("Ω", "\u03a9").replace("⊂", "\u2282").replace("⊃", "\u2283").replace("⊆", "\u2286").replace("⊇", "\u2287").replace("∇", "\u2207").replace("…", "\u2026").replace("↓", "\u2193").replace("⇓", "\u21d3").replace("↑", "\u2191").replace("⇑", "\u21d1").replace("→", "\u2192").replace("⇒", "\u21d2").replace("←", "\u2190").replace("⇐", "\u21d0").replace("↔", "\u2194").replace("⇔", "\u21d4").replace("ℜ", "\u211c").replace("ℑ", "\u2111").replace("∂", "\u2202").replace("∞", "\u221e").replace("ℵ", "\u2135").replace("∃", "\u2203").replace("∅", "\u2205").replace("∪", "\u222a").replace("∩", "\u2229").replace("°", "\u00b0").replace("∠", "\u2220").replace("∫", "\u222b").replace("∏", "\u220f").replace("∐", "\u2210");
|
||||
return mathMl;
|
||||
}
|
||||
|
||||
public static void mathMlToLatex(Map<String, String> formulaMap, Path path) {
|
||||
if (!MapUtils.isEmpty(formulaMap)) {
|
||||
log.info("mathML\u8f6clatex\u6570\u91cf:{}", (Object)formulaMap.size());
|
||||
}
|
||||
Collection<Map<String, String>> maps = MapUtil.splitMap(formulaMap, 500);
|
||||
HashMap convertMap = new HashMap();
|
||||
maps.forEach(map -> {
|
||||
block11: {
|
||||
if (MapUtils.isEmpty((Map)map)) {
|
||||
return;
|
||||
}
|
||||
HashMap<String, Map> convertParam = new HashMap<String, Map>();
|
||||
String result = "";
|
||||
if (Boolean.TRUE.equals(officeCoreConfig.getMathMlToLatexApiSwitch())) {
|
||||
try {
|
||||
convertParam.put("mathml_dict", (Map)map);
|
||||
long ts = System.currentTimeMillis();
|
||||
result = HttpClientUtil.doPost((String)officeCoreConfig.getMathMlToLatexApi(), convertParam, (int)5000, (int)15000);
|
||||
log.info("mathML\u8f6clatex\u8c03\u7528python\u63a5\u53e3\u6210\u529f, \u8017\u65f6\uff1a{}\u6beb\u79d2", (Object)(System.currentTimeMillis() - ts));
|
||||
result = result.replace("<", "\\\\lt ");
|
||||
Map convertResult = (Map)HttpClientUtil.parseResult((String)result, (TypeReference)new TypeReference<Map<String, String>>(){});
|
||||
if (MapUtils.isNotEmpty((Map)convertResult)) {
|
||||
convertMap.putAll(convertResult);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("mathML\u8f6clatex\u8c03\u7528python\u63a5\u53e3\u5f02\u5e38, param:{}, result:{}", new Object[]{JSON.toJSONString(convertParam), result, e});
|
||||
}
|
||||
ThreadUtil.sleep((long)2000L);
|
||||
} else {
|
||||
try {
|
||||
Map convertResult;
|
||||
JSONObject json;
|
||||
String data;
|
||||
convertParam.put("mathml_dict", (Map)map);
|
||||
File tempFile = File.createTempFile("mathml_input-", ".json", new File(path.toString()));
|
||||
String absolutePath = tempFile.getAbsolutePath();
|
||||
if (!StringUtils.isNotBlank((CharSequence)absolutePath) || map.isEmpty()) break block11;
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.enable(SerializationFeature.INDENT_OUTPUT);
|
||||
mapper.writeValue(tempFile, convertParam);
|
||||
CommandLine cmdLine = CommandLine.parse((String)officeCoreConfig.getPythonCommand());
|
||||
cmdLine.addArgument(officeCoreConfig.getTransformScriptPath() + "/mathml2latex/batch_converter.py");
|
||||
cmdLine.addArgument("--input-file=" + absolutePath);
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
PumpStreamHandler streamHandler = new PumpStreamHandler((OutputStream)output, (OutputStream)output);
|
||||
DefaultExecutor executor = new DefaultExecutor();
|
||||
executor.setStreamHandler((ExecuteStreamHandler)streamHandler);
|
||||
long ts = System.currentTimeMillis();
|
||||
try {
|
||||
executor.execute(cmdLine);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("mathml2latex/batch_converter.py error, \n\u8f93\u51fa:{}", (Object)output, (Object)e);
|
||||
}
|
||||
log.info("mathml2latex/batch_converter.py end, \u6570\u91cf:{}, \u8017\u65f6:{}\u6beb\u79d2", (Object)map.size(), (Object)(System.currentTimeMillis() - ts));
|
||||
String fullOutput = output.toString();
|
||||
CharSequence[] lines = fullOutput.split("\n");
|
||||
result = String.join((CharSequence)"", lines);
|
||||
result = result.replace("<", "\\\\lt ");
|
||||
if (StringUtils.isNotBlank((CharSequence)result) && Objects.nonNull(data = (json = JSONObject.parseObject((String)result)).getString("data")) && MapUtils.isNotEmpty((Map)(convertResult = (Map)JSON.parseObject((String)data, (TypeReference)new TypeReference<Map<String, String>>(){}, (Feature[])new Feature[0])))) {
|
||||
convertMap.putAll(convertResult);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("mathML\u8f6clatex\u8c03\u7528\u672c\u5730python\u7a0b\u5e8f\u5f02\u5e38,param:{}, result:{}", new Object[]{JSON.toJSONString(convertParam), result, e});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
formulaMap.forEach((formulaKey, mathMl) -> {
|
||||
String latex = (String)convertMap.get(formulaKey);
|
||||
if (StringUtils.isBlank((CharSequence)latex)) {
|
||||
try {
|
||||
latex = ConvertFromMathMLToLatex.convertToLatex((String)mathMl);
|
||||
log.info("mathML\u8f6clatex\u672c\u5730\u8f6c\u6362,latex:{}", (Object)latex);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("mathML\u8f6clatex\u672c\u5730\u8f6c\u6362\u5f02\u5e38, mathMl:{}, latex:{}", new Object[]{mathMl, latex, e});
|
||||
}
|
||||
}
|
||||
if (StringUtils.isNotBlank((CharSequence)latex) && latex.length() > 2) {
|
||||
formulaMap.put((String)formulaKey, latex.substring(1, latex.length() - 1));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static Matcher getLatexMatcher(String content) {
|
||||
return LATEX_PATTERN.matcher(content);
|
||||
}
|
||||
|
||||
public static void mathMlToLatexIgnoreNull(Map<String, String> formulaMap, String copyrightAddresses, Path path) {
|
||||
Map<String, String> map = formulaMap.entrySet().stream().filter(f -> Objects.nonNull(f.getValue())).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
LatexUtil.mathMlToLatex(map, path);
|
||||
String[] original = copyrightAddresses.split(",");
|
||||
String[] transformed = (String[])Arrays.stream(original).map(s -> s.chars().mapToObj(c -> {
|
||||
if (c == 46) {
|
||||
return ".";
|
||||
}
|
||||
return "\\mathrm{" + (char)c + "}";
|
||||
}).collect(Collectors.joining())).toArray(String[]::new);
|
||||
String[] splits = (String[])Stream.concat(Arrays.stream(original), Arrays.stream(transformed)).toArray(String[]::new);
|
||||
map.replaceAll((key, value) -> {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
return Arrays.stream(splits).anyMatch(value::contains) ? null : value;
|
||||
});
|
||||
formulaMap.putAll(map);
|
||||
}
|
||||
|
||||
public static void ommlAndMathMlToLatex(Map<String, String> formulaMap, Path path) {
|
||||
if (!MapUtils.isEmpty(formulaMap)) {
|
||||
log.info("Omml\u6216MathML\u8f6clatex\u6570\u91cf:{}", (Object)formulaMap.size());
|
||||
}
|
||||
Collection<Map<String, String>> maps = MapUtil.splitMap(formulaMap, 1000);
|
||||
maps.forEach(map -> {
|
||||
block6: {
|
||||
if (MapUtils.isEmpty((Map)map)) {
|
||||
return;
|
||||
}
|
||||
String result = "";
|
||||
try {
|
||||
Map convertResult;
|
||||
File tempFile = File.createTempFile("input-", ".json", new File(path.toString()));
|
||||
String absolutePath = tempFile.getAbsolutePath();
|
||||
if (!StringUtils.isNotBlank((CharSequence)absolutePath) || map.isEmpty()) break block6;
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
mapper.enable(SerializationFeature.INDENT_OUTPUT);
|
||||
mapper.writeValue(tempFile, map);
|
||||
CommandLine cmdLine = CommandLine.parse((String)officeCoreConfig.getPythonCommand());
|
||||
cmdLine.addArgument(officeCoreConfig.getTransformScriptPath() + "/omml_mathml2latex/omml_mathml2latex.py");
|
||||
cmdLine.addArgument("--json");
|
||||
cmdLine.addArgument(absolutePath);
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
PumpStreamHandler streamHandler = new PumpStreamHandler((OutputStream)output, (OutputStream)output);
|
||||
DefaultExecutor executor = new DefaultExecutor();
|
||||
executor.setStreamHandler((ExecuteStreamHandler)streamHandler);
|
||||
long ts = System.currentTimeMillis();
|
||||
try {
|
||||
executor.execute(cmdLine);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("/omml_mathml2latex/omml_mathml2latex.py error, \n\u8f93\u51fa:{}", (Object)output, (Object)e);
|
||||
}
|
||||
log.info("/omml_mathml2latex/omml_mathml2latex.py end, \u6570\u91cf:{}, \u8017\u65f6:{}\u6beb\u79d2", (Object)map.size(), (Object)(System.currentTimeMillis() - ts));
|
||||
String fullOutput = output.toString();
|
||||
CharSequence[] lines = fullOutput.split("\n");
|
||||
result = String.join((CharSequence)"", lines);
|
||||
if (StringUtils.isNotBlank((CharSequence)result) && MapUtils.isNotEmpty((Map)(convertResult = (Map)JSON.parseObject((String)result, (TypeReference)new TypeReference<Map<String, String>>(){}, (Feature[])new Feature[0])))) {
|
||||
formulaMap.putAll(convertResult);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("Omml\u6216MathML\u8f6clatex\u8c03\u7528\u672c\u5730python\u7a0b\u5e8f\u5f02\u5e38,param:{}, result:{}", new Object[]{JSON.toJSONString((Object)map), result, e});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void ommlMathMlToLatexIgnoreNull(Map<String, String> formulaMap, String copyrightAddresses, Path path) {
|
||||
Map<String, String> map = formulaMap.entrySet().stream().filter(f -> Objects.nonNull(f.getValue())).collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
|
||||
LatexUtil.ommlAndMathMlToLatex(map, path);
|
||||
String[] original = copyrightAddresses.split(",");
|
||||
String[] transformed = (String[])Arrays.stream(original).map(s -> s.chars().mapToObj(c -> {
|
||||
if (c == 46) {
|
||||
return ".";
|
||||
}
|
||||
return "\\mathrm{" + (char)c + "}";
|
||||
}).collect(Collectors.joining())).toArray(String[]::new);
|
||||
String[] splits = (String[])Stream.concat(Arrays.stream(original), Arrays.stream(transformed)).toArray(String[]::new);
|
||||
map.replaceAll((key, value) -> {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
return Arrays.stream(splits).anyMatch(value.replace(" ", "")::contains) ? null : value;
|
||||
});
|
||||
formulaMap.putAll(map);
|
||||
}
|
||||
|
||||
public static void latexAndMathMlToOmml(Map<String, String> latexMathmlMap) {
|
||||
if (!MapUtils.isEmpty(latexMathmlMap)) {
|
||||
log.info("Latex\u6216MathML\u8f6cOmml\u6570\u91cf:{}", (Object)latexMathmlMap.size());
|
||||
}
|
||||
String tempFolder = officeCoreConfig.getTmpPath() + "/download" + File.separator + UniqueUtil.getUuid() + File.separator;
|
||||
Collection<Map<String, String>> maps = MapUtil.splitMap(latexMathmlMap, 1000);
|
||||
maps.forEach(map -> {
|
||||
block10: {
|
||||
if (MapUtils.isEmpty((Map)map)) {
|
||||
return;
|
||||
}
|
||||
String result = "";
|
||||
try {
|
||||
Map convertResult;
|
||||
File tempFile = FileUtil.getFile((String)(tempFolder + UniqueUtil.getUuid() + ".json"));
|
||||
String absolutePath = tempFile.getAbsolutePath();
|
||||
if (!StringUtils.isNotBlank((CharSequence)absolutePath) || map.isEmpty()) break block10;
|
||||
MAPPER.enable(SerializationFeature.INDENT_OUTPUT);
|
||||
MAPPER.writeValue(tempFile, map);
|
||||
CommandLine cmdLine = CommandLine.parse((String)officeCoreConfig.getPythonCommand());
|
||||
cmdLine.addArguments(new String[]{officeCoreConfig.getTransformScriptPath() + "/latex_mathml2omml/latex_mathml2omml.py", "--json", absolutePath}, false);
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
PumpStreamHandler streamHandler = new PumpStreamHandler((OutputStream)output, (OutputStream)output);
|
||||
DefaultExecutor executor = new DefaultExecutor();
|
||||
executor.setStreamHandler((ExecuteStreamHandler)streamHandler);
|
||||
long ts = System.currentTimeMillis();
|
||||
try {
|
||||
executor.execute(cmdLine);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("/latex_mathml2omml/latex_mathml2omml.py error, \n\u8f93\u51fa:{}", (Object)output, (Object)e);
|
||||
}
|
||||
log.info("/latex_mathml2omml/latex_mathml2omml.py end, \u6570\u91cf:{}, \u8017\u65f6:{}\u6beb\u79d2", (Object)map.size(), (Object)(System.currentTimeMillis() - ts));
|
||||
String fullOutput = output.toString();
|
||||
CharSequence[] lines = fullOutput.split("\n");
|
||||
result = String.join((CharSequence)"", lines);
|
||||
if (StringUtils.isNotBlank((CharSequence)result) && MapUtils.isNotEmpty((Map)(convertResult = (Map)JSON.parseObject((String)result, (TypeReference)new TypeReference<Map<String, String>>(){}, (Feature[])new Feature[0])))) {
|
||||
latexMathmlMap.putAll(convertResult);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("Latex\u6216MathML\u8f6cOmml\u8c03\u7528\u672c\u5730python\u7a0b\u5e8f\u5f02\u5e38,param:{}, result:{}", new Object[]{JSON.toJSONString((Object)map), result, e});
|
||||
}
|
||||
finally {
|
||||
if (Boolean.TRUE.equals(officeCoreConfig.getDeleteTmpFile())) {
|
||||
FileUtil.delFolder((String)tempFolder);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static {
|
||||
MAPPER = new ObjectMapper();
|
||||
}
|
||||
}
|
||||
|
||||
131
java-src/utils/MathTypeUtil.java
Normal file
131
java-src/utils/MathTypeUtil.java
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*
|
||||
* Could not load the following classes:
|
||||
* com.alibaba.fastjson.JSON
|
||||
* com.alibaba.fastjson.JSONObject
|
||||
* org.apache.commons.collections4.MapUtils
|
||||
* org.apache.commons.exec.CommandLine
|
||||
* org.apache.commons.exec.DefaultExecutor
|
||||
* org.apache.commons.exec.ExecuteStreamHandler
|
||||
* org.apache.commons.exec.PumpStreamHandler
|
||||
* org.slf4j.Logger
|
||||
* org.slf4j.LoggerFactory
|
||||
* org.springframework.beans.factory.annotation.Autowired
|
||||
* org.springframework.stereotype.Component
|
||||
*/
|
||||
package com.jby.officecore.utils;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.jby.officecore.config.OfficeCoreConfig;
|
||||
import com.jby.officecore.utils.MapUtil;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.OpenOption;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.attribute.FileAttribute;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
import org.apache.commons.exec.CommandLine;
|
||||
import org.apache.commons.exec.DefaultExecutor;
|
||||
import org.apache.commons.exec.ExecuteStreamHandler;
|
||||
import org.apache.commons.exec.PumpStreamHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class MathTypeUtil {
|
||||
private static final Logger log = LoggerFactory.getLogger(MathTypeUtil.class);
|
||||
private static OfficeCoreConfig officeCoreConfig;
|
||||
|
||||
@Autowired
|
||||
public void setOfficeCoreConfig(OfficeCoreConfig officeCoreConfig) {
|
||||
MathTypeUtil.officeCoreConfig = officeCoreConfig;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
HashMap<String, String> map = new HashMap<String, String>();
|
||||
for (int i = 1; i < 927; ++i) {
|
||||
map.put("jby_" + i, "/Users/hking/test/embeddings/oleObject" + i + ".bin");
|
||||
}
|
||||
MathTypeUtil.mathTypeToMathMl(map);
|
||||
System.out.println(map);
|
||||
}
|
||||
|
||||
public static void mathTypeToMathMl(Map<String, String> formulaMap) {
|
||||
if (!MapUtils.isEmpty(formulaMap)) {
|
||||
log.info("mathtype\u8f6cmathml\u6570\u91cf:{}", (Object)formulaMap.size());
|
||||
}
|
||||
try {
|
||||
Collection<Map<String, String>> maps = MapUtil.splitMap(formulaMap, 500);
|
||||
maps.forEach(m -> {
|
||||
Path tempJsonFile;
|
||||
if (MapUtils.isEmpty((Map)formulaMap)) {
|
||||
return;
|
||||
}
|
||||
CommandLine cmdLine = CommandLine.parse((String)"ruby");
|
||||
cmdLine.addArgument(officeCoreConfig.getTransformScriptPath() + "/mathtype2mathml/batch_converter.rb");
|
||||
String data = JSONObject.toJSONString((Object)m);
|
||||
try {
|
||||
tempJsonFile = Files.createTempFile("mathtype_input-", ".json", new FileAttribute[0]);
|
||||
Files.write(tempJsonFile, data.getBytes(StandardCharsets.UTF_8), new OpenOption[0]);
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("\u521b\u5efa\u4e34\u65f6JSON\u6587\u4ef6\u5931\u8d25", (Throwable)e);
|
||||
return;
|
||||
}
|
||||
Path finalTempJsonFile = tempJsonFile;
|
||||
cmdLine.addArgument(tempJsonFile.toString());
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
PumpStreamHandler streamHandler = new PumpStreamHandler((OutputStream)output, (OutputStream)output);
|
||||
DefaultExecutor executor = new DefaultExecutor();
|
||||
executor.setStreamHandler((ExecuteStreamHandler)streamHandler);
|
||||
long ts = System.currentTimeMillis();
|
||||
try {
|
||||
executor.execute(cmdLine);
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("/mathtype2mathml/batch_converter.rb error, \n\u547d\u4ee4:{}, \n\u8f93\u51fa:{}", new Object[]{cmdLine, output, e});
|
||||
}
|
||||
finally {
|
||||
try {
|
||||
Files.deleteIfExists(finalTempJsonFile);
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.warn("\u5220\u9664JSON\u4e34\u65f6\u6587\u4ef6\u5931\u8d25: {}", (Object)finalTempJsonFile, (Object)e);
|
||||
}
|
||||
}
|
||||
String fullOutput = output.toString();
|
||||
log.info("/mathtype2mathml/batch_converter.rb end, \u6570\u91cf:{}, \u8017\u65f6:{}\u6beb\u79d2", (Object)m.size(), (Object)(System.currentTimeMillis() - ts));
|
||||
String[] lines = fullOutput.split("\n");
|
||||
String jbyOutput = Arrays.stream(lines).filter(f -> f.startsWith("JBY_RUBY_")).collect(Collectors.joining());
|
||||
String result = jbyOutput.replace("JBY_RUBY_", "");
|
||||
result = result.replace("display=\\\"block\\", "display=\\\"inline\\");
|
||||
result = result.replace("~", "JBYSIMJBY");
|
||||
JSONObject rootObj = JSON.parseObject((String)result);
|
||||
JSONObject results = rootObj.getJSONObject("results");
|
||||
HashMap<String, String> resultMap = new HashMap<String, String>();
|
||||
for (String key : results.keySet()) {
|
||||
JSONObject item = results.getJSONObject(key);
|
||||
String mathml = item.getString("mathml");
|
||||
resultMap.put(key, mathml);
|
||||
}
|
||||
formulaMap.putAll(resultMap);
|
||||
});
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("MathType\u8f6cMathMl\u51fa\u73b0\u5f02\u5e38", (Throwable)e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
109
java-src/utils/NumPr.java
Normal file
109
java-src/utils/NumPr.java
Normal file
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*/
|
||||
package com.jby.officecore.utils;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
||||
public class NumPr {
|
||||
private BigInteger start;
|
||||
private BigInteger current;
|
||||
private String numFmt;
|
||||
private String lvlText;
|
||||
|
||||
public NumPr() {
|
||||
}
|
||||
|
||||
public NumPr(BigInteger start, BigInteger current, String numFmt, String lvlText) {
|
||||
this.start = start;
|
||||
this.current = current;
|
||||
this.numFmt = numFmt;
|
||||
this.lvlText = lvlText;
|
||||
}
|
||||
|
||||
public BigInteger getStart() {
|
||||
return this.start;
|
||||
}
|
||||
|
||||
public BigInteger getCurrent() {
|
||||
return this.current;
|
||||
}
|
||||
|
||||
public String getNumFmt() {
|
||||
return this.numFmt;
|
||||
}
|
||||
|
||||
public String getLvlText() {
|
||||
return this.lvlText;
|
||||
}
|
||||
|
||||
public void setStart(BigInteger start) {
|
||||
this.start = start;
|
||||
}
|
||||
|
||||
public void setCurrent(BigInteger current) {
|
||||
this.current = current;
|
||||
}
|
||||
|
||||
public void setNumFmt(String numFmt) {
|
||||
this.numFmt = numFmt;
|
||||
}
|
||||
|
||||
public void setLvlText(String lvlText) {
|
||||
this.lvlText = lvlText;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) {
|
||||
return true;
|
||||
}
|
||||
if (!(o instanceof NumPr)) {
|
||||
return false;
|
||||
}
|
||||
NumPr other = (NumPr)o;
|
||||
if (!other.canEqual(this)) {
|
||||
return false;
|
||||
}
|
||||
BigInteger this$start = this.getStart();
|
||||
BigInteger other$start = other.getStart();
|
||||
if (this$start == null ? other$start != null : !((Object)this$start).equals(other$start)) {
|
||||
return false;
|
||||
}
|
||||
BigInteger this$current = this.getCurrent();
|
||||
BigInteger other$current = other.getCurrent();
|
||||
if (this$current == null ? other$current != null : !((Object)this$current).equals(other$current)) {
|
||||
return false;
|
||||
}
|
||||
String this$numFmt = this.getNumFmt();
|
||||
String other$numFmt = other.getNumFmt();
|
||||
if (this$numFmt == null ? other$numFmt != null : !this$numFmt.equals(other$numFmt)) {
|
||||
return false;
|
||||
}
|
||||
String this$lvlText = this.getLvlText();
|
||||
String other$lvlText = other.getLvlText();
|
||||
return !(this$lvlText == null ? other$lvlText != null : !this$lvlText.equals(other$lvlText));
|
||||
}
|
||||
|
||||
protected boolean canEqual(Object other) {
|
||||
return other instanceof NumPr;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
int PRIME = 59;
|
||||
int result = 1;
|
||||
BigInteger $start = this.getStart();
|
||||
result = result * 59 + ($start == null ? 43 : ((Object)$start).hashCode());
|
||||
BigInteger $current = this.getCurrent();
|
||||
result = result * 59 + ($current == null ? 43 : ((Object)$current).hashCode());
|
||||
String $numFmt = this.getNumFmt();
|
||||
result = result * 59 + ($numFmt == null ? 43 : $numFmt.hashCode());
|
||||
String $lvlText = this.getLvlText();
|
||||
result = result * 59 + ($lvlText == null ? 43 : $lvlText.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return "NumPr(start=" + this.getStart() + ", current=" + this.getCurrent() + ", numFmt=" + this.getNumFmt() + ", lvlText=" + this.getLvlText() + ")";
|
||||
}
|
||||
}
|
||||
|
||||
235
java-src/utils/OfficeFileUtil.java
Normal file
235
java-src/utils/OfficeFileUtil.java
Normal file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*
|
||||
* Could not load the following classes:
|
||||
* cn.hutool.core.io.FileUtil
|
||||
* com.alibaba.fastjson.JSON
|
||||
* com.alibaba.fastjson.JSONObject
|
||||
* com.alibaba.fastjson.TypeReference
|
||||
* com.jby.common.exceptions.BusinessException
|
||||
* com.jby.common.util.FileUtil
|
||||
* com.jby.common.util.HttpClientUtil
|
||||
* com.jby.common.util.RequestHeaderUtil
|
||||
* com.jby.oss.domain.param.OssParam
|
||||
* com.jby.system.enums.AttachmentModuleEnum
|
||||
* org.apache.poi.xwpf.usermodel.XWPFDocument
|
||||
* org.slf4j.Logger
|
||||
* org.slf4j.LoggerFactory
|
||||
* org.springframework.beans.factory.annotation.Autowired
|
||||
* org.springframework.stereotype.Component
|
||||
* org.springframework.web.multipart.MultipartFile
|
||||
*/
|
||||
package com.jby.officecore.utils;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
import com.jby.common.exceptions.BusinessException;
|
||||
import com.jby.common.util.HttpClientUtil;
|
||||
import com.jby.common.util.RequestHeaderUtil;
|
||||
import com.jby.officecore.config.OfficeCoreConfig;
|
||||
import com.jby.officecore.utils.OssServiceUtil;
|
||||
import com.jby.oss.domain.param.OssParam;
|
||||
import com.jby.system.enums.AttachmentModuleEnum;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.OpenOption;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import org.apache.poi.xwpf.usermodel.XWPFDocument;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@Component
|
||||
public class OfficeFileUtil {
|
||||
private static final Logger log = LoggerFactory.getLogger(OfficeFileUtil.class);
|
||||
private static OfficeCoreConfig officeCoreConfig;
|
||||
|
||||
@Autowired
|
||||
public void setOfficeCoreConfig(OfficeCoreConfig officeCoreConfig) {
|
||||
OfficeFileUtil.officeCoreConfig = officeCoreConfig;
|
||||
}
|
||||
|
||||
public static File writeFile(String content, String savePath) {
|
||||
FileWriter fw = null;
|
||||
BufferedWriter bW = null;
|
||||
try {
|
||||
File file = com.jby.common.util.FileUtil.getFile((String)savePath);
|
||||
fw = new FileWriter(file);
|
||||
bW = new BufferedWriter(fw);
|
||||
bW.write(content);
|
||||
File file2 = file;
|
||||
return file2;
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("\u5199\u5165\u6587\u4ef6\u5f02\u5e38, savePath:{}", (Object)savePath, (Object)e);
|
||||
throw new BusinessException("\u5199\u5165\u6587\u4ef6\u5f02\u5e38");
|
||||
}
|
||||
finally {
|
||||
if (bW != null) {
|
||||
try {
|
||||
bW.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("close error", (Throwable)e);
|
||||
}
|
||||
}
|
||||
if (fw != null) {
|
||||
try {
|
||||
fw.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("close error", (Throwable)e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static File writeWord(XWPFDocument document, String savePath) {
|
||||
OutputStream os = null;
|
||||
try {
|
||||
File file = com.jby.common.util.FileUtil.getFile((String)savePath);
|
||||
os = Files.newOutputStream(file.toPath(), new OpenOption[0]);
|
||||
document.write(os);
|
||||
File file2 = file;
|
||||
return file2;
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("\u751f\u6210word\u6587\u4ef6\u5f02\u5e38, savePath:{}", (Object)savePath, (Object)e);
|
||||
throw new BusinessException("\u751f\u6210word\u6587\u4ef6\u5f02\u5e38\uff01");
|
||||
}
|
||||
finally {
|
||||
if (Objects.nonNull(os)) {
|
||||
try {
|
||||
os.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("close error", (Throwable)e);
|
||||
}
|
||||
}
|
||||
if (Objects.nonNull(document)) {
|
||||
try {
|
||||
document.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("close error", (Throwable)e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static File writeFile(MultipartFile file, String savePath) {
|
||||
try {
|
||||
return OfficeFileUtil.writeFile(file.getInputStream(), savePath);
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("\u5199\u5165\u6587\u4ef6\u5f02\u5e38, savePath:{}", (Object)savePath, (Object)e);
|
||||
throw new BusinessException("\u5199\u5165\u6587\u4ef6\u5f02\u5e38");
|
||||
}
|
||||
}
|
||||
|
||||
public static File writeFile(InputStream is, String savePath) {
|
||||
FileOutputStream os = null;
|
||||
try {
|
||||
int length;
|
||||
File saveFile = com.jby.common.util.FileUtil.getFile((String)savePath);
|
||||
os = new FileOutputStream(saveFile);
|
||||
byte[] buffer = new byte[15360];
|
||||
while ((length = is.read(buffer)) != -1) {
|
||||
((OutputStream)os).write(buffer, 0, length);
|
||||
}
|
||||
os.flush();
|
||||
File file = saveFile;
|
||||
return file;
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("\u5199\u5165\u6587\u4ef6\u5f02\u5e38, savePath:{}", (Object)savePath, (Object)e);
|
||||
throw new BusinessException("\u5199\u5165\u6587\u4ef6\u5f02\u5e38");
|
||||
}
|
||||
finally {
|
||||
if (is != null) {
|
||||
try {
|
||||
is.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("close error", (Throwable)e);
|
||||
}
|
||||
}
|
||||
if (os != null) {
|
||||
try {
|
||||
((OutputStream)os).close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("close error", (Throwable)e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* WARNING - Removed try catching itself - possible behaviour change.
|
||||
*/
|
||||
public static String mf2svg(InputStream is, String imgPath) {
|
||||
HashMap<String, Object> params = null;
|
||||
String result = null;
|
||||
try {
|
||||
File localFile = com.jby.common.util.FileUtil.getFile((String)imgPath);
|
||||
FileUtil.writeFromStream((InputStream)is, (File)localFile);
|
||||
String accessUrl = OssServiceUtil.uploadFile(new OssParam().setModule(AttachmentModuleEnum.OFFICE_IMG.getModule()).setFile(com.jby.common.util.FileUtil.getMultipartFile((String)localFile.getName(), (File)localFile)));
|
||||
params = new HashMap<String, Object>();
|
||||
params.put("fileUrl", accessUrl);
|
||||
params.put("refreshImg", false);
|
||||
Map headers = RequestHeaderUtil.getAuthHeaders();
|
||||
result = HttpClientUtil.doPost((String)officeCoreConfig.getMf2SvgApi(), params, (Map)headers);
|
||||
JSONObject json = (JSONObject)HttpClientUtil.parseResult((String)result, (TypeReference)new TypeReference<JSONObject>(){});
|
||||
String string = Objects.isNull(json) ? null : json.getString("svgUrl");
|
||||
return string;
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("mf2svg exception, imgPath:{}, params:{}, result:{}", new Object[]{imgPath, JSON.toJSONString(params), result, e});
|
||||
String string = null;
|
||||
return string;
|
||||
}
|
||||
finally {
|
||||
if (is != null) {
|
||||
try {
|
||||
is.close();
|
||||
}
|
||||
catch (IOException e) {
|
||||
log.error("close error");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String mf2svg(InputStream is, String ossFolder, String imgName) {
|
||||
HashMap<String, Object> params = null;
|
||||
String result = null;
|
||||
try {
|
||||
String imgUrl = OssServiceUtil.uploadStream(new OssParam().setModule(AttachmentModuleEnum.OFFICE_IMG.getModule()).setFolder(ossFolder).setFileName(imgName).setInputStream(is));
|
||||
params = new HashMap<String, Object>();
|
||||
params.put("fileUrl", imgUrl);
|
||||
params.put("refreshImg", false);
|
||||
Map headers = RequestHeaderUtil.getAuthHeaders();
|
||||
result = HttpClientUtil.doPost((String)officeCoreConfig.getMf2SvgApi(), params, (Map)headers);
|
||||
JSONObject json = (JSONObject)HttpClientUtil.parseResult((String)result, (TypeReference)new TypeReference<JSONObject>(){});
|
||||
return Objects.isNull(json) ? null : json.getString("svgUrl");
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("mf2svg exception, ossFolder:{}, imgName:{}, params:{}, result:{}", new Object[]{ossFolder, imgName, JSON.toJSONString(params), result, e});
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
1791
java-src/utils/WordParseUtil.java
Normal file
1791
java-src/utils/WordParseUtil.java
Normal file
File diff suppressed because it is too large
Load Diff
46
java-src/utils/finder/CtObjectFinder.java
Normal file
46
java-src/utils/finder/CtObjectFinder.java
Normal file
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*
|
||||
* Could not load the following classes:
|
||||
* org.docx4j.TraversalUtil$CallbackImpl
|
||||
* org.docx4j.openpackaging.packages.WordprocessingMLPackage
|
||||
* org.docx4j.openpackaging.parts.Part
|
||||
* org.docx4j.openpackaging.parts.relationships.RelationshipsPart
|
||||
* org.docx4j.vml.officedrawing.CTOLEObject
|
||||
*/
|
||||
package com.jby.officecore.utils.finder;
|
||||
|
||||
import com.jby.officecore.domain.bo.ParseBO;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import org.docx4j.TraversalUtil;
|
||||
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
|
||||
import org.docx4j.openpackaging.parts.Part;
|
||||
import org.docx4j.openpackaging.parts.relationships.RelationshipsPart;
|
||||
import org.docx4j.vml.officedrawing.CTOLEObject;
|
||||
|
||||
public class CtObjectFinder
|
||||
extends TraversalUtil.CallbackImpl {
|
||||
private final WordprocessingMLPackage wordMlPackage;
|
||||
private final ParseBO parseBO;
|
||||
|
||||
public CtObjectFinder(WordprocessingMLPackage wordMlPackage, ParseBO parseBO) {
|
||||
this.wordMlPackage = wordMlPackage;
|
||||
this.parseBO = parseBO;
|
||||
}
|
||||
|
||||
public List<Object> apply(Object o) {
|
||||
if (o instanceof CTOLEObject) {
|
||||
CTOLEObject ctoleObject = (CTOLEObject)o;
|
||||
RelationshipsPart rsPart = this.wordMlPackage.getMainDocumentPart().getRelationshipsPart();
|
||||
if (Objects.nonNull(ctoleObject.getId())) {
|
||||
Part part = rsPart.getPart(ctoleObject.getId());
|
||||
String binFilePath = part.getPartName().getURI().getPath();
|
||||
String placeholder = this.parseBO.getMathTypePlaceholder(ctoleObject.getId());
|
||||
this.parseBO.getMathTypeMap().put(placeholder, this.parseBO.getTempDir() + "/temp" + binFilePath);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
121
java-src/utils/finder/CtTextBoxFinder.java
Normal file
121
java-src/utils/finder/CtTextBoxFinder.java
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*
|
||||
* Could not load the following classes:
|
||||
* javax.xml.bind.JAXBElement
|
||||
* org.apache.commons.lang3.StringUtils
|
||||
* org.docx4j.TextUtils
|
||||
* org.docx4j.TraversalUtil$CallbackImpl
|
||||
* org.docx4j.mce.AlternateContent
|
||||
* org.docx4j.mce.AlternateContent$Fallback
|
||||
* org.docx4j.openpackaging.packages.WordprocessingMLPackage
|
||||
* org.docx4j.vml.CTGroup
|
||||
* org.docx4j.vml.CTRoundRect
|
||||
* org.docx4j.vml.CTShape
|
||||
* org.docx4j.vml.CTTextbox
|
||||
* org.docx4j.vml.VmlShapeElements
|
||||
* org.docx4j.wml.CTTxbxContent
|
||||
* org.docx4j.wml.ObjectFactory
|
||||
* org.docx4j.wml.Pict
|
||||
* org.docx4j.wml.R
|
||||
* org.docx4j.wml.Text
|
||||
* org.slf4j.Logger
|
||||
* org.slf4j.LoggerFactory
|
||||
*/
|
||||
package com.jby.officecore.utils.finder;
|
||||
|
||||
import com.jby.officecore.domain.bo.ParseBO;
|
||||
import java.util.List;
|
||||
import javax.xml.bind.JAXBElement;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.docx4j.TextUtils;
|
||||
import org.docx4j.TraversalUtil;
|
||||
import org.docx4j.mce.AlternateContent;
|
||||
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
|
||||
import org.docx4j.vml.CTGroup;
|
||||
import org.docx4j.vml.CTRoundRect;
|
||||
import org.docx4j.vml.CTShape;
|
||||
import org.docx4j.vml.CTTextbox;
|
||||
import org.docx4j.vml.VmlShapeElements;
|
||||
import org.docx4j.wml.CTTxbxContent;
|
||||
import org.docx4j.wml.ObjectFactory;
|
||||
import org.docx4j.wml.Pict;
|
||||
import org.docx4j.wml.R;
|
||||
import org.docx4j.wml.Text;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class CtTextBoxFinder
|
||||
extends TraversalUtil.CallbackImpl {
|
||||
private static final Logger log = LoggerFactory.getLogger(CtTextBoxFinder.class);
|
||||
private WordprocessingMLPackage wordMlPackage;
|
||||
private ParseBO parseBO;
|
||||
|
||||
public CtTextBoxFinder(WordprocessingMLPackage wordMlPackage, ParseBO parseBO) {
|
||||
this.wordMlPackage = wordMlPackage;
|
||||
this.parseBO = parseBO;
|
||||
}
|
||||
|
||||
public List<Object> apply(Object o) {
|
||||
if (o instanceof Pict) {
|
||||
boolean isFirstRun = true;
|
||||
ObjectFactory factory = new ObjectFactory();
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
R sourceR = factory.createR();
|
||||
Pict pict = (Pict)o;
|
||||
List anyAndAny = pict.getAnyAndAny();
|
||||
for (Object object : anyAndAny) {
|
||||
if (!(object instanceof JAXBElement)) continue;
|
||||
JAXBElement jbe = (JAXBElement)object;
|
||||
this.findTextBox(jbe.getValue(), stringBuilder, isFirstRun, sourceR);
|
||||
}
|
||||
if (StringUtils.isNotBlank((CharSequence)stringBuilder.toString())) {
|
||||
AlternateContent.Fallback fallback = (AlternateContent.Fallback)pict.getParent();
|
||||
AlternateContent alternateContent = (AlternateContent)fallback.getParent();
|
||||
R r = (R)alternateContent.getParent();
|
||||
Text text = factory.createText();
|
||||
text.setValue(stringBuilder + "JBY_TEXTBOX_JBY");
|
||||
r.getContent().set(0, text);
|
||||
r.setRPr(sourceR.getRPr());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void findTextBox(Object object, StringBuilder sb, boolean isFirstRun, R sourceR) {
|
||||
block8: {
|
||||
List egShapeElements;
|
||||
if (object instanceof CTShape || object instanceof CTRoundRect) {
|
||||
VmlShapeElements vmlShapeElements = (VmlShapeElements)object;
|
||||
egShapeElements = vmlShapeElements.getEGShapeElements();
|
||||
for (JAXBElement egShapeElement : egShapeElements) {
|
||||
if (!(egShapeElement.getValue() instanceof CTTextbox)) continue;
|
||||
CTTextbox ctTextbox = (CTTextbox)egShapeElement.getValue();
|
||||
CTTxbxContent txbxContent = ctTextbox.getTxbxContent();
|
||||
for (int i = 0; i < txbxContent.getContent().size(); ++i) {
|
||||
Object obj = txbxContent.getContent().get(i);
|
||||
String text = TextUtils.getText(obj);
|
||||
if (txbxContent.getContent().size() > 1 && i != txbxContent.getContent().size() - 1) {
|
||||
text = text + "JBY_TEXTBOX_JBYBR";
|
||||
}
|
||||
sb.append(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!(object instanceof CTGroup)) break block8;
|
||||
CTGroup ctGroup = (CTGroup)object;
|
||||
egShapeElements = ctGroup.getEGShapeElements();
|
||||
boolean isCtShape = egShapeElements.stream().anyMatch(f -> f.getValue() instanceof CTShape);
|
||||
if (isCtShape) {
|
||||
for (int i = egShapeElements.size() - 1; i >= 0; --i) {
|
||||
this.findTextBox(((JAXBElement)egShapeElements.get(i)).getValue(), sb, isFirstRun, sourceR);
|
||||
}
|
||||
} else {
|
||||
for (JAXBElement egShapeElement : egShapeElements) {
|
||||
this.findTextBox(egShapeElement.getValue(), sb, isFirstRun, sourceR);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
427
java-src/utils/finder/CtoMathFinder.java
Normal file
427
java-src/utils/finder/CtoMathFinder.java
Normal file
@@ -0,0 +1,427 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*
|
||||
* Could not load the following classes:
|
||||
* javax.xml.bind.JAXBElement
|
||||
* org.apache.commons.collections4.CollectionUtils
|
||||
* org.apache.commons.lang3.StringUtils
|
||||
* org.docx4j.TraversalUtil$CallbackImpl
|
||||
* org.docx4j.XmlUtils
|
||||
* org.docx4j.com.microsoft.schemas.office.word.x2010.wordprocessingShape.CTTextboxInfo
|
||||
* org.docx4j.math.CTOMath
|
||||
* org.docx4j.math.CTOMathPara
|
||||
* org.docx4j.wml.CTTxbxContent
|
||||
* org.docx4j.wml.CTVerticalAlignRun
|
||||
* org.docx4j.wml.FldChar
|
||||
* org.docx4j.wml.ObjectFactory
|
||||
* org.docx4j.wml.P
|
||||
* org.docx4j.wml.PPr
|
||||
* org.docx4j.wml.PPrBase$NumPr
|
||||
* org.docx4j.wml.PPrBase$NumPr$Ilvl
|
||||
* org.docx4j.wml.R
|
||||
* org.docx4j.wml.RPrAbstract
|
||||
* org.docx4j.wml.STFldCharType
|
||||
* org.docx4j.wml.Style
|
||||
* org.docx4j.wml.Text
|
||||
* org.docx4j.wml.U
|
||||
* org.docx4j.wml.UnderlineEnumeration
|
||||
* org.slf4j.Logger
|
||||
* org.slf4j.LoggerFactory
|
||||
*/
|
||||
package com.jby.officecore.utils.finder;
|
||||
|
||||
import com.jby.officecore.domain.bo.ParseBO;
|
||||
import com.jby.officecore.utils.EqToLatexUtil;
|
||||
import com.jby.officecore.utils.NumPr;
|
||||
import com.jby.officecore.utils.WordParseUtil;
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.xml.bind.JAXBElement;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.docx4j.TraversalUtil;
|
||||
import org.docx4j.XmlUtils;
|
||||
import org.docx4j.com.microsoft.schemas.office.word.x2010.wordprocessingShape.CTTextboxInfo;
|
||||
import org.docx4j.math.CTOMath;
|
||||
import org.docx4j.math.CTOMathPara;
|
||||
import org.docx4j.wml.CTTxbxContent;
|
||||
import org.docx4j.wml.CTVerticalAlignRun;
|
||||
import org.docx4j.wml.FldChar;
|
||||
import org.docx4j.wml.ObjectFactory;
|
||||
import org.docx4j.wml.P;
|
||||
import org.docx4j.wml.PPr;
|
||||
import org.docx4j.wml.PPrBase;
|
||||
import org.docx4j.wml.R;
|
||||
import org.docx4j.wml.RPrAbstract;
|
||||
import org.docx4j.wml.STFldCharType;
|
||||
import org.docx4j.wml.Style;
|
||||
import org.docx4j.wml.Text;
|
||||
import org.docx4j.wml.U;
|
||||
import org.docx4j.wml.UnderlineEnumeration;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class CtoMathFinder
|
||||
extends TraversalUtil.CallbackImpl {
|
||||
private static final Logger log = LoggerFactory.getLogger(CtoMathFinder.class);
|
||||
private ParseBO parseBO;
|
||||
private static final Pattern CIRCLED_NUMBER_PATTERN = Pattern.compile("^\\s*eq\\s*\\\\o\\((?:\u25cb,\\\\s\\\\up\\d+\\((\\d+)\\)|\\\\s\\\\up\\d+\\((\\d+)\\),\u25cb)\\)");
|
||||
|
||||
public CtoMathFinder(ParseBO parseBO) {
|
||||
this.parseBO = parseBO;
|
||||
}
|
||||
|
||||
public List<Object> apply(Object o) {
|
||||
if (o instanceof P) {
|
||||
Text text;
|
||||
Style style;
|
||||
CTTxbxContent ctTxbxContent;
|
||||
StringBuilder eqCode = new StringBuilder();
|
||||
StringBuilder originEqCode = new StringBuilder();
|
||||
boolean inFiled = false;
|
||||
boolean isEq = false;
|
||||
boolean superScriptFlag = false;
|
||||
boolean subScriptFlag = false;
|
||||
ArrayList<Integer> fieldRunIndexs = new ArrayList<Integer>();
|
||||
P paragraph = (P)o;
|
||||
ObjectFactory factory = new ObjectFactory();
|
||||
boolean isNumPr = true;
|
||||
if (paragraph.getParent() instanceof CTTxbxContent && (ctTxbxContent = (CTTxbxContent)paragraph.getParent()).getParent() instanceof CTTextboxInfo) {
|
||||
isNumPr = false;
|
||||
}
|
||||
PPr pPr = paragraph.getPPr();
|
||||
PPrBase.NumPr numPr = null;
|
||||
if (Objects.nonNull(pPr)) {
|
||||
numPr = pPr.getNumPr();
|
||||
}
|
||||
if (Objects.isNull(numPr) && Objects.nonNull(pPr) && Objects.nonNull(pPr.getPStyle()) && Objects.nonNull(style = this.parseBO.getStyleDefinitionsPart().getStyleById(pPr.getPStyle().getVal())) && Objects.nonNull(style.getPPr()) && Objects.nonNull(style.getPPr().getNumPr()) && Objects.isNull((numPr = style.getPPr().getNumPr()).getIlvl())) {
|
||||
PPrBase.NumPr.Ilvl ilvl = new PPrBase.NumPr.Ilvl();
|
||||
ilvl.setVal(BigInteger.ZERO);
|
||||
numPr.setIlvl(ilvl);
|
||||
}
|
||||
if (isNumPr && Objects.nonNull(numPr) && Objects.nonNull(numPr.getNumId()) && Objects.nonNull(numPr.getIlvl())) {
|
||||
String numPrKey = numPr.getNumId().getVal() + "_" + numPr.getIlvl().getVal();
|
||||
Map<String, NumPr> numberingDefinitionsMap = this.parseBO.getNumberingDefinitionsMap();
|
||||
if (numberingDefinitionsMap.containsKey(numPrKey)) {
|
||||
NumPr currentNumPr = numberingDefinitionsMap.get(numPrKey);
|
||||
String lvlText = currentNumPr.getLvlText();
|
||||
for (int i = 0; i <= numPr.getIlvl().getVal().intValue(); ++i) {
|
||||
NumPr numPrDefine;
|
||||
if (i == numPr.getIlvl().getVal().intValue()) {
|
||||
currentNumPr.setCurrent(currentNumPr.getCurrent().add(BigInteger.ONE));
|
||||
}
|
||||
String rep = String.valueOf((numPrDefine = numberingDefinitionsMap.get(numPr.getNumId().getVal() + "_" + i)).getCurrent().compareTo(BigInteger.ZERO) == 0 ? numPrDefine.getStart() : numPrDefine.getCurrent());
|
||||
if (i == numPr.getIlvl().getVal().intValue()) {
|
||||
switch (currentNumPr.getNumFmt()) {
|
||||
case "UPPER_ROMAN": {
|
||||
rep = this.strToUpperRoman(rep);
|
||||
break;
|
||||
}
|
||||
case "DECIMAL_ZERO": {
|
||||
rep = CtoMathFinder.strToDecimalZero(rep);
|
||||
break;
|
||||
}
|
||||
case "LOWER_LETTER": {
|
||||
rep = CtoMathFinder.strToLowerLetter(rep);
|
||||
break;
|
||||
}
|
||||
case "UPPER_LETTER": {
|
||||
rep = CtoMathFinder.strToLowerLetter(rep).toUpperCase();
|
||||
break;
|
||||
}
|
||||
case "LOWER_ROMAN": {
|
||||
rep = this.strToUpperRoman(rep).toLowerCase();
|
||||
break;
|
||||
}
|
||||
case "CHINESE_COUNTING":
|
||||
case "CHINESE_COUNTING_THOUSAND": {
|
||||
rep = this.strToChineseCounting(rep);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
lvlText = lvlText.replace("%" + (i + 1), rep);
|
||||
}
|
||||
if (StringUtils.isNotBlank((CharSequence)lvlText)) {
|
||||
R run = factory.createR();
|
||||
text = factory.createText();
|
||||
text.setValue(lvlText + " ");
|
||||
run.getContent().add(text);
|
||||
paragraph.getContent().add(0, run);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < paragraph.getContent().size(); ++i) {
|
||||
JAXBElement jaxbElement;
|
||||
Object content = paragraph.getContent().get(i);
|
||||
if (content instanceof JAXBElement && ((jaxbElement = (JAXBElement)content).getValue() instanceof CTOMath || jaxbElement.getValue() instanceof CTOMathPara)) {
|
||||
String placeholder = "";
|
||||
if (Boolean.TRUE.equals(this.parseBO.getNewParseVersion())) {
|
||||
String omml = XmlUtils.marshaltoString((Object)jaxbElement);
|
||||
placeholder = this.parseBO.getOpenOfficeXmlPlaceholder();
|
||||
this.parseBO.getOpenOfficeXmlMap().put(placeholder, omml);
|
||||
} else {
|
||||
String mathMl = WordParseUtil.getMathMl(jaxbElement, this.parseBO.getTransformer());
|
||||
placeholder = this.parseBO.getOpenOfficeXmlPlaceholder();
|
||||
this.parseBO.getOpenOfficeXmlMap().put(placeholder, mathMl);
|
||||
}
|
||||
R run = factory.createR();
|
||||
text = factory.createText();
|
||||
text.setValue(placeholder);
|
||||
run.getContent().add(text);
|
||||
paragraph.getContent().set(i, run);
|
||||
}
|
||||
if (!(content instanceof R)) continue;
|
||||
R run = (R)content;
|
||||
for (int j = 0; j < run.getContent().size(); ++j) {
|
||||
Object runC = run.getContent().get(j);
|
||||
if (!(runC instanceof JAXBElement)) continue;
|
||||
JAXBElement runCj = (JAXBElement)runC;
|
||||
if (runCj.getValue() instanceof FldChar) {
|
||||
FldChar fldChar = (FldChar)runCj.getValue();
|
||||
if (fldChar.getFldCharType().equals((Object)STFldCharType.BEGIN)) {
|
||||
eqCode = new StringBuilder();
|
||||
originEqCode = new StringBuilder();
|
||||
inFiled = true;
|
||||
isEq = false;
|
||||
superScriptFlag = false;
|
||||
subScriptFlag = false;
|
||||
fieldRunIndexs = new ArrayList();
|
||||
fieldRunIndexs.add(i);
|
||||
continue;
|
||||
}
|
||||
if (inFiled && fldChar.getFldCharType().equals((Object)STFldCharType.END)) {
|
||||
if (isEq) {
|
||||
String placeholder;
|
||||
Matcher matcher = CIRCLED_NUMBER_PATTERN.matcher(originEqCode);
|
||||
if (matcher.matches()) {
|
||||
String numStr = matcher.group(1) != null ? matcher.group(1) : matcher.group(2);
|
||||
placeholder = this.parseBO.getEqLatexPlaceholder() + "JBYEQNUM";
|
||||
this.parseBO.getEqLatexMap().put(placeholder, CtoMathFinder.getCircledNumber(numStr));
|
||||
R runN = factory.createR();
|
||||
Text text2 = factory.createText();
|
||||
text2.setValue(placeholder);
|
||||
runN.getContent().add(text2);
|
||||
paragraph.getContent().set(i, runN);
|
||||
} else if (StringUtils.isNotBlank((CharSequence)eqCode.toString())) {
|
||||
String latex = EqToLatexUtil.convert(eqCode.toString());
|
||||
latex = latex.replaceAll("<", "<").replaceAll(">", ">");
|
||||
placeholder = this.parseBO.getEqLatexPlaceholder();
|
||||
this.parseBO.getEqLatexMap().put(placeholder, latex);
|
||||
R runN = factory.createR();
|
||||
Text text3 = factory.createText();
|
||||
text3.setValue(placeholder);
|
||||
runN.getContent().add(text3);
|
||||
paragraph.getContent().set(i, runN);
|
||||
}
|
||||
}
|
||||
inFiled = false;
|
||||
isEq = false;
|
||||
fieldRunIndexs.clear();
|
||||
continue;
|
||||
}
|
||||
if (inFiled && isEq && !fldChar.getFldCharType().value().equals("separate")) continue;
|
||||
}
|
||||
if (!inFiled || !(runCj.getValue() instanceof Text)) continue;
|
||||
CTVerticalAlignRun vertAlign = Optional.ofNullable(run.getRPr()).map(RPrAbstract::getVertAlign).orElse(null);
|
||||
String value = ((Text)runCj.getValue()).getValue();
|
||||
originEqCode.append(value);
|
||||
U u = Optional.ofNullable(run.getRPr()).filter(f -> Objects.nonNull(f.getU()) && !UnderlineEnumeration.NONE.equals((Object)f.getU().getVal()) && Objects.nonNull(f.getU().getVal())).map(RPrAbstract::getU).orElse(null);
|
||||
if (StringUtils.isBlank((CharSequence)value) && Objects.nonNull(u)) {
|
||||
value = value.replace("\u3000", "JBYU1JBYU").replace(" ", "JBYU1JBYU");
|
||||
} else if (StringUtils.isNotBlank((CharSequence)value) && Objects.nonNull(u)) {
|
||||
value = "JBYU2BEGIN" + value + "JBYU2END";
|
||||
} else if (StringUtils.isBlank((CharSequence)value)) {
|
||||
// empty if block
|
||||
}
|
||||
String trimmedOrigin = CtoMathFinder.extractEqPrefix(originEqCode);
|
||||
if (trimmedOrigin.startsWith("eq")) {
|
||||
isEq = true;
|
||||
}
|
||||
if (isEq) {
|
||||
if (CollectionUtils.isNotEmpty(fieldRunIndexs)) {
|
||||
fieldRunIndexs.forEach(m -> paragraph.getContent().set((int)m, factory.createR()));
|
||||
fieldRunIndexs.clear();
|
||||
}
|
||||
if (Objects.nonNull(vertAlign)) {
|
||||
String newContent;
|
||||
String tmp;
|
||||
if ("superscript".equalsIgnoreCase(vertAlign.getVal().toString())) {
|
||||
int end;
|
||||
int start;
|
||||
if (superScriptFlag && (start = eqCode.lastIndexOf("\\s\\up4(")) != -1 && (end = eqCode.toString().indexOf(41, start)) != -1) {
|
||||
tmp = eqCode.substring(start + 7, end);
|
||||
newContent = tmp + value;
|
||||
eqCode = new StringBuilder(eqCode.substring(0, start));
|
||||
eqCode.append("\\s\\up4(").append(newContent).append(")");
|
||||
value = "";
|
||||
}
|
||||
if (StringUtils.isNotBlank((CharSequence)value)) {
|
||||
value = "\\s\\up4(" + value + ")";
|
||||
}
|
||||
superScriptFlag = true;
|
||||
subScriptFlag = false;
|
||||
} else if ("subscript".equalsIgnoreCase(vertAlign.getVal().toString())) {
|
||||
int end;
|
||||
int start;
|
||||
if (subScriptFlag && (start = eqCode.lastIndexOf("\\s\\do4(")) != -1 && (end = eqCode.toString().indexOf(41, start)) != -1) {
|
||||
tmp = eqCode.substring(start + 7, end);
|
||||
newContent = tmp + value;
|
||||
eqCode = new StringBuilder(eqCode.substring(0, start));
|
||||
eqCode.append("\\s\\do4(").append(newContent).append(")");
|
||||
value = "";
|
||||
}
|
||||
if (StringUtils.isNotBlank((CharSequence)value)) {
|
||||
value = "\\s\\do4(" + value + ")";
|
||||
}
|
||||
subScriptFlag = true;
|
||||
superScriptFlag = false;
|
||||
} else {
|
||||
superScriptFlag = false;
|
||||
subScriptFlag = false;
|
||||
}
|
||||
} else {
|
||||
superScriptFlag = false;
|
||||
subScriptFlag = false;
|
||||
}
|
||||
eqCode.append(value);
|
||||
paragraph.getContent().set(i, factory.createR());
|
||||
continue;
|
||||
}
|
||||
if (trimmedOrigin.length() < 2 || "eq".startsWith(trimmedOrigin)) {
|
||||
eqCode.append(value);
|
||||
fieldRunIndexs.add(i);
|
||||
continue;
|
||||
}
|
||||
inFiled = false;
|
||||
fieldRunIndexs.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String strToUpperRoman(String str) {
|
||||
int num = Integer.parseInt(str);
|
||||
if (num < 1 || num > 3999) {
|
||||
return "I";
|
||||
}
|
||||
int[] values = new int[]{1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
|
||||
String[] symbols = new String[]{"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"};
|
||||
StringBuilder roman = new StringBuilder();
|
||||
for (int i = 0; i < values.length; ++i) {
|
||||
while (num >= values[i]) {
|
||||
roman.append(symbols[i]);
|
||||
num -= values[i];
|
||||
}
|
||||
}
|
||||
return roman.toString();
|
||||
}
|
||||
|
||||
private static String strToDecimalZero(String str) {
|
||||
if (str.length() == 1) {
|
||||
return "0" + str;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
private static String strToLowerLetter(String str) {
|
||||
int n = Integer.parseInt(str);
|
||||
int length = (n - 1) / 26 + 1;
|
||||
char baseChar = (char)(97 + (n - 1) % 26);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < length; ++i) {
|
||||
sb.append(baseChar);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public String strToChineseCounting(String str) {
|
||||
String s;
|
||||
int num = Integer.parseInt(str);
|
||||
if (num < 0 || num >= 1000000000) {
|
||||
throw new IllegalArgumentException("\u4ec5\u652f\u6301 0 \u5230 999,999,999");
|
||||
}
|
||||
if (num == 0) {
|
||||
return "\u3007";
|
||||
}
|
||||
char[] digits = new char[]{'\u3007', '\u4e00', '\u4e8c', '\u4e09', '\u56db', '\u4e94', '\u516d', '\u4e03', '\u516b', '\u4e5d'};
|
||||
String[] units = new String[]{"", "\u5341", "\u767e", "\u5343"};
|
||||
String[] bigUnits = new String[]{"", "\u4e07", "\u4ebf"};
|
||||
StringBuilder result = new StringBuilder();
|
||||
int yi = num / 100000000;
|
||||
int wan = num / 10000 % 10000;
|
||||
int ge = num % 10000;
|
||||
if (yi > 0) {
|
||||
result.append(CtoMathFinder.convertSegment(yi, digits, units)).append(bigUnits[2]);
|
||||
if (wan == 0 && ge > 0) {
|
||||
result.append('\u3007');
|
||||
}
|
||||
}
|
||||
if (wan > 0) {
|
||||
result.append(CtoMathFinder.convertSegment(wan, digits, units)).append(bigUnits[1]);
|
||||
if (ge > 0 && ge < 1000) {
|
||||
result.append('\u3007');
|
||||
}
|
||||
}
|
||||
if (ge > 0) {
|
||||
result.append(CtoMathFinder.convertSegment(ge, digits, units));
|
||||
}
|
||||
if ((s = result.toString()).startsWith("\u4e00\u5341")) {
|
||||
s = s.substring(1);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
private static String convertSegment(int n, char[] digits, String[] units) {
|
||||
if (n == 0) {
|
||||
return "";
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
int power = 3 - i;
|
||||
int base = (int)Math.pow(10.0, power);
|
||||
int digit = n / base % 10;
|
||||
if (digit != 0) {
|
||||
sb.append(digits[digit]).append(units[power]);
|
||||
continue;
|
||||
}
|
||||
if (sb.length() <= 0 || n % base == 0 || power <= 0) continue;
|
||||
sb.append('\u3007');
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static String getCircledNumber(String num) {
|
||||
int n = Integer.parseInt(num);
|
||||
if (n >= 1 && n <= 20) {
|
||||
return String.valueOf((char)(9312 + n - 1));
|
||||
}
|
||||
if (n >= 21 && n <= 35) {
|
||||
return String.valueOf((char)(12881 + n - 21));
|
||||
}
|
||||
if (n >= 36 && n <= 40) {
|
||||
return String.valueOf((char)(12977 + n - 36));
|
||||
}
|
||||
if (n >= 41 && n <= 50) {
|
||||
return String.valueOf((char)(12982 + n - 41));
|
||||
}
|
||||
log.info("\u83b7\u53d6\u5e26\u5708\u5b57\u7b26\u5931\u8d25 {}", (Object)num);
|
||||
return "";
|
||||
}
|
||||
|
||||
private static String extractEqPrefix(StringBuilder originEqCode) {
|
||||
int i;
|
||||
String s = originEqCode.toString().trim();
|
||||
for (i = 0; i < s.length() && s.charAt(i) == '{'; ++i) {
|
||||
}
|
||||
return s.substring(i).trim().toLowerCase();
|
||||
}
|
||||
}
|
||||
|
||||
434
java-src/utils/finder/DrawingPictFinder.java
Normal file
434
java-src/utils/finder/DrawingPictFinder.java
Normal file
@@ -0,0 +1,434 @@
|
||||
/*
|
||||
* Decompiled with CFR 0.152.
|
||||
*
|
||||
* Could not load the following classes:
|
||||
* com.alibaba.excel.util.StringUtils
|
||||
* com.jby.common.util.UniqueUtil
|
||||
* javax.xml.bind.JAXBElement
|
||||
* org.apache.commons.collections4.CollectionUtils
|
||||
* org.docx4j.TraversalUtil$CallbackImpl
|
||||
* org.docx4j.dml.GraphicData
|
||||
* org.docx4j.dml.picture.Pic
|
||||
* org.docx4j.dml.wordprocessingDrawing.Anchor
|
||||
* org.docx4j.dml.wordprocessingDrawing.Inline
|
||||
* org.docx4j.openpackaging.packages.WordprocessingMLPackage
|
||||
* org.docx4j.openpackaging.parts.Part
|
||||
* org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage
|
||||
* org.docx4j.openpackaging.parts.relationships.RelationshipsPart
|
||||
* org.docx4j.vml.CTImageData
|
||||
* org.docx4j.vml.CTShape
|
||||
* org.docx4j.vml.officedrawing.CTOLEObject
|
||||
* org.docx4j.wml.CTObject
|
||||
* org.docx4j.wml.Drawing
|
||||
* org.docx4j.wml.ObjectFactory
|
||||
* org.docx4j.wml.Pict
|
||||
* org.docx4j.wml.R
|
||||
* org.docx4j.wml.Text
|
||||
* org.slf4j.Logger
|
||||
* org.slf4j.LoggerFactory
|
||||
*/
|
||||
package com.jby.officecore.utils.finder;
|
||||
|
||||
import com.alibaba.excel.util.StringUtils;
|
||||
import com.jby.common.util.UniqueUtil;
|
||||
import com.jby.officecore.domain.bo.ImageBO;
|
||||
import com.jby.officecore.domain.bo.ParseBO;
|
||||
import com.jby.officecore.enums.AttrEnum;
|
||||
import java.awt.AlphaComposite;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.RenderingHints;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.RenderedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.xml.bind.JAXBElement;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.docx4j.TraversalUtil;
|
||||
import org.docx4j.dml.GraphicData;
|
||||
import org.docx4j.dml.picture.Pic;
|
||||
import org.docx4j.dml.wordprocessingDrawing.Anchor;
|
||||
import org.docx4j.dml.wordprocessingDrawing.Inline;
|
||||
import org.docx4j.openpackaging.packages.WordprocessingMLPackage;
|
||||
import org.docx4j.openpackaging.parts.Part;
|
||||
import org.docx4j.openpackaging.parts.WordprocessingML.BinaryPartAbstractImage;
|
||||
import org.docx4j.openpackaging.parts.relationships.RelationshipsPart;
|
||||
import org.docx4j.vml.CTImageData;
|
||||
import org.docx4j.vml.CTShape;
|
||||
import org.docx4j.vml.officedrawing.CTOLEObject;
|
||||
import org.docx4j.wml.CTObject;
|
||||
import org.docx4j.wml.Drawing;
|
||||
import org.docx4j.wml.ObjectFactory;
|
||||
import org.docx4j.wml.Pict;
|
||||
import org.docx4j.wml.R;
|
||||
import org.docx4j.wml.Text;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class DrawingPictFinder
|
||||
extends TraversalUtil.CallbackImpl {
|
||||
private static final Logger log = LoggerFactory.getLogger(DrawingPictFinder.class);
|
||||
private final WordprocessingMLPackage wordMlPackage;
|
||||
private final ParseBO parseBO;
|
||||
private static final double CROP_SCALE = 1.52587890625;
|
||||
|
||||
public DrawingPictFinder(WordprocessingMLPackage wordMlPackage, ParseBO parseBO) {
|
||||
this.wordMlPackage = wordMlPackage;
|
||||
this.parseBO = parseBO;
|
||||
}
|
||||
|
||||
public List<Object> apply(Object o) {
|
||||
List contentList;
|
||||
List anyAndAny;
|
||||
R r;
|
||||
if (o instanceof Drawing && ((Drawing)o).getParent() instanceof R) {
|
||||
RelationshipsPart relationshipsPart = this.wordMlPackage.getMainDocumentPart().getRelationshipsPart();
|
||||
Drawing drawing = (Drawing)o;
|
||||
List anchorOrInline = drawing.getAnchorOrInline();
|
||||
if (CollectionUtils.isNotEmpty((Collection)anchorOrInline)) {
|
||||
Object anchorOrInlineObj = anchorOrInline.get(0);
|
||||
GraphicData graphicData = null;
|
||||
long cx = 0L;
|
||||
long cy = 0L;
|
||||
if (anchorOrInlineObj instanceof Inline) {
|
||||
Inline inline = (Inline)anchorOrInlineObj;
|
||||
graphicData = inline.getGraphic().getGraphicData();
|
||||
cx = inline.getExtent().getCx();
|
||||
cy = inline.getExtent().getCy();
|
||||
} else if (anchorOrInlineObj instanceof Anchor) {
|
||||
Anchor anchor = (Anchor)anchorOrInlineObj;
|
||||
graphicData = anchor.getGraphic().getGraphicData();
|
||||
cx = anchor.getExtent().getCx();
|
||||
cy = anchor.getExtent().getCy();
|
||||
}
|
||||
if (Objects.nonNull(graphicData) && "http://schemas.openxmlformats.org/drawingml/2006/picture".equals(graphicData.getUri())) {
|
||||
for (Object object : graphicData.getAny()) {
|
||||
String path;
|
||||
JAXBElement jaxbElement;
|
||||
if (!(object instanceof JAXBElement) || !((jaxbElement = (JAXBElement)object).getValue() instanceof Pic)) continue;
|
||||
Pic pic = (Pic)jaxbElement.getValue();
|
||||
String imageDataId = null;
|
||||
int cropLeft = 0;
|
||||
int cropTop = 0;
|
||||
int cropRight = 0;
|
||||
int cropBottom = 0;
|
||||
int rotation = 0;
|
||||
if (Objects.nonNull(pic.getBlipFill())) {
|
||||
if (Objects.nonNull(pic.getBlipFill().getBlip())) {
|
||||
imageDataId = pic.getBlipFill().getBlip().getEmbed();
|
||||
}
|
||||
if (Objects.nonNull(pic.getBlipFill().getSrcRect())) {
|
||||
cropLeft = pic.getBlipFill().getSrcRect().getL();
|
||||
cropTop = pic.getBlipFill().getSrcRect().getT();
|
||||
cropRight = pic.getBlipFill().getSrcRect().getR();
|
||||
cropBottom = pic.getBlipFill().getSrcRect().getB();
|
||||
}
|
||||
if (Objects.nonNull(pic.getSpPr()) && Objects.nonNull(pic.getSpPr().getXfrm())) {
|
||||
rotation = pic.getSpPr().getXfrm().getRot();
|
||||
}
|
||||
}
|
||||
Map<String, Object> map = this.dealCropRotate(imageDataId, cx, cropLeft, cropTop, cropRight, cropBottom, rotation);
|
||||
Object widthObj = map.get(AttrEnum.WIDTH.getAttr());
|
||||
Object heightObj = map.get(AttrEnum.HEIGHT.getAttr());
|
||||
Object pathObj = map.get("imagePath");
|
||||
double width = Objects.nonNull(widthObj) ? Double.parseDouble(widthObj.toString()) : (double)Math.round((double)cx / 9525.0);
|
||||
double height = Objects.nonNull(heightObj) ? Double.parseDouble(heightObj.toString()) : (double)Math.round((double)cy / 9525.0);
|
||||
Part part = relationshipsPart.getPart(imageDataId);
|
||||
if (Objects.nonNull(pathObj)) {
|
||||
path = String.valueOf(pathObj);
|
||||
} else if (Objects.nonNull(part)) {
|
||||
path = part.getPartName().getURI().getPath();
|
||||
} else {
|
||||
log.warn("\u65e0\u6cd5\u83b7\u53d6\u56fe\u7247Part\uff0cimageDataId={}", (Object)imageDataId);
|
||||
continue;
|
||||
}
|
||||
String imagePlaceholder = this.parseBO.getImagePlaceholder(imageDataId);
|
||||
ImageBO imageBO = new ImageBO().setWidth(width).setHeight(height).setPictureUrl(path);
|
||||
this.parseBO.getImageMap().put(imagePlaceholder, imageBO);
|
||||
R r2 = (R)drawing.getParent();
|
||||
List contentList2 = r2.getContent();
|
||||
int drawingIndex = contentList2.indexOf(drawing);
|
||||
if (drawingIndex != -1) {
|
||||
Text text = new ObjectFactory().createText();
|
||||
text.setValue(imagePlaceholder);
|
||||
contentList2.set(drawingIndex, text);
|
||||
continue;
|
||||
}
|
||||
log.warn("\u672a\u627e\u5230drawing\u5bf9\u8c61\u5728\u7236\u5143\u7d20\u4e2d\u7684\u7d22\u5f15\uff0c\u8df3\u8fc7\u66ff\u6362\u64cd\u4f5c");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (o instanceof Pict && ((Pict)o).getParent() instanceof R) {
|
||||
Pict pict = (Pict)o;
|
||||
r = (R)pict.getParent();
|
||||
anyAndAny = pict.getAnyAndAny();
|
||||
contentList = r.getContent();
|
||||
int pictIndex = contentList.indexOf(pict);
|
||||
if (pictIndex != -1) {
|
||||
this.dealCtShape(anyAndAny, r, pictIndex);
|
||||
}
|
||||
}
|
||||
if (o instanceof CTObject && ((CTObject)o).getParent() instanceof R) {
|
||||
CTObject ctObject = (CTObject)o;
|
||||
r = (R)ctObject.getParent();
|
||||
anyAndAny = ctObject.getAnyAndAny();
|
||||
contentList = r.getContent();
|
||||
int ctObjectIndex = contentList.indexOf(ctObject);
|
||||
if (ctObjectIndex != -1) {
|
||||
this.dealCtShape(anyAndAny, r, ctObjectIndex);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String extractValue(String style, String property) {
|
||||
if (style == null || property == null) {
|
||||
return null;
|
||||
}
|
||||
String regex = "\\b" + Pattern.quote(property) + "\\s*:\\s*([\\d.]+[a-zA-Z]*)";
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
Matcher matcher = pattern.matcher(style);
|
||||
if (matcher.find()) {
|
||||
return matcher.group(1);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void dealCtShape(List<Object> anyAndAny, R r, int pictIndex) {
|
||||
String ctOleObjectRid = anyAndAny.stream().filter(f -> f instanceof JAXBElement && ((JAXBElement)f).getValue() instanceof CTOLEObject).map(f -> ((CTOLEObject)((JAXBElement)f).getValue()).getId()).filter(Objects::nonNull).findFirst().orElse(null);
|
||||
if (Objects.nonNull(ctOleObjectRid) && Objects.nonNull(this.parseBO.getMathTypeMap().get(this.parseBO.getMathTypePlaceholder(ctOleObjectRid)))) {
|
||||
Text text = new ObjectFactory().createText();
|
||||
text.setValue(this.parseBO.getMathTypePlaceholder(ctOleObjectRid));
|
||||
r.getContent().set(pictIndex, text);
|
||||
} else if (Objects.isNull(ctOleObjectRid) || Objects.isNull(this.parseBO.getMathTypeMap().get(this.parseBO.getMathTypePlaceholder(ctOleObjectRid)))) {
|
||||
if (Objects.nonNull(ctOleObjectRid)) {
|
||||
this.parseBO.getMathTypeMap().remove(this.parseBO.getMathTypePlaceholder(ctOleObjectRid));
|
||||
}
|
||||
for (Object object : anyAndAny) {
|
||||
String path;
|
||||
double heightPx;
|
||||
double widthPx;
|
||||
if (!(object instanceof JAXBElement) || !(((JAXBElement)object).getValue() instanceof CTShape)) continue;
|
||||
CTShape ctShape = (CTShape)((JAXBElement)object).getValue();
|
||||
String width = this.extractValue(ctShape.getStyle(), "width");
|
||||
String height = this.extractValue(ctShape.getStyle(), "height");
|
||||
CTImageData ctImageData = ctShape.getEGShapeElements().stream().filter(f -> f.getValue() instanceof CTImageData).map(m -> (CTImageData)m.getValue()).findFirst().orElse(null);
|
||||
if (!Objects.nonNull(ctImageData) || !StringUtils.isNotBlank((CharSequence)width) || !StringUtils.isNotBlank((CharSequence)height)) continue;
|
||||
String ctImageDataId = ctImageData.getId();
|
||||
long cx = 0L;
|
||||
try {
|
||||
double widthPtIn = Double.parseDouble(width.substring(0, width.length() - 2));
|
||||
if (width.endsWith("pt")) {
|
||||
cx = Math.round(widthPtIn * 12700.0);
|
||||
} else if (width.endsWith("in")) {
|
||||
cx = Math.round(widthPtIn * 914400.0);
|
||||
}
|
||||
}
|
||||
catch (NumberFormatException ignored) {
|
||||
log.error("extractWidth error");
|
||||
}
|
||||
int cropLeft = this.parseVmlCrop(ctImageData.getCropleft());
|
||||
int cropTop = this.parseVmlCrop(ctImageData.getCroptop());
|
||||
int cropRight = this.parseVmlCrop(ctImageData.getCropright());
|
||||
int cropBottom = this.parseVmlCrop(ctImageData.getCropbottom());
|
||||
String rotRaw = this.extractValue(ctShape.getStyle(), "rotation");
|
||||
int rotation = rotRaw == null ? 0 : (int)Math.round((double)Long.parseLong(rotRaw.replaceAll("[^\\d-]", "")) * 0.91552734375);
|
||||
Map<String, Object> map = this.dealCropRotate(ctImageDataId, cx, cropLeft, cropTop, cropRight, cropBottom, rotation);
|
||||
Object widthObj = map.get(AttrEnum.WIDTH.getAttr());
|
||||
Object heightObj = map.get(AttrEnum.HEIGHT.getAttr());
|
||||
Object pathObj = map.get("imagePath");
|
||||
if (Objects.nonNull(widthObj) && Objects.nonNull(heightObj)) {
|
||||
widthPx = (Double)map.get(AttrEnum.WIDTH.getAttr());
|
||||
heightPx = (Double)map.get(AttrEnum.HEIGHT.getAttr());
|
||||
} else {
|
||||
widthPx = Double.parseDouble(width.replaceAll("pt|in", ""));
|
||||
if (width.endsWith("pt")) {
|
||||
widthPx = Math.round(widthPx * 96.0 / 72.0);
|
||||
} else if (width.endsWith("in")) {
|
||||
widthPx = Math.round(widthPx * 96.0);
|
||||
}
|
||||
heightPx = Double.parseDouble(height.replaceAll("pt|in", ""));
|
||||
if (height.endsWith("pt")) {
|
||||
heightPx = heightPx * 96.0 / 72.0;
|
||||
} else if (height.endsWith("in")) {
|
||||
heightPx *= 96.0;
|
||||
}
|
||||
}
|
||||
RelationshipsPart relationshipsPart = this.wordMlPackage.getMainDocumentPart().getRelationshipsPart();
|
||||
Part part = relationshipsPart.getPart(ctImageDataId);
|
||||
if (Objects.nonNull(pathObj)) {
|
||||
path = String.valueOf(pathObj);
|
||||
} else if (Objects.nonNull(part)) {
|
||||
path = part.getPartName().getURI().getPath();
|
||||
} else {
|
||||
log.warn("\u65e0\u6cd5\u83b7\u53d6\u8001\u7248VML\u56fe\u7247Part\uff0cctImageDataId={}", (Object)ctImageDataId);
|
||||
continue;
|
||||
}
|
||||
ImageBO imageBO = new ImageBO().setWidth(widthPx).setHeight(heightPx).setPictureUrl(path);
|
||||
String imagePlaceholder = this.parseBO.getImagePlaceholder(ctImageDataId);
|
||||
this.parseBO.getImageMap().put(imagePlaceholder, imageBO);
|
||||
Text text = new ObjectFactory().createText();
|
||||
text.setValue(imagePlaceholder);
|
||||
r.getContent().set(pictIndex, text);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Object> dealCropRotate(String imageDataId, long cx, int cropLeft, int cropTop, int cropRight, int cropBottom, int rotation) {
|
||||
HashMap<String, Object> result = new HashMap<String, Object>();
|
||||
try {
|
||||
if (Objects.nonNull(imageDataId)) {
|
||||
boolean isRotate;
|
||||
boolean isCrop = cropLeft > 0 || cropTop > 0 || cropRight > 0 || cropBottom > 0;
|
||||
boolean bl = isRotate = rotation != 0;
|
||||
if (isCrop || isRotate) {
|
||||
RelationshipsPart relationshipsPart = this.wordMlPackage.getMainDocumentPart().getRelationshipsPart();
|
||||
Part part = relationshipsPart.getPart(imageDataId);
|
||||
BinaryPartAbstractImage imagePart = (BinaryPartAbstractImage)part;
|
||||
BufferedImage targetImage = ImageIO.read(new ByteArrayInputStream(imagePart.getBytes()));
|
||||
if (isCrop) {
|
||||
targetImage = this.cropImage(targetImage, cropLeft, cropTop, cropRight, cropBottom);
|
||||
}
|
||||
if (isRotate) {
|
||||
targetImage = this.rotateImage(targetImage, rotation, cx, result);
|
||||
}
|
||||
if (Objects.nonNull(targetImage)) {
|
||||
String formatName = this.getFormatName(imagePart);
|
||||
String path = "/word/media/" + UniqueUtil.getUuid() + "." + formatName;
|
||||
ImageIO.write((RenderedImage)targetImage, formatName, new File(this.parseBO.getTempDir() + "/temp" + path));
|
||||
result.put("imagePath", path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
log.error("\u5904\u7406\u56fe\u7247\u88c1\u526a\u4e0e\u65cb\u8f6c\u5f02\u5e38", (Throwable)e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private String getFormatName(BinaryPartAbstractImage imagePart) {
|
||||
String contentType = imagePart.getContentType();
|
||||
String formatName = contentType.contains("png") ? "png" : (contentType.contains("jpeg") ? "jpeg" : (contentType.contains("gif") ? "gif" : (contentType.contains("bmp") ? "bmp" : "png")));
|
||||
return formatName;
|
||||
}
|
||||
|
||||
public BufferedImage cropImage(BufferedImage originalImage, int srcRectL, int srcRectT, int srcRectR, int srcRectB) {
|
||||
double leftRatio = srcRectL < 0 ? 0.0 : (double)srcRectL / 100000.0;
|
||||
double topRatio = srcRectT < 0 ? 0.0 : (double)srcRectT / 100000.0;
|
||||
double rightRatio = srcRectR < 0 ? 0.0 : (double)srcRectR / 100000.0;
|
||||
double bottomRatio = srcRectB < 0 ? 0.0 : (double)srcRectB / 100000.0;
|
||||
int originalWidth = originalImage.getWidth();
|
||||
int originalHeight = originalImage.getHeight();
|
||||
int left = (int)Math.floor(leftRatio * (double)originalWidth);
|
||||
int top = (int)Math.floor(topRatio * (double)originalHeight);
|
||||
int right = (int)Math.floor(rightRatio * (double)originalWidth);
|
||||
int bottom = (int)Math.floor(bottomRatio * (double)originalHeight);
|
||||
int cropWidth = Math.max(1, originalWidth - left - right);
|
||||
int cropHeight = Math.max(1, originalHeight - top - bottom);
|
||||
if (left < 0 || top < 0 || left + cropWidth > originalWidth || top + cropHeight > originalHeight) {
|
||||
log.error("\u88c1\u526a\u533a\u57df\u65e0\u6548\u6216\u8d85\u51fa\u56fe\u7247\u8fb9\u754c");
|
||||
}
|
||||
return originalImage.getSubimage(left, top, cropWidth, cropHeight);
|
||||
}
|
||||
|
||||
private BufferedImage rotateImage(BufferedImage originalImage, long rotation, long currentCx, Map<String, Object> result) {
|
||||
int origWidth = originalImage.getWidth();
|
||||
int origHeight = originalImage.getHeight();
|
||||
if (origWidth <= 0 || origHeight <= 0) {
|
||||
log.error("\u56fe\u7247\u533a\u57df\u65e0\u6548");
|
||||
}
|
||||
double emuPerPx = (double)currentCx / (double)origWidth;
|
||||
if (currentCx == 0L) {
|
||||
emuPerPx = 9525.0;
|
||||
}
|
||||
double degrees = (double)rotation / 60000.0;
|
||||
double radians = Math.toRadians(degrees);
|
||||
double sin = Math.abs(Math.sin(radians));
|
||||
double cos = Math.abs(Math.cos(radians));
|
||||
double TOLERANCE = 1.0E-10;
|
||||
if (sin < 1.0E-10) {
|
||||
sin = 0.0;
|
||||
}
|
||||
if (cos < 1.0E-10) {
|
||||
cos = 0.0;
|
||||
}
|
||||
int newWidth = (int)Math.ceil((double)origWidth * cos + (double)origHeight * sin);
|
||||
int newHeight = (int)Math.ceil((double)origWidth * sin + (double)origHeight * cos);
|
||||
newWidth = Math.max(1, newWidth);
|
||||
newHeight = Math.max(1, newHeight);
|
||||
int superSampleFactor = 4;
|
||||
int ssWidth = origWidth * superSampleFactor;
|
||||
int ssHeight = origHeight * superSampleFactor;
|
||||
int ssNewW = newWidth * superSampleFactor;
|
||||
int ssNewH = newHeight * superSampleFactor;
|
||||
int imgType1 = originalImage.getType() == 0 ? 2 : originalImage.getType();
|
||||
BufferedImage highResOriginal = new BufferedImage(ssWidth, ssHeight, imgType1);
|
||||
Graphics2D g2dHighRes = highResOriginal.createGraphics();
|
||||
this.configureGraphics2D(g2dHighRes);
|
||||
g2dHighRes.drawImage(originalImage, 0, 0, ssWidth, ssHeight, null);
|
||||
g2dHighRes.dispose();
|
||||
int imgType2 = highResOriginal.getType() == 0 ? 2 : highResOriginal.getType();
|
||||
BufferedImage rotatedSuperSample = new BufferedImage(ssNewW, ssNewH, imgType2);
|
||||
Graphics2D g2dRotated = rotatedSuperSample.createGraphics();
|
||||
if (highResOriginal.getType() == 2) {
|
||||
g2dRotated.setComposite(AlphaComposite.Clear);
|
||||
g2dRotated.fillRect(0, 0, ssNewW, ssNewH);
|
||||
g2dRotated.setComposite(AlphaComposite.SrcOver);
|
||||
} else {
|
||||
g2dRotated.setColor(Color.WHITE);
|
||||
g2dRotated.fillRect(0, 0, ssNewW, ssNewH);
|
||||
}
|
||||
g2dRotated.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
g2dRotated.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
|
||||
g2dRotated.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
g2dRotated.translate((double)ssNewW / 2.0, (double)ssNewH / 2.0);
|
||||
g2dRotated.rotate(radians);
|
||||
g2dRotated.drawImage((Image)highResOriginal, -ssWidth / 2, -ssHeight / 2, null);
|
||||
g2dRotated.dispose();
|
||||
BufferedImage rotatedImage = new BufferedImage(newWidth, newHeight, rotatedSuperSample.getType() == 0 ? 2 : rotatedSuperSample.getType());
|
||||
Graphics2D g2dFinal = rotatedImage.createGraphics();
|
||||
this.configureGraphics2D(g2dFinal);
|
||||
g2dFinal.drawImage(rotatedSuperSample, 0, 0, newWidth, newHeight, null);
|
||||
g2dFinal.dispose();
|
||||
long newCx = Math.round((double)newWidth * emuPerPx);
|
||||
long newCy = Math.round((double)newHeight * emuPerPx);
|
||||
double newWidthPx = Math.round((double)newCx / 9525.0);
|
||||
double newHeightPx = Math.round((double)newCy / 9525.0);
|
||||
result.put(AttrEnum.WIDTH.getAttr(), newWidthPx);
|
||||
result.put(AttrEnum.HEIGHT.getAttr(), newHeightPx);
|
||||
return rotatedImage;
|
||||
}
|
||||
|
||||
private void configureGraphics2D(Graphics2D g2d) {
|
||||
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
|
||||
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
|
||||
}
|
||||
|
||||
private int parseVmlCrop(String vmlCrop) {
|
||||
if (vmlCrop == null || StringUtils.isBlank((CharSequence)vmlCrop)) {
|
||||
return 0;
|
||||
}
|
||||
String clean = vmlCrop.trim().replaceAll("[fF]$", "");
|
||||
try {
|
||||
int value = Integer.parseInt(clean);
|
||||
return (int)Math.round((double)value * 1.52587890625);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user