diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..549e00a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,33 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
+.vscode/
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..0786182
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,102 @@
+
+
+ 4.0.0
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 2.7.5
+
+
+ com.example
+ mathToImg
+ 0.0.1-SNAPSHOT
+ mathToImg
+ Demo project for Spring Boot
+
+ 1.8
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+ org.apache.poi
+ poi
+ 4.1.2
+
+
+ org.apache.poi
+ poi-ooxml
+ 4.1.2
+
+
+ org.apache.poi
+ poi-ooxml-schemas
+ 4.1.2
+
+
+ org.apache.poi
+ ooxml-schemas
+ 1.4
+
+
+ org.apache.xmlgraphics
+ batik-codec
+ 1.7
+
+
+ net.sourceforge.jeuclid
+ jeuclid-core
+ 3.1.9
+
+
+ org.apache.commons
+ commons-lang3
+ 3.9
+
+
+ io.minio
+ minio
+ 8.0.3
+
+
+ okio
+ com.squareup.okio
+
+
+ okhttp
+ com.squareup.okhttp3
+
+
+
+
+ com.squareup.okhttp3
+ okhttp
+ 4.4.1
+
+
+ org.springframework
+ spring-test
+ 5.3.9
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
+
diff --git a/src/main/java/com/example/mathtoimg/MathToImgApplication.java b/src/main/java/com/example/mathtoimg/MathToImgApplication.java
new file mode 100644
index 0000000..f13faae
--- /dev/null
+++ b/src/main/java/com/example/mathtoimg/MathToImgApplication.java
@@ -0,0 +1,13 @@
+package com.example.mathtoimg;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class MathToImgApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(MathToImgApplication.class, args);
+ }
+
+}
diff --git a/src/main/java/com/example/mathtoimg/controller/mathToImgController.java b/src/main/java/com/example/mathtoimg/controller/mathToImgController.java
new file mode 100644
index 0000000..84855fa
--- /dev/null
+++ b/src/main/java/com/example/mathtoimg/controller/mathToImgController.java
@@ -0,0 +1,640 @@
+package com.example.mathtoimg.controller;
+
+import com.example.mathtoimg.utils.ImageParse;
+import com.example.mathtoimg.utils.MinioUtil;
+import com.example.mathtoimg.utils.OmmlUtils;
+import org.apache.xmlbeans.XmlException;
+import org.apache.xmlbeans.XmlObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.mock.web.MockMultipartFile;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.*;
+import java.net.URLDecoder;
+import java.util.Map;
+
+@RestController
+public class mathToImgController {
+ private static final Logger log = LoggerFactory.getLogger(mathToImgController.class);
+
+ @Value("${file.mathToImgFilePath}")
+ private String mathToImgFilePath;
+ @Value("${xsl.omml2mmlFilePath}")
+ private String omml2mmlFilePath;
+
+
+ @PostMapping("/mathToImg")
+ public String mathToImg(@RequestBody String oriMathXmlStr) throws XmlException, UnsupportedEncodingException {
+ String result = "";
+ //String oriMathXmlStr = decoder((String) map.get("encode"));
+ XmlObject object = XmlObject.Factory.parse(oriMathXmlStr);
+ ImageParse imageParser = new ImageParse();
+ File file = OmmlUtils.convertOmathToPng(object, imageParser,mathToImgFilePath,omml2mmlFilePath);
+ try {
+ MultipartFile multipartFile = new MockMultipartFile(file.getName(), new FileInputStream(file));
+ String upload = MinioUtil.upload(multipartFile, "1");
+ file.delete();
+ return upload;
+ } catch (IOException e) {
+ log.error("",e);
+ return "公式转换图片失败";
+ }
+ }
+
+ public String decoder(String encode){
+ String decode = null;
+ try {
+ decode = URLDecoder.decode(encode, "UTF-8");
+ } catch (UnsupportedEncodingException e) {
+ e.printStackTrace();
+ }
+ return decode;
+ }
+
+ public static String oriMathXmlStr = "\n" +
+ "\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " f\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " x\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " =\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " a\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " 0\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " +\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " n=1\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " ∞\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " a\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " n\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " cos\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " nπx\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " L\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " +\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " b\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " n\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " sin\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " nπx\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " L\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ "";
+
+}
diff --git a/src/main/java/com/example/mathtoimg/utils/ImageParse.java b/src/main/java/com/example/mathtoimg/utils/ImageParse.java
new file mode 100644
index 0000000..fa66832
--- /dev/null
+++ b/src/main/java/com/example/mathtoimg/utils/ImageParse.java
@@ -0,0 +1,45 @@
+package com.example.mathtoimg.utils;
+
+import org.apache.commons.io.IOUtils;
+import org.springframework.beans.factory.annotation.Value;
+
+import java.io.*;
+import java.util.UUID;
+
+public class ImageParse {
+
+ private int number = 0;
+// private String targetDir;
+
+ public ImageParse() {
+ super();
+// this.targetDir = targetDir;
+ }
+
+ public String parse(byte[] data, String extName,String mathToImgFilePath) {
+ return parse(new ByteArrayInputStream(data), extName,mathToImgFilePath);
+ }
+
+ public String parse(InputStream in, String extName,String mathToImgFilePath) {
+ if (extName.lastIndexOf(".") > -1) {
+ extName = extName.substring(extName.lastIndexOf(".") + 1);
+ }
+
+ mathToImgFilePath = mathToImgFilePath + "/" + UUID.randomUUID().toString().replaceAll("-","");
+
+ File target = new File(mathToImgFilePath);
+ if (!target.exists()) {
+ target.mkdirs();
+ }
+ String filename = mathToImgFilePath + "/" + "image_" + (number++) + "." + extName;
+ try {
+ IOUtils.copy(in, new FileOutputStream(filename));
+ in.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return filename;
+ }
+
+
+}
diff --git a/src/main/java/com/example/mathtoimg/utils/MinioConfig.java b/src/main/java/com/example/mathtoimg/utils/MinioConfig.java
new file mode 100644
index 0000000..463e096
--- /dev/null
+++ b/src/main/java/com/example/mathtoimg/utils/MinioConfig.java
@@ -0,0 +1,35 @@
+package com.example.mathtoimg.utils;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Minio文件上传配置文件
+ */
+@Configuration
+public class MinioConfig {
+ @Value(value = "${jero.minio.minio_url}")
+ private String minioUrl;
+ @Value(value = "${jero.minio.minio_name}")
+ private String minioName;
+ @Value(value = "${jero.minio.minio_pass}")
+ private String minioPass;
+ @Value(value = "${jero.minio.bucketName}")
+ private String bucketName;
+
+ @Bean
+ public void initMinio(){
+ if(!minioUrl.startsWith("http")){
+ minioUrl = "http://" + minioUrl;
+ }
+ if(!minioUrl.endsWith("/")){
+ minioUrl = minioUrl.concat("/");
+ }
+ MinioUtil.setMinioUrl(minioUrl);
+ MinioUtil.setMinioName(minioName);
+ MinioUtil.setMinioPass(minioPass);
+ MinioUtil.setBucketName(bucketName);
+ }
+
+}
diff --git a/src/main/java/com/example/mathtoimg/utils/MinioUtil.java b/src/main/java/com/example/mathtoimg/utils/MinioUtil.java
new file mode 100644
index 0000000..00a16d9
--- /dev/null
+++ b/src/main/java/com/example/mathtoimg/utils/MinioUtil.java
@@ -0,0 +1,368 @@
+package com.example.mathtoimg.utils;
+
+import io.minio.*;
+import io.minio.errors.*;
+import io.minio.http.Method;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * minio文件上传工具类
+ */
+public class MinioUtil {
+ private static final Logger log = LoggerFactory.getLogger(MinioUtil.class);
+ private MinioUtil(){
+
+ }
+ private static String minioUrl;
+ private static String minioName;
+ private static String minioPass;
+ private static String bucketName;
+
+ public static void setMinioUrl(String minioUrl) {
+ MinioUtil.minioUrl = minioUrl;
+ }
+
+ public static void setMinioName(String minioName) {
+ MinioUtil.minioName = minioName;
+ }
+
+ public static void setMinioPass(String minioPass) {
+ MinioUtil.minioPass = minioPass;
+ }
+
+ public static void setBucketName(String bucketName) {
+ MinioUtil.bucketName = bucketName;
+ }
+
+ public static String getMinioUrl() {
+ return minioUrl;
+ }
+
+ public static String getBucketName() {
+ return bucketName;
+ }
+
+ private static MinioClient minioClient = null;
+
+ /**
+ * 上传文件
+ * @param file
+ * @return
+ */
+ public static String upload(MultipartFile file, String bizPath, String customBucket) {
+ String fileName = "";
+ //update-begin-author:wangshuai date:20201012 for: 过滤上传文件夹名特殊字符,防止攻击
+ //update-end-author:wangshuai date:20201012 for: 过滤上传文件夹名特殊字符,防止攻击
+ String newBucket = bucketName;
+ if(isNotEmpty(customBucket)){
+ newBucket = customBucket;
+ }
+ try {
+ initMinio(minioUrl, minioName,minioPass);
+ // 检查存储桶是否已经存在
+ if(!minioClient.bucketExists(BucketExistsArgs.builder().bucket(newBucket).build())) {
+ // 创建一个名为ota的存储桶
+ minioClient.makeBucket(MakeBucketArgs.builder().bucket(newBucket).build());
+ }
+ //update-end-author:liusq date:20210809 for: 过滤上传文件类型
+ InputStream stream = file.getInputStream();
+ // 获取文件名
+ String orgName = file.getOriginalFilename();
+ if("".equals(orgName)){
+ orgName=file.getName();
+ }
+ orgName = getFileName(orgName);
+ fileName = (!orgName.contains(".")
+ ? orgName + "_" + System.currentTimeMillis()
+ : orgName.substring(0, orgName.lastIndexOf(".")) + "_" + System.currentTimeMillis() + orgName.substring(orgName.lastIndexOf(".")));
+ String objectName = bizPath + "/" + fileName;
+ // 使用putObject上传一个本地文件到存储桶中。
+ if(objectName.startsWith("/")){
+ objectName = objectName.substring(1);
+ }
+ PutObjectArgs objectArgs = PutObjectArgs.builder().object(objectName)
+ .bucket(newBucket)
+ .contentType("application/octet-stream")
+ .stream(stream,stream.available(),-1).build();
+ minioClient.putObject(objectArgs);
+ stream.close();
+ }catch (Exception e){
+ log.error(e.getMessage(), e);
+ }
+ return fileName;
+ }
+
+ public static String getFileName(String fileName) {
+ if (StringUtils.isBlank(fileName)) {
+ return "";
+ }
+ //判断是否带有盘符信息
+ // Check for Unix-style path
+ int unixSep = fileName.lastIndexOf('/');
+ // Check for Windows-style path
+ int winSep = fileName.lastIndexOf('\\');
+ // Cut off at latest possible point
+ int pos = (winSep > unixSep ? winSep : unixSep);
+ if (pos != -1) {
+ // Any sort of path separator found...
+ fileName = fileName.substring(pos + 1);
+ }
+ //替换上传文件名字的特殊字符
+ fileName = fileName.replace("=", "").replace(",", "").replace("&", "")
+ .replace("#", "").replace("“", "").replace("”", "");
+ //替换上传文件名字中的空格
+ fileName = fileName.replaceAll("\\s", "");
+ return fileName;
+ }
+
+ public static boolean isNotEmpty(Object object) {
+ if (object != null && !object.equals("") && !object.equals("null")) {
+ return (true);
+ }
+ return (false);
+ }
+
+ /**
+ * 文件上传
+ * @param file
+ * @param bizPath
+ * @return
+ */
+ public static String upload(MultipartFile file, String bizPath) {
+ return upload(file,bizPath,null);
+ }
+
+ /**
+ * 判断文件是否存在
+ * @param objectName 文件名
+ * @return
+ */
+ public static boolean doesObjectExist(String objectName) {
+ boolean exist = true;
+ try {
+ initMinio(minioUrl, minioName,minioPass);
+ minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
+ } catch (Exception e) {
+ exist = false;
+ }
+ return exist;
+ }
+
+ /**
+ * 获取文件流
+ * @param bucketName
+ * @param objectName
+ * @return
+ */
+ public static InputStream getMinioFile(String bucketName, String objectName){
+ InputStream inputStream = null;
+ try {
+ initMinio(minioUrl, minioName, minioPass);
+ GetObjectArgs objectArgs = GetObjectArgs.builder().object(objectName)
+ .bucket(bucketName).build();
+ inputStream = minioClient.getObject(objectArgs);
+ } catch (Exception e) {
+ log.info("文件获取失败" + e.getMessage());
+ }
+ return inputStream;
+ }
+
+ /**
+ * 获取文件流
+ * @param objectName
+ * @return
+ */
+ public static InputStream download(String objectName){
+ InputStream inputStream = null;
+ try {
+ initMinio(minioUrl, minioName, minioPass);
+ GetObjectArgs objectArgs = GetObjectArgs.builder().object(objectName)
+ .bucket(bucketName).build();
+ inputStream = minioClient.getObject(objectArgs);
+ } catch (Exception e) {
+ log.info("文件获取失败" + e.getMessage());
+ }
+ return inputStream;
+ }
+
+ /**
+ * 删除文件
+ * @param objectName
+ * @throws Exception
+ */
+ public static void removeObject(String objectName) {
+ try {
+ initMinio(minioUrl, minioName,minioPass);
+ RemoveObjectArgs objectArgs = RemoveObjectArgs.builder().object(objectName)
+ .bucket(bucketName).build();
+ minioClient.removeObject(objectArgs);
+ }catch (Exception e){
+ log.info("文件删除失败" + e.getMessage());
+ }
+ }
+
+ /**
+ * 删除文件
+ * @param objectName
+ * @throws Exception
+ */
+ public static void delete(String objectName) {
+ try {
+ initMinio(minioUrl, minioName,minioPass);
+ RemoveObjectArgs objectArgs = RemoveObjectArgs.builder().object(objectName)
+ .bucket(bucketName).build();
+ minioClient.removeObject(objectArgs);
+ }catch (Exception e){
+ log.info("文件删除失败" + e.getMessage());
+ }
+ }
+
+ /**
+ * 获取文件外链
+ * @param bucketName
+ * @param objectName
+ * @param expires
+ * @return
+ */
+ public static String getObjectURL(String bucketName, String objectName, Integer expires) {
+ initMinio(minioUrl, minioName,minioPass);
+ try{
+ GetPresignedObjectUrlArgs objectArgs = GetPresignedObjectUrlArgs.builder().object(objectName)
+ .bucket(bucketName)
+ .expiry(expires).build();
+ String url = minioClient.getPresignedObjectUrl(objectArgs);
+ return URLDecoder.decode(url,"UTF-8");
+ }catch (Exception e){
+ log.info("文件路径获取失败" + e.getMessage());
+ }
+ return null;
+ }
+
+ /**
+ * 初始化客户端
+ * @param minioUrl
+ * @param minioName
+ * @param minioPass
+ * @return
+ */
+ private static MinioClient initMinio(String minioUrl, String minioName,String minioPass) {
+ if (minioClient == null) {
+ try {
+ minioClient = MinioClient.builder()
+ .endpoint(minioUrl)
+ .credentials(minioName, minioPass)
+ .build();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ return minioClient;
+ }
+
+ /**
+ * 上传文件到minio
+ * @param stream
+ * @param relativePath
+ * @return
+ */
+ public static String upload(InputStream stream,String relativePath) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, ServerException, InternalException, XmlParserException, ErrorResponseException {
+ initMinio(minioUrl, minioName,minioPass);
+ if(minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
+ log.info("Bucket already exists.");
+ } else {
+ // 创建一个名为ota的存储桶
+ minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
+ log.info("create a new bucket.");
+ }
+ PutObjectArgs objectArgs = PutObjectArgs.builder().object(relativePath)
+ .bucket(bucketName)
+ .contentType("application/octet-stream")
+ .stream(stream,stream.available(),-1).build();
+ minioClient.putObject(objectArgs);
+ stream.close();
+ return minioUrl+bucketName+"/"+relativePath;
+ }
+
+ /**
+ * cos 上传
+ * 相同key 文件会覆盖
+ * @param bytev
+ * @param key
+ */
+ public static void uploadByte(byte[] bytev, String key){
+ initMinio(minioUrl, minioName,minioPass);
+ try {
+ // 生成预签名上传 URL
+ Map reqParams = new HashMap();
+ reqParams.put("response-content-type", "application/json");
+ String url = minioClient.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder()
+ .method(Method.PUT)
+ .bucket(bucketName)
+ .object(key)
+ .expiry(1, TimeUnit.DAYS)
+ .extraQueryParams(reqParams)
+ .build());
+ log.info("生成预签名上传URL:" + url);
+ int responseCode = upLoadFileByte(url.toString(), bytev);
+ if (responseCode == 200) {
+ log.info("上传成功!");
+ } else {
+ log.info("上传失败!");
+ }
+ } catch (ErrorResponseException | InsufficientDataException | InternalException | ServerException | XmlParserException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static int upLoadFileByte(String singnedurl,byte[] bytev){
+ InputStream inputStream= null;
+ DataOutputStream out = null;
+ int responseCode = 0;
+ try {
+ URL url= null;
+ url = new URL(singnedurl);
+ inputStream= new ByteArrayInputStream(bytev);
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ connection.setDoOutput(true);
+ connection.setRequestMethod("PUT");
+ out = new DataOutputStream(connection.getOutputStream());
+
+ // 写入要上传的数据
+ IOUtils.copy(inputStream, out);
+ responseCode = connection.getResponseCode();
+ log.info("Service returned response code " + responseCode);
+ } catch (IOException e) {
+ log.error(e.getMessage(), e);
+ } finally {
+ try {
+ inputStream.close();
+ } catch (IOException e) {
+ log.error(e.getMessage(), e);
+ }
+ try {
+ out.close();
+ } catch (IOException e) {
+ log.error(e.getMessage(), e);
+ }
+ return responseCode;
+ }
+ }
+
+}
diff --git a/src/main/java/com/example/mathtoimg/utils/OmmlUtils.java b/src/main/java/com/example/mathtoimg/utils/OmmlUtils.java
new file mode 100644
index 0000000..b59b21d
--- /dev/null
+++ b/src/main/java/com/example/mathtoimg/utils/OmmlUtils.java
@@ -0,0 +1,94 @@
+package com.example.mathtoimg.utils;
+
+import com.example.mathtoimg.controller.mathToImgController;
+import net.sourceforge.jeuclid.context.LayoutContextImpl;
+import net.sourceforge.jeuclid.context.Parameter;
+import net.sourceforge.jeuclid.converter.Converter;
+import org.apache.xmlbeans.XmlObject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.stream.StreamSource;
+import java.io.*;
+import java.net.URL;
+
+public class OmmlUtils {
+ private static final Logger log = LoggerFactory.getLogger(OmmlUtils.class);
+ public static File convertOmathToPng(XmlObject xmlObject, ImageParse imageParser,String mathToImgFilePath,String omml2mmlFilePath) {
+ Document document = null;
+ try {
+ String mathMLStr = getMathMLFromNode(xmlObject.getDomNode(),omml2mmlFilePath);
+ System.out.println("xxxxxxxxxxxxxxxxxxxxxxx : " + mathMLStr);
+ document = W3cNodeUtil.xmlStr2Node(mathMLStr, "utf-16");
+ String imageName = documentToImageHTML(document, imageParser,mathToImgFilePath);
+ if (imageName != null) {
+ File tf = new File(imageName);
+ System.out.println("图片是否存在 ======== " + tf.exists() + "Name : " + tf.getName());
+ return tf;
+ }
+ } catch (Exception e) {
+ log.error("",e);
+ }
+ return null;
+ }
+
+
+
+ /**
+ * 直接转node有等号会出问题,先转成xml的string,再转成mathML的字符串
+ *
+ * @param node
+ * @return
+ * @throws IOException
+ * @throws TransformerException
+ */
+ private static String getMathMLFromNode(Node node,String omml2mmlFilePath) throws IOException, TransformerException {
+ ClassLoader classLoader = OmmlUtils.class.getClassLoader();
+ URL url = classLoader.getResource("xsl/OMML2MML.XSL");
+ File xslFile = null;
+ if (url != null) {
+ try {
+ xslFile = new File(url.toURI());
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+// final File xslFile = new File("/omml2mml.xsl");
+// final File xslFile = new File("D:\\MyCode\\omml-test\\omml2mml.xsl");
+// boolean exists = xslFile.exists();
+
+ //final File xslFile = new File(omml2mmlFilePath);
+
+ StreamSource streamSource = new StreamSource(xslFile);
+ String s = W3cNodeUtil.node2XmlStr(node);
+ // encoding utf-16
+ String mathML = W3cNodeUtil.xml2Xml(s, streamSource);
+ if (mathML != null) {
+ mathML = mathML.replaceAll("xmlns:m=\"http://schemas.openxmlformats.org/officeDocument/2006/math\"", "");
+ mathML = mathML.replaceAll("xmlns:mml", "xmlns");
+ mathML = mathML.replaceAll("mml:", "");
+ }
+ return mathML;
+ }
+
+ private static String documentToImageHTML(Document document, ImageParse imageParser,String mathToImgFilePath) {
+ try {
+ Converter mathMLConvert = Converter.getInstance();
+ LayoutContextImpl localLayoutContextImpl = new LayoutContextImpl(LayoutContextImpl.getDefaultLayoutContext());
+ localLayoutContextImpl.setParameter(Parameter.MATHSIZE, 50);
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ mathMLConvert.convert(document, os, "image/png", localLayoutContextImpl);
+ String pngName = imageParser.parse(os.toByteArray(), ".png",mathToImgFilePath);
+ os.close();
+ return pngName;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
+}
diff --git a/src/main/java/com/example/mathtoimg/utils/TestMain.java b/src/main/java/com/example/mathtoimg/utils/TestMain.java
new file mode 100644
index 0000000..58af6cf
--- /dev/null
+++ b/src/main/java/com/example/mathtoimg/utils/TestMain.java
@@ -0,0 +1,21 @@
+package com.example.mathtoimg.utils;
+
+import org.apache.xmlbeans.XmlException;
+import org.apache.xmlbeans.XmlObject;
+
+import java.io.File;
+import java.io.UnsupportedEncodingException;
+
+public class TestMain {
+
+ public static void main(String[] args) throws XmlException, UnsupportedEncodingException {
+ String oriMathXmlStr = "fx=a0+n=1∞ancosnπxL+bnsinnπxL";
+ oriMathXmlStr = new String(oriMathXmlStr.getBytes("gbk"), "utf-8");
+
+ XmlObject object = XmlObject.Factory.parse(oriMathXmlStr);
+ ImageParse imageParser = new ImageParse();
+ File file = OmmlUtils.convertOmathToPng(object, imageParser,"","");
+ System.out.printf(file.toString());
+ }
+
+}
diff --git a/src/main/java/com/example/mathtoimg/utils/W3cNodeUtil.java b/src/main/java/com/example/mathtoimg/utils/W3cNodeUtil.java
new file mode 100644
index 0000000..428d692
--- /dev/null
+++ b/src/main/java/com/example/mathtoimg/utils/W3cNodeUtil.java
@@ -0,0 +1,115 @@
+package com.example.mathtoimg.utils;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+public class W3cNodeUtil {
+
+ public static String node2XmlStr(Node node) {
+ Transformer transformer = null;
+ if (node == null) {
+ throw new IllegalArgumentException("node 不能为空..");
+ }
+ try {
+ transformer = TransformerFactory.newInstance().newTransformer();
+ } catch (Exception e) {
+ throw new RuntimeException(e.getMessage());
+ }
+ if (transformer != null) {
+ try {
+ StringWriter sw = new StringWriter();
+ transformer.transform(new DOMSource(node), new StreamResult(sw));
+ return sw.toString();
+ } catch (TransformerException te) {
+ throw new RuntimeException(te.getMessage());
+ }
+ }
+ return null;
+ }
+
+ public static String xml2Xml(String xml, Source XSLSource) {
+ Transformer transformer = null;
+ if (xml == null) {
+ throw new IllegalArgumentException("node 不能为空..");
+ }
+ try {
+ if (XSLSource == null) {
+ transformer = TransformerFactory.newInstance().newTransformer();
+ } else {
+ transformer = TransformerFactory.newInstance().newTransformer(XSLSource);
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e.getMessage());
+ }
+ if (transformer != null) {
+ try {
+ Source source = new StreamSource(new StringReader(xml));
+ StringWriter sw = new StringWriter();
+ transformer.transform(source, new StreamResult(sw));
+ return sw.toString();
+ } catch (TransformerException te) {
+ throw new RuntimeException(te.getMessage());
+ }
+ }
+ return null;
+ }
+
+ //MathML转成Document
+ public static Document xmlStr2Node(String xmlString, String encoding) {
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ Document doc = null;
+ try {
+ InputStream is = new ByteArrayInputStream(xmlString.getBytes(encoding));
+ doc = dbf.newDocumentBuilder().parse(is);
+ is.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return doc;
+ }
+
+ private static Node getChildNode(Node node, String nodeName) {
+ if (!node.hasChildNodes()) {
+ return null;
+ }
+ NodeList childNodes = node.getChildNodes();
+ for (int i = 0; i < childNodes.getLength(); i++) {
+ Node childNode = childNodes.item(i);
+ if (nodeName.equals(childNode.getNodeName())) {
+ return childNode;
+ }
+ childNode = getChildNode(childNode, nodeName);
+ if (childNode != null) {
+ return childNode;
+ }
+ }
+ return null;
+ }
+
+ public static Node getChildChainNode(Node node, String... nodeName) {
+ Node childNode = node;
+ for (int i = 0; i < nodeName.length; i++) {
+ String tmp = nodeName[i];
+ childNode = getChildNode(childNode, tmp);
+ if (childNode == null) {
+ return null;
+ }
+ }
+ return childNode;
+ }
+
+}
diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties
new file mode 100644
index 0000000..b42af5e
--- /dev/null
+++ b/src/main/resources/application.properties
@@ -0,0 +1,11 @@
+
+server.port = 9998
+# \u751F\u6210\u7684\u7279\u6B8A\u516C\u5F0F\u6587\u4EF6\u5B58\u50A8\u8DEF\u5F84
+file.mathToImgFilePath = D://opt//mathToImg
+# \u5904\u7406\u7279\u6B8A\u516C\u5F0F\u6240\u9700\u6587\u4EF6\u8DEF\u5F84
+xsl.omml2mmlFilePath = D://workspace//laws_biyadi//mathToImg//xsl//OMML2MML.XSL
+# minio\u6587\u4EF6\u4E0A\u4F20
+jero.minio.minio_url = 10.10.10.45:9000
+jero.minio.minio_name = admin
+jero.minio.minio_pass = hzwlsoft.com
+jero.minio.bucketName = laws-sinotruk
diff --git a/src/main/resources/xsl/OMML2MML.XSL b/src/main/resources/xsl/OMML2MML.XSL
new file mode 100644
index 0000000..b46ae33
--- /dev/null
+++ b/src/main/resources/xsl/OMML2MML.XSL
@@ -0,0 +1,2068 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ˘
+
+ ¸
+
+ `
+
+ -
+
+ −
+
+ .
+
+ ˙
+
+ ˝
+
+ ´
+
+ ~
+
+ ˜
+
+ ¨
+
+ ˇ
+
+ ^
+
+ ¯
+
+ _
+
+ →
+
+ ⟶
+
+ ←
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ left
+
+
+ right
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0in
+
+
+ 0in
+
+
+ 0in
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ false
+
+
+
+
+ ∫
+
+
+
+
+
+
+
+
+
+
+
+
+
+ off
+
+
+
+
+
+
+
+
+
+
+ off
+
+
+
+
+
+
+
+
+
+
+
+
+
+ off
+
+
+
+
+
+
+
+
+ 1
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ⏟
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ /
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ 0pt
+
+
+
+ right
+
+
+ left
+
+
+
+
+ right
+
+
+ left
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+ 0
+
+
+
+
+
+
+
+
+
+ ¯
+
+
+
+
+
+
+
+
+
+ _
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ normal
+
+
+
+
+
+
+
+ monospace
+ sans-serif-italic
+ bold-sans-serif
+ sans-serif-bold-italic
+ sans-serif
+ bold-fraktur
+ fraktur
+ double-struck
+ bold-script
+ script
+ bold
+ italic
+ normal
+ bold-italic
+
+
+
+
+
+ bold
+ normal
+
+
+
+
+ normal
+ italic
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ italic
+
+
+ bold
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+ 0
+
+
+
+
+ 1
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+ 0
+
+
+
+
+ 1
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ box
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ left right top bottom
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+ 0
+ -1
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+ 0
+
+
+
diff --git a/src/test/java/com/example/mathtoimg/MathToImgApplicationTests.java b/src/test/java/com/example/mathtoimg/MathToImgApplicationTests.java
new file mode 100644
index 0000000..a2b5120
--- /dev/null
+++ b/src/test/java/com/example/mathtoimg/MathToImgApplicationTests.java
@@ -0,0 +1,13 @@
+package com.example.mathtoimg;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+class MathToImgApplicationTests {
+
+ @Test
+ void contextLoads() {
+ }
+
+}
diff --git a/xsl/OMML2MML.XSL b/xsl/OMML2MML.XSL
new file mode 100644
index 0000000..b46ae33
--- /dev/null
+++ b/xsl/OMML2MML.XSL
@@ -0,0 +1,2068 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ˘
+
+ ¸
+
+ `
+
+ -
+
+ −
+
+ .
+
+ ˙
+
+ ˝
+
+ ´
+
+ ~
+
+ ˜
+
+ ¨
+
+ ˇ
+
+ ^
+
+ ¯
+
+ _
+
+ →
+
+ ⟶
+
+ ←
+
+
+
+
+
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ left
+
+
+ right
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0in
+
+
+ 0in
+
+
+ 0in
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ false
+
+
+
+
+ ∫
+
+
+
+
+
+
+
+
+
+
+
+
+
+ off
+
+
+
+
+
+
+
+
+
+
+ off
+
+
+
+
+
+
+
+
+
+
+
+
+
+ off
+
+
+
+
+
+
+
+
+ 1
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ⏟
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ /
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ 0pt
+
+
+
+ right
+
+
+ left
+
+
+
+
+ right
+
+
+ left
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+ 0
+
+
+
+
+
+
+
+
+
+ ¯
+
+
+
+
+
+
+
+
+
+ _
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ normal
+
+
+
+
+
+
+
+ monospace
+ sans-serif-italic
+ bold-sans-serif
+ sans-serif-bold-italic
+ sans-serif
+ bold-fraktur
+ fraktur
+ double-struck
+ bold-script
+ script
+ bold
+ italic
+ normal
+ bold-italic
+
+
+
+
+
+ bold
+ normal
+
+
+
+
+ normal
+ italic
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ italic
+
+
+ bold
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+ 0
+
+
+
+
+ 1
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+ 0
+
+
+
+
+ 1
+ 0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ box
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ left right top bottom
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+ 0
+ -1
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+ 1
+ 0
+
+
+