From 322b41504a43ea7481c650cbb5862a4b55c4667c Mon Sep 17 00:00:00 2001 From: Evezerest <50011306+Evezerest@users.noreply.github.com> Date: Wed, 24 Aug 2022 16:43:29 +0800 Subject: [PATCH 01/12] Delete ScreenShotWidget.py --- ScreenShotWidget.py | 1108 ------------------------------------------- 1 file changed, 1108 deletions(-) delete mode 100644 ScreenShotWidget.py diff --git a/ScreenShotWidget.py b/ScreenShotWidget.py deleted file mode 100644 index 87d46198c0..0000000000 --- a/ScreenShotWidget.py +++ /dev/null @@ -1,1108 +0,0 @@ -# coding=utf-8 -# author: fardeas -# from: https://blog.csdn.net/u010501845/article/details/124931326 -import os -import sys -from datetime import datetime - -from qtpy import QtCore, QtGui -from qtpy.QtWidgets import * -from qtpy.QtCore import * -from qtpy.QtGui import * - - -class TextInputWidget(QTextEdit): - '''在截图区域内的文本输入框''' - - def __init__(self, god=None): - super().__init__(god) - self.god = god - # 设置背景透明 - # self.setStyleSheet("QTextEdit{background-color: transparent;}") - palette = self.palette() - palette.setBrush(QtGui.QPalette.ColorRole.Base, self.god.color_transparent) - self.setPalette(palette) - self.setTextColor(self.god.toolbar.curColor()) - self.setCurrentFont(self.god.toolbar.curFont()) - self._doc = self.document() # QTextDocument - self.textChanged.connect(self.adjustSizeByContent) - self.adjustSizeByContent() # 初始化调整高度为一行 - self.hide() - - def adjustSizeByContent(self, margin=30): - '''限制宽度不超出截图区域,根据文本内容调整高度,不会出现滚动条''' - self._doc.setTextWidth(self.viewport().width()) - margins = self.contentsMargins() - h = int(self._doc.size().height() + margins.top() + margins.bottom()) - self.setFixedHeight(h) - - def beginNewInput(self, pos, endPointF): - '''开始新的文本输入''' - self._maxRect = self.god.screenArea.normalizeRectF(pos, endPointF) - self.waitForInput() - - def waitForInput(self): - self.setGeometry(self._maxRect.toRect()) - # self.setGeometry(self._maxRect.adjusted(0, 0, -1, 0)) # 宽度-1 - self.setFocus() - self.show() - - def loadTextInputBy(self, action): - '''载入修改旧的文本 - action:(type, color, font, rectf, txt)''' - self.setTextColor(action[1]) - self.setCurrentFont(action[2]) - self._maxRect = action[3] - self.append(action[4]) - self.god.isDrawing = True - self.waitForInput() - - -class LineWidthAction(QAction): - - '''画笔粗细选择器''' - - def __init__(self, text, parent, lineWidth): - super().__init__(text, parent) - self._lineWidth = lineWidth - self.refresh(QtCore.Qt.GlobalColor.red) - self.triggered.connect(self.onTriggered) - self.setVisible(False) - - def refresh(self, color): - painter = self.parent().god.screenArea._painter - dotRadius = QPointF(self._lineWidth, self._lineWidth) - centerPoint = self.parent().iconPixmapCenter() - pixmap = self.parent().iconPixmapCopy() - painter.begin(pixmap) - painter.setPen(self.parent().god.pen_transparent) - painter.setBrush(color) - painter.drawEllipse(QRectF(centerPoint - dotRadius, centerPoint + dotRadius)) - painter.end() - self.setIcon(QIcon(pixmap)) - - def onTriggered(self): - self.parent()._curLineWidth = self._lineWidth - - -class FontAction(QAction): - - '''字体选择器''' - - def __init__(self, text, parent): - super().__init__(text, parent) - self.setIcon(QIcon(r"img/sys/font.png")) - self._curFont = self.parent().god.font_textInput - self.triggered.connect(self.onTriggered) - self.setVisible(False) - - def onTriggered(self): - font, ok = QFontDialog.getFont(self._curFont, self.parent(), caption='选择字体') - if ok: - self._curFont = font - self.parent().god.textInputWg.setCurrentFont(font) - - -class ColorAction(QAction): - - '''颜色选择器''' - - def __init__(self, text, parent): - super().__init__(text, parent) - self._curColor = QtCore.Qt.GlobalColor.red - self._pixmap = QPixmap(32, 32) - self.refresh(self._curColor) - self.triggered.connect(self.onTriggered) - - def refresh(self, color): - self._curColor = color - self._pixmap.fill(color) - self.setIcon(QIcon(self._pixmap)) - self.parent()._at_line_small.refresh(color) - self.parent()._at_line_normal.refresh(color) - self.parent()._at_line_big.refresh(color) - - def onTriggered(self): - col = QColorDialog.getColor(self._curColor, self.parent(), title='选择颜色') - if col.isValid(): - self.refresh(col) - self.parent().god.textInputWg.setTextColor(col) - - -class ScreenShotToolBar(QToolBar): - '''截图区域工具条''' - - def __init__(self, god): - super().__init__(god) - self.god = god - self.setToolButtonStyle(QtCore.Qt.ToolButtonStyle.ToolButtonTextUnderIcon) - self.setStyleSheet("QToolBar {border-radius: 5px;padding: 3px;background-color: #eeeeef;}") - self._style_normal = "QToolBar QToolButton{color: black;}" - self._style_selected = "QToolBar QToolButton{color: #ff7300;border: 1px solid #BEDAF2;background-color: #D6E4F1}" # 与鼠标悬停样式一样 - self._iconPixmap = QPixmap(32, 32) - self._iconPixmap.fill(self.god.color_transparent) - self._iconPixmapCenter = QPointF(self._iconPixmap.rect().center()) - self._curLineWidth = 3 - self._at_line_small = LineWidthAction('细', self, self._curLineWidth - 2) - self._at_line_normal = LineWidthAction('中', self, self._curLineWidth) - self._at_line_big = LineWidthAction('粗', self, self._curLineWidth + 2) - self._at_font = FontAction('字体', self) - self._at_color = ColorAction('颜色', self) - # self._at_rectangle = QAction(QIcon(r"img/sys/rectangle.png"), '矩形', self, triggered=self.beforeDrawRectangle) - # self._at_ellipse = QAction(QIcon(r"img/sys/ellipse.png"), '椭圆', self, triggered=self.beforeDrawEllipse) - # self._at_graffiti = QAction(QIcon(r"img/sys/graffiti.png"), '涂鸦', self, triggered=self.beforeDrawGraffiti) - # self._at_textInput = QAction(QIcon(r"img/sys/write.png"), '文字', self, triggered=self.beforeDrawText) - # self.addAction(self._at_line_small) - # self.addAction(self._at_line_normal) - # self.addAction(self._at_line_big) - # self.addAction(self._at_font) - # self.addAction(self._at_color) - # self.addSeparator() - # self.addAction(self._at_rectangle) - # self.addAction(self._at_ellipse) - # self.addAction(self._at_graffiti) - # self.addAction(self._at_textInput) - # self.addAction(QAction(QIcon(r"img/sys/undo.png"), '撤销', self, triggered=self.undo)) - # self.addSeparator() - self.addAction(QAction(QApplication.style().standardIcon(40), - '退出', self, triggered=self.god.rejectSlot)) - self.addAction(QAction(QApplication.style().standardIcon(45), - '接受', self, triggered=self.god.acceptSlot)) - # self.addAction(QAction(QIcon(r"img/chat/download.png"), '保存', self, triggered=lambda: self.beforeSave('local'))) - # self.addAction(QAction(QIcon(r"img/chat/sendImg.png"), '复制', self, triggered=lambda: self.beforeSave('clipboard'))) - # self.actionTriggered.connect(self.onActionTriggered) - - def curLineWidth(self): - return self._curLineWidth - - def curFont(self): - return self._at_font._curFont - - def curColor(self): - return self._at_color._curColor - # return QColor(self._at_color._curColor.toRgb()) # 颜色的副本 - - def iconPixmapCopy(self): - return self._iconPixmap.copy() - - def iconPixmapCenter(self): - return self._iconPixmapCenter - - # def onActionTriggered(self, action): - # '''突出显示已选中的画笔粗细、编辑模式''' - # for at in [self._at_line_small, self._at_line_normal, self._at_line_big]: - # if at._lineWidth == self._curLineWidth: - # self.widgetForAction(at).setStyleSheet(self._style_selected) - # else: - # self.widgetForAction(at).setStyleSheet(self._style_normal) - # if self.god.isDrawRectangle: - # self.widgetForAction(self._at_rectangle).setStyleSheet(self._style_selected) - # else: - # self.widgetForAction(self._at_rectangle).setStyleSheet(self._style_normal) - # if self.god.isDrawEllipse: - # self.widgetForAction(self._at_ellipse).setStyleSheet(self._style_selected) - # else: - # self.widgetForAction(self._at_ellipse).setStyleSheet(self._style_normal) - # if self.god.isDrawGraffiti: - # self.widgetForAction(self._at_graffiti).setStyleSheet(self._style_selected) - # else: - # self.widgetForAction(self._at_graffiti).setStyleSheet(self._style_normal) - # if self.god.isDrawText: - # self.widgetForAction(self._at_textInput).setStyleSheet(self._style_selected) - # else: - # self.widgetForAction(self._at_textInput).setStyleSheet(self._style_normal) - - def setLineWidthActionVisible(self, flag): - self._at_line_small.setVisible(flag) - self._at_line_normal.setVisible(flag) - self._at_line_big.setVisible(flag) - - def beforeDrawRectangle(self): - self.god.clearEditFlags() - self.god.isDrawRectangle = True - self.setLineWidthActionVisible(True) - self._at_font.setVisible(False) - - def beforeDrawEllipse(self): - self.god.clearEditFlags() - self.god.isDrawEllipse = True - self.setLineWidthActionVisible(True) - self._at_font.setVisible(False) - - def beforeDrawGraffiti(self): - self.god.clearEditFlags() - self.god.isDrawGraffiti = True - self.setLineWidthActionVisible(True) - self._at_font.setVisible(False) - - def beforeDrawText(self): - self.god.clearEditFlags() - self.god.isDrawText = True - self.setLineWidthActionVisible(False) - self._at_font.setVisible(True) - - def undo(self): - '''撤销上次编辑行为''' - if self.god.screenArea.undoEditAction(): - self.god.update() - - def beforeSave(self, target): - # 若正在编辑文本未保存,先完成编辑 - if self.god.isDrawing and self.god.isDrawText: - self.god.screenArea.saveTextInputAction() - if target == 'local': - self.god.save2Local() - elif target == 'clipboard': - self.god.save2Clipboard() - - def enterEvent(self, event): - self.god.setCursor(QtCore.Qt.CursorShape.ArrowCursor) # 工具条上显示标准箭头cursor - - def leaveEvent(self, event): - self.god.setCursor(QtCore.Qt.CursorShape.CrossCursor) # 十字无箭头 - - -class ScreenArea(QtCore.QObject): - '''屏幕区域(提供各种算法的核心类),划分为9个子区域: - TopLeft,Top,TopRight - Left,Center,Right - BottomLeft,Bottom,BottomRight - 其中Center根据start、end两个QPointF确定 - ''' - - def __init__(self, god): - super().__init__() - self.god = god - self._pt_start = QPointF() # 划定截图区域时鼠标左键按下的位置(topLeft) - self._pt_end = QPointF() # 划定截图区域时鼠标左键松开的位置(bottomRight) - self._rt_toolbar = QRectF() # 工具条的矩形 - self._actions = [] # 在截图区域上的所有编辑行为(矩形、椭圆、涂鸦、文本输入等) - self._pt_startEdit = QPointF() # 在截图区域上绘制矩形、椭圆时鼠标左键按下的位置(topLeft) - self._pt_endEdit = QPointF() # 在截图区域上绘制矩形、椭圆时鼠标左键松开的位置(bottomRight) - self._pointfs = [] # 涂鸦经过的所有点 - self._painter = QPainter() # 独立于ScreenShotWidget之外的画家类 - self._textOption = QtGui.QTextOption(QtCore.Qt.AlignmentFlag.AlignLeft | QtCore.Qt.AlignmentFlag.AlignTop) - self._textOption.setWrapMode(QtGui.QTextOption.WrapMode.WrapAnywhere) # 文本在矩形内自动换行 - # self._textOption.setWrapMode(QtGui.QTextOption.WrapMode.WrapAtWordBoundaryOrAnywhere) - self.captureScreen() - - def captureScreen(self): - '''抓取整个屏幕的截图''' - # screen = QtGui.QGuiApplication.primaryScreen() - self._screenPixmap = QApplication.primaryScreen().grabWindow(0) - self._pixelRatio = self._screenPixmap.devicePixelRatio() # 设备像素比 - self._rt_screen = self.screenLogicalRectF() - self.remakeNightArea() - - def normalizeRectF(self, topLeftPoint, bottomRightPoint): - '''根据起止点生成宽高非负数的QRectF,通常用于bottomRightPoint比topLeftPoint更左更上的情况 - 入参可以是QPoint或QPointF''' - rectf = QRectF(topLeftPoint, bottomRightPoint) - x = rectf.x() - y = rectf.y() - w = rectf.width() - h = rectf.height() - if w < 0: # bottomRightPoint在topLeftPoint左侧时,topLeftPoint往左移动 - x = x + w - w = -w - if h < 0: # bottomRightPoint在topLeftPoint上侧时,topLeftPoint往上移动 - y = y + h - h = -h - return QRectF(x, y, w, h) - - def physicalRectF(self, rectf): - '''计算划定的截图区域的(缩放倍率1.0的)原始矩形(会变大) - rectf:划定的截图区域的矩形。可为QRect或QRectF''' - return QRectF(rectf.x() * self._pixelRatio, rectf.y() * self._pixelRatio, - rectf.width() * self._pixelRatio, rectf.height() * self._pixelRatio) - - def logicalRectF(self, physicalRectF): - '''根据原始矩形计算缩放后的矩形(会变小) - physicalRectF:缩放倍率1.0的原始矩形。可为QRect或QRectF''' - return QRectF(physicalRectF.x() / self._pixelRatio, physicalRectF.y() / self._pixelRatio, - physicalRectF.width() / self._pixelRatio, physicalRectF.height() / self._pixelRatio) - - def physicalPixmap(self, rectf, editAction=False): - '''根据指定区域获取其原始大小的(缩放倍率1.0的)QPixmap - rectf:指定区域。可为QRect或QRectF - editAction:是否带上编辑结果''' - if editAction: - canvasPixmap = self.screenPhysicalPixmapCopy() - self._painter.begin(canvasPixmap) - self.paintEachEditAction(self._painter, textBorder=False) - self._painter.end() - return canvasPixmap.copy(self.physicalRectF(rectf).toRect()) - else: - return self._screenPixmap.copy(self.physicalRectF(rectf).toRect()) - - def screenPhysicalRectF(self): - return QRectF(self._screenPixmap.rect()) - - def screenLogicalRectF(self): - return QRectF(QPointF(0, 0), self.screenLogicalSizeF()) # 即当前屏幕显示的大小 - - def screenPhysicalSizeF(self): - return QSizeF(self._screenPixmap.size()) - - def screenLogicalSizeF(self): - return QSizeF(self._screenPixmap.width() / self._pixelRatio, self._screenPixmap.height() / self._pixelRatio) - - def screenPhysicalPixmapCopy(self): - return self._screenPixmap.copy() - - def screenLogicalPixmapCopy(self): - return self._screenPixmap.scaled(self.screenLogicalSizeF().toSize()) - - def centerPhysicalRectF(self): - return self.physicalRectF(self._rt_center) - - def centerLogicalRectF(self): - '''根据屏幕上的start、end两个QPointF确定''' - return self._rt_center - - def centerPhysicalPixmap(self, editAction=True): - '''截图区域的QPixmap - editAction:是否带上编辑结果''' - return self.physicalPixmap(self._rt_center + QMarginsF(-1, -1, 1, 1), editAction=editAction) - - def centerTopMid(self): - return self._pt_centerTopMid - - def centerBottomMid(self): - return self._pt_centerBottomMid - - def centerLeftMid(self): - return self._pt_centerLeftMid - - def centerRightMid(self): - return self._pt_centerRightMid - - def setStartPoint(self, pointf, remake=False): - self._pt_start = pointf - if remake: - self.remakeNightArea() - - def setEndPoint(self, pointf, remake=False): - self._pt_end = pointf - if remake: - self.remakeNightArea() - - def setCenterArea(self, start, end): - self._pt_start = start - self._pt_end = end - self.remakeNightArea() - - def remakeNightArea(self): - '''重新划分九宫格区域。根据中央截图区域计算出来的其他8个区域、截图区域四个边框中点坐标等都是logical的''' - self._rt_center = self.normalizeRectF(self._pt_start, self._pt_end) - # 中央区域上下左右边框的中点,用于调整大小 - self._pt_centerTopMid = (self._rt_center.topLeft() + self._rt_center.topRight()) / 2 - self._pt_centerBottomMid = (self._rt_center.bottomLeft() + self._rt_center.bottomRight()) / 2 - self._pt_centerLeftMid = (self._rt_center.topLeft() + self._rt_center.bottomLeft()) / 2 - self._pt_centerRightMid = (self._rt_center.topRight() + self._rt_center.bottomRight()) / 2 - # 以截图区域左上、上中、右上、左中、右中、左下、下中、右下为中心的正方形区域,用于调整大小 - self._square_topLeft = self.squareAreaByCenter(self._rt_center.topLeft()) - self._square_topRight = self.squareAreaByCenter(self._rt_center.topRight()) - self._square_bottomLeft = self.squareAreaByCenter(self._rt_center.bottomLeft()) - self._square_bottomRight = self.squareAreaByCenter(self._rt_center.bottomRight()) - self._square_topMid = self.squareAreaByCenter(self._pt_centerTopMid) - self._square_bottomMid = self.squareAreaByCenter(self._pt_centerBottomMid) - self._square_leftMid = self.squareAreaByCenter(self._pt_centerLeftMid) - self._square_rightMid = self.squareAreaByCenter(self._pt_centerRightMid) - # 除中央截图区域外的8个区域 - self._rt_topLeft = QRectF(self._rt_screen.topLeft(), self._rt_center.topLeft()) - self._rt_top = QRectF(QPointF(self._rt_center.topLeft().x(), 0), self._rt_center.topRight()) - self._rt_topRight = QRectF(QPointF(self._rt_center.topRight().x(), 0), QPointF(self._rt_screen.width(), self._rt_center.topRight().y())) - self._rt_left = QRectF(QPointF(0, self._rt_center.topLeft().y()), self._rt_center.bottomLeft()) - self._rt_right = QRectF(self._rt_center.topRight(), QPointF(self._rt_screen.width(), self._rt_center.bottomRight().y())) - self._rt_bottomLeft = QRectF(QPointF(0, self._rt_center.bottomLeft().y()), QPointF(self._rt_center.bottomLeft().x(), self._rt_screen.height())) - self._rt_bottom = QRectF(self._rt_center.bottomLeft(), QPointF(self._rt_center.bottomRight().x(), self._rt_screen.height())) - self._rt_bottomRight = QRectF(self._rt_center.bottomRight(), self._rt_screen.bottomRight()) - - def squareAreaByCenter(self, pointf): - '''以QPointF为中心的正方形QRectF''' - rectf = QRectF(0, 0, 15, 15) - rectf.moveCenter(pointf) - return rectf - - def aroundAreaIn8Direction(self): - '''中央区域周边的8个方向的区域(无交集)''' - return [self._rt_topLeft, self._rt_top, self._rt_topRight, - self._rt_left, self._rt_right, - self._rt_bottomLeft, self._rt_bottom, self._rt_bottomRight] - - def aroundAreaIn4Direction(self): - '''中央区域周边的4个方向的区域(有交集) - 上区域(左上、上、右上):0, 0, maxX, topRight.y - 下区域(左下、下、右下):0, bottomLeft.y, maxX, maxY-bottomLeft.y - 左区域(左上、左、左下):0, 0, bottomLeft.x, maxY - 右区域(右上、右、右下):topRight.x, 0, maxX - topRight.x, maxY''' - screenSizeF = self.screenLogicalSizeF() - pt_topRight = self._rt_center.topRight() - pt_bottomLeft = self._rt_center.bottomLeft() - return [QRectF(0, 0, screenSizeF.width(), pt_topRight.y()), - QRectF(0, pt_bottomLeft.y(), screenSizeF.width(), screenSizeF.height() - pt_bottomLeft.y()), - QRectF(0, 0, pt_bottomLeft.x(), screenSizeF.height()), - QRectF(pt_topRight.x(), 0, screenSizeF.width() - pt_topRight.x(), screenSizeF.height())] - - def aroundAreaWithoutIntersection(self): - '''中央区域周边的4个方向的区域(无交集) - 上区域(左上、上、右上):0, 0, maxX, topRight.y - 下区域(左下、下、右下):0, bottomLeft.y, maxX, maxY-bottomLeft.y - 左区域(左):0, topRight.y, bottomLeft.x-1, center.height - 右区域(右):topRight.x+1, topRight.y, maxX - topRight.x, center.height''' - screenSizeF = self.screenLogicalSizeF() - pt_topRight = self._rt_center.topRight() - pt_bottomLeft = self._rt_center.bottomLeft() - centerHeight = pt_bottomLeft.y() - pt_topRight.y() - return [QRectF(0, 0, screenSizeF.width(), pt_topRight.y()), - QRectF(0, pt_bottomLeft.y(), screenSizeF.width(), screenSizeF.height() - pt_bottomLeft.y()), - QRectF(0, pt_topRight.y(), pt_bottomLeft.x() - 1, centerHeight), - QRectF(pt_topRight.x() + 1, pt_topRight.y(), screenSizeF.width() - pt_topRight.x(), centerHeight)] - - def setBeginDragPoint(self, pointf): - '''计算开始拖拽位置距离截图区域左上角的向量''' - self._drag_vector = pointf - self._rt_center.topLeft() - - def getNewPosAfterDrag(self, pointf): - '''计算拖拽后截图区域左上角的新位置''' - return pointf - self._drag_vector - - def moveCenterAreaTo(self, pointf): - '''限制拖拽不能超出屏幕范围''' - self._rt_center.moveTo(self.getNewPosAfterDrag(pointf)) - startPointF = self._rt_center.topLeft() - if startPointF.x() < 0: - self._rt_center.moveTo(0, startPointF.y()) - startPointF = self._rt_center.topLeft() - if startPointF.y() < 0: - self._rt_center.moveTo(startPointF.x(), 0) - screenSizeF = self.screenLogicalSizeF() - endPointF = self._rt_center.bottomRight() - if endPointF.x() > screenSizeF.width(): - self._rt_center.moveBottomRight(QPointF(screenSizeF.width(), endPointF.y())) - endPointF = self._rt_center.bottomRight() - if endPointF.y() > screenSizeF.height(): - self._rt_center.moveBottomRight(QPointF(endPointF.x(), screenSizeF.height())) - self.setCenterArea(self._rt_center.topLeft(), self._rt_center.bottomRight()) - - def setBeginAdjustPoint(self, pointf): - '''判断开始调整截图区域大小时鼠标左键在哪个区(不可能是中央区域),用于判断调整大小的意图方向''' - self._mousePos = self.getMousePosBy(pointf) - - def getMousePosBy(self, pointf): - if self._square_topLeft.contains(pointf): - return 'TL' - elif self._square_topMid.contains(pointf): - return 'T' - elif self._square_topRight.contains(pointf): - return 'TR' - elif self._square_leftMid.contains(pointf): - return 'L' - elif self._rt_center.contains(pointf): - return 'CENTER' - elif self._square_rightMid.contains(pointf): - return 'R' - elif self._square_bottomLeft.contains(pointf): - return 'BL' - elif self._square_bottomMid.contains(pointf): - return 'B' - elif self._square_bottomRight.contains(pointf): - return 'BR' - else: - return 'ERROR' - - def adjustCenterAreaBy(self, pointf): - '''根据开始调整截图区域大小时鼠标左键在哪个区(不可能是中央区域),判断调整大小的意图方向,判定新的开始、结束位置''' - startPointF = self._rt_center.topLeft() - endPointF = self._rt_center.bottomRight() - if self._mousePos == 'TL': - startPointF = pointf - elif self._mousePos == 'T': - startPointF = QPointF(startPointF.x(), pointf.y()) - elif self._mousePos == 'TR': - startPointF = QPointF(startPointF.x(), pointf.y()) - endPointF = QPointF(pointf.x(), endPointF.y()) - elif self._mousePos == 'L': - startPointF = QPointF(pointf.x(), startPointF.y()) - elif self._mousePos == 'R': - endPointF = QPointF(pointf.x(), endPointF.y()) - elif self._mousePos == 'BL': - startPointF = QPointF(pointf.x(), startPointF.y()) - endPointF = QPointF(endPointF.x(), pointf.y()) - elif self._mousePos == 'B': - endPointF = QPointF(endPointF.x(), pointf.y()) - elif self._mousePos == 'BR': - endPointF = pointf - else: # 'ERROR' - return - newRectF = self.normalizeRectF(startPointF, endPointF) - self.setCenterArea(newRectF.topLeft(), newRectF.bottomRight()) - - def getMouseShapeBy(self, pointf): - '''根据鼠标位置返回对应的鼠标样式''' - if self._rt_center.contains(pointf): - if self.god.isDrawRectangle or self.god.isDrawEllipse: - return QtCore.Qt.CursorShape.ArrowCursor - elif self.god.isDrawGraffiti: - return QtCore.Qt.CursorShape.PointingHandCursor # 超链接上的手势 - elif self.god.isDrawText: - return QtCore.Qt.CursorShape.IBeamCursor # 工字 - else: - return QtCore.Qt.CursorShape.SizeAllCursor # 十字有箭头 - # return QtCore.Qt.CursorShape.OpenHandCursor # 打开的手,表示可拖拽 - elif self._square_topLeft.contains(pointf) or self._square_bottomRight.contains(pointf): - return QtCore.Qt.CursorShape.SizeFDiagCursor # ↖↘ - elif self._square_topMid.contains(pointf) or self._square_bottomMid.contains(pointf): - return QtCore.Qt.CursorShape.SizeVerCursor # ↑↓ - elif self._square_topRight.contains(pointf) or self._square_bottomLeft.contains(pointf): - return QtCore.Qt.CursorShape.SizeBDiagCursor # ↙↗ - elif self._square_leftMid.contains(pointf) or self._square_rightMid.contains(pointf): - return QtCore.Qt.CursorShape.SizeHorCursor # ←→ - else: - return QtCore.Qt.CursorShape.CrossCursor # 十字无箭头 - - def isMousePosInCenterRectF(self, pointf): - return self._rt_center.contains(pointf) - - def paintMagnifyingGlassPixmap(self, pos, glassSize): - '''绘制放大镜内的图像(含纵横十字线) - pos:鼠标光标位置 - glassSize:放大镜边框大小''' - pixmapRect = QRect(0, 0, 20, 20) # 以鼠标光标为中心的正方形区域,最好是偶数 - pixmapRect.moveCenter(pos) - glassPixmap = self.physicalPixmap(pixmapRect) - glassPixmap.setDevicePixelRatio(1.0) - glassPixmap = glassPixmap.scaled(glassSize, glassSize, QtCore.Qt.AspectRatioMode.KeepAspectRatio) - # 在放大后的QPixmap上画纵横十字线 - self._painter.begin(glassPixmap) - halfWidth = glassPixmap.width() / 2 - halfHeight = glassPixmap.height() / 2 - self._painter.setPen(self.god.pen_SolidLine_lightBlue) - self._painter.drawLine(QPointF(0, halfHeight), QPointF(glassPixmap.width(), halfHeight)) - self._painter.drawLine(QPointF(halfWidth, 0), QPointF(halfWidth, glassPixmap.height())) - self._painter.end() - return glassPixmap - - def paintEachEditAction(self, painter, textBorder=True): - '''绘制所有已保存的编辑行为。编辑行为超出截图区域也无所谓,保存图像时只截取截图区域内 - textBorder:是否绘制文本边框''' - for action in self.getEditActions(): - if action[0] == 'rectangle': # (type, color, lineWidth, startPoint, endPoint) - self.paintRectangle(painter, action[1], action[2], action[3], action[4]) - elif action[0] == 'ellipse': # (type, color, lineWidth, startPoint, endPoint) - self.paintEllipse(painter, action[1], action[2], action[3], action[4]) - elif action[0] == 'graffiti': # (type, color, lineWidth, points) - self.paintGraffiti(painter, action[1], action[2], action[3]) - elif action[0] == 'text': # (type, color, font, rectf, txt) - self.paintTextInput(painter, action[1], action[2], action[3], action[4], textBorder=textBorder) - - def paintRectangle(self, painter, color, lineWidth, startPoint=None, endPoint=None): - if not startPoint: - startPoint = self._pt_startEdit - if not endPoint: - endPoint = self._pt_endEdit - qrectf = self.normalizeRectF(startPoint, endPoint) - if qrectf.isValid(): - pen = QPen(color) - pen.setWidth(lineWidth) - painter.setPen(pen) - painter.setBrush(self.god.color_transparent) - painter.drawRect(qrectf) - - def paintEllipse(self, painter, color, lineWidth, startPoint=None, endPoint=None): - if not startPoint: - startPoint = self._pt_startEdit - if not endPoint: - endPoint = self._pt_endEdit - qrectf = self.normalizeRectF(startPoint, endPoint) - if qrectf.isValid(): - pen = QPen(color) - pen.setWidth(lineWidth) - painter.setPen(pen) - painter.setBrush(self.god.color_transparent) - painter.drawEllipse(qrectf) - - def paintGraffiti(self, painter, color, lineWidth, pointfs=None): - if not pointfs: - pointfs = self.getGraffitiPointFs() - pen = QPen(color) - pen.setWidth(lineWidth) - painter.setPen(pen) - total = len(pointfs) - if total == 0: - return - elif total == 1: - painter.drawPoint(pointfs[0]) - else: - previousPoint = pointfs[0] - for i in range(1, total): - nextPoint = pointfs[i] - painter.drawLine(previousPoint, nextPoint) - previousPoint = nextPoint - - def paintTextInput(self, painter, color, font, rectf, txt, textBorder=True): - painter.setPen(color) - painter.setFont(font) - painter.drawText(rectf, txt, self._textOption) - if textBorder: - painter.setPen(QtCore.Qt.PenStyle.DotLine) # 点线 - painter.setBrush(self.god.color_transparent) - painter.drawRect(rectf) - - def getEditActions(self): - return self._actions.copy() - - def takeTextInputActionAt(self, pointf): - '''根据鼠标位置查找已保存的文本输入结果,找到后取出''' - for i in range(len(self._actions)): - action = self._actions[i] - if action[0] == 'text' and action[3].contains(pointf): - return self._actions.pop(i) - return None - - def undoEditAction(self): - reply = False - if self._actions: - reply = self._actions.pop() - if not self._actions: # 所有编辑行为都被撤销后退出编辑模式 - self.god.exitEditMode() - else: - self.god.exitEditMode() - return reply - - def clearEditActions(self): - self._actions.clear() - - def setBeginEditPoint(self, pointf): - '''在截图区域上绘制矩形、椭圆时鼠标左键按下的位置(topLeft)''' - self._pt_startEdit = pointf - self.god.isDrawing = True - - def setEndEditPoint(self, pointf): - '''在截图区域上绘制矩形、椭圆时鼠标左键松开的位置(bottomRight)''' - self._pt_endEdit = pointf - - def saveRectangleAction(self): - rectf = self.normalizeRectF(self._pt_startEdit, self._pt_endEdit) - self._actions.append(('rectangle', self.god.toolbar.curColor(), self.god.toolbar.curLineWidth(), - rectf.topLeft(), rectf.bottomRight())) - self._pt_startEdit = QPointF() - self._pt_endEdit = QPointF() - self.god.isDrawing = False - - def saveEllipseleAction(self): - rectf = self.normalizeRectF(self._pt_startEdit, self._pt_endEdit) - self._actions.append(('ellipse', self.god.toolbar.curColor(), self.god.toolbar.curLineWidth(), - rectf.topLeft(), rectf.bottomRight())) - self._pt_startEdit = QPointF() - self._pt_endEdit = QPointF() - self.god.isDrawing = False - - def saveGraffitiPointF(self, pointf, first=False): - self._pointfs.append(pointf) - if first: - self.god.isDrawing = True - - def getGraffitiPointFs(self): - return self._pointfs.copy() - - def saveGraffitiAction(self): - if self._pointfs: - self._actions.append(('graffiti', self.god.toolbar.curColor(), self.god.toolbar.curLineWidth(), self._pointfs.copy())) - self._pointfs.clear() - self.god.isDrawing = False - - def setBeginInputTextPoint(self, pointf): - '''在截图区域上输入文字时鼠标左键按下的位置(topLeft)''' - self.god.isDrawing = True - self.god.textInputWg.beginNewInput(pointf, self._pt_end) - - def saveTextInputAction(self): - txt = self.god.textInputWg.toPlainText() - if txt: - rectf = self.god.textInputWg._maxRect # 取最大矩形的topLeft - rectf.setSize(QRectF(self.god.textInputWg.rect()).size()) # 取实际矩形的宽高 - self._actions.append(('text', self.god.toolbar.curColor(), self.god.toolbar.curFont(), - rectf, txt)) - self.god.textInputWg.clear() - self.god.textInputWg.hide() # 不管保存成功与否都取消编辑 - self.god.isDrawing = False - - def saveNightAreaImg(self): - '''将九宫格区域保存为本地图片,仅用于开发测试''' - screenPixmap = self.screenPhysicalPixmapCopy() - self._painter.begin(screenPixmap) - self._painter.setPen(self.pen_SolidLine_lightBlue) - self._painter.setFont(self.god.font_normal) - self._painter.drawRect(self._rt_center) - for area in self.aroundAreaIn8Direction(): - self._painter.drawRect(area) - for pointf in [self._rt_center.topLeft(), self._rt_center.topRight(), - self._rt_center.bottomLeft(), self._rt_center.bottomRight(), - self._pt_centerTopMid, self._pt_centerBottomMid, - self._pt_centerLeftMid, self._pt_centerRightMid]: - self._painter.drawText(pointf + QPointF(5, -5), '(%s, %s)' % (pointf.x(), pointf.y())) - self._painter.end() - screenPixmap.save('1.jpg', quality=100) - self.centerPhysicalPixmap().save('2.jpg', quality=100) - - -class ScreenShotWidget(QWidget): - - fileType_all = '所有文件 (*);;Excel文件 (*.xls *.xlsx);;图片文件 (*.jpg *.jpeg *.gif *.png *.bmp)' - fileType_img = '图片文件 (*.jpg *.jpeg *.gif *.png *.bmp)' - dir_lastAccess = os.getcwd() # 最后访问目录 - - def __init__(self): - super().__init__() - self.setMouseTracking(True) - self.setWindowFlags(QtCore.Qt.WindowType.FramelessWindowHint | QtCore.Qt.WindowType.WindowStaysOnTopHint) - self.initPainterTool() - self.initFunctionalFlag() - self.screenArea = ScreenArea(self) - self.toolbar = ScreenShotToolBar(self) - self.textInputWg = TextInputWidget(self) - - self.captureImage = None - # 设置 screenPixmap 为窗口背景 - # palette = QtGui.QPalette() - # palette.setBrush(QtGui.QPalette.ColorRole.Window, QtGui.QBrush(self.screenArea.screenPhysicalPixmapCopy())) - # self.setPalette(palette) - - def rejectSlot(self): - self.captureImage = None - self.close() - - def acceptSlot(self): - self.captureImage = self.screenArea.centerPhysicalPixmap().toImage() - self.close() - - def start(self): - self.screenArea.captureScreen() - self.setGeometry(self.screenArea.screenPhysicalRectF().toRect()) - self.clearScreenShotArea() - self.showFullScreen() - - def initPainterTool(self): - self.painter = QPainter() - self.color_transparent = QtCore.Qt.GlobalColor.transparent - self.color_black = QColor(0, 0, 0, 64) # 黑色背景 - self.color_lightBlue = QColor(30, 120, 255) # 浅蓝色。深蓝色QtCore.Qt.GlobalColor.blue - self.font_normal = QtGui.QFont('Times New Roman', 11, QtGui.QFont.Weight.Normal) - self.font_textInput = QtGui.QFont('微软雅黑', 16, QtGui.QFont.Weight.Normal) # 工具条文字工具默认字体 - self.pen_transparent = QPen(QtCore.Qt.PenStyle.NoPen) # 没有笔迹,画不出线条 - self.pen_white = QPen(QtCore.Qt.GlobalColor.white) - self.pen_SolidLine_lightBlue = QPen(self.color_lightBlue) # 实线,浅蓝色 - self.pen_SolidLine_lightBlue.setStyle(QtCore.Qt.PenStyle.DashLine) # 实线SolidLine,虚线DashLine,点线DotLine - self.pen_SolidLine_lightBlue.setWidthF(0) # 0表示线宽为1 - self.pen_DashLine_lightBlue = QPen(self.color_lightBlue) # 虚线,浅蓝色 - self.pen_DashLine_lightBlue.setStyle(QtCore.Qt.PenStyle.DashLine) - - def initFunctionalFlag(self): - self.hasScreenShot = False # 是否已通过拖动鼠标左键划定截图区域 - self.isCapturing = False # 正在拖动鼠标左键选定截图区域时 - self.isMoving = False # 在截图区域内拖动时 - self.isAdjusting = False # 在截图区域的边框按住鼠标左键调整大小时 - self.isDrawing = False # 是否已在截图区域内开始绘制 - self.isDrawRectangle = False # 正在截图区域内画矩形 - self.isDrawEllipse = False # 正在截图区域内画椭圆 - self.isDrawGraffiti = False # 正在截图区域内进行涂鸦 - self.isDrawText = False # 正在截图区域内画文字 - self.setCursor(QtCore.Qt.CursorShape.CrossCursor) # 设置鼠标样式 十字 - - def paintEvent(self, event): - centerRectF = self.screenArea.centerLogicalRectF() - screenSizeF = self.screenArea.screenLogicalSizeF() - canvasPixmap = self.screenArea.screenPhysicalPixmapCopy() - # canvasPixmap = QPixmap(screenSizeF.toSize()) - # canvasPixmap.fill(self.color_transparent) - # 在屏幕截图的副本上绘制已选定的截图区域 - self.painter.begin(canvasPixmap) - if self.hasScreenShot: - self.paintCenterArea(centerRectF) # 绘制中央截图区域 - self.paintMaskLayer(screenSizeF, fullScreen=False) # 绘制截图区域的周边区域遮罩层 - else: - self.paintMaskLayer(screenSizeF) - self.paintMagnifyingGlass(screenSizeF) # 在鼠标光标右下角显示放大镜 - self.paintToolbar(centerRectF, screenSizeF) # 在截图区域右下角显示工具条 - self.paintEditActions() # 在截图区域绘制编辑行为结果 - self.painter.end() - # 把画好的绘制结果显示到窗口上 - self.painter.begin(self) - self.painter.drawPixmap(0, 0, canvasPixmap) # 从坐标(0, 0)开始绘制 - self.painter.end() - - def paintCenterArea(self, centerRectF): - '''绘制已选定的截图区域''' - self.painter.setRenderHint(QPainter.RenderHint.Antialiasing, True) # 反走样 - # 1.绘制矩形线框 - self.painter.setPen(self.pen_DashLine_lightBlue) - self.painter.drawRect(centerRectF) - # 2.绘制矩形线框4个端点和4条边框的中间点 - if centerRectF.width() >= 100 and centerRectF.height() >= 100: - points = [ # 点坐标 - centerRectF.topLeft(), centerRectF.topRight(), centerRectF.bottomLeft(), centerRectF.bottomRight(), - self.screenArea.centerLeftMid(), self.screenArea.centerRightMid(), - self.screenArea.centerTopMid(), self.screenArea.centerBottomMid() - ] - blueDotRadius = QPointF(2, 2) # 椭圆蓝点 - self.painter.setBrush(self.color_lightBlue) - for point in points: - self.painter.drawEllipse(QRectF(point - blueDotRadius, point + blueDotRadius)) - # 3.在截图区域左上角显示截图区域宽高 - if centerRectF.topLeft().y() > 20: - labelPos = centerRectF.topLeft() + QPointF(5, -5) - else: # 拖拽截图区域到贴近屏幕上边缘时“宽x高”移动到截图区域左上角的下侧 - labelPos = centerRectF.topLeft() + QPointF(5, 15) - centerPhysicalRect = self.screenArea.centerPhysicalRectF().toRect() - self.painter.setPen(self.pen_white) - self.painter.setFont(self.font_normal) - self.painter.drawText(labelPos, '%s x %s' % (centerPhysicalRect.width(), centerPhysicalRect.height())) - # 4.在屏幕左上角预览截图结果 - # self.painter.drawPixmap(0, 0, self.screenArea.centerPhysicalPixmap()) # 从坐标(0, 0)开始绘制 - - def paintMaskLayer(self, screenSizeF, fullScreen=True): - if fullScreen: # 全屏遮罩层 - maskPixmap = QPixmap(screenSizeF.toSize()) - maskPixmap.fill(self.color_black) - self.painter.drawPixmap(0, 0, maskPixmap) - else: # 绘制截图区域的周边区域遮罩层,以凸显截图区域 - # 方法一:截图区域以外的8个方向区域 - # for area in self.screenArea.aroundAreaIn8Direction(): - # area = area.normalized() - # maskPixmap = QPixmap(area.size().toSize()) # 由于float转int的精度问题,可能会存在黑线条缝隙 - # maskPixmap.fill(self.color_black) - # self.painter.drawPixmap(area.topLeft(), maskPixmap) - # 方法二:截图区域以外的上下左右区域(有交集,交集部分颜色加深,有明显的纵横效果) - # for area in self.screenArea.aroundAreaIn4Direction(): - # maskPixmap = QPixmap(area.size().toSize()) - # maskPixmap.fill(self.color_black) - # self.painter.drawPixmap(area.topLeft(), maskPixmap) - # 方法三:截图区域以外的上下左右区域(无交集) - for area in self.screenArea.aroundAreaWithoutIntersection(): - maskPixmap = QPixmap(area.size().toSize()) - maskPixmap.fill(self.color_black) - self.painter.drawPixmap(area.topLeft(), maskPixmap) - - def paintMagnifyingGlass(self, screenSizeF, glassSize=150, offset=30, labelHeight=30): - '''未划定截图区域模式时、正在划定截取区域时、调整截取区域大小时在鼠标光标右下角显示放大镜 - glassSize:放大镜正方形边长 - offset:放大镜任意一个端点距离鼠标光标位置的最近距离 - labelHeight:pos和rgb两行文字的高度''' - if self.hasScreenShot and (not self.isCapturing) and (not self.isAdjusting): - return - pos = QtGui.QCursor.pos() - glassPixmap = self.screenArea.paintMagnifyingGlassPixmap(pos, glassSize) # 画好纵横十字线后的放大镜内QPixmap - # 限制放大镜显示不超出屏幕外 - glassRect = glassPixmap.rect() - if (pos.x() + glassSize + offset) < screenSizeF.width(): - if (pos.y() + offset + glassSize + labelHeight) < screenSizeF.height(): - glassRect.moveTo(pos + QPoint(offset, offset)) - else: - glassRect.moveBottomLeft(pos + QPoint(offset, -offset)) - else: - if (pos.y() + offset + glassSize + labelHeight) < screenSizeF.height(): - glassRect.moveTopRight(pos + QPoint(-offset, offset)) - else: - glassRect.moveBottomRight(pos + QPoint(-offset, -offset)) - self.painter.drawPixmap(glassRect.topLeft(), glassPixmap) - # 显示pos:(x, y)、rgb:(255,255,255) - qrgb = QtGui.QRgba64.fromArgb32(glassPixmap.toImage().pixel(glassPixmap.rect().center())) - labelRectF = QRectF(glassRect.bottomLeft().x(), glassRect.bottomLeft().y(), glassSize, labelHeight) - self.painter.setPen(self.pen_transparent) - self.painter.setBrush(self.color_black) # 黑底 - self.painter.drawRect(labelRectF) - self.painter.setPen(self.pen_white) - self.painter.setFont(self.font_normal) - self.painter.drawText(labelRectF, - QtCore.Qt.AlignmentFlag.AlignLeft | QtCore.Qt.AlignmentFlag.AlignVCenter, - 'pos:(%s, %s)\nrgb:(%s, %s, %s)' % (pos.x(), pos.y(), qrgb.red8(), qrgb.green8(), qrgb.blue8())) - - def paintToolbar(self, centerRectF, screenSizeF): - '''在截图区域右下角显示工具条''' - if self.hasScreenShot: - if self.isCapturing or self.isAdjusting: - self.toolbar.hide() # 正在划定截取区域时、调整截图区域大小时不显示工具条 - else: - self.toolbar.adjustSize() - toolbarRectF = QRectF(self.toolbar.rect()) - # 工具条位置优先顺序:右下角下侧,右上角上侧,右下角上侧 - if (screenSizeF.height() - centerRectF.bottomRight().y()) > toolbarRectF.height(): - toolbarRectF.moveTopRight(centerRectF.bottomRight() + QPointF(-5, 5)) - elif centerRectF.topRight().y() > toolbarRectF.height(): - toolbarRectF.moveBottomRight(centerRectF.topRight() + QPointF(-5, -5)) - else: - toolbarRectF.moveBottomRight(centerRectF.bottomRight() + QPointF(-5, -5)) - # 限制工具条的x坐标不为负数,不能移出屏幕外 - if toolbarRectF.x() < 0: - pos = toolbarRectF.topLeft() - pos.setX(centerRectF.x() + 5) - toolbarRectF.moveTo(pos) - self.toolbar.move(toolbarRectF.topLeft().toPoint()) - self.toolbar.show() - else: - self.toolbar.hide() - - def paintEditActions(self): - '''在截图区域绘制编辑行为结果。编辑行为超出截图区域也无所谓,保存图像时只截取截图区域内''' - # 1.绘制正在拖拽编辑中的矩形、椭圆、涂鸦 - if self.isDrawRectangle: - self.screenArea.paintRectangle(self.painter, self.toolbar.curColor(), self.toolbar.curLineWidth()) - elif self.isDrawEllipse: - self.screenArea.paintEllipse(self.painter, self.toolbar.curColor(), self.toolbar.curLineWidth()) - elif self.isDrawGraffiti: - self.screenArea.paintGraffiti(self.painter, self.toolbar.curColor(), self.toolbar.curLineWidth()) - # 2.绘制所有已保存的编辑行为 - self.screenArea.paintEachEditAction(self.painter) - - def clearEditFlags(self): - self.isDrawing = False - self.isDrawRectangle = False - self.isDrawEllipse = False - self.isDrawGraffiti = False - self.isDrawText = False - - def exitEditMode(self): - '''退出编辑模式''' - self.clearEditFlags() - # self.toolbar.onActionTriggered(None) # 清空工具条工具按钮选中状态 - self.textInputWg.hide() - - def clearScreenShotArea(self): - '''清空已划定的截取区域''' - self.screenArea.clearEditActions() # 清除已保存的编辑行为 - self.exitEditMode() - self.hasScreenShot = False - self.isCapturing = False - pos = QPointF() - self.screenArea.setCenterArea(pos, pos) - self.update() - self.setCursor(QtCore.Qt.CursorShape.CrossCursor) # 设置鼠标样式 十字 - - def mousePressEvent(self, event): - if event.button() == QtCore.Qt.MouseButton.LeftButton: - pos = event.pos() - if self.hasScreenShot: - if self.isDrawRectangle or self.isDrawEllipse: - self.screenArea.setBeginEditPoint(pos) - elif self.isDrawGraffiti: # 保存涂鸦经过的每一个点 - self.screenArea.saveGraffitiPointF(pos, first=True) - elif self.isDrawText: - if self.isDrawing: - if QRectF(self.textInputWg.rect()).contains(pos): - pass # 在输入框内调整光标位置,忽略 - else: # 鼠标点到输入框之外,完成编辑 - self.screenArea.saveTextInputAction() - else: # 未开始编辑时(暂不支持文本拖拽) - action = self.screenArea.takeTextInputActionAt(pos) - if action: # 鼠标点到输入框之内,修改旧的文本输入 - self.textInputWg.loadTextInputBy(action) - else: # 鼠标点到输入框之外,开始新的文本输入 - self.screenArea.setBeginInputTextPoint(pos) - elif self.screenArea.isMousePosInCenterRectF(pos): - self.isMoving = True # 进入拖拽移动模式 - self.screenArea.setBeginDragPoint(pos) - else: - self.isAdjusting = True # 进入调整大小模式 - self.screenArea.setBeginAdjustPoint(pos) - else: - self.screenArea.setCenterArea(pos, pos) - self.isCapturing = True # 进入划定截图区域模式 - if event.button() == QtCore.Qt.MouseButton.RightButton: - if self.hasScreenShot or self.isCapturing: # 清空已划定的的截图区域 - self.clearScreenShotArea() - else: - self.close() - - def mouseReleaseEvent(self, event): - if event.button() == QtCore.Qt.MouseButton.LeftButton: - if self.isDrawRectangle: - self.screenArea.saveRectangleAction() - elif self.isDrawEllipse: - self.screenArea.saveEllipseleAction() - elif self.isDrawGraffiti: - self.screenArea.saveGraffitiAction() - self.isCapturing = False - self.isMoving = False - self.isAdjusting = False - self.toolbar.show() - - def mouseMoveEvent(self, event): - pos = event.pos() - if self.isDrawing: - if self.isDrawRectangle or self.isDrawEllipse: - self.screenArea.setEndEditPoint(pos) - elif self.isDrawGraffiti: - self.screenArea.saveGraffitiPointF(pos) - elif self.isCapturing: - self.hasScreenShot = True - self.screenArea.setEndPoint(pos, remake=True) - elif self.isMoving: - self.screenArea.moveCenterAreaTo(pos) - elif self.isAdjusting: - self.screenArea.adjustCenterAreaBy(pos) - self.update() - if self.hasScreenShot: - self.setCursor(self.screenArea.getMouseShapeBy(pos)) - else: - self.setCursor(QtCore.Qt.CursorShape.CrossCursor) # 设置鼠标样式 十字 - - def mouseDoubleClickEvent(self, event): - if event.button() == QtCore.Qt.MouseButton.LeftButton: - if self.screenArea.isMousePosInCenterRectF(event.pos()): - self.save2Clipboard() - self.close() - - def keyPressEvent(self, QKeyEvent): - if QKeyEvent.key() == QtCore.Qt.Key.Key_Escape: - self.close() - if QKeyEvent.key() in (QtCore.Qt.Key.Key_Return, QtCore.Qt.Key.Key_Enter): # 大键盘、小键盘回车 - self.save2Clipboard() - self.close() - - def save2Clipboard(self): - '''将截图区域复制到剪贴板''' - if self.hasScreenShot: - mimData = QtCore.QMimeData() - mimData.setImageData(self.screenArea.centerPhysicalPixmap().toImage()) - QApplication.clipboard().setMimeData(mimData) - # self.screenArea.saveNightAreaImg() - self.close() - - def save2Local(self): - fileType = self.fileType_img - filePath, fileFormat = self.sys_selectSaveFilePath(self, fileType=fileType) - if filePath: - self.screenArea.centerPhysicalPixmap().save(filePath, quality=100) - self.close() - - def sys_getCurTime(self, fmt='%Y-%m-%d %H:%M:%S'): - '''获取字符串格式的当前时间''' - # return QtCore.QDateTime.currentDateTime().toString('yyyy-MM-dd hh:mm:ss') - return datetime.now().strftime(fmt) - - def sys_selectSaveFilePath(self, widget, title='选择文件保存路径', saveFileDir=None, - saveFileName='', defaultFileFmt='%Y%m%d%H%M%S', fileType=None): - '''选择文件保存路径 - title:选择窗口标题 - saveFileDir:指定保存目录 - saveFileName:默认保存文件名 - defaultFileFmt:不指定saveFileName时,自动以此格式的时间字符串命名文件 - fileType:可以选择的文件类型 - return:(所选的文件保存路径, 文件的类型) - ''' - options = QFileDialog.Option.ReadOnly - if saveFileName == '': - saveFileName = self.sys_getCurTime(defaultFileFmt) - if not saveFileDir: - saveFileDir = self.dir_lastAccess - saveFilePath = os.path.join(saveFileDir, saveFileName) - if not fileType: - fileType = self.fileType_all - filePath, fileFormat = QFileDialog.getSaveFileName(widget, title, saveFilePath, fileType, options=options) - if filePath: - self.dir_lastAccess = os.path.dirname(filePath) - return (filePath, fileFormat) - - From 3c79159d74b18d7fe21e4373ff3b3516bb7ef619 Mon Sep 17 00:00:00 2001 From: Evezerest <50011306+Evezerest@users.noreply.github.com> Date: Wed, 24 Aug 2022 16:44:14 +0800 Subject: [PATCH 02/12] Update pdf2word.py --- ppstructure/pdf2word/pdf2word.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/ppstructure/pdf2word/pdf2word.py b/ppstructure/pdf2word/pdf2word.py index add8a6f405..b05886f62a 100644 --- a/ppstructure/pdf2word/pdf2word.py +++ b/ppstructure/pdf2word/pdf2word.py @@ -21,7 +21,7 @@ from ppstructure.predict_system import StructureSystem, save_structure_res from ppstructure.utility import parse_args, draw_structure_result from ppocr.utils.network import download_with_progressbar from ppstructure.recovery.recovery_to_doc import sorted_layout_boxes, convert_info_docx -from ScreenShotWidget import ScreenShotWidget +# from ScreenShotWidget import ScreenShotWidget __APPNAME__ = "pdf2word" __VERSION__ = "0.1.1" @@ -181,7 +181,7 @@ class APP_Image2Doc(QWidget): # settings self.imagePaths = [] - self.screenShotWg = ScreenShotWidget() +# self.screenShotWg = ScreenShotWidget() self.screenShot = None self.save_pdf = False self.output_dir = None @@ -358,17 +358,17 @@ class APP_Image2Doc(QWidget): self.pb.setRange(0, len(self.imagePaths)) self.pb.setValue(0) - def screenShotSlot(self): - ''' - 选定图像文件和截图的转换过程只能同时进行一个 - 截图只能同时转换一个 - ''' - self.screenShotWg.start() - if self.screenShotWg.captureImage: - self.screenShot = self.screenShotWg.captureImage - self.imagePaths.clear() # discard openfile temp list - self.pb.setRange(0, 1) - self.pb.setValue(0) +# def screenShotSlot(self): +# ''' +# 选定图像文件和截图的转换过程只能同时进行一个 +# 截图只能同时转换一个 +# ''' +# self.screenShotWg.start() +# if self.screenShotWg.captureImage: +# self.screenShot = self.screenShotWg.captureImage +# self.imagePaths.clear() # discard openfile temp list +# self.pb.setRange(0, 1) +# self.pb.setValue(0) def handleStartSignal(self, lang): if self.screenShot: # for screenShot @@ -438,4 +438,4 @@ def main(): if __name__ == "__main__": - main() \ No newline at end of file + main() From d106954a02e358d77bff557dff582f2423440797 Mon Sep 17 00:00:00 2001 From: Evezerest <50011306+Evezerest@users.noreply.github.com> Date: Wed, 24 Aug 2022 16:46:25 +0800 Subject: [PATCH 03/12] Update pdf2word.md --- ppstructure/pdf2word/pdf2word.md | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/ppstructure/pdf2word/pdf2word.md b/ppstructure/pdf2word/pdf2word.md index 8d69d60748..564df4063e 100644 --- a/ppstructure/pdf2word/pdf2word.md +++ b/ppstructure/pdf2word/pdf2word.md @@ -1,11 +1,6 @@ # PDF2WORD -PDF2WORD是PaddleOCR社区开发者@whj 基于PP-Structure智能文档分析模型实现的PDF转换Word应用程序,提供可直接安装的exe,方便windows用户运行 - -
- -
- +PDF2WORD是PaddleOCR社区开发者[whjdark](https://github.com/whjdark) 基于PP-Structure智能文档分析模型实现的PDF转换Word应用程序,提供可直接安装的exe,方便windows用户运行 ## 1.使用 @@ -23,17 +18,7 @@ PDF2WORD是PaddleOCR社区开发者@whj 基于PP-Structure智能文档分析模 python pdf2word.py ``` -## 2.自行打包 - -PDF2WORD应用程序通过[QPT](https://github.com/QPT-Family/QPT)工具打包实现,若您修改了界面代码需要重新打包,请在 `PaddleOCR` 文件夹下运行下方指令 - -``` -cd ./ -mv ./ppstructure/pdf2word .. -r -python GenEXE.py -``` - -## 3.软件下载 +## 2.软件下载 如需获取已打包程序,可以扫描下方二维码,关注公众号填写问卷后,加入PaddleOCR官方交流群免费获取20G OCR学习大礼包,内含OCR场景应用集合(包含数码管、液晶屏、车牌、高精度SVTR模型等7个垂类模型)、《动手学OCR》电子书、课程回放视频、前沿论文等重磅资料 From 6154a1280d98e1afe9a55ad3b4ce01bf29e2a7fe Mon Sep 17 00:00:00 2001 From: littletomatodonkey Date: Wed, 24 Aug 2022 08:55:53 +0000 Subject: [PATCH 04/12] fixc --- ppstructure/kie/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/ppstructure/kie/README.md b/ppstructure/kie/README.md index adb19a3ca7..aadeeafdb8 100644 --- a/ppstructure/kie/README.md +++ b/ppstructure/kie/README.md @@ -244,8 +244,6 @@ For training, evaluation and inference tutorial for text detection models, pleas For training, evaluation and inference tutorial for text recognition models, please refer to [text recognition doc](../../doc/doc_en/recognition.md). -If you want to finish the KIE tasks in your scene, and don't know what to prepare, please refer to [End cdoc](../../doc/doc_en/recognition.md). - To complete the key information extraction task in your own scenario from data preparation to model selection, please refer to: [Guide to End-to-end KIE](./how_to_do_kie_en.md)。 From 368d6d64d46bbd8a35d0f07eac1136fa5ad26e1f Mon Sep 17 00:00:00 2001 From: littletomatodonkey Date: Wed, 24 Aug 2022 08:57:02 +0000 Subject: [PATCH 05/12] fix --- ppstructure/kie/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ppstructure/kie/README.md b/ppstructure/kie/README.md index aadeeafdb8..d9471fb18d 100644 --- a/ppstructure/kie/README.md +++ b/ppstructure/kie/README.md @@ -242,7 +242,7 @@ For training, evaluation and inference tutorial for KIE models, please refer to For training, evaluation and inference tutorial for text detection models, please refer to [text detection doc](../../doc/doc_en/detection_en.md). -For training, evaluation and inference tutorial for text recognition models, please refer to [text recognition doc](../../doc/doc_en/recognition.md). +For training, evaluation and inference tutorial for text recognition models, please refer to [text recognition doc](../../doc/doc_en/recognition_en.md). To complete the key information extraction task in your own scenario from data preparation to model selection, please refer to: [Guide to End-to-end KIE](./how_to_do_kie_en.md)。 From 872bdfc1613f08973a53728b386c2c3161b15000 Mon Sep 17 00:00:00 2001 From: WenmuZhou <572459439@qq.com> Date: Wed, 24 Aug 2022 09:21:46 +0000 Subject: [PATCH 06/12] rm opencv version limit --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index cf80775f73..2ccd486f34 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,7 +7,7 @@ tqdm numpy visualdl rapidfuzz -opencv-contrib-python==4.4.0.46 +opencv-contrib-python cython lxml premailer From fc7c2dc455a5febbbd079dd719909f0cbfa4e7f9 Mon Sep 17 00:00:00 2001 From: littletomatodonkey Date: Wed, 24 Aug 2022 17:44:52 +0800 Subject: [PATCH 07/12] fix link --- doc/doc_ch/algorithm_overview.md | 8 ++++---- doc/doc_en/algorithm_overview_en.md | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/doc_ch/algorithm_overview.md b/doc/doc_ch/algorithm_overview.md index 858dc02b9d..1a554d7f16 100755 --- a/doc/doc_ch/algorithm_overview.md +++ b/doc/doc_ch/algorithm_overview.md @@ -129,10 +129,10 @@ PaddleOCR将**持续新增**支持OCR领域前沿算法与模型,**欢迎广 已支持的关键信息抽取算法列表(戳链接获取使用教程): -- [x] [VI-LayoutXLM](./algorithm_kie_vi_laoutxlm.md) -- [x] [LayoutLM](./algorithm_kie_laoutxlm.md) -- [x] [LayoutLMv2](./algorithm_kie_laoutxlm.md) -- [x] [LayoutXLM](./algorithm_kie_laoutxlm.md) +- [x] [VI-LayoutXLM](./algorithm_kie_vi_layoutxlm.md) +- [x] [LayoutLM](./algorithm_kie_layoutxlm.md) +- [x] [LayoutLMv2](./algorithm_kie_layoutxlm.md) +- [x] [LayoutXLM](./algorithm_kie_layoutxlm.md) - [x] [SDMGR](././algorithm_kie_sdmgr.md) 在wildreceipt发票公开数据集上,算法复现效果如下: diff --git a/doc/doc_en/algorithm_overview_en.md b/doc/doc_en/algorithm_overview_en.md index 5bf569e3e1..f086b4f4b8 100755 --- a/doc/doc_en/algorithm_overview_en.md +++ b/doc/doc_en/algorithm_overview_en.md @@ -127,10 +127,10 @@ On the PubTabNet dataset, the algorithm result is as follows: Supported KIE algorithms (Click the link to get the tutorial): -- [x] [VI-LayoutXLM](./algorithm_kie_vi_laoutxlm_en.md) -- [x] [LayoutLM](./algorithm_kie_laoutxlm_en.md) -- [x] [LayoutLMv2](./algorithm_kie_laoutxlm_en.md) -- [x] [LayoutXLM](./algorithm_kie_laoutxlm_en.md) +- [x] [VI-LayoutXLM](./algorithm_kie_vi_layoutxlm_en.md) +- [x] [LayoutLM](./algorithm_kie_layoutxlm_en.md) +- [x] [LayoutLMv2](./algorithm_kie_layoutxlm_en.md) +- [x] [LayoutXLM](./algorithm_kie_layoutxlm_en.md) - [x] [SDMGR](./algorithm_kie_sdmgr_en.md) On wildreceipt dataset, the algorithm result is as follows: From 6500ff1f21bc17794baf45cb70b2f19fd8623e9f Mon Sep 17 00:00:00 2001 From: zhoujun Date: Wed, 24 Aug 2022 18:38:48 +0800 Subject: [PATCH 08/12] rm opencv version limit (#7327) --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index cf80775f73..2ccd486f34 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,7 +7,7 @@ tqdm numpy visualdl rapidfuzz -opencv-contrib-python==4.4.0.46 +opencv-contrib-python cython lxml premailer From 37479c01cdf12533e6c058c3838622925fe635f1 Mon Sep 17 00:00:00 2001 From: wangjingyeye <62890723+wangjingyeye@users.noreply.github.com> Date: Wed, 24 Aug 2022 21:06:59 +0800 Subject: [PATCH 09/12] add db++ doc (#7334) * db++ doc * db++ doc * db++ doc * db++ doc --- doc/doc_ch/algorithm_overview.md | 3 ++- doc/doc_en/algorithm_det_db_en.md | 22 ++++++++++++++++++++-- doc/doc_en/algorithm_overview_en.md | 3 ++- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/doc/doc_ch/algorithm_overview.md b/doc/doc_ch/algorithm_overview.md index 1a554d7f16..ecb0e9dfef 100755 --- a/doc/doc_ch/algorithm_overview.md +++ b/doc/doc_ch/algorithm_overview.md @@ -24,7 +24,7 @@ PaddleOCR将**持续新增**支持OCR领域前沿算法与模型,**欢迎广 ### 1.1 文本检测算法 已支持的文本检测算法列表(戳链接获取使用教程): -- [x] [DB](./algorithm_det_db.md) +- [x] [DB与DB++](./algorithm_det_db.md) - [x] [EAST](./algorithm_det_east.md) - [x] [SAST](./algorithm_det_sast.md) - [x] [PSENet](./algorithm_det_psenet.md) @@ -41,6 +41,7 @@ PaddleOCR将**持续新增**支持OCR领域前沿算法与模型,**欢迎广 |SAST|ResNet50_vd|91.39%|83.77%|87.42%|[训练模型](https://paddleocr.bj.bcebos.com/dygraph_v2.0/en/det_r50_vd_sast_icdar15_v2.0_train.tar)| |PSE|ResNet50_vd|85.81%|79.53%|82.55%|[训练模型](https://paddleocr.bj.bcebos.com/dygraph_v2.1/en_det/det_r50_vd_pse_v2.0_train.tar)| |PSE|MobileNetV3|82.20%|70.48%|75.89%|[训练模型](https://paddleocr.bj.bcebos.com/dygraph_v2.1/en_det/det_mv3_pse_v2.0_train.tar)| +|DB++|ResNet50|90.89%|82.66%|86.58%|[合成数据预训练模型](https://paddleocr.bj.bcebos.com/dygraph_v2.1/en_det/ResNet50_dcn_asf_synthtext_pretrained.pdparams)/[训练模型](https://paddleocr.bj.bcebos.com/dygraph_v2.1/en_det/det_r50_db%2B%2B_icdar15_train.tar)| 在Total-text文本检测公开数据集上,算法效果如下: diff --git a/doc/doc_en/algorithm_det_db_en.md b/doc/doc_en/algorithm_det_db_en.md index f5f333a039..fde344c357 100644 --- a/doc/doc_en/algorithm_det_db_en.md +++ b/doc/doc_en/algorithm_det_db_en.md @@ -1,4 +1,4 @@ -# DB +# DB && DB++ - [1. Introduction](#1) - [2. Environment](#2) @@ -21,13 +21,23 @@ Paper: > Liao, Minghui and Wan, Zhaoyi and Yao, Cong and Chen, Kai and Bai, Xiang > AAAI, 2020 +> [Real-Time Scene Text Detection with Differentiable Binarization and Adaptive Scale Fusion](https://arxiv.org/abs/2202.10304) +> Liao, Minghui and Zou, Zhisheng and Wan, Zhaoyi and Yao, Cong and Bai, Xiang +> TPAMI, 2022 + On the ICDAR2015 dataset, the text detection result is as follows: |Model|Backbone|Configuration|Precision|Recall|Hmean|Download| | --- | --- | --- | --- | --- | --- | --- | |DB|ResNet50_vd|[configs/det/det_r50_vd_db.yml](../../configs/det/det_r50_vd_db.yml)|86.41%|78.72%|82.38%|[trained model](https://paddleocr.bj.bcebos.com/dygraph_v2.0/en/det_r50_vd_db_v2.0_train.tar)| |DB|MobileNetV3|[configs/det/det_mv3_db.yml](../../configs/det/det_mv3_db.yml)|77.29%|73.08%|75.12%|[trained model](https://paddleocr.bj.bcebos.com/dygraph_v2.0/en/det_mv3_db_v2.0_train.tar)| +|DB++|ResNet50|[configs/det/det_r50_db++_ic15.yml](../../configs/det/det_r50_db++_ic15.yml)|90.89%|82.66%|86.58%|[pretrained model](https://paddleocr.bj.bcebos.com/dygraph_v2.1/en_det/ResNet50_dcn_asf_synthtext_pretrained.pdparams)/[trained model](https://paddleocr.bj.bcebos.com/dygraph_v2.1/en_det/det_r50_db%2B%2B_icdar15_train.tar)| +On the TD_TR dataset, the text detection result is as follows: + +|Model|Backbone|Configuration|Precision|Recall|Hmean|Download| +| --- | --- | --- | --- | --- | --- | --- | +|DB++|ResNet50|[configs/det/det_r50_db++_td_tr.yml](../../configs/det/det_r50_db++_td_tr.yml)|92.92%|86.48%|89.58%|[pretrained model](https://paddleocr.bj.bcebos.com/dygraph_v2.1/en_det/ResNet50_dcn_asf_synthtext_pretrained.pdparams)/[trained model](https://paddleocr.bj.bcebos.com/dygraph_v2.1/en_det/det_r50_db%2B%2B_td_tr_train.tar)| ## 2. Environment @@ -96,4 +106,12 @@ More deployment schemes supported for DB: pages={11474--11481}, year={2020} } -``` \ No newline at end of file + +@article{liao2022real, + title={Real-Time Scene Text Detection with Differentiable Binarization and Adaptive Scale Fusion}, + author={Liao, Minghui and Zou, Zhisheng and Wan, Zhaoyi and Yao, Cong and Bai, Xiang}, + journal={IEEE Transactions on Pattern Analysis and Machine Intelligence}, + year={2022}, + publisher={IEEE} +} +``` diff --git a/doc/doc_en/algorithm_overview_en.md b/doc/doc_en/algorithm_overview_en.md index f086b4f4b8..bca22f7848 100755 --- a/doc/doc_en/algorithm_overview_en.md +++ b/doc/doc_en/algorithm_overview_en.md @@ -22,7 +22,7 @@ Developers are welcome to contribute more algorithms! Please refer to [add new a ### 1.1 Text Detection Algorithms Supported text detection algorithms (Click the link to get the tutorial): -- [x] [DB](./algorithm_det_db_en.md) +- [x] [DB && DB++](./algorithm_det_db_en.md) - [x] [EAST](./algorithm_det_east_en.md) - [x] [SAST](./algorithm_det_sast_en.md) - [x] [PSENet](./algorithm_det_psenet_en.md) @@ -39,6 +39,7 @@ On the ICDAR2015 dataset, the text detection result is as follows: |SAST|ResNet50_vd|91.39%|83.77%|87.42%|[trained model](https://paddleocr.bj.bcebos.com/dygraph_v2.0/en/det_r50_vd_sast_icdar15_v2.0_train.tar)| |PSE|ResNet50_vd|85.81%|79.53%|82.55%|[trianed model](https://paddleocr.bj.bcebos.com/dygraph_v2.1/en_det/det_r50_vd_pse_v2.0_train.tar)| |PSE|MobileNetV3|82.20%|70.48%|75.89%|[trianed model](https://paddleocr.bj.bcebos.com/dygraph_v2.1/en_det/det_mv3_pse_v2.0_train.tar)| +|DB++|ResNet50|90.89%|82.66%|86.58%|[pretrained model](https://paddleocr.bj.bcebos.com/dygraph_v2.1/en_det/ResNet50_dcn_asf_synthtext_pretrained.pdparams)/[trained model](https://paddleocr.bj.bcebos.com/dygraph_v2.1/en_det/det_r50_db%2B%2B_icdar15_train.tar)| On Total-Text dataset, the text detection result is as follows: From 6cded42b104c808108e94e7907fb01a06d9cdee4 Mon Sep 17 00:00:00 2001 From: Topdu <784990967@qq.com> Date: Thu, 25 Aug 2022 04:33:42 +0000 Subject: [PATCH 10/12] fix arabic postprocess bug --- ppocr/postprocess/rec_postprocess.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/ppocr/postprocess/rec_postprocess.py b/ppocr/postprocess/rec_postprocess.py index 1ebafc15f9..385cf09a9e 100644 --- a/ppocr/postprocess/rec_postprocess.py +++ b/ppocr/postprocess/rec_postprocess.py @@ -38,6 +38,10 @@ class BaseRecLabelDecode(object): if use_space_char: self.character_str.append(" ") dict_character = list(self.character_str) + if 'arabic' in character_dict_path: + self.reverse = True + else: + self.reverse = False dict_character = self.add_special_char(dict_character) self.dict = {} @@ -45,11 +49,6 @@ class BaseRecLabelDecode(object): self.dict[char] = i self.character = dict_character - if 'arabic' in character_dict_path: - self.reverse = True - else: - self.reverse = False - def pred_reverse(self, pred): pred_re = [] c_current = '' From 4f7b28e89f963423bc5359dd3c73a4efa1bff5c5 Mon Sep 17 00:00:00 2001 From: topduke <784990967@qq.com> Date: Thu, 25 Aug 2022 12:52:45 +0800 Subject: [PATCH 11/12] Update rec_postprocess.py --- ppocr/postprocess/rec_postprocess.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ppocr/postprocess/rec_postprocess.py b/ppocr/postprocess/rec_postprocess.py index 385cf09a9e..69d3f7de9c 100644 --- a/ppocr/postprocess/rec_postprocess.py +++ b/ppocr/postprocess/rec_postprocess.py @@ -24,7 +24,7 @@ class BaseRecLabelDecode(object): def __init__(self, character_dict_path=None, use_space_char=False): self.beg_str = "sos" self.end_str = "eos" - + self.reverse = False self.character_str = [] if character_dict_path is None: self.character_str = "0123456789abcdefghijklmnopqrstuvwxyz" @@ -40,8 +40,6 @@ class BaseRecLabelDecode(object): dict_character = list(self.character_str) if 'arabic' in character_dict_path: self.reverse = True - else: - self.reverse = False dict_character = self.add_special_char(dict_character) self.dict = {} From a8ac0a130999dfab96c1eff67dfbcdcbe03d4459 Mon Sep 17 00:00:00 2001 From: WenmuZhou <572459439@qq.com> Date: Thu, 25 Aug 2022 05:49:27 +0000 Subject: [PATCH 12/12] add quick start link in table doc --- ppstructure/table/README.md | 4 +++- ppstructure/table/README_ch.md | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ppstructure/table/README.md b/ppstructure/table/README.md index c606d64197..08635516ba 100644 --- a/ppstructure/table/README.md +++ b/ppstructure/table/README.md @@ -51,7 +51,9 @@ The performance indicators are explained as follows: ### 4.1 Quick start -PP-Structure currently provides table recognition models in both Chinese and English. For the model link, see [models_list](../docs/models_list.md). The following takes the Chinese table recognition model as an example to introduce how to recognize a table. +PP-Structure currently provides table recognition models in both Chinese and English. For the model link, see [models_list](../docs/models_list.md). The whl package is also provided for quick use, see [quickstart](../docs/quickstart_en.md) for details. + +The following takes the Chinese table recognition model as an example to introduce how to recognize a table. Use the following commands to quickly complete the identification of a table. diff --git a/ppstructure/table/README_ch.md b/ppstructure/table/README_ch.md index 8aa0dc8653..1ef126261d 100644 --- a/ppstructure/table/README_ch.md +++ b/ppstructure/table/README_ch.md @@ -57,7 +57,9 @@ ### 4.1 快速开始 -PP-Structure目前提供了中英文两种语言的表格识别模型,模型链接见 [models_list](../docs/models_list.md)。下面以中文表格识别模型为例,介绍如何识别一张表格。 +PP-Structure目前提供了中英文两种语言的表格识别模型,模型链接见 [models_list](../docs/models_list.md)。也提供了whl包的形式方便快速使用,详见 [quickstart](../docs/quickstart.md)。 + +下面以中文表格识别模型为例,介绍如何识别一张表格。 使用如下命令即可快速完成一张表格的识别。 ```python