diff --git a/mallinkVideo/pom.xml b/mallinkVideo/pom.xml
new file mode 100644
index 000000000..1e706c42f
--- /dev/null
+++ b/mallinkVideo/pom.xml
@@ -0,0 +1,18 @@
+
+
+
+ mallink
+ com.iformall
+ 1.0
+
+ 4.0.0
+
+ mallinkVideo
+
+
+
+
+
+
\ No newline at end of file
diff --git a/mallinkVideo/src/main/java/com/iformall/video/FormallTess4j.java b/mallinkVideo/src/main/java/com/iformall/video/FormallTess4j.java
new file mode 100644
index 000000000..d5912dfb7
--- /dev/null
+++ b/mallinkVideo/src/main/java/com/iformall/video/FormallTess4j.java
@@ -0,0 +1,290 @@
+package com.iformall.ocr;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLConnection;
+
+import com.baomidou.mybatisplus.core.toolkit.IdWorker;
+import com.recognition.software.jdeskew.ImageDeskew;
+import net.sourceforge.tess4j.ITessAPI.TessPageIteratorLevel;
+import net.sourceforge.tess4j.ITesseract;
+import net.sourceforge.tess4j.ITesseract.RenderedFormat;
+import net.sourceforge.tess4j.Tesseract;
+import net.sourceforge.tess4j.Word;
+import net.sourceforge.tess4j.util.ImageHelper;
+import net.sourceforge.tess4j.util.LoggHelper;
+import net.sourceforge.tess4j.util.Utils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * https://www.cnblogs.com/pejsidney/p/9487881.html
+ * Tess4J是对Tesseract OCR API.的Java JNA 封装。使java能够通过调用Tess4J的API来使用Tesseract OCR。支持的格式:TIFF,JPEG,GIF,PNG,BMP,JPEG,and PDF
+ Tesseract 的github地址:https://github.com/tesseract-ocr/tesseract
+ Tess4J的github地址:https://github.com/nguyenq/tess4j
+
+ Tess4J API 提供的功能:
+ 1、直接识别支持的文件
+ 2、识别图片流
+ 3、识别图片的某块区域
+ 4、将识别结果保存为 TEXT/ HOCR/ PDF/ UNLV/ BOX
+ 5、通过设置取词的等级,提取识别出来的文字
+ 6、获得每一个识别区域的具体坐标范围
+ 7、调整倾斜的图片
+ 8、裁剪图片
+ 9、调整图片分辨率
+ 10、从粘贴板获得图像
+ 11、克隆一个图像(目的:创建一份一模一样的图片,与原图在操作修改上,不相 互影响)
+ 12、图片转换为二进制、黑白图像、灰度图像
+ 13、反转图片颜色
+ * @author alascor
+ */
+public class FormallTess4j {
+
+
+ private static final Logger logger = LoggerFactory.getLogger(new LoggHelper().toString());
+ static final double MINIMUM_DESKEW_THRESHOLD = 0.05d;
+
+ private static final String datapath = "src/main/resources";
+ private static final String testResourcesLanguagePath = datapath+"/tessdata";
+ private static final String tempfile = "/ocrtempfile/";
+
+ private static ITesseract instance = new Tesseract();
+
+ static {
+ instance.setDatapath(new File(datapath).getPath());
+ }
+
+ private static File urlImgToFile(String fileUrl) {
+ InputStream ins = null;
+ OutputStream os = null;
+ try {
+ URL url = new URL(fileUrl);
+ URLConnection c = url.openConnection();
+ ins = c.getInputStream();
+ File folder = new File (tempfile) ;
+ if (!folder.exists()) {
+ folder.mkdirs();
+ }
+ File f = new File(tempfile+System.currentTimeMillis()+"-"+IdWorker.get32UUID()+".jpg");
+ if (f.exists()) {
+ f.delete();
+ }
+ f.createNewFile();
+ os = new FileOutputStream(f);
+ int bytesRead = 0;
+ byte[] buffer = new byte[8192];
+ while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
+ os.write(buffer, 0, bytesRead);
+ }
+ os.close();
+ ins.close();
+ return f;
+ } catch (MalformedURLException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }finally {
+ if (null != os) {
+ try {
+ os.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ if (null != ins) {
+ try {
+ ins.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ return null;
+ }
+
+ private static void deletetempFile(File file) {
+ if (file.exists()) {
+ file.delete();
+ }
+ }
+
+ private static String ocrLocalImgFile(String languagePath,String filePath,String fontName) throws Exception {
+ File imageFile = new File(filePath);
+ String result = testDoOCR_File(languagePath,imageFile,fontName);
+ deletetempFile(imageFile);
+ return result;
+ }
+
+ public static String ocrNetImgFile(String languagePath,String fileUrl,String fontName) throws Exception {
+ File imageFile = urlImgToFile(fileUrl);
+ String result = testDoOCR_File(languagePath,imageFile,fontName);
+ deletetempFile(imageFile);
+ return result;
+ }
+
+ /**
+ * Test of doOCR method, of class Tesseract.
+ * 根据图片文件进行识别
+ * @throws Exception while processing image.
+ */
+ public static String testDoOCR_File(String languagePath,File imageFile,String fontName) throws Exception {
+ logger.info("doOCR on a jpg image");
+ //set language
+ instance.setDatapath(languagePath);
+ instance.setLanguage(fontName);
+ String result = instance.doOCR(imageFile);
+ return result;
+ }
+
+
+ public static void main(String[] args) {
+ try {
+ //System.out.println(ocrNetImgFile(testResourcesLanguagePath,"https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.my0832.com%2Fattachments%2Fbbs%2F20140424%2F201442413083356803_740_1186.jpg&refer=http%3A%2F%2Fimg.my0832.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1613903848&t=985fc4c6c7b7ee82cb98f97ab5bf1459","test1"));
+ System.out.println(ocrLocalImgFile(testResourcesLanguagePath,"C:\\Users\\iformall\\Desktop\\01.jpg","test1"));
+ } catch (Exception e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
+ }
+
+//
+// /**
+// * Test of doOCR method, of class Tesseract.
+// * 根据图片流进行识别
+// * @throws Exception while processing image.
+// */
+// public void testDoOCR_BufferedImage() throws Exception {
+// logger.info("doOCR on a buffered image of a PNG");
+// File imageFile = new File(this.testResourcesDataPath, "ocr.png");
+// BufferedImage bi = ImageIO.read(imageFile);
+//
+// //set language
+// instance.setDatapath(testResourcesLanguagePath);
+// instance.setLanguage("chi_sim");
+//
+// String result = instance.doOCR(bi);
+// logger.info(result);
+// }
+//
+// /**
+// * Test of getSegmentedRegions method, of class Tesseract.
+// * 得到每一个划分区域的具体坐标
+// * @throws java.lang.Exception
+// */
+// public void testGetSegmentedRegions() throws Exception {
+// logger.info("getSegmentedRegions at given TessPageIteratorLevel");
+// File imageFile = new File(testResourcesDataPath, "ocr.png");
+// BufferedImage bi = ImageIO.read(imageFile);
+// int level = TessPageIteratorLevel.RIL_SYMBOL;
+// logger.info("PageIteratorLevel: " + Utils.getConstantName(level, TessPageIteratorLevel.class));
+// List result = instance.getSegmentedRegions(bi, level);
+// for (int i = 0; i < result.size(); i++) {
+// Rectangle rect = result.get(i);
+// logger.info(String.format("Box[%d]: x=%d, y=%d, w=%d, h=%d", i, rect.x, rect.y, rect.width, rect.height));
+// }
+//
+// assertTrue(result.size() > 0);
+// }
+//
+//
+// /**
+// * Test of doOCR method, of class Tesseract.
+// * 根据定义坐标范围进行识别
+// * @throws Exception while processing image.
+// */
+// public void testDoOCR_File_Rectangle() throws Exception {
+// logger.info("doOCR on a BMP image with bounding rectangle");
+// File imageFile = new File(this.testResourcesDataPath, "ocr.png");
+// //设置语言库
+// instance.setDatapath(testResourcesLanguagePath);
+// instance.setLanguage("chi_sim");
+// //划定区域
+// // x,y是以左上角为原点,width和height是以xy为基础
+// Rectangle rect = new Rectangle(84, 21, 15, 13);
+// String result = instance.doOCR(imageFile, rect);
+// logger.info(result);
+// }
+//
+// /**
+// * Test of createDocuments method, of class Tesseract.
+// * 存储结果
+// * @throws java.lang.Exception
+// */
+// public void testCreateDocuments() throws Exception {
+// logger.info("createDocuments for png");
+// File imageFile = new File(this.testResourcesDataPath, "ocr.png");
+// String outputbase = "target/test-classes/docrenderer-2";
+// List formats = new ArrayList(Arrays.asList(RenderedFormat.HOCR, RenderedFormat.TEXT));
+//
+// //设置语言库
+// instance.setDatapath(testResourcesLanguagePath);
+// instance.setLanguage("chi_sim");
+//
+// instance.createDocuments(new String[]{imageFile.getPath()}, new String[]{outputbase}, formats);
+// }
+//
+// /**
+// * Test of getWords method, of class Tesseract.
+// * 取词方法
+// * @throws java.lang.Exception
+// */
+// public void testGetWords() throws Exception {
+// logger.info("getWords");
+// File imageFile = new File(this.testResourcesDataPath, "ocr.png");
+//
+// //设置语言库
+// instance.setDatapath(testResourcesLanguagePath);
+// instance.setLanguage("chi_sim");
+//
+// //按照每个字取词
+// int pageIteratorLevel = TessPageIteratorLevel.RIL_SYMBOL;
+// logger.info("PageIteratorLevel: " + Utils.getConstantName(pageIteratorLevel, TessPageIteratorLevel.class));
+// BufferedImage bi = ImageIO.read(imageFile);
+// List result = instance.getWords(bi, pageIteratorLevel);
+//
+// //print the complete result
+// for (Word word : result) {
+// logger.info(word.toString());
+// }
+// }
+//
+// /**
+// * Test of Invalid memory access.
+// * 处理倾斜
+// * @throws Exception while processing image.
+// */
+// public void testDoOCR_SkewedImage() throws Exception {
+// //设置语言库
+// instance.setDatapath(testResourcesLanguagePath);
+// instance.setLanguage("chi_sim");
+//
+// logger.info("doOCR on a skewed PNG image");
+// File imageFile = new File(this.testResourcesDataPath, "ocr_skewed.jpg");
+// BufferedImage bi = ImageIO.read(imageFile);
+// ImageDeskew id = new ImageDeskew(bi);
+// double imageSkewAngle = id.getSkewAngle(); // determine skew angle
+// if ((imageSkewAngle > MINIMUM_DESKEW_THRESHOLD || imageSkewAngle < -(MINIMUM_DESKEW_THRESHOLD))) {
+// bi = ImageHelper.rotateImage(bi, -imageSkewAngle); // deskew image
+// }
+//
+// String result = instance.doOCR(bi);
+// logger.info(result);
+// }
+
+}
diff --git a/mallinkVideo/src/main/java/com/iformall/video/FormallTess4jTrain.java b/mallinkVideo/src/main/java/com/iformall/video/FormallTess4jTrain.java
new file mode 100644
index 000000000..d2006fd4c
--- /dev/null
+++ b/mallinkVideo/src/main/java/com/iformall/video/FormallTess4jTrain.java
@@ -0,0 +1,135 @@
+package com.iformall.ocr;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.LineNumberReader;
+
+/**
+ * 训练
+ * @author iformall
+ */
+public class FormallTess4jTrain {
+
+ private static final String newFileFolder = "C:\\Users\\iformall\\Desktop\\newfile";
+
+ private static final String huanhangstr = " \n ";
+
+ private static String getprefix(String lang,String fontName) {
+ String realFileName = lang+"."+fontName+".exp0";
+ return realFileName;
+ }
+
+ private static String createBoxFile(String tifFileName,String lang,String fontName) {
+ String prefix = getprefix(lang,fontName);
+ String realFileName = prefix+".tif";
+ if (tifFileName.equals(realFileName)) {
+ String cmdstr = "tesseract "+tifFileName+" "+prefix+" -l chi_sim batch.nochop makebox";
+ return cmdstr;
+ //String result = executeLocalCmd(cmdstr, null);
+
+ //System.out.println("Done createBoxFile"+result);
+ }else {
+ return "文件必须是.tif";
+ }
+ }
+
+ private static String createTranFile(String lang,String fontName) {
+ String prefix = getprefix(lang,fontName);
+ String realFileName = prefix+".tif";
+ String trainCmdstr = "tesseract "+realFileName+" "+prefix+" nobatch box.train";
+ return trainCmdstr;
+ }
+
+ private static String getBoxFont(String lang,String fontName) {
+ String prefix = getprefix(lang,fontName);
+ String extractorCmdstr = "unicharset_extractor "+prefix+".box [other .box files...]";
+ return extractorCmdstr;
+ }
+
+ /**
+ * 第六步,执行完成后生成以下几个文件加前缀
+ * unicharset、inttemp、pffmtable、shapetable、normproto 添加这几个文件的前缀为fontName
+ * @param lang
+ * @param fontName
+ * @return
+ */
+ private static String renameTrainFiles(String fontName) {
+ StringBuffer sb = new StringBuffer();
+ String renCmdstr = "REN unicharset "+fontName+".unicharset";
+ sb.append(renCmdstr).append(huanhangstr);
+
+ renCmdstr = "REN inttemp "+fontName+".inttemp";
+ sb.append(renCmdstr).append(huanhangstr);
+
+ renCmdstr = "REN pffmtable "+fontName+".pffmtable";
+ sb.append(renCmdstr).append(huanhangstr);
+
+ renCmdstr = "REN shapetable "+fontName+".shapetable";
+ sb.append(renCmdstr).append(huanhangstr);
+
+ renCmdstr = "REN normproto "+fontName+".normproto";
+ sb.append(renCmdstr).append(huanhangstr);
+ return sb.toString();
+ }
+
+ /**
+ * 第七步:合并5个文件
+ * @param lang
+ * @param fontName
+ * @return
+ */
+ private static String mergeTrainFiles(String fontName) {
+ String mergeCmdstr = "combine_tessdata "+fontName+".";
+ return mergeCmdstr;
+ }
+
+
+ public static String getTrainSteps(String lang,String fontName) {
+
+ StringBuffer sb = new StringBuffer("请先安装tess4j(4.0以上),配置好环境变量. 下载jTessBoxEditor(用于训练,带FX的支持中文)").append(huanhangstr);
+ sb.append("请进入到样本图片文件夹用doc命令执行.").append(huanhangstr);
+ sb.append("第一步,用jTessBoxEditor --> Tools --> Merge 多选图片,保存为tif格式 .命名格式为[lang].[fontName].exp0.tif. 命名:").append(lang).append(".").append(fontName).append(".exp0.tif ").append(huanhangstr);
+ sb.append("............ ").append(huanhangstr);
+ sb.append("第二步,用tif生成box ").append(huanhangstr);
+ sb.append(createBoxFile(lang+"."+fontName+".exp0.tif", lang, fontName)).append(huanhangstr);
+ sb.append("............ ").append(huanhangstr);
+ sb.append("第三步,用jTessBoxEditor 打开.box文件进行矫正 ").append(huanhangstr);
+ sb.append("............ ").append(huanhangstr);
+ sb.append("第四步:用box文件生成。tr文件 ").append(huanhangstr);
+ sb.append(createTranFile(lang,fontName)).append(huanhangstr);
+ sb.append("............ ").append(huanhangstr);
+ sb.append("@@@!!!!从此处开始,可以处理多个字库处理。如原来的字库现在做升级,需要把老的字库的。tif,.box,.tr文件重新命名也放到同目录文件夹, ").append(huanhangstr);
+ sb.append("............ ").append(huanhangstr);
+ sb.append("第五步:提取box字符 ").append(huanhangstr);
+ sb.append(getBoxFont(lang,fontName)).append(huanhangstr);
+ sb.append("............ ").append(huanhangstr);
+ sb.append("第六步:新建font_properties(没有.txt后缀), 把所有box对应的字体特征加进去。").append(huanhangstr);
+ sb.append("fontname为字体名称,保持和 图片集文件 .tif 和.box文件的前缀名一致 . 、 、 、、 的取值为1或0,表示字体是否具有这些属性。 ").append(huanhangstr);
+ sb.append("如以下内容: ").append(huanhangstr);
+ sb.append("fontName1 0 0 0 0 0 ").append(huanhangstr);
+ sb.append("fontName2 0 1 0 0 0 ").append(huanhangstr);
+ sb.append("fontName3 1 1 0 0 0 ").append(huanhangstr);
+ sb.append("............ ").append(huanhangstr);
+ sb.append("第六步:批量执行系列命令。多个文件在后面累加。 ").append(huanhangstr);
+ String prefix = getprefix(lang,fontName);
+ String shapeCmdStr = "### shapeclustering -F font_properties -U unicharset "+prefix+".tr [other .tr files...] ";
+ sb.append(shapeCmdStr).append(huanhangstr);
+ String mftraingCmdstr = "mftraining -F font_properties -U unicharset -O unicharset "+prefix+".tr [other .tr files...] ";
+ sb.append(mftraingCmdstr).append(huanhangstr);
+ String cntrainCmdstr = "cntraining "+prefix+".tr [other .tr files...] ";
+ sb.append(cntrainCmdstr).append(huanhangstr);
+ sb.append("............ ").append(huanhangstr);
+ sb.append("第七步,执行完成后生成以下几个文件加前缀: unicharset、inttemp、pffmtable、shapetable、normproto 添加这几个文件的前缀为[fontName] ").append(huanhangstr);
+ sb.append(renameTrainFiles(fontName));
+ sb.append("............ ").append(huanhangstr);
+ sb.append("第七步:合并5个文件").append(huanhangstr);
+ sb.append(mergeTrainFiles(fontName)).append(huanhangstr);
+ sb.append("............ ").append(huanhangstr);
+ sb.append("第八步:将").append(fontName).append(".traineddata 文件拷贝到后端服务器ocr_data(项目配置fm.ocr_data)目录下。 .tif、。box、。tr文件也需要保留,后面如果这个字库有更新,需要用到这些文件。").append(huanhangstr);
+ return sb.toString();
+ }
+
+}