图片转文字OCR识图工具
图片文字识别,只支持在windows上运行,语言自动识别,调用的是百度OCR-API,需要提供百度智能云管理后台的应用的API Key和Secret Key。
打包成jar文件放桌面可以自己用也可以给亲人朋友用。
只需三个文件
即可自己开发一个OCR工具软件:
App.java
package translate.image; import javax.swing.*; import javax.swing.border.EmptyBorder; import javax.swing.filechooser.FileFilter; import javax.swing.filechooser.FileSystemView; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.IOException; import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * 图片文字识别,只支持在windows上运行,语言自动识别,调用的是百度OCR-API,需要提供百度智能云管理后台的应用的API Key和Secret Key * * @author tang */ public class App { public static void main(String[] args) throws Exception { UIManager.setLookAndFeel(com.sun.java.swing.plaf.windows.WindowsLookAndFeel.class.getName()); UIManager.put("ScrollBarUI", "com.sun.java.swing.plaf.windows.WindowsScrollBarUI");// 设置滚动条样式为window风格的滚动条样式 // 设置文件夹在swing中所显示的图标 UIManager.put("FileView.directoryIcon", FileSystemView.getFileSystemView().getSystemIcon(new File(System.getProperty("user.dir")))); String oldApiKey = ""; String oldSecretKey = ""; final File keyFile = new File(System.getProperty("user.dir") + "/百度OCR应用密钥.txt"); if (keyFile.exists()) { try { ListkeyTextList = Files.readAllLines(keyFile.toPath()); if (keyTextList != null && keyTextList.size() >= 2) { oldApiKey = keyTextList.get(0); oldSecretKey = keyTextList.get(1); } } catch (Exception e) { e.printStackTrace(); } } final JFrame jFrame = new JFrame(); JPanel contentPane = new JPanel(); jFrame.setContentPane(contentPane); contentPane.setBorder(new EmptyBorder(10, 10, 10, 10)); contentPane.setLayout(new FlowLayout(FlowLayout.CENTER, 0, 20)); JPanel jp1 = new JPanel(); jp1.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); jp1.setBorder(new EmptyBorder(0, 0, 0, 0)); jp1.setPreferredSize(new Dimension(400, 30)); JLabel apiKeyLabel = new JLabel(" API Key : "); jp1.add(apiKeyLabel); final JTextField apiKeyTextField = new JTextField("", 40); apiKeyTextField.setText(oldApiKey); jp1.add(apiKeyTextField); contentPane.add(jp1); JPanel jp2 = new JPanel(); jp2.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); jp2.setBorder(new EmptyBorder(0, 0, 0, 0)); jp2.setPreferredSize(new Dimension(400, 30)); JLabel secretKeyLabel = new JLabel("Secret Key : "); jp2.add(secretKeyLabel); final JTextField secretKeyTextField = new JTextField("", 40); secretKeyTextField.setText(oldSecretKey); jp2.add(secretKeyTextField); contentPane.add(jp2); JPanel jp3 = new JPanel(); jp3.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); jp3.setBorder(new EmptyBorder(0, 0, 0, 0)); jp2.setPreferredSize(new Dimension(400, 30)); JLabel imageLabel = new JLabel(" Image : "); jp3.add(imageLabel); final JTextField imageTextField = new JTextField("", 40); jp3.add(imageTextField); JButton selFileBtn = new JButton("..."); jp3.add(selFileBtn); final JFileChooser chooser = new JFileChooser(); chooser.setCurrentDirectory(new File(System.getProperty("user.home") + "/Desktop")); chooser.setFileFilter(new FileFilter() { public boolean accept(File f) { if (f.isDirectory()) { return true; } if (f.getName().endsWith(".png") || f.getName().endsWith(".jpg") || f.getName().endsWith(".jpeg") || f.getName().endsWith(".bmp")) { return true; } return false; } public String getDescription() { return "png/jpg/bmp"; } }); selFileBtn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { int i = chooser.showOpenDialog(jFrame); if (JFileChooser.APPROVE_OPTION == i) { File selectedFile = chooser.getSelectedFile(); if (selectedFile != null && selectedFile.getAbsolutePath() != null) { imageTextField.setText(selectedFile.getAbsolutePath()); return; } } imageTextField.setText(""); } }); contentPane.add(jp3); JPanel jp4 = new JPanel(); jp4.setLayout(new FlowLayout(FlowLayout.RIGHT, 0, 0)); jp4.setBorder(new EmptyBorder(0, 0, 0, 0)); jp4.setPreferredSize(new Dimension(400, 30)); JButton saveKeyBtn = new JButton("保存密钥"); jp4.add(saveKeyBtn); contentPane.add(jp4); JButton okBtn = new JButton("识别文字"); jp4.add(okBtn); JPanel jp5 = new JPanel(); jp5.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0)); jp5.setBorder(new EmptyBorder(0, 0, 0, 0)); jp5.setPreferredSize(new Dimension(400, 500)); final JTextArea textArea = new JTextArea(30, 40); textArea.setSize(new Dimension(380, 500)); textArea.setText("1,调用的是百度OCR-API,需要提供百度智能云管理后台的应用的API Key和Secret Key。\r\n" + "\t1.1,进入百度智能云服务列表:https://console.bce.baidu.com/ai/#/ai/ocr/overview/index 。\r\n" + "\t1.2,点击'通用场景OCR',然后找到'通用文字识别(高精度版)'后点击开通。\r\n" + "\t1.3,进入创建应用页面:https://console.bce.baidu.com/ai/#/ai/ocr/app/create。\r\n" + "\t1.4,填写应用名称,应用归属选择'个人',随便填写应用描述,然后点击'立即创建'。\r\n" + "\t1.5,进入应用列表页面:https://console.bce.baidu.com/ai/#/ai/ocr/app/list。\r\n" + "\t1.6,复制出API Key和Secret Key。\r\n" + "\t1.7,该接口每天只能免费调用500次,超出部分百度要收费。\r\n" + "2,语言可以自动识别。\r\n" + "3,只支持png/jpg/bmp格式图片。"); textArea.setWrapStyleWord(true); textArea.setAutoscrolls(true); textArea.setLineWrap(true); JScrollPane jsp = new JScrollPane(textArea); jsp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); jsp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED); jp5.add(jsp); contentPane.add(jp5); saveKeyBtn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (BaiduCloudApiUtil.appApiKey.trim().isEmpty() || BaiduCloudApiUtil.appSecretKey.trim().isEmpty()) { textArea.setText("请先调用接口,成功后才能保存密钥!"); return; } List list = new ArrayList<>(2); list.add(BaiduCloudApiUtil.appApiKey); list.add(BaiduCloudApiUtil.appSecretKey); try { Files.write(keyFile.toPath(), list, Charset.forName("UTF-8"), StandardOpenOption.CREATE); textArea.setText("保存密钥成功!"); } catch (IOException ex) { ex.printStackTrace(); } } }); okBtn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (apiKeyTextField.getText().trim().isEmpty()) { textArea.setText("请输入API Key!"); return; } if (secretKeyTextField.getText().trim().isEmpty()) { textArea.setText("请输入Secret Key!"); return; } BaiduCloudApiUtil.appApiKey = apiKeyTextField.getText().trim(); BaiduCloudApiUtil.appSecretKey = secretKeyTextField.getText().trim(); if (!"".equals(imageTextField.getText().trim())) { try { byte[] bytes = Files.readAllBytes(chooser.getSelectedFile().toPath()); Map map = BaiduCloudApiUtil.queryOcrResult(bytes); if (map != null && !map.isEmpty()) { Boolean success = (Boolean) map.get("success"); if (success) { String data = (String) map.get("data"); if (data != null && !data.trim().isEmpty()) { textArea.setText(data); } else { textArea.setText(""); } } else { String message = (String) map.get("message"); textArea.setText(message); } return; } } catch (Exception ex) { ex.printStackTrace(); } textArea.setText("转化文字失败!"); } else { textArea.setText("没有选择文件!"); } } }); jFrame.setSize(500, 800); jFrame.setLocationRelativeTo(null); jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); jFrame.setVisible(true); } }
BaiduCloudApiUtil.java
package translate.image; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import java.io.BufferedReader; import java.io.File; import java.io.InputStreamReader; import java.lang.reflect.Method; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.nio.file.Files; import java.util.HashMap; import java.util.Map; public class BaiduCloudApiUtil { static String appApiKey = ""; static String appSecretKey = ""; private static volatile String accessToken; private static volatile long accessTokenTime;// 获取凭证时的时间,单位:毫秒数,System.currentTimeMillis private static volatile int expireTime;// 凭证有效时间,单位:秒 private static void clearToken() { accessToken = ""; expireTime = 0; accessTokenTime = 0; } public static String getAccessToken() { if (!(accessToken == null || accessToken.trim().isEmpty()) && accessTokenTime > 0 && expireTime > 0) { long extime = accessTokenTime + (expireTime * 1000); long nowTime = System.currentTimeMillis(); if (extime - nowTime > 1000) {// 仍然有效 return accessToken; } } String authHost = "https://aip.baidubce.com/oauth/2.0/token?"; String getAccessTokenUrl = authHost + "grant_type=client_credentials" + "&client_id=" + appApiKey + "&client_secret=" + appSecretKey; try { URL realUrl = new URL(getAccessTokenUrl); HttpURLConnection connection = (HttpURLConnection) realUrl.openConnection(); connection.setRequestMethod("GET"); connection.connect(); try (BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()))) { String result = ""; String line; while ((line = in.readLine()) != null) { result += line; } JSONObject jsonObject = (JSONObject) JSONObject.parse(result); expireTime = jsonObject.getInteger("expires_in"); accessToken = jsonObject.getString("access_token"); accessTokenTime = System.currentTimeMillis(); } catch (Throwable e) { e.printStackTrace(); clearToken(); } } catch (Throwable e) { e.printStackTrace(); clearToken(); } return accessToken; } public static Mapparse(JSONObject jsonObject) { HashMap map = new HashMap<>(); map.put("success", false); if (jsonObject == null) { map.put("message", "空的调用结果"); return map; } try { Integer words_result_num = jsonObject.getInteger("words_result_num"); if (words_result_num == null || words_result_num.intValue() <= 0) { map.put("message", "未解析到结果"); return map; } JSONArray words_result = jsonObject.getJSONArray("words_result"); StringBuffer sb = new StringBuffer(); for (Object obj : words_result) { JSONObject jo = (JSONObject) obj; String words = jo.getString("words"); sb.append(words + "\r\n"); } System.out.println(sb); map.put("data", sb.toString()); map.put("success", true); } catch (Exception e) { map.put("message", "无法解析调用结果"); } return map; } public static JSONObject ocr(String httpUrl, String httpArg) { try { URL url = new URL(httpUrl); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setRequestMethod("POST"); connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); connection.setRequestProperty("apikey", appApiKey); connection.setDoOutput(true); connection.getOutputStream().write(httpArg.getBytes("UTF-8")); connection.connect(); try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-8"))) { StringBuffer sbf = new StringBuffer(); String strRead = null; while ((strRead = reader.readLine()) != null) { sbf.append(strRead); sbf.append("\r\n"); } String result = sbf.toString(); JSONObject jsonObject = (JSONObject) JSONObject.parse(result); return jsonObject; } catch (Throwable e) { e.printStackTrace(); } } catch (Throwable e) { e.printStackTrace(); } return null; } public static String encodeBase64(byte[] input) throws Exception { Class> clazz = Class.forName("com.sun.org.apache.xerces.internal.impl.dv.util.Base64"); Method mainMethod = clazz.getMethod("encode", byte[].class); mainMethod.setAccessible(true); Object retObj = mainMethod.invoke(null, new Object[]{input}); return (String) retObj; } public static Map queryOcrResult(byte[] fileBytes) { try { String imageBase = encodeBase64(fileBytes); imageBase = URLEncoder.encode(imageBase, "UTF-8"); String httpUrl = "https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic?access_token=" + getAccessToken(); String httpArg = "language_type=auto_detect&image=" + imageBase; JSONObject jsonObject = ocr(httpUrl, httpArg); if (jsonObject == null) { HashMap map = new HashMap<>(); map.put("success", false); map.put("message", "系统错误,请稍后重试"); return map; } Map map = parse(jsonObject); return map; } catch (Exception e) { HashMap map = new HashMap<>(); map.put("success", false); map.put("message", "系统错误,请稍后重试"); return map; } } public static void main(String[] args) throws Exception { File file = new File("C:\\Users\\tang8\\Desktop\\2022-07-21_070822.png"); byte[] data = Files.readAllBytes(file.toPath()); Map map = queryOcrResult(data); System.out.println(map.get("data")); } }
pom.xml
4.0.0 translate.image TranslateImage 1.0-SNAPSHOT TranslateImage http://www.example.com UTF-8 1.8 1.8 com.alibaba fastjson 1.2.29 maven-compiler-plugin 3.8.0 maven-jar-plugin 3.0.2 org.apache.maven.plugins maven-shade-plugin 3.1.1 maven-compiler-plugin 8 maven-jar-plugin translate.image.App maven-shade-plugin package shade
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。