CommUtils.java 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. package com.luooqi.ocr.utils;
  2. import java.awt.Point;
  3. import java.awt.Rectangle;
  4. import java.awt.image.BufferedImage;
  5. import java.io.ByteArrayOutputStream;
  6. import java.io.IOException;
  7. import java.lang.reflect.Method;
  8. import java.net.URL;
  9. import java.util.ArrayList;
  10. import java.util.Comparator;
  11. import java.util.Iterator;
  12. import java.util.List;
  13. import java.util.regex.Pattern;
  14. import javax.imageio.IIOImage;
  15. import javax.imageio.ImageIO;
  16. import javax.imageio.ImageWriteParam;
  17. import javax.imageio.ImageWriter;
  18. import javax.imageio.stream.MemoryCacheImageOutputStream;
  19. import javax.swing.ImageIcon;
  20. import com.luooqi.ocr.MainFm;
  21. import com.luooqi.ocr.model.TextBlock;
  22. import cn.hutool.core.util.CharUtil;
  23. import cn.hutool.core.util.StrUtil;
  24. import cn.hutool.http.HttpRequest;
  25. import cn.hutool.http.HttpResponse;
  26. import cn.hutool.http.HttpUtil;
  27. import cn.hutool.log.StaticLog;
  28. import javafx.geometry.Insets;
  29. import javafx.geometry.Orientation;
  30. import javafx.geometry.Rectangle2D;
  31. import javafx.scene.control.Button;
  32. import javafx.scene.control.ButtonBase;
  33. import javafx.scene.control.Separator;
  34. import javafx.scene.control.ToggleButton;
  35. import javafx.scene.control.ToggleGroup;
  36. import javafx.scene.control.Tooltip;
  37. import javafx.scene.layout.Background;
  38. import javafx.scene.layout.BackgroundFill;
  39. import javafx.scene.layout.CornerRadii;
  40. import javafx.scene.paint.Color;
  41. import javafx.scene.paint.Paint;
  42. import javafx.stage.Screen;
  43. import javafx.stage.Stage;
  44. public class CommUtils {
  45. public static final Paint MASK_COLOR = Color.rgb(0, 0, 0, 0.4);
  46. public static final int BUTTON_SIZE = 28;
  47. public static Background BG_TRANSPARENT = new Background(new BackgroundFill(Color.TRANSPARENT,
  48. CornerRadii.EMPTY, Insets.EMPTY));
  49. private static Pattern NORMAL_CHAR = Pattern.compile("[\\u4e00-\\u9fa5\\w、-,/|_]");
  50. private static final float IMAGE_QUALITY = 0.5f;
  51. private static final int SAME_LINE_LIMIT = 8;
  52. private static final int CHAR_WIDTH = 12;
  53. public static final String STYLE_TRANSPARENT = "-fx-background-color: transparent;";
  54. public static final String SPECIAL_CHARS = "[\\s`~!@#$%^&*()_\\-+=|{}':;,\\[\\].<>/?!¥…()【】‘;:”“’。,、?]+";
  55. public static boolean IS_MAC_OS = false;
  56. static {
  57. String osName = System.getProperty("os.name", "generic").toLowerCase();
  58. if ((osName.contains("mac")) || (osName.contains("darwin"))) {
  59. IS_MAC_OS = true;
  60. }
  61. }
  62. public static byte[] imageToBytes(BufferedImage img) {
  63. ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
  64. MemoryCacheImageOutputStream outputStream = new MemoryCacheImageOutputStream(byteArrayOutputStream);
  65. try {
  66. Iterator<?> iter = ImageIO.getImageWritersByFormatName("jpeg");
  67. ImageWriter writer = (ImageWriter) iter.next();
  68. ImageWriteParam iwp = writer.getDefaultWriteParam();
  69. iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
  70. iwp.setCompressionQuality(IMAGE_QUALITY);
  71. writer.setOutput(outputStream);
  72. IIOImage image = new IIOImage(img, null, null);
  73. writer.write(null, image, iwp);
  74. writer.dispose();
  75. byte[] result = byteArrayOutputStream.toByteArray();
  76. byteArrayOutputStream.close();
  77. outputStream.close();
  78. return result;
  79. } catch (IOException e) {
  80. StaticLog.error(e);
  81. return new byte[0];
  82. }
  83. }
  84. static String combineTextBlocks(List<TextBlock> textBlocks, boolean isEng) {
  85. textBlocks.sort(Comparator.comparingInt(o -> o.getTopLeft().y));
  86. List<List<TextBlock>> lineBlocks = new ArrayList<>();
  87. int lastY = -1;
  88. List<TextBlock> lineBlock = new ArrayList<>();
  89. boolean sameLine = true;
  90. int minX = Integer.MAX_VALUE;
  91. TextBlock minBlock = null;
  92. TextBlock maxBlock = null;
  93. int maxX = -1;
  94. double maxAngle = -100;
  95. for (TextBlock textBlock : textBlocks) {
  96. System.out.println(textBlock.getAngle()+ "\t" + textBlock.getFontSize());
  97. if (textBlock.getTopLeft().x < minX) {
  98. minX = textBlock.getTopLeft().x;
  99. minBlock = textBlock;
  100. }
  101. if (textBlock.getTopRight().x > maxX) {
  102. maxX = textBlock.getTopRight().x;
  103. maxBlock = textBlock;
  104. }
  105. if (Math.abs(textBlock.getAngle()) > maxAngle){
  106. maxAngle = Math.abs(textBlock.getAngle());
  107. }
  108. if (lastY == -1) {
  109. lastY = textBlock.getTopLeft().y;
  110. } else {
  111. sameLine = textBlock.getTopLeft().y - lastY <= SAME_LINE_LIMIT;
  112. }
  113. if (!sameLine) {
  114. lineBlock.sort(Comparator.comparingInt(o -> o.getTopLeft().x));
  115. lineBlocks.add(lineBlock);
  116. lineBlock = new ArrayList<>();
  117. sameLine = true;
  118. lastY = textBlock.getTopLeft().y;
  119. }
  120. lineBlock.add(textBlock);
  121. }
  122. if (maxAngle >= 0.05){
  123. //todo 文本倾斜校正
  124. }
  125. if (lineBlock.size() > 0) {
  126. lineBlock.sort(Comparator.comparingInt(o -> o.getTopLeft().x));
  127. lineBlocks.add(lineBlock);
  128. }
  129. StringBuilder sb = new StringBuilder();
  130. TextBlock lastBlock = null;
  131. for (List<TextBlock> line : lineBlocks) {
  132. TextBlock firstBlock = line.get(0);
  133. if (lastBlock != null) {
  134. String blockTxt = lastBlock.getText().trim();
  135. String endTxt = blockTxt.substring(blockTxt.length() - 1);
  136. if (maxX - lastBlock.getTopRight().x >= CHAR_WIDTH * 2 ||
  137. !NORMAL_CHAR.matcher(endTxt).find() ||
  138. (NORMAL_CHAR.matcher(endTxt).find() &&
  139. (firstBlock.getTopLeft().x - minX) > CHAR_WIDTH * 2)){
  140. sb.append("\n");
  141. for (int i = 0, ln = (firstBlock.getTopLeft().x - minX) / CHAR_WIDTH; i < ln; i++) {
  142. if (i % 2 == 0){
  143. sb.append(" ");
  144. }
  145. }
  146. }
  147. else{
  148. if (CharUtil.isLetterOrNumber(endTxt.charAt(0)) && CharUtil.isLetterOrNumber(firstBlock.getText().charAt(0))){
  149. sb.append(" ");
  150. }
  151. }
  152. }
  153. else{
  154. for (int i = 0, ln = (firstBlock.getTopLeft().x - minX) / CHAR_WIDTH; i < ln; i++) {
  155. if (i % 2 == 0){
  156. sb.append(" ");
  157. }
  158. }
  159. }
  160. for (int i = 0; i < line.size(); i++) {
  161. TextBlock text = line.get(i);
  162. String ocrText = text.getText();
  163. if (i > 0) {
  164. for (int a = 0, ln = (text.getTopLeft().x - line.get(i - 1).getTopRight().x) / (CHAR_WIDTH * 2);
  165. a < ln; a++) {
  166. sb.append(" ");
  167. }
  168. }
  169. sb.append(ocrText);
  170. }
  171. lastBlock = line.get(line.size() - 1);
  172. }
  173. return sb.toString();
  174. }
  175. static Point frameToPoint(String text) {
  176. String[] arr = text.split(",");
  177. return new Point(Integer.valueOf(arr[0].trim()), Integer.valueOf(arr[1].trim()));
  178. }
  179. static String postMultiData(String url, byte[] data, String boundary) {
  180. return postMultiData(url, data, boundary, "", "");
  181. }
  182. private static String postMultiData(String url, byte[] data, String boundary, String cookie, String referer) {
  183. try {
  184. HttpRequest request = HttpUtil.createPost(url).timeout(15000);
  185. request.contentType("multipart/form-data; boundary=" + boundary);
  186. request.body(data);
  187. if (StrUtil.isNotBlank(referer)) {
  188. request.header("Referer", referer);
  189. }
  190. if (StrUtil.isNotBlank(cookie)) {
  191. request.cookie(cookie);
  192. }
  193. HttpResponse response = request.execute();
  194. return WebUtils.getSafeHtml(response);
  195. } catch (Exception ex) {
  196. StaticLog.error(ex);
  197. return null;
  198. }
  199. }
  200. static byte[] mergeByte(byte[]... bytes) {
  201. int length = 0;
  202. for (byte[] b : bytes) {
  203. length += b.length;
  204. }
  205. byte[] resultBytes = new byte[length];
  206. int offset = 0;
  207. for (byte[] arr : bytes) {
  208. System.arraycopy(arr, 0, resultBytes, offset, arr.length);
  209. offset += arr.length;
  210. }
  211. return resultBytes;
  212. }
  213. public static Button createButton(String id, Runnable action, String toolTip){
  214. return createButton(id, BUTTON_SIZE, action, toolTip);
  215. }
  216. public static Button createButton(String id, int size, Runnable action, String toolTip) {
  217. javafx.scene.control.Button button = new Button();
  218. initButton(button, id, size, action, toolTip);
  219. return button;
  220. }
  221. public static ToggleButton createToggleButton(ToggleGroup grp, String id, Runnable action, String toolTip){
  222. return createToggleButton(grp, id, BUTTON_SIZE, action, toolTip);
  223. }
  224. public static ToggleButton createToggleButton(ToggleGroup grp, String id, int size, Runnable action, String toolTip) {
  225. ToggleButton button = new ToggleButton();
  226. button.setToggleGroup(grp);
  227. initButton(button, id, size, action, toolTip);
  228. return button;
  229. }
  230. private static void initButton(ButtonBase button, String id, int size, Runnable action, String toolTip) {
  231. button.setId(id);
  232. button.setOnAction(evt -> action.run());
  233. button.setMinSize(size, size);
  234. if (toolTip != null) {
  235. button.setTooltip(new Tooltip(toolTip));
  236. }
  237. }
  238. public static void initStage(Stage stage) {
  239. try {
  240. if (CommUtils.IS_MAC_OS) {
  241. URL iconURL = MainFm.class.getResource("/img/logo.png");
  242. java.awt.Image image = new ImageIcon(iconURL).getImage();
  243. Class<?> appleApp = Class.forName("com.apple.eawt.Application");
  244. //noinspection unchecked
  245. Method getApplication = appleApp.getMethod("getApplication");
  246. Object application = getApplication.invoke(appleApp);
  247. Class[] params = new Class[1];
  248. params[0] = java.awt.Image.class;
  249. //noinspection unchecked
  250. Method setDockIconImage = appleApp.getMethod("setDockIconImage", params);
  251. setDockIconImage.invoke(application, image);
  252. }
  253. } catch (Exception e) {
  254. StaticLog.error(e);
  255. }
  256. stage.setTitle("树洞OCR文字识别");
  257. stage.getIcons().add(new javafx.scene.image.Image(MainFm.class.getResource("/img/logo.png").toExternalForm()));
  258. }
  259. public static Rectangle snapScreen(Stage stage){
  260. double x = stage.getX();
  261. Screen crtScreen = null;
  262. for (Screen screen : Screen.getScreens()) {
  263. crtScreen = screen;
  264. Rectangle2D bounds = screen.getBounds();
  265. if (bounds.getMaxX() > x){
  266. break;
  267. }
  268. }
  269. Rectangle2D rectangle2D = crtScreen.getBounds();
  270. return new Rectangle((int)rectangle2D.getMinX (), (int)rectangle2D.getMinY(), (int) rectangle2D.getWidth(),
  271. (int) rectangle2D.getHeight());
  272. }
  273. }