目錄
最近在閱讀PDF文檔做筆記時,發現無法複製內容,手機QQ有功能(圖片文字識別)可以但電腦上來回傳輸太麻煩.
需求分析:截圖PDF==>文字識別OCR==>輸出文字
三個步驟中其他功能好實現,只有OCR不好自己實現;如何解決實現文字識別呢?網上搜索了一下,最後決定使用百度提供的文字識別API。
1 申請百度AI賬號
http://ai.baidu.com/?track=cp:aipinzhuan|pf:pc|pp:AIpingtai|pu:title|ci:|kw:10005792
點鏈接,進去後點擊控制檯:
然後點擊創建應用,信息隨便填一填就好了,我這裏已經創建好了:
\
2 創建AipOcr客戶端client對象
閱讀AIPOcr的api創建client客戶端:
public class OcrClient {
//設置APPID/AK/SK
public static final String APP_ID = "自己申請的";
public static final String API_KEY = "自己申請的";
public static final String SECRET_KEY = "自己申請的";
public static AipOcr createClient() {
return new AipOcr(APP_ID, API_KEY, SECRET_KEY);
}
//文字識別
public static void ocrOps( String fileName,AipOcr client) {//文字識別
JSONObject res= client.basicAccurateGeneral(fileName,new HashMap<String, String>());
JSONArray jsonArray = res.getJSONArray("words_result");
int num = (int)res.get("words_result_num");
for (int i = 0; i < num; i++) {
String words = jsonArray.getJSONObject(i).get("words").toString();
System.out.println(words);
}
}
}
把圖片保存到本地並提取filename(路徑及圖片名),測試一下
結果: 測試文字識別成功
3 創建圖片操作對象
爲了減小存儲壓力,我把截取的圖片又刪除了;
public class ImageOps {
//保存文件
public static void saveToFile(String pathStr, String fileName, BufferedImage saveImage){
SimpleDateFormat sdf=new SimpleDateFormat("yyyymmddHHmmss");
String name=sdf.format(new Date());
File path= FileSystemView.getFileSystemView().getHomeDirectory();
//pathStr= OcrServiceApplication.class.getResource("/").getPath();//class下
String format="png";
pathStr = path + "\\";
//fileName = path + File.separator + name + "." + format;
fileName = pathStr + name + "." + format;
File f=new File(fileName);
try {
ImageIO.write(saveImage, format, f);
} catch (IOException e) {
e.printStackTrace();
}
}
//快照截屏
public static void snapshot(BufferedImage image ){
try {
Robot robot= new Robot();
Dimension d=Toolkit.getDefaultToolkit().getScreenSize();
image=robot.createScreenCapture(new Rectangle(0,0,d.width,d.height));
} catch (AWTException e) {
e.printStackTrace();
}
}
//刪除本地圖片
public static void deleteDir(String path) {
File file = new File(path);
if (!file.exists()) {//判斷是否待刪除目錄是否存在
System.err.println("The dir are not exists!");
}
String[] content = file.list();//取得當前目錄下所有文件和文件夾
for (String name : content) {
if (name.endsWith(".png")) {
File temp = new File(path, name);
if (temp.isDirectory()) {//判斷是否是目錄
deleteDir(temp.getAbsolutePath());//遞歸調用,刪除目錄裏的內容
temp.delete();//刪除空目錄
} else {
if (!temp.delete()) {//直接刪除文件
System.err.println("Failed to delete " + name);
}
}
}
}
}
}
4 創建OcrServiceApplication對象
@SpringBootApplication
@Slf4j
public class OcrServiceApplication extends JFrame{
private static final long serialVersionUID = 1L;
int orgx,orgy,endx,endy;
static BufferedImage image;
static BufferedImage tempImage;
static BufferedImage saveImage;
Graphics g;
static String fileName;
static String pathStr;
static AipOcr client ;
//繪製圖片
@Override
public void paint(Graphics g) {
//縮放因子和偏移量
RescaleOp ro=new RescaleOp(0.8f, 0, null);
tempImage=ro.filter(image, null);
g.drawImage(tempImage, 0, 0,this);
}
//構造器初始化監聽器
public OcrServiceApplication(){
setVisible(true);//可視化
//setSize(d);//最大化窗口
setDefaultCloseOperation(EXIT_ON_CLOSE);//關閉退出
this.addMouseListener(new MouseAdapter(){
public void mousePressed(MouseEvent e){
orgx=e.getX();
orgy=e.getY();
}
});
//鼠標運動監聽器
this.addMouseMotionListener(new MouseMotionAdapter() {//鼠標拖拽事件
public void mouseDragged(MouseEvent e) {
endx=e.getX();
endy=e.getY();
g=getGraphics();
g.drawImage(tempImage, 0, 0, OcrServiceApplication.this);
int x=Math.min(orgx, endx);
int y=Math.min(orgy,endy);
//加上1,防止width,height爲0
int width=Math.abs(endx-orgx)+1;
int height=Math.abs(endy-orgy)+1;
g.setColor(Color.BLUE);
g.drawRect(x-1, y-1, width+1, height+1);
//減1,加1都是爲了防止圖片將矩形框覆蓋掉
saveImage=image.getSubimage(x, y, width, height);
g.drawImage(saveImage, x, y,OcrServiceApplication.this);
}
});
//鍵盤監聽器
this.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e){
if (e.isControlDown() && e.isShiftDown() && e.getKeyCode() == KeyEvent.VK_H) {
log.debug("鍵盤按下了ctrl+shift+j:開始截圖了");
image=ImageOps.snapshot(image);
log.debug("開始截圖了成功");
setExtendedState(MAXIMIZED_BOTH);//最大化
}
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
log.debug("鍵盤按下了enter");
fileName=ImageOps.saveToFile(pathStr,fileName,saveImage);
log.debug("保存圖片成功");
OcrClient.ocrOps(fileName, client);
log.debug("文字識別");
ImageOps.deleteDir(fileName.substring(0, fileName.lastIndexOf("\\")+1));
log.debug("刪除圖片");
setExtendedState(JFrame.ICONIFIED);//最小化
}
if(e.getKeyCode()==27){
System.exit(0); //按Esc鍵退出
}
}
});
}
public static void main(String[] args) {
// 初始化一個AipOcr
client = OcrClient.createClient();
SpringApplication.run(OcrServiceApplication.class, args);
}
}
5 打jar包方便以後使用
下載資源jar包: 點擊 OCR.jar包下載使用
百度網盤:
鏈接:https://pan.baidu.com/s/1KJ1NXFVzDtGkaEAScUPnOA 提取碼:cp26
操作: 先點擊激活窗體,在按Ctrl+Shift+H鍵並且鼠標拖拉選中截圖,然後按Enter鍵OCR識別文字輸出使用;Esc鍵或×號關閉程序
不足之處:
每次使用前都要點擊程序圖標激活(沒有使用全局鍵盤監聽,不能直接使用Ctrl+Shift+H鍵).
歡迎各位大佬幫忙提建議改善一下!
出現:
測試要提取的文字圖片:
結果展示使用:
文字使用:
1、520那天我給我喜歡的女生髮了520的紅包。
女生也給我回了個520的紅包。
把我高興壞了。。。
後來約她出來看電影的時候,姑娘說:我不是把紅包還你了麼,你還約我出來幹嘛。
我
2、別人問你有談戀愛嗎?只要說現在沒有,能掩蓋過去也沒有的事實。
3、"一隻小鳥受傷了,小鳥媽媽關心地問道:“是怎麼受的傷?”小鳥說:“我跟在爸爸身後,
不
料爸爸放了個屁,我一捂嘴巴,結果掉到地上受傷了鳥媽媽語重心長的說:“前事不忘後事之
師,傻孩子,記住了,以後別人放屁千萬別捂嘴了。”
4、公司新來了一個小夥,斯斯文文挺乾淨的感覺。
公司一女的對他有意思,但她性格要強,抹不開面,於是就每天利用工作找他麻煩,和他鬥嘴,
想着
能像電視裏那樣成爲一對歡喜冤家。
果然,沒過幾天,小夥子打了她一頓,辭職走了。
歡迎各位大佬幫忙提建議改善一下!
改善一下: 使用全局監聽
1.加入jintellitype依賴
<dependency>
<groupId>com.melloware</groupId>
<artifactId>jintellitype</artifactId>
<version>1.3.9</version>
</dependency>
2.把JIntellitype.dll和JIntellitype64.dll複製到java的bin文件夾下如:D:\Java\jdk1.8.0_40\bin
否則,會拋出異常:
Exception in thread "main" com.melloware.jintellitype.JIntellitypeException: Could not load JIntellitype.dll from local file system or from inside JAR
at com.melloware.jintellitype.JIntellitype.<init>(JIntellitype.java:114)
at com.melloware.jintellitype.JIntellitype.getInstance(JIntellitype.java:177)
at com.bjlemon.automsg.Application.<init>(Application.java:50)
at com.bjlemon.automsg.Application.main(Application.java:29)
Caused by: java.io.IOException: FromJarToFileSystem could not load DLL: com/melloware/jintellitype/JIntellitype.dll
at com.melloware.jintellitype.JIntellitype.fromJarToFs(JIntellitype.java:150)
at com.melloware.jintellitype.JIntellitype.<init>(JIntellitype.java:105)
... 3 more
Caused by: java.lang.NullPointerException
at com.melloware.jintellitype.JIntellitype.fromJarToFs(JIntellitype.java:146)
... 4 more
解決方法:
把JIntellitype.dll和JIntellitype64.dll複製到JAVA_HOME使用到的java的bin文件夾下如:D:\Java\jdk1.8.0_40\bin
3.修改程序中的鍵盤監聽器
//鍵盤監聽器
this.addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(KeyEvent e){
if (e.isControlDown() && e.isShiftDown() && e.getKeyCode() == KeyEvent.VK_H) {
log.debug("鍵盤按下了ctrl+shift+j:開始截圖了");
image=ImageOps.snapshot(image);
log.debug("開始截圖了成功");
setExtendedState(MAXIMIZED_BOTH);//最大化
}
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
log.debug("鍵盤按下了enter");
fileName=ImageOps.saveToFile(pathStr,fileName,saveImage);
log.debug("保存圖片成功");
OcrClient.ocrOps(fileName, client);
log.debug("文字識別");
ImageOps.deleteDir(fileName.substring(0, fileName.lastIndexOf("\\")+1));
log.debug("刪除圖片");
setExtendedState(JFrame.ICONIFIED);//最小化
}
if(e.getKeyCode()==27){
System.exit(0); //按Esc鍵退出
}
}
});
修改後:
// ......
//鍵盤監聽器
init();
}
// 初始化
private void init() {
// 第一步:註冊熱鍵,熱鍵標識
JIntellitype.getInstance().registerHotKey(GLOBAL_HOT_KEY_1,0, 0x1B);//esc
JIntellitype.getInstance().registerHotKey(GLOBAL_HOT_KEY_2,JIntellitype.MOD_ALT , (int) 'Q');//Alt+Q
JIntellitype.getInstance().registerHotKey(GLOBAL_HOT_KEY_3,JIntellitype.MOD_ALT , (int) 'S');//Alt+S
//JIntellitype.getInstance().registerHotKey(GLOBAL_HOT_KEY_3,0 , 0x0D);//Enter
// 添加熱鍵監聽器
// 第二步:添加熱鍵監聽器
JIntellitype.getInstance().addHotKeyListener(new HotkeyListener() {
@Override
public void onHotKey(int markCode) {
switch (markCode) {
case GLOBAL_HOT_KEY_1:
log.debug("鍵盤按下了Esc:退出程序!");
System.exit(0);
break;
case GLOBAL_HOT_KEY_2:
log.debug(" 鍵盤按下了Alt+Q:開始截圖了");
image=ImageOps.snapshot(image);
setExtendedState(MAXIMIZED_BOTH);//最大化
break;
case GLOBAL_HOT_KEY_3:
log.debug("鍵盤按下了Alt+S");
fileName=ImageOps.saveToFile(pathStr,fileName,saveImage);
OcrClient.ocrOps(fileName, client);
ImageOps.deleteDir(fileName.substring(0, fileName.lastIndexOf("\\")+1));
setExtendedState(JFrame.ICONIFIED);//最小化
break;
}
}
});
4. 打包並運行jar
複製使用:
5使用方法
按下Alt+Q(使用了全局監聽) 開啓應用,然後選中要識別的文字,按Alt+S開始識別文字
進一步改善程序:
用exe4j把jar程序轉換爲exe,雙擊即可使用,.下一篇:
用exe4j轉換jar包爲exe文件,不用配置jdk jre環境變量可直接雙擊使用
下載使用 :ocr04_jar2exe