吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 2003|回复: 44
收起左侧

[原创工具] 基于PaddleOCR的【一键截图+文字识别】工具【支持win7】【2026.1.30更新】

  [复制链接]
881638243 发表于 2026-1-14 15:05
本帖最后由 881638243 于 2026-1-30 14:00 编辑

●这是一个基于PaddleOCR的【一键截图文字识别】工具(已于2026.1.30更新本地离线部署版本)
由于是大模型OCR,因此可以识别:普通文本、手写中英文、数学公式等复杂文本。
--------------------------------------------------------------【API版】-------------------------------------------------------------------------------
调用PaddleOCR-VL官方API接口进行文字识别,需前往PaddleOCR官网(https://aistudio.baidu.com/paddleocr)免费申请API_TOKEN,并在工具”设置“菜单中填入。
已发布适配win7的版本,与正常版本无区别~win7朋友也能用啦,嘿嘿嘿
image.png

image.png image.png image.png
【API版】使用提示:

1.如工具无法打开,可能是运行库缺失问题,我已将必备运行库上传至工具下载地址。

2.需前往PaddleOCR官网(https://aistudio.baidu.com/paddleocr)免费申请API_TOKEN,并在工具”设置“菜单中填入,方可使用本工具。

3.截图过程中按右键或ESC可取消截图,截图区域过小自动取消截图。

4.图片解析后的文字自动存入剪贴板,也可直接在文本框里划选并复制(copy)。

5.点击热键如果没有反应,请尝试以管理员身份运行本工具。

6.工具使用过程中需全程联网,网络情况不佳时,解析时间可能较长,请耐心等待或重新识别。

7.如遇文字解析失败情况,请尝试重新识别。
--------------------------------------------------------------【本地离线版】--------------------------------------------------------------------------
功能与API版无区别,但可在毫秒内出结果。同样支持普通文本、手写中英文、数学公式等复杂文本。
CPU要求要有AVX指令集,故不支持  凌动Atom,安腾Itanium,赛扬Celeron,奔腾Pentium CPU。
推荐运行内存:8GB+
2026.1.30已发布v1.42版本
------------------------------------------------------------【本地离线Lite版】-------------------------------------------------------------------------
超轻量级,适合低配置机器
支持所有CPU
预计2月初发布,敬请期待


【本地版】使用提示:

1.如工具无法打开,可能是运行库缺失问题,我已将必备运行库上传至工具下载地址。


2.需确保压缩包内所有文件完整解压,目录内点击exe文件方可启动使用本工具

3.截图过程中按右键或ESC可取消截图,截图区域过小自动取消截图。

4.图片解析后的文字自动存入剪贴板,也可直接在文本框里划选并复制(copy)。

5.点击热键如果没有反应,请尝试以管理员身份运行本工具。

6.如遇文字解析失败情况,请尝试重新识别。
---------------------------------------------------------------------------------------------------------------------------------------------------------

工具下载地址: 下载地址.txt (292 Bytes, 下载次数: 126)


更新日志:
v1.41:①新增热键功能,热键可在“设置”中绑定,点击热键即可开始截图;②新增公式预览功能,点击按钮可对识别出的LaTex数学公式进行可读化预览;③新增排版优化功能,点击按钮可对识别出的文字段落进行排版优化;④工具更名为抠抠截图文字识别工具
v1.42:①修复识别文字后出现“##”的问题;




本工具将持续更新,欢迎各位大佬反馈问题与BUG。

源代码:
[Python] 纯文本查看 复制代码
import sys, re, io, time, base64, requests, threading, keyboard
from PyQt6.QtWidgets import (QApplication, QMainWindow, QPushButton, QVBoxLayout, 
                             QWidget, QTextEdit, QLabel, QLineEdit, QStackedWidget, QHBoxLayout)
from PyQt6.QtCore import Qt, QRect, pyqtSignal, QObject, QTimer, QSettings
from PyQt6.QtGui import QPainter, QPen, QColor
from PIL import ImageGrab, ImageEnhance, ImageFilter
import pyperclip


class WorkerSignals(QObject):
    finished = pyqtSignal(str, str)

#截图层
class CaptureWindow(QWidget):
    def __init__(self, callback, cancel_callback):
        super().__init__()
        self.callback = callback
        self.cancel_callback = cancel_callback
        self.setWindowFlags(Qt.WindowType.FramelessWindowHint | Qt.WindowType.WindowStaysOnTopHint | Qt.WindowType.Tool)
        self.setWindowState(Qt.WindowState.WindowFullScreen)
        self.setWindowOpacity(0.3)
        self.setCursor(Qt.CursorShape.CrossCursor)
        self.start_pos = self.end_pos = None
        self.is_drawing = False

    def paintEvent(self, event):
        if self.is_drawing and self.start_pos and self.end_pos:
            painter = QPainter(self)
            painter.setPen(QPen(QColor(255, 0, 0), 2, Qt.PenStyle.SolidLine)) 
            painter.drawRect(QRect(self.start_pos, self.end_pos))

    def mousePressEvent(self, event):
        if event.button() == Qt.MouseButton.RightButton:
            self.cancel_callback(); self.close()
        elif event.button() == Qt.MouseButton.LeftButton:
            self.start_pos = event.pos(); self.is_drawing = True

    def mouseMoveEvent(self, event):
        if self.is_drawing: self.end_pos = event.pos(); self.update()

    def mouseReleaseEvent(self, event):
        if event.button() == Qt.MouseButton.LeftButton:
            self.is_drawing = False
            self.hide()
            QApplication.processEvents()
            time.sleep(0.15)
            x1, y1 = min(self.start_pos.x(), event.pos().x()), min(self.start_pos.y(), event.pos().y())
            x2, y2 = max(self.start_pos.x(), event.pos().x()), max(self.start_pos.y(), event.pos().y())
            if x2 - x1 < 10 or y2 - y1 < 10:
                self.cancel_callback(); self.close(); return
            ratio = self.screen().devicePixelRatio()
            bbox = (x1 * ratio, y1 * ratio, x2 * ratio, y2 * ratio)
            img = ImageGrab.grab(bbox)
            self.callback(img); self.close()

#主窗口
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("截图文字识别工具v1.30")
        self.resize(450, 600)
        
        #配置保存
        self.settings = QSettings("MyOCRTool", "Settings")
        
        
        self.stack = QStackedWidget()
        self.setCentralWidget(self.stack)
        
        self.init_main_ui()    
        self.init_setting_ui() 
        self.init_about_ui()
        
        self.signals = WorkerSignals()
        self.signals.finished.connect(self.on_ocr_finished)
        
        #初始热键绑定
        #self.current_hotkey = self.settings.value("hotkey", "alt+q")
        #self.rebind_hotkey(self.current_hotkey)

    def init_main_ui(self):
        page = QWidget()
        layout = QVBoxLayout(page)
        
        header_layout = QHBoxLayout()
        
        self.btn_to_setting = QPushButton("设置")
        self.btn_to_setting.clicked.connect(lambda: self.stack.setCurrentIndex(1))

        self.btn_to_about = QPushButton("关于")
        self.btn_to_about.clicked.connect(lambda: self.stack.setCurrentIndex(2))


       
        header_layout.addWidget(self.btn_to_setting)
        header_layout.addWidget(self.btn_to_about)
        header_layout.addStretch()

        layout.addLayout(header_layout)

        self.btn_capture = QPushButton("开始截图")
        self.btn_capture.setMinimumHeight(60)
        self.btn_capture.setStyleSheet("background-color: #4CAF50; color: white; font-weight: bold;")
        self.btn_capture.clicked.connect(self.start_capture)
        layout.addWidget(self.btn_capture)

        self.label_status = QLabel("工具已就绪")
        layout.addWidget(self.label_status)

        self.result_box = QTextEdit()
        layout.addWidget(self.result_box)
        
        self.stack.addWidget(page)

    def init_setting_ui(self):
        page = QWidget()
        layout = QVBoxLayout(page)

        layout.addWidget(QLabel("<b>API_URL:</b>"))
        self.edit_url = QLineEdit(self.settings.value("url", "在此输入API_URL"))
        layout.addWidget(self.edit_url)

        layout.addWidget(QLabel("<b>API_TOKEN:</b>"))
        self.edit_token = QLineEdit(self.settings.value("token", "在此输入TOKEN"))
        layout.addWidget(self.edit_token)

        # layout.addWidget(QLabel("<b>快捷键 (如 alt+q, ctrl+shift+a):</b>"))
        # self.edit_hotkey = QLineEdit(self.settings.value("hotkey", "alt+q"))
        # layout.addWidget(self.edit_hotkey)

        layout.addStretch()

        btn_save = QPushButton("保存并返回")
        btn_save.setMinimumHeight(40)
        btn_save.setStyleSheet("background-color: #4CAF50; color: white; font-weight: bold;")
        btn_save.clicked.connect(self.save_settings)
        layout.addWidget(btn_save)

        self.stack.addWidget(page)

    def init_about_ui(self):
        page = QWidget()
        layout = QVBoxLayout(page)
        layout.addWidget(QLabel("<h2>截图文字识别工具v1.30</h2>"))
        layout.addWidget(QLabel("<b>本工具免费且已开源,仅供学习交流,严禁倒卖!</b>"))
        layout.addWidget(QLabel("<p>功能说明:截图区域文字识别,鼠标右键或ESC可取消截图</p>"))
        

        layout.addStretch()
        
        btn_back = QPushButton("返回")
        btn_back.setMinimumHeight(40)
        btn_back.setStyleSheet("background-color: #2196F3; color: white; font-weight: bold;")
        btn_back.clicked.connect(lambda: self.stack.setCurrentIndex(0))
        layout.addWidget(btn_back)
        
        self.stack.addWidget(page) 
        

    def save_settings(self):
        #保存到配置
        self.settings.setValue("url", self.edit_url.text())
        self.settings.setValue("token", self.edit_token.text())
        
        #new_hotkey = self.edit_hotkey.text().lower()
        #if new_hotkey != self.current_hotkey:
            #self.rebind_hotkey(new_hotkey)
            #self.current_hotkey = new_hotkey
            #self.settings.setValue("hotkey", new_hotkey)
            
        self.stack.setCurrentIndex(0)
        self.label_status.setText("设置已保存")

    def rebind_hotkey(self, key_str):
        try:
            keyboard.unhook_all() #清除旧的
            keyboard.add_hotkey(key_str, self.start_capture)
        except:
            print("热键绑定失败")

    def start_capture(self):
        if self.isVisible():
            self.hide()
            QTimer.singleShot(250, self.show_capture_window)
        
    def show_capture_window(self):
        self.cap_win = CaptureWindow(self.request_ocr_thread, self.on_capture_cancel)
        self.cap_win.show()

    def on_capture_cancel(self):
        self.show(); self.label_status.setText("截图已取消")

    def request_ocr_thread(self, img_obj):
        self.show()
        self.label_status.setText("图片解析中")
        self.btn_capture.setEnabled(False)
        threading.Thread(target=self.ocr_worker, args=(img_obj,), daemon=True).start()
        
    def ocr_worker(self, img):
        try:
            #图像预处理
            img = img.convert('L')
            img = ImageEnhance.Contrast(img).enhance(2.0)
            img = img.filter(ImageFilter.SHARPEN)
            img = img.convert('RGB')
            #图像压缩
            img_byte_arr = io.BytesIO()
            img.save(img_byte_arr, format='JPEG', quality=95)
            file_data = base64.b64encode(img_byte_arr.getvalue()).decode("ascii")

            # 从界面获取实时配置
            url = self.settings.value("url")
            token = self.settings.value("token")

            headers = {"Authorization": f"token {token}", "Content-Type": "application/json"}
            payload = {"file": file_data, "fileType": 1, "useDocOrientationClassify": False, "useChartRecognition": False}
            
            response = requests.post(url, json=payload, headers=headers, timeout=20)
            
            if response.status_code == 200:
                result = response.json()["result"]
                text = "".join([re.sub(r'<[^>]+>', '', res["markdown"]["text"]) + "\n" for res in result.get("layoutParsingResults", [])])
                self.signals.finished.emit(text.strip() or "解析失败,请尝试重新识别", "识别完成")
            else:
                self.signals.finished.emit("", f"API错误: {response.status_code}")
        except Exception as e:
            self.signals.finished.emit("", f"异常: {str(e)}")

    def on_ocr_finished(self, text, status):
        self.btn_capture.setEnabled(True)
        self.label_status.setText(status)
        if text:
            self.result_box.setText(text)
            pyperclip.copy(text)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec())














                                
                                
                                
                                
                                
                                
                                
                                
                                
                                
                                
                                
                                
                                
                                
                                
image.png

免费评分

参与人数 9吾爱币 +14 热心值 +8 收起 理由
lshyl111 + 1 + 1 用心讨论,共获提升!
confiant + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
浩博网络 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
胡言爱语 + 1 + 1 谢谢@Thanks!
简忘 + 1 + 1 谢谢@Thanks!
gxf000001 + 1 我很赞同!
cnnets + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
zhangwei6929 + 1 + 1 热心回复!
风之暇想 + 7 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

isure211314 发表于 2026-1-22 11:26
真的好用,是那种我要上传备份程序,电脑重装也要装的应用,比复制截图到豆包然后命令它识别文字方便很多。就是识别速度有一点慢,可能是api的问题,期待作者会不会开发什么新功能,反正我想不出怎么继续迭代了
 楼主| 881638243 发表于 2026-1-20 14:03
xinhairen 发表于 2026-1-20 09:38
很好的工具,感谢分享。
我使用的时候,提示错误:
异常: Expecting value: lIine 1 column 1(char 0)

进PaddleOCR官网(https://aistudio.baidu.com/paddleocr)。点击”API调用“按钮,会弹出带有API URL和API TOKEN的代码界面——把引号里的URL和TOKEN复制后填到工具设置界面就行了。
fengtian99 发表于 2026-1-16 10:54
wmsjyd 发表于 2026-1-16 10:55
这个工具不错,自己搞定Access Token就行了
10001 发表于 2026-1-16 10:59
支持下。谢谢
wmsjyd 发表于 2026-1-16 11:12
能常驻任务栏再加一个快捷键,并能对识别文字智能排版段落就更精准了。
zyfwhx 发表于 2026-1-16 15:43
感谢楼主,试了一下,能很好的识别公式。如果增加识别后直接复制的选项。就更好了。目前在寻找哪一款公式识别准确而且方便的app。
 楼主| 881638243 发表于 2026-1-16 17:58
zyfwhx 发表于 2026-1-16 15:43
感谢楼主,试了一下,能很好的识别公式。如果增加识别后直接复制的选项。就更好了。目前在寻找哪一款公式识 ...

抱歉忘了设置提示了,识别完成后是直接存进剪贴板的。后面我改一下
 楼主| 881638243 发表于 2026-1-16 17:59
wmsjyd 发表于 2026-1-16 11:12
能常驻任务栏再加一个快捷键,并能对识别文字智能排版段落就更精准了。

收到,后面我改一下
gxf000001 发表于 2026-1-17 09:16
很好用,用上了
xhmotor 发表于 2026-1-17 09:52
一直在用pot;感觉还行;等下载这个来试试;准确率不知道咋样;感谢分享
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - 52pojie.cn ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2026-1-31 13:32

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表