[Python] 纯文本查看 复制代码
import tkinter as tk
from tkinter import filedialog, messagebox,scrolledtext
from tkinter import ttk
from tkinterdnd2 import TkinterDnD, DND_FILES
import json
import base64
import pathlib
import requests
import io
from PIL import ImageGrab
import ctypes
ctypes.windll.shcore.SetProcessDpiAwareness(2)
url_base = 'http://127.0.0.1:1224/'
url_options = url_base + 'api/ocr/get_options'
url_ocr = url_base + "api/ocr"
def test_http(url_base):
'''test the server'''
try:
response = requests.get(url=url_base)
response.raise_for_status()
except Exception as e:
messagebox.showwarning("warning","服务未连通,请确保软件或服务端已经打开")
def img_base64(img_file):
if isinstance(img_file,io.BytesIO):
img_bytes = img_file.getvalue()
else:
img_bytes = pathlib.Path(img_file).read_bytes()
return base64.b64encode(img_bytes).decode('utf-8')
def to_ocr(url,options:dict,img:str | io.BytesIO):
data = {
"base64":img_base64(img),
"options": options
}
headers = {"Content-Type": "application/json"}
data_str = json.dumps(data)
response = requests.post(url,data=data_str, headers=headers) #也可用 json 参数
response.raise_for_status()
res_dict = json.loads(response.text)
return res_dict
class OptTranslator:
'''en --> zh'''
__slots__=('ocr_language','tbpu_parser','opt_name')
def __init__(self) -> None:
self.opt_name:dict = {"ocr.language":"语言:","ocr.cls":"对正文字:","ocr.limit_side_len":"限制边长:","tbpu.parser":"排版:","tbpu.ignoreArea":"忽略区域:","data.format":"数据格式:",}
self.ocr_language:dict={"简体中文":"models/config_chinese.txt",
"English":"models/config_en.txt",
"繁體中文":"models/config_chinese_cht(v2).txt",
"日本語":"models/config_japan.txt",
"한국어":"models/config_korean.txt",
"Русский":"models/config_cyrillic.txt"}
self.tbpu_parser:dict = {"单栏-按自然段换行":"single_para",
"单栏-总是换行":"single_line",
"多栏-按自然段换行":"multi_para",
"多栏-总是换行":"multi_line",
"多栏-无换行":"multi_none",
"单栏-按自然段换行":"single_para",
"单栏-总是换行":"single_line",
"单栏-无换行":"single_none",
"单栏-保留缩进":"single_code",
"不做处理":"none"}
class App:
def __init__(self, root):
self.root = root
self.root.title("OCR")
self.root.geometry("520x450")
self.file_path_label = tk.Label(root, text="File Path:")
self.file_path_label.grid(row=0, column=0, sticky="w", padx=10, pady=10)
self.file_path_entry = tk.Entry(root, width=50)
self.file_path_entry.grid(row=0, column=1, padx=10, pady=10)
self.open_button = tk.Button(root, text="Open", command=self.open_file)
self.open_button.grid(row=0, column=2, padx=10, pady=10)
self.root.drop_target_register(DND_FILES)
self.root.dnd_bind('<<Drop>>', self.on_file_drop)
self.clipboard = None
self.root.bind("<Control-v>", self.on_paste)
self.arg_vars = [tk.StringVar() for _ in range(6)]
self.arg_comboboxes = []
self.arg_comboboxes_label = []
self.OptTranslator = OptTranslator()
self.option_list = [{'opt_name':'ocr.language','value':[ ("models/config_chinese.txt","简体中文"),
("models/config_en.txt","English"),
("models/config_chinese_cht(v2).txt","繁體中文"),
("models/config_japan.txt","日本語"),
("models/config_korean.txt","한국어"),
("models/config_cyrillic.txt","Русский")]},
{'opt_name':'ocr.limit_side_len','value':("960", "2880", "4320", "999999")},
{'opt_name':'tbpu.parser','value':[
("single_para","单栏-按自然段换行"),
("single_line","单栏-总是换行"),
("multi_para","多栏-按自然段换行"),
("multi_line","多栏-总是换行"),
("multi_none","多栏-无换行"),
("single_para","单栏-按自然段换行"),
("single_line","单栏-总是换行"),
("single_none","单栏-无换行"),
("single_code","单栏-保留缩进"),
("none","不做处理")]},
{'opt_name':'ocr.cls','value':("false", "true")},
{'opt_name':'tbpu.ignoreArea','value':[""]}, #修复原始版本 "[]" -> "" ,旧版不会报错,新版2.1.4会报错
{'opt_name':'data.format','value':("text","dict")}]
for i in range(6):
arg_label = tk.Label(root, text=self.OptTranslator.opt_name[self.option_list[i]['opt_name']])
arg_combobox = ttk.Combobox(root, textvariable=self.arg_vars[i], values=self.option_list[i]['value'], state="readonly", width=20)
if i < 3:
arg_label.grid(row=i+1, column=0, sticky="w", padx=10, pady=2)
arg_combobox.grid(row=i+1, column=1, padx=10, pady=2)
_value_dict = self.option_list[i]
if _value_dict['opt_name'] =='tbpu.parser' or _value_dict['opt_name']== 'ocr.language':
arg_combobox['value'] = [item[1] for item in _value_dict['value']]
else:
arg_combobox['value'] = _value_dict['value']
arg_combobox.current(0)
self.arg_comboboxes.append(arg_combobox)
self.arg_comboboxes_label.append(arg_label)
#operate 按钮(识别)
self.operate_button = tk.Button(root, text="Operate", command=self.operate)
self.operate_button.grid(row=7, column=1, pady=20)
#更多选项 按钮
self.hide_toggle = tk.Button(root, text="更多选项", command=self.visible_toggle)
self.hide_toggle.grid(row=7, column=0, pady=20)
self.result_text =scrolledtext.ScrolledText(root, width=70, height=14,wrap=tk.WORD)
self.result_text.grid(row=8, column=0, columnspan=3, padx=10, pady=10)
#测试 http 是否开启
test_http(url_base)
def visible_toggle(self):
for i,(label,combo) in enumerate(zip(self.arg_comboboxes_label[3:],self.arg_comboboxes[3:])):
if label.grid_info() or combo.grid_info() :
label.grid_forget()
combo.grid_forget()
else:
label.grid(row=i+1+3, column=0, sticky="w", padx=10, pady=2)
combo.grid(row=i+1+3, column=1, padx=10, pady=2)
def open_file(self):
"""Open file dialog to select a file."""
file_path = filedialog.askopenfilename()
if file_path:
self.file_path_entry.delete(0, tk.END)
self.file_path_entry.insert(0, file_path)
def on_file_drop(self, event):
"""Handles the drag-and-drop event."""
file_path = event.data.strip('{}')
self.file_path_entry.delete(0, tk.END)
self.file_path_entry.insert(0, file_path)
if pathlib.Path(file_path).is_file():
try:
self.operate()
except Exception as e:
print(e)
def on_paste(self,event):
try:
image = ImageGrab.grabclipboard()
if image:
img_data = io.BytesIO()
image.convert('RGB').save(img_data,'PNG')
self.clipboard = img_data
self.operate(clipboard=True)
self.clipboard = None
else:
messagebox.showinfo("Clipboard", "No image found in clipboard.")
except Exception as e:
messagebox.showerror("Error", f"An error occurred: {e}")
def operate(self,clipboard=False):
"""Run the operation and display results."""
file_path = self.file_path_entry.get()
if clipboard:
file_path = self.clipboard
args = [var.get() for var in self.arg_vars]
options = {}
for index,box in enumerate(self.arg_comboboxes):
key = self.option_list[index]['opt_name']
value = box.get()
if key == 'ocr.language' or key == 'tbpu.parser':
value = getattr(self.OptTranslator,key.replace('.','_'))[value]
options[key] = value
result = to_ocr(url_ocr,options=options,img=file_path)
self.result_text.delete(1.0, tk.END)
self.result_text.insert(tk.END, result['data'])
if __name__=="__main__":
root = TkinterDnD.Tk()
app = App(root)
root.mainloop()