荐 图像转文本、PDF 转文字(包括html、xml)、关键句提取 软件开发手记

2022-08-09,,,,

文章目录

  • 准备工作
    • 声明
    • 所需模块:
      • 模块简介
      • 安装方法:
  • 软件开发
    • 图像文本
      • API 使用代码
      • 其他
    • PDF 转文字
      • 代码
      • Tooltip
    • 关键句提取
    • 截图
    • 古文排版
  • 软件使用
    • 关于界面
      • 国际化效果展示
      • 国际化实现
    • 使用指南
      • 图像转文本
      • PDF 转文字
      • 关键句提取
      • 古文排版
  • Tkinter 有关指南:

准备工作

声明

要源码的请关注后留言
软件效果请看使用指南

所需模块:

模块简介

Tkinter:主要是 GUI 模块
pytesseract:图像转文字 API 接口
pdfminter3:读取 PDF 并转换成其他格式
pyhanlp:进行关键句提取

安装方法:

清华源 pip 走起:
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple pytesseract

软件开发

图像转文本

图像转文本 软件中,需要首先下载一个 tesseract 的开源,文本转图像工具。然后,通过 pytesseract 调用其 API,来实现图像识别文本(OCR)

tesseract 的下载地址

可以下载任意版本,这里推荐下载最新版本

API 使用代码

# coding: utf-8
import pytesseract
from PIL import Image
from tkinter import messagebox as mBox
import tkinter as tk
import os

def img2text(engine_path,img_path,text_path,Widget,lang):
    pytesseract.pytesseract.tesseract_cmd = engine_path
    mBox.showinfo('提示', '运行中,请耐心等待\n 文件越复杂,运行时间越久哦(关了吧,没关系的)')
    text = pytesseract.image_to_string(Image.open(img_path),lang=lang)

    with open(text_path+r'\output.txt', "w", encoding='utf-8') as f:
        f.write(text)
        f.close()
    mBox.showinfo('提示', '运行完毕')
    Widget.insert(tk.INSERT,text)
 
def img2text_TEST(engine_path,img_path,text_path):
    pytesseract.pytesseract.tesseract_cmd = engine_path  
    text = pytesseract.image_to_string(Image.open(img_path),lang='chi_sim')

    with open(text_path+r'\output.txt', "w", encoding='utf-8') as f:
        f.write(text)
        f.close()
    mBox.showinfo('提示', '运行完毕')

if __name__ == '__main__':    
    engine_path = r'C:\Program Files\Tesseract-OCR\tesseract.exe'
    img_path = r'E:\java-2020-03\eclipse\workspace\Img2Txt\Input\test_math.jpg'
    text_path = r'E:\java-2020-03\eclipse\workspace\Img2Txt\Output'
    img2text_TEST(engine_path,img_path,text_path) 

其他

可以尝试使用百度识图,里面也有相应的 API,不过一天只能使用有限次,所以这里不再采用。详细地,可以参照这篇博文:
https://blog.csdn.net/qq_38144563/article/details/96138470

其实,对于公式的识别,把他转成 latex,还有一个工具,具体是什么,请在评论区提问吧。不过,也是一个有限次使用的主。他的 API,因为某些无聊的原因,现在不对我国开放了,实在可惜。!!!!!

PDF 转文字

pdf 转文字用的是 pdfminer3,最近开发了 python3 版本。所以,网上的那些,都是用不了的,大家大可不一试,因为我试过了。有些模块已经被改了,所以也用不了。因此,就看我怎么写吧?

代码

# coding: utf-8
import argparse
import logging
import sys
import pdfminer3.settings
pdfminer3.settings.STRICT = False
import pdfminer3.high_level
import pdfminer3.layout
from pdfminer3.image import ImageWriter
import tkinter as tk
from tkinter import messagebox as mBox


def extract_text(files=[], outfile='-',
            _py2_no_more_posargs=None,  
            no_laparams=False, all_texts=None, detect_vertical=None, # LAParams
            word_margin=None, char_margin=None, line_margin=None, boxes_flow=None, # LAParams
            output_type='text', codec='utf-8', strip_control=False,
            maxpages=0, page_numbers=None, password="", scale=1.0, rotation=0,
            layoutmode='normal', output_dir=None, debug=False,
            disable_caching=False, **other):
    if _py2_no_more_posargs is not None:
        raise ValueError("Too many positional arguments passed.")
    if not files:
        raise ValueError("Must provide files to work upon!")

    if not no_laparams:
        laparams = pdfminer3.layout.LAParams()
        for param in ("all_texts", "detect_vertical", "word_margin", "char_margin", "line_margin", "boxes_flow"):
            paramv = locals().get(param, None)
            if paramv is not None:
                setattr(laparams, param, paramv)
    else:
        laparams = None

    imagewriter = None
    if output_dir:
        imagewriter = ImageWriter(output_dir)

    if output_type == "text" and outfile != "-":
        for override, alttype in (  (".htm", "html"),
                                    (".html", "html"),
                                    (".xml", "xml"),
                                    (".tag", "tag") ):
            if outfile.endswith(override):
                output_type = alttype

    if outfile == "-":
        outfp = sys.stdout
        if outfp.encoding is not None:
            codec = 'utf-8'
    else:
        outfp = open(outfile, "wb")


    for fname in files:
        with open(fname, "rb") as fp:
            pdfminer3.high_level.extract_text_to_fp(fp, **locals())
    return outfp



def trans(files, outfile):
    mBox.showinfo('提示', '运行中,请耐心等待\n 文件越复杂,运行时间越久哦(关了吧,没关系的)')
    outfp = extract_text(files=files,outfile=outfile)
    outfp.close()
    mBox.showinfo('提示ʾ', '运行完毕')


if __name__ == '__main__': 
    trans(files=['E:/java-2020-03/eclipse/workspace/Img2Txt/Fun/test.pdf'],outfile='output.html')

在运行代码的时候,注意删掉一些哈。

Tooltip

在 PDF 转文本哪里,用了一个弹出说明,我把代码封装成一个类了,希望以后能够用到:

# -*- coding: utf-8 -*-
import tkinter as tk

class Tooltip():
    def __init__(self,widget):
        self.widget = widget
        self.tipwindow = None   
        self.id = None    
        self.x = self.y = 0    
    def showtip(self,text):
        self.text = text
        if self.tipwindow or not self.text:
            return
        x,y,_cx,cy = self.widget.bbox("insert")
        x = x + self.widget.winfo_rootx()+27
        y = y + cy + self.widget.winfo_rooty()+27
        self.tipwindow = tw = tk.Toplevel(self.widget)
        tw.wm_overrideredirect(1)    
        tw.wm_geometry("+%d+%d"%(x,y))
        label = tk.Label(tw,text=self.text,justify=tk.LEFT,
                         background='#ffffe0',relief=tk.SOLID,
                         borderwidth=1,font=('tahma',"8","normal"))
        label.pack(ipadx=1)    
    
    def hidetip(self):
        tw = self.tipwindow
        self.tipwindow = None 
        if tw:
            tw.destroy()
            
def createToolTip(widget,text):
    aTooltip = Tooltip(widget)    
    def enter(event):    
        aTooltip.showtip(text)
    def leave(event):
        aTooltip.hidetip()
    widget.bind('<Enter>',enter)    
    widget.bind('<Leave>',leave)

关键句提取

这个很容易啦,直接用 pyhanlp 就行了。里面用的是 PageRank 算法,相当于 Google 的网页排名算法。

# -*- coding: utf-8 -*-
"""
Created on Thu May  7 14:52:32 2020

@author: 
"""
from pyhanlp import *
from tkinter import messagebox as mBox

import tkinter as tk

def summary(text,num,Widget):
    
    text_list = HanLP.extractSummary(text,num)
    text = '\n'.join([t for t in text_list])
    Widget.insert(tk.INSERT,text)
    mBox.showinfo('提示', '运行完毕')
    

if __name__ == "__main__":
    summary_list = summary('“芦花滩上有扁舟, 俊杰黄昏独自游, 义到尽头原是命, 反躬逃难必无忧。”\
这是一首出自《水浒传》中吴用留下的藏头反诗;电视剧《裂变》中汉奸“蝙蝠”也曾\
使用数字对应书本页面和文字的方法传递消息给日寇;电影《暗算》中更是提到了黄依\
依解决多种密文的具体情节;甚至连动画片《名侦探柯南》也出现了 skytale 加密的细\
节。事实上,密文不仅存在于荧幕中,而且深入到生活的方方面面,例如用于存储互联\
网消息的 cookie、以及互联网安全中常提到的数字签名、在银行等网站上填写个人信息\
时,都会用一定的手段将明文加密成密文传输到在远处的服务器中,可以说,在互联网\
的世界里,只要有比特流动,就一定会有加密的存在。为此,各大高校还设立了专门的\
学科,如密码学、密码分析学、密码史等。不得不说,密码的发展更数学密切相关、大\
多数的密码学家都兼任数学家的身份,而密码学,这一学科在战争时代更是快速地发展。\
以下将会介绍密码学的发展史、以及一些经典密码学的典型加密方法和其对应的解密方\
法的介绍、文章最后会简单地提及现代密码学的一些实现手段',5)
    print(summary_list)

截图

在图像转文本哪里,我还内置了截图功能,代码如下:

# -*- coding:utf-8 -*-  
import tkinter as tk
from tkinter import filedialog as fd
import os
from os import path
from PIL import ImageGrab
from time import sleep

class ScreenShot:
    def __init__(self,master,filename):
        
        self._createWidge(master, filename)
        #变量X和Y用来记录鼠标左键按下的位置
        
    def _onLeftButtonDown(self,event):
        self._X.set(event.x)
        self._Y.set(event.y)
        #开始截图
        self._sel = True
    
    def _onLeftButtonMove(self,event):
        if not self._sel:
            return
        try:
            #删除刚画完的图形,要不然鼠标移动的时候是黑乎乎的一片矩形
            self._canvas.delete(self._lastDraw)
        except Exception as e:
            pass
        self._lastDraw = self._canvas.create_rectangle(self._X.get(), self._Y.get(), 
                                                 event.x, event.y, outline='black',
                                                width = 5)

    def _onLeftButtonUp(self,event):
        self.fileName = os.path.join(os.path.dirname(__file__),'../Input') 
        self._sel = False
        try:
            self._canvas.delete(self._lastDraw)
        except Exception as e:
            pass
        sleep(0.1)
        #考虑鼠标左键从右下方按下而从左上方抬起的截图
        leftSel, rightSel = sorted([self._X.get(), event.x])
        topSel, bottomSel = sorted([self._Y.get(), event.y])
        pic = ImageGrab.grab((leftSel+1,topSel,rightSel+1,bottomSel))     
         #弹出保存截图对话框
        fDir = os.path.join(os.path.dirname(__file__),'../Input')  #���ϼ��ļ�Ŀ¼��
        self.fileName = fd.asksaveasfilename(title='保存截图',
                                        filetypes=[('JPG files','*.jpg')],
                                        initialdir=fDir)
        #默认的文件夹呀!!
        if self.fileName: 
            pic.save(self.fileName)
        pic.close()
        #关闭当前窗口
        #print(left, '  ', top,'  ',right,'  ',bottom)
        self.top.destroy()
        print(self.fileName)
        sleep(1)
        

    def _createWidge(self,master,filename):
        self.fileName =  os.path.abspath(os.path.join( os.path.dirname(__file__),".."))+'\Input'
        self._X = tk.IntVar(0)
        self._Y = tk.IntVar(0)
        
        #屏幕尺寸
        screenWidth = master.winfo_screenwidth()
        #print(screenWidth)
        screenHeight = master.winfo_screenheight()
        #print(screenHeight)
        #创建顶级组件容器
        self.top = tk.Toplevel(master, width=screenWidth, height=screenHeight)
        #不显示最大化、最小化按钮
        self.top.overrideredirect(True)
        self._canvas = tk.Canvas(self.top,bg='white', width=screenWidth, height=screenHeight)
        #显示全屏截图,在全屏截图上进行区域截图
        self._img = tk.PhotoImage(file=filename)
        self._canvas.create_image(screenWidth//2, screenHeight//2,image=self._img)
        #鼠标左键按下的位置
        self._canvas.bind('<Button-1>', self._onLeftButtonDown)
        #鼠标左键移动,显示选取的区域

        self._canvas.bind('<B1-Motion>', self._onLeftButtonMove)
        #获取鼠标左键抬起的位置,保存区域截图
            
        self._canvas.bind('<ButtonRelease-1>', self._onLeftButtonUp)
        self._canvas.pack(fill=tk.BOTH, expand=tk.YES)


def buttonCaptureClick(master):
    #最小化主窗口
    master.state('icon')
    sleep(0.5)
    filename = 'screenShot.png'
    im = ImageGrab.grab()
    im.save(filename)
    im.close()
    #显示全屏幕截图
    
    w = ScreenShot(master,filename)

    os.remove(filename)
    print(w.fileName)
    return w.fileName

古文排版

所谓古文排版,就是将横的转为右起,竖的。实现代码如下:

# -*- coding: utf-8 -*-
import re
import tkinter as tk
from tkinter import messagebox as mBox
def cut_text(text,lenth):
    textArr = re.findall('.{'+str(lenth)+'}', text)
    textArr.append(text[(len(textArr)*lenth):])
    return textArr

def verticalPrint(text,counts,Widget):
    mBox.showinfo('提示', '运行中,请耐心等待\n 文件越复杂,运行时间越久哦(关了吧,没关系的)')
    text = cut_text(text,counts)
    text[-1] = text[-1].ljust(counts,' ')
    cols = len(text)
    text.reverse()
    
    rows = []
    for i in range(counts):
        row = ''
        for col in range(cols):
            row += text[col][i]
        rows.append(row)
    
    text = '\n'.join(rows)
    
    string = ''
    for char in text:
        if  not char.isdigit() and not char==' ':
            if  (char >= u'\u0041' and char<=u'\u005a') or (char >= u'\u0061' and char<=u'\u007a'):
                char += ' '
            else:
                pass
        else:
            char +=' '     
        string += char
    
    Widget.insert(tk.INSERT,string)
    mBox.showinfo('提示', '运行完毕')
    
if __name__ == '__main__':
    x=u"凡是到达了的地方,都I want to die, but I still to my life 属于昨天。哪怕那山再青,那水再秀,那风再温柔。带深的流连便成了一种羁绊,\
绊住的不仅是双脚,还有未来。可我的钱不够[笑哭]"
#    counts = 12
#    string = verticalPrint(x,counts)
#    print(string)

软件使用

关于界面

界面如下:

国际化效果展示

在开始菜单里,有弄了个国际化,效果如下:

国际化实现

将文本封装成一个类即可,就是 GUI 文件里面的 I18N.py,大家可以看一下。

然后,在定义处,添加如下代码:

class OOP:
    def __init__(self):
        self.win = tk.Tk()
        self.win.resizable(0,0)    #这个是设置窗口不可缩放
        self.i18n = I18N('chi')
        self._createWidget()
        self.win.mainloop()
        
    def _quit(self):    #设置一个 menu 菜单项的激活函数
        self.win.quit()    #退出
        self.win.destroy()   #销毁
        exit()   #结束程序
    def _chi(self):
        self.win.quit()
        self.win.destroy()
        self.win = tk.Tk()
        self.win.resizable(0,0)    #这个是设置窗口不可缩放
        self.i18n = I18N('chi')
        self._createWidget()
        self.win.mainloop()
        
    def _jap(self):
        self.win.quit()
        self.win.destroy()
        self.win = tk.Tk()
        self.win.resizable(0,0)    #这个是设置窗口不可缩放
        self.i18n = I18N('jap')
        self._createWidget()
        self.win.mainloop()
        
    def _eng(self):
        self.win.quit()
        self.win.destroy()
        self.win = tk.Tk()
        self.win.resizable(0,0)    #这个是设置窗口不可缩放
        self.i18n = I18N('eng')
        self._createWidget()
        self.win.mainloop()

使用指南

图像转文本

在 输出路径中,可以得到 output.txt 文件

也可以识别日文、英文、繁体中文,而且效果不错。不过,公式就算了吧,效果太 low 了。

(支持输入任意图片格式~~)

PDF 转文字

效果:

日文:

英文当然也可以,这里不再展示了。

关键句提取

古文排版

Tkinter 有关指南:

这里使用的是 Tkinter 来开发一款软件的,如果不是用 Tkinter,请移步。
首先推荐一些 Tkinter 的教程吧:
Tkinter GUI 01
Tkinter GUI 02
Tkinter GUI 03
Tkinter GUI 04
Tkinter GUI 05
Tkinter GUI 06
Tkinter GUI 07
Tkinter GUI 08

然后,是一些有用的参考资料和书籍的下载地址:
Python GUI Tkinter 参考资料

下面是另一个软件,Word 转手写体
https://blog.csdn.net/weixin_42141390/article/details/106840073

本文地址:https://blog.csdn.net/weixin_42141390/article/details/107147254

《荐 图像转文本、PDF 转文字(包括html、xml)、关键句提取 软件开发手记.doc》

下载本文的Word格式文档,以方便收藏与打印。