目录
- 图片转文字OCR识图工具
- 只需三个文件
图片转文字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 {
List<String> keyTextList = Files.readAllLines(keyFile.toPath());
if (keyTextList != null && keyTextList.size() >=) {
oldApiKey = keyTextList.get();
oldSecretKey = keyTextList.get();
}
} catch (Exception e) {
e.printStackTrace();
}
}
final JFrame jFrame = new JFrame();
JPanel contentPane = new JPanel();
jFrame.setContentPane(contentPane);
contentPane.setBorder(new EmptyBorder(, 10, 10, 10));
contentPane.setLayout(new FlowLayout(FlowLayout.CENTER,, 20));
JPanel jp = new JPanel();
jp.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
jp.setBorder(new EmptyBorder(0, 0, 0, 0));
jp.setPreferredSize(new Dimension(400, 30));
JLabel apiKeyLabel = new JLabel(" API Key : ");
jp.add(apiKeyLabel);
final JTextField apiKeyTextField = new JTextField("",);
apiKeyTextField.setText(oldApiKey);
jp.add(apiKeyTextField);
contentPane.add(jp);
JPanel jp = new JPanel();
jp.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
jp.setBorder(new EmptyBorder(0, 0, 0, 0));
jp.setPreferredSize(new Dimension(400, 30));
JLabel secretKeyLabel = new JLabel("Secret Key : ");
jp.add(secretKeyLabel);
final JTextField secretKeyTextField = new JTextField("",);
secretKeyTextField.setText(oldSecretKey);
jp.add(secretKeyTextField);
contentPane.add(jp);
JPanel jp = new JPanel();
jp.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
jp.setBorder(new EmptyBorder(0, 0, 0, 0));
jp.setPreferredSize(new Dimension(400, 30));
JLabel imageLabel = new JLabel(" Image : ");
jp.add(imageLabel);
final JTextField imageTextField = new JTextField("",);
jp.add(imageTextField);
JButton selFileBtn = new JButton("...");
jp.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(jp);
JPanel jp = new JPanel();
jp.setLayout(new FlowLayout(FlowLayout.RIGHT, 0, 0));
jp.setBorder(new EmptyBorder(0, 0, 0, 0));
jp.setPreferredSize(new Dimension(400, 30));
JButton saveKeyBtn = new JButton("保存密钥");
jp.add(saveKeyBtn);
contentPane.add(jp);
JButton okBtn = new JButton("识别文字");
jp.add(okBtn);
JPanel jp = new JPanel();
jp.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
jp.setBorder(new EmptyBorder(0, 0, 0, 0));
jp.setPreferredSize(new Dimension(400, 500));
final JTextArea textArea = new JTextArea(, 40);
textArea.setSize(new Dimension(, 500));
textArea.setText(",调用的是百度OCR-API,需要提供百度智能云管理后台的应用的API Key和Secret Key。\r\n" +
"\t.1,进入百度智能云服务列表:https://console.bce.baidu.com/ai/#/ai/ocr/overview/index 。\r\n" +
"\t.2,点击'通用场景OCR',然后找到'通用文字识别(高精度版)'后点击开通。\r\n" +
"\t.3,进入创建应用页面:https://console.bce.baidu.com/ai/#/ai/ocr/app/create。\r\n" +
"\t.4,填写应用名称,应用归属选择'个人',随便填写应用描述,然后点击'立即创建'。\r\n" +
"\t.5,进入应用列表页面:https://console.bce.baidu.com/ai/#/ai/ocr/app/list。\r\n" +
"\t.6,复制出API Key和Secret Key。\r\n" +
"\t.7,该接口每天只能免费调用500次,超出部分百度要收费。\r\n" +
",语言可以自动识别。\r\n" +
",只支持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);
jp.add(jsp);
contentPane.add(jp);
saveKeyBtn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (BaiduCloudApiUtil.appApiKey.trim().isEmpty() || BaiduCloudApiUtil.appSecretKey.trim().isEmpty()) {
textArea.setText("请先调用接口,成功后才能保存密钥!");
return;
}
List<String> list = new ArrayList<>();
list.add(BaiduCloudApiUtil.appApiKey);
list.add(BaiduCloudApiUtil.appSecretKey);
try {
Files.write(keyFile.toPath(), list, Charset.forName("UTF-"), 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<String, Object> 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(, 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 =;
accessTokenTime =;
}
public static String getAccessToken() {
if (!(accessToken == null || accessToken.trim().isEmpty()) && accessTokenTime > && expireTime > 0) {
long extime = accessTokenTime + (expireTime *);
long nowTime = System.currentTimeMillis();
if (extime - nowTime >) {// 仍然有效
return accessToken;
}
}
String authHost = "https://aip.baidubce.com/oauth/.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 Map<String, Object> parse(JSONObject jsonObject) {
HashMap<String, Object> 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() <=) {
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-"));
connection.connect();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream(), "UTF-"))) {
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 encodeBase(byte[] input) throws Exception {
Class<?> clazz = Class.forName("com.sun.org.apache.xerces.internal.impl.dv.util.Base");
Method mainMethod = clazz.getMethod("encode", byte[].class);
mainMethod.setAccessible(true);
Object retObj = mainMethod.invoke(null, new Object[]{input});
return (String) retObj;
}
public static Map<String, Object> queryOcrResult(byte[] fileBytes) {
try {
String imageBase = encodeBase(fileBytes);
imageBase = URLEncoder.encode(imageBase, "UTF-");
String httpUrl = "https://aip.baidubce.com/rest/.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<String, Object> map = new HashMap<>();
map.put("success", false);
map.put("message", "系统错误,请稍后重试");
return map;
}
Map<String, Object> map = parse(jsonObject);
return map;
} catch (Exception e) {
HashMap<String, Object> 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\\tang\\Desktop\\2022-07-21_070822.png");
byte[] data = Files.readAllBytes(file.toPath());
Map<String, Object> map = queryOcrResult(data);
System.out.println(map.get("data"));
}
}
pom.xml
<?xml version=".0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>.0.0</modelVersion>
<groupId>translate.image</groupId>
<artifactId>TranslateImage</artifactId>
<version>.0-SNAPSHOT</version>
<name>TranslateImage</name>
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-</project.build.sourceEncoding>
<maven.compiler.source>.8</maven.compiler.source>
<maven.compiler.target>.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>.2.29</version>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>.8.0</version>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>.0.2</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>.1.1</version>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source></source>
<target></target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>translate.image.App</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>