157 lines
5.6 KiB
Python
157 lines
5.6 KiB
Python
|
|
# Umi-OCR
|
|||
|
|
# OCR software, free and offline. 开源、免费的离线OCR软件。
|
|||
|
|
# Website - https://github.com/hiroi-sora/Umi-OCR
|
|||
|
|
# Author - hiroi-sora
|
|||
|
|
#
|
|||
|
|
# You are free to use, modify, and distribute Umi-OCR, but it must include
|
|||
|
|
# the original author's copyright statement and the following license statement.
|
|||
|
|
# 您可以免费地使用、修改和分发 Umi-OCR ,但必须包含原始作者的版权声明和下列许可声明。
|
|||
|
|
"""
|
|||
|
|
Copyright (c) 2023 hiroi-sora
|
|||
|
|
|
|||
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|||
|
|
of this software and associated documentation files (the "Software"), to deal
|
|||
|
|
in the Software without restriction, including without limitation the rights
|
|||
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|||
|
|
copies of the Software, and to permit persons to whom the Software is
|
|||
|
|
furnished to do so, subject to the following conditions:
|
|||
|
|
|
|||
|
|
The above copyright notice and this permission notice shall be included in all
|
|||
|
|
copies or substantial portions of the Software.
|
|||
|
|
|
|||
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|||
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|||
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|||
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|||
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|||
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|||
|
|
SOFTWARE.
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
|
|||
|
|
"""
|
|||
|
|
======================================================
|
|||
|
|
========== Umi-OCR Windows 运行环境初始化入口 ==========
|
|||
|
|
======================================================
|
|||
|
|
|
|||
|
|
说明:
|
|||
|
|
本文件负责 Windows + PyStand 运行环境的初始化,主要涉及:
|
|||
|
|
- 创建底层弹窗接口 os.MessageBox
|
|||
|
|
- 重定向标准输入输出流
|
|||
|
|
- 指定工作目录为 "/UmiOCR-data"
|
|||
|
|
- 添加Python库搜索目录 "site-packages"
|
|||
|
|
- 添加PySide2插件搜索目录 "PySide2/plugins"
|
|||
|
|
|
|||
|
|
环境初始化后,调用正式入口 py_src/run.py 启动软件。
|
|||
|
|
|
|||
|
|
耗时分析:
|
|||
|
|
runtime/python.exe -X importtime main.py
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
|
|||
|
|
import os
|
|||
|
|
import sys
|
|||
|
|
import site
|
|||
|
|
import traceback
|
|||
|
|
import subprocess
|
|||
|
|
|
|||
|
|
|
|||
|
|
def MessageBox(msg, type_="error"):
|
|||
|
|
# 软件中如遇到错误,会优先用QT弹窗来警示。
|
|||
|
|
# 但一些异常可能触发太早或导致QT事件循环崩溃。
|
|||
|
|
# 因此 os.MessageBox() 是用于报告错误的最后防线。
|
|||
|
|
info = "Umi-OCR Message"
|
|||
|
|
if type_ == "error":
|
|||
|
|
info = "【错误】 Umi-OCR Error"
|
|||
|
|
elif type_ == "warning":
|
|||
|
|
info = "【警告】 Umi-OCR Warning"
|
|||
|
|
try:
|
|||
|
|
# 通过 ctypes 发起弹窗
|
|||
|
|
import ctypes
|
|||
|
|
|
|||
|
|
ctypes.windll.user32.MessageBoxW(None, str(msg), str(info), 0)
|
|||
|
|
except Exception:
|
|||
|
|
# 部分系统,连ctypes也用不了。转为在新的控制台窗口中打印信息。
|
|||
|
|
msg_cmd = (
|
|||
|
|
msg.replace("^", "^^")
|
|||
|
|
.replace("&", "^&")
|
|||
|
|
.replace("<", "^<")
|
|||
|
|
.replace(">", "^>")
|
|||
|
|
.replace("|", "^|")
|
|||
|
|
.replace("\n\n", "___")
|
|||
|
|
.replace("\n", "___")
|
|||
|
|
)
|
|||
|
|
subprocess.Popen(["start", "cmd", "/k", f"echo {info}: {msg_cmd}"], shell=True)
|
|||
|
|
return 0
|
|||
|
|
|
|||
|
|
|
|||
|
|
os.MessageBox = MessageBox
|
|||
|
|
|
|||
|
|
|
|||
|
|
def initRuntimeEnvironment():
|
|||
|
|
"""初始化运行环境"""
|
|||
|
|
|
|||
|
|
# 尝试获取控制台的输出对象
|
|||
|
|
try:
|
|||
|
|
fd = os.open("CONOUT$", os.O_RDWR | os.O_BINARY)
|
|||
|
|
fp = os.fdopen(fd, "w", encoding="utf-8")
|
|||
|
|
except Exception as e:
|
|||
|
|
fp = open(os.devnull, "w", encoding="utf-8")
|
|||
|
|
# 输出流不存在时,重定向到控制台
|
|||
|
|
if not sys.stdout:
|
|||
|
|
sys.stdout = fp
|
|||
|
|
if not sys.stderr:
|
|||
|
|
sys.stderr = fp
|
|||
|
|
# def except_hook(cls, exception, traceback):
|
|||
|
|
# sys.__excepthook__(cls, exception, traceback)
|
|||
|
|
# sys.excepthook = except_hook
|
|||
|
|
|
|||
|
|
# 初始化工作目录和Python搜索路径
|
|||
|
|
script = os.path.abspath(__file__) # 启动脚本.py的路径
|
|||
|
|
cwd = os.path.dirname(script) # 工作目录
|
|||
|
|
os.chdir(cwd) # 重新设定工作目录(不在最顶层,而在 UmiOCR-data 文件夹下)
|
|||
|
|
for n in [".", "site-packages"]: # 将模块目录添加到 Python 搜索路径中
|
|||
|
|
path = os.path.abspath(os.path.join(cwd, n))
|
|||
|
|
if os.path.exists(path):
|
|||
|
|
site.addsitedir(path)
|
|||
|
|
# 初始化Qt搜索路径为相对路径,避免上层目录存在中文编码
|
|||
|
|
from PySide2.QtCore import QCoreApplication
|
|||
|
|
|
|||
|
|
QCoreApplication.addLibraryPath("./site-packages/PySide2/plugins")
|
|||
|
|
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
try:
|
|||
|
|
initRuntimeEnvironment() # 初始化运行环境
|
|||
|
|
except Exception:
|
|||
|
|
err = traceback.format_exc()
|
|||
|
|
from py_src.imports.umi_log import logger, Logs_Dir
|
|||
|
|
|
|||
|
|
logger.critical(
|
|||
|
|
"Failed to initialize running environment!",
|
|||
|
|
exc_info=True,
|
|||
|
|
stack_info=True,
|
|||
|
|
)
|
|||
|
|
msg = f"Failed to initialize running environment!\n\n{err}\n\nSave the log file to: {Logs_Dir}"
|
|||
|
|
MessageBox(msg)
|
|||
|
|
sys.exit(0)
|
|||
|
|
try:
|
|||
|
|
# 获取 pystand.exe 记录的程序入口环境变量
|
|||
|
|
app_path = os.environ.get("PYSTAND", "")
|
|||
|
|
# 启动正式入口
|
|||
|
|
from py_src.run import main
|
|||
|
|
|
|||
|
|
main(app_path=app_path, engineAddImportPath="./site-packages/PySide2/qml")
|
|||
|
|
except Exception:
|
|||
|
|
err = traceback.format_exc()
|
|||
|
|
from py_src.imports.umi_log import logger, Logs_Dir
|
|||
|
|
|
|||
|
|
logger.critical(
|
|||
|
|
"Failed to startup main program!",
|
|||
|
|
exc_info=True,
|
|||
|
|
stack_info=True,
|
|||
|
|
)
|
|||
|
|
msg = f"Failed to startup main program!\n\n{err}\n\nSave the log file to: {Logs_Dir}"
|
|||
|
|
MessageBox(msg)
|
|||
|
|
sys.exit(0)
|