Files
work-secretfile-selfcheck/UmiOCR-data/qt_res/qml/TabPages/ScreenshotOCR/ScreenshotOCR.qml

484 lines
17 KiB
QML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ==============================================
// =============== 功能页截图OCR ===============
// ==============================================
import QtQuick 2.15
import ".."
import "../../Widgets"
import "../../Widgets/ResultLayout"
import "../../Widgets/ImageViewer"
TabPage {
id: tabPage
// 配置
configsComp: ScreenshotOcrConfigs {}
property string msnState: "none" // OCR任务状态 none run
// ========================= 【逻辑】 =========================
// 重复截图
function reScreenshot() {
qmlapp.imageManager.reScreenshot(screenshotEnd)
}
// 开始截图
function screenshot() {
qmlapp.imageManager.screenshot(screenshotEnd)
}
// 截图完毕
function screenshotEnd(clipID) {
popMainWindow()
if(!clipID) { // 截图取消
tabPage.callPy("ocrImgID", undefined, undefined)
return
}
const configDict = configsComp.getValueDict()
tabPage.callPy("ocrImgID", clipID, configDict)
qmlapp.tab.showTabPageObj(tabPage) // 切换标签页
imageText.showImgID(clipID) // 展示图片
}
// 指定区域截图。rect=[x,y,w,h] screen=屏幕编号 返回"[Success]"为成功
function autoScreenshot(rect, screen) {
// 获取截图
const clipID = qmlapp.imageManager.getScreenshot(rect, screen)
if(!clipID) {
tabPage.callPy("ocrImgID", "[Error] Unknow", undefined)
return
}
if(clipID.startsWith("[")) {
tabPage.callPy("ocrImgID", clipID, undefined)
return
}
// 进行识别
const configDict = configsComp.getValueDict()
tabPage.callPy("ocrImgID", clipID, configDict)
}
// 开始粘贴
function paste() {
popMainWindow()
const res = qmlapp.imageManager.getPaste()
if(res.error) {
const t = qsTr("获取剪贴板异常")
qmlapp.popup.simple(t, res.error)
tabPage.callPy("ocrImgID", `[Error] ${t} ${res.error}`, undefined)
return
}
if(res.text) {
const t = qsTr("剪贴板中为文本")
qmlapp.popup.simple(t, res.text)
tabPage.callPy("ocrImgID", `[Warning] ${t}`, undefined)
return
}
qmlapp.tab.showTabPageObj(tabPage) // 切换标签页
if(res.imgID) { // 图片
imageText.showImgID(res.imgID)
const configDict = configsComp.getValueDict()
tabPage.callPy("ocrImgID", res.imgID, configDict)
}
else if(res.paths) { // 地址
ocrPaths(res.paths)
}
}
// 异步扫描一批图像路径
function ocrPaths(paths) {
qmlapp.asynFilesLoader.run(paths,"image",false,onAddImages)
}
// 完毕后对合法路径进行OCR
function onAddImages(paths) {
if(!paths || paths.length < 1) {
qmlapp.popup.simple(qsTr("无有效图片"), "")
return
}
const configDict = configsComp.getValueDict()
const simpleType = configDict["other.simpleNotificationType"]
qmlapp.popup.simple(qsTr("导入%1条图片路径").arg(paths.length), "", simpleType)
imageText.showPath(paths[0])
tabPage.callPy("ocrPaths", paths, configDict)
}
// 停止所有任务
function msnStop() {
tabPage.callPy("msnStop")
}
// 关闭页面
function closePage() {
if(msnState !== "none") {
const argd = {yesText: qsTr("依然关闭")}
const callback = (flag)=>{
if(flag) {
msnStop()
eventUnsub()
delPage()
}
}
qmlapp.popup.dialog("", qsTr("任务正在进行中。\n要结束任务并关闭页面吗"), callback, "warning", argd)
}
else {
eventUnsub()
delPage()
}
}
// 弹出主窗口
function popMainWindow() {
// 若主窗口已经可见,则不处理
if(qmlapp.mainWin.getVisibility())
return
// 等一回合再弹,防止与收回截图窗口相冲突
if(configsComp.getValue("action.popMainWindow")) {
Qt.callLater(()=>{
qmlapp.mainWin.loadGeometry(false)
qmlapp.mainWin.setVisibility(true)
})
}
}
// ========================= 【事件管理】 =========================
Component.onCompleted: {
eventSub() // 订阅事件
}
// 订阅事件
function eventSub() {
qmlapp.pubSub.subscribeGroup("<<reScreenshot>>", this, "reScreenshot", ctrlKey)
qmlapp.pubSub.subscribeGroup("<<screenshot>>", this, "screenshot", ctrlKey)
qmlapp.pubSub.subscribeGroup("<<paste>>", this, "paste", ctrlKey)
qmlapp.systemTray.addMenuItem("<<screenshot>>", qsTr("屏幕截图"), screenshot)
qmlapp.systemTray.addMenuItem("<<paste>>", qsTr("粘贴图片"), paste)
}
// 取消订阅事件
function eventUnsub() {
qmlapp.pubSub.unsubscribeGroup(ctrlKey)
qmlapp.systemTray.delMenuItem("<<screenshot>>")
qmlapp.systemTray.delMenuItem("<<paste>>")
}
// ========================= 【python调用qml】 =========================
// 设置任务状态
function setMsnState(flag) {
msnState = flag
}
// 获取一个OCR的返回值
function onOcrGet(res, imgID="", imgPath="") {
// 添加到结果
const resText = resultsTableView.addOcrResult(res)
if(imgID) // 图片类型
imageText.showImgID(imgID)
else if(imgPath) // 地址类型
imageText.showPath(imgPath)
imageText.showTextBoxes(res)
// 若tabPanel面板的下标没有变化过则切换到记录页
if(tabPanel.indexChangeNum < 2)
tabPanel.currentIndex = 1
// 复制到剪贴板
const copy = configsComp.getValue("action.copy")
if(copy && resText!="")
qmlapp.utilsConnector.copyText(resText)
// 弹出通知
showSimple(res, resText, copy)
// 升起主窗口
popMainWindow()
}
// 一组OCR任务完毕
function onOcrEnd(msg) {
if(msg.startsWith("[Error]")) {
qmlapp.popup.message(qsTr("截图识别任务异常"), msg, "error")
}
}
// ========================= 【后处理】 =========================
// 任务完成后发送通知
function showSimple(res, resText, isCopy) {
// 获取弹窗类型
let simpleType = configsComp.getValue("other.simpleNotificationType")
if(simpleType==="default") {
simpleType = qmlapp.globalConfigs.getValue("window.simpleNotificationType")
}
const code = res.code
const time = res.time.toFixed(2)
let title = ""
resText = resText.replace(/\n/g, " ") // 换行符替换空格
if(code === 100 || code === 101) { // 成功时,不发送内部弹窗
if(simpleType==="inside" || simpleType==="onlyInside")
if(qmlapp.mainWin.getVisibility())
return
}
if(code === 100) {
if(isCopy) title = qsTr("已复制到剪贴板")
else title = qsTr("识图完成")
}
else if(code === 101) {
title = qsTr("无文字")
resText = ""
}
else {
title = qsTr("识别失败")
}
title += ` - ${time}s`
qmlapp.popup.simple(title, resText, simpleType)
}
// ========================= 【布局】 =========================
// 左侧栏。主区域为左右双栏且左栏隐藏时,才显示左侧栏。
Item {
id: leftCtrlPanel
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
// 展示条件
visible: doubleLayout.isRow && doubleLayout.hideAB === 1
anchors.leftMargin: visible ? size_.smallSpacing : 0
width: visible ? size_.line * 1.5 : 0
Column {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.rightMargin: -size_.smallSpacing // 负间距,增加空间利用
spacing: size_.spacing
Item {
anchors.left: parent.left
anchors.right: parent.right
height: width
}
IconButton {
anchors.left: parent.left
anchors.right: parent.right
height: width
icon_: "screenshot"
color: theme.textColor
toolTip: qsTr("屏幕截图")
onClicked: tabPage.screenshot()
}
IconButton {
anchors.left: parent.left
anchors.right: parent.right
height: width
icon_: "paste"
color: theme.textColor
toolTip: qsTr("粘贴图片")
onClicked: tabPage.paste()
}
IconButton {
visible: msnState==="run"
anchors.left: parent.left
anchors.right: parent.right
height: width
icon_: "stop"
color: theme.noColor
toolTip: qsTr("停止任务")
onClicked: tabPage.msnStop()
}
}
}
// 主区域:可切换双栏面板
DoubleSwitchableLayout {
id: doubleLayout
saveKey: "ScreenshotOCR_1"
anchors.left: leftCtrlPanel.right
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.right: parent.right
// 面板A图像展示
itemA: Panel {
anchors.fill: parent
clip: true
// 顶部控制栏
Item {
id: dLeftTop
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: size_.spacing
anchors.bottomMargin: 0
height: size_.line * 1.5
clip: true
// 靠右
Row {
id: dLeftTopR
anchors.top: parent.top
anchors.right: parent.right
anchors.bottom: parent.bottom
spacing: size_.smallSpacing
// 显示文字
CheckButton {
anchors.top: parent.top
anchors.bottom: parent.bottom
text_: qsTr("文字")
toolTip: qsTr("在图片上叠加显示识别文字\n可在全局设置中设为默认关闭")
checked: imageText.showOverlay
enabledAnime: true
onCheckedChanged: imageText.showOverlay = checked
}
IconButtonBar {
anchors.top: parent.top
anchors.bottom: parent.bottom
btnList: [
{
icon: "menu",
onClicked: imageText.popupMenu,
toolTip: tr("右键菜单"),
},
{
icon: "save",
onClicked: imageText.saveImage,
toolTip: tr("保存图片"),
},
{
icon: "full_screen",
onClicked: imageText.imageFullFit,
toolTip: tr("图片大小:适应窗口"),
},
{
icon: "one_to_one",
onClicked: imageText.imageScaleAddSub,
toolTip: tr("图片大小:实际"),
},
]
}
// 百分比显示
Text_ {
anchors.top: parent.top
anchors.bottom: parent.bottom
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignRight
text: (imageText.scale*100).toFixed(0) + "%"
color: theme.subTextColor
width: size_.line * 2.5
}
}
// 靠左
Rectangle { // 背景
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
width: dLeftTopL.width
color: theme.bgColor
Rectangle {
anchors.fill: parent
color: theme.coverColor1
}
}
Row { // 按钮栏
id: dLeftTopL
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
spacing: size_.smallSpacing
IconButtonBar {
anchors.top: parent.top
anchors.bottom: parent.bottom
btnList: [
{
icon: "screenshot",
onClicked: tabPage.screenshot,
color: theme.textColor,
bgColor: theme.bgColor,
text: tr("截图"),
toolTip: tr("屏幕截图"),
},
{
icon: "paste",
onClicked: tabPage.paste,
color: theme.textColor,
bgColor: theme.bgColor,
text: tr("粘贴"),
toolTip: tr("粘贴图片"),
},
]
}
// 停止任务
Button_ {
visible: msnState==="run"
anchors.top: parent.top
anchors.bottom: parent.bottom
text_: qsTr("停止任务")
textColor_: theme.noColor
onClicked: tabPage.msnStop()
}
}
}
// 图片预览区域
ImageWithText {
id: imageText
anchors.top: dLeftTop.bottom
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: size_.spacing
anchors.topMargin: size_.smallSpacing
// 加载中 动态图标
Loading {
visible: msnState==="run"
anchors.centerIn: parent
}
// 提示
DefaultTips {
visibleFlag: msnState
anchors.fill: parent
tips: qsTr("截图、拖入或粘贴图片")
}
}
}
// 面板B结果
itemB: Panel {
anchors.fill: parent
TabPanel {
id: tabPanel
anchors.fill: parent
anchors.margins: size_.spacing
isMenuTop: doubleLayout.isRow // 左右布局时,菜单在顶部;上下布局时菜单在底部
menuHeight: size_.line * 1.5
// 结果面板
ResultsTableView {
id: resultsTableView
anchors.fill: parent
visible: false
}
tabsModel: [
{
"key": "configs",
"title": qsTr("设置"),
"component": configsComp.panelComponent,
},
{
"key": "ocrResult",
"title": qsTr("记录"),
"component": resultsTableView,
},
]
}
}
}
// 鼠标拖入图片
DropArea_ {
anchors.fill: parent
callback: tabPage.ocrPaths
}
}