docs: 添加涉密文件自检工具实施计划
This commit is contained in:
32
UmiOCR-data/qt_res/qml/ImageManager/ImageManager.qml
Normal file
32
UmiOCR-data/qt_res/qml/ImageManager/ImageManager.qml
Normal file
@@ -0,0 +1,32 @@
|
||||
// =========================================
|
||||
// =============== 图片管理器 ===============
|
||||
// =========================================
|
||||
|
||||
import QtQuick 2.15
|
||||
import ImageConnector 1.0 // 图片连接器
|
||||
|
||||
Item {
|
||||
// ========================= 【接口】 =========================
|
||||
|
||||
// 截图,向回调函数传入裁切后的 clipImgID
|
||||
readonly property var screenshot: screenshotManager.screenshot
|
||||
// 重复截图
|
||||
readonly property var reScreenshot: screenshotManager.reScreenshot
|
||||
// 获取指定区域的截图ID
|
||||
readonly property var getScreenshot: screenshotManager.getScreenshot
|
||||
// 复制图片
|
||||
readonly property var copyImage: imageConnector.copyImage
|
||||
// 用系统默认应用打开图片
|
||||
readonly property var openImage: imageConnector.openImage
|
||||
// 保存图片
|
||||
readonly property var saveImage: imageConnector.saveImage
|
||||
// 获取剪贴板
|
||||
readonly property var getPaste: imageConnector.getPaste
|
||||
|
||||
// ===========================================================
|
||||
|
||||
// 图片连接器
|
||||
property QtObject imageConnector: ImageConnector {}
|
||||
// 截图管理器
|
||||
property QtObject screenshotManager: ScreenshotManager {}
|
||||
}
|
||||
213
UmiOCR-data/qt_res/qml/ImageManager/ScreenshotManager.qml
Normal file
213
UmiOCR-data/qt_res/qml/ImageManager/ScreenshotManager.qml
Normal file
@@ -0,0 +1,213 @@
|
||||
// =========================================
|
||||
// =============== 截图管理器 ===============
|
||||
// =========================================
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Window 2.15
|
||||
|
||||
Item {
|
||||
id: ssWinRoot
|
||||
|
||||
// ==================== 【接口】 ====================
|
||||
|
||||
// 开始一次截图。传入回调函数。
|
||||
function screenshot(callback) {
|
||||
// 重复调用验证
|
||||
if(running) {
|
||||
qmlapp.popup.simple(errorTitle, errorRepeat)
|
||||
return
|
||||
}
|
||||
running = true
|
||||
// 获取所有屏幕的截图图像
|
||||
const grabList = getGrabList()
|
||||
// 遍历截图列表,收集覆盖窗口属性 argds
|
||||
let argds = []
|
||||
for(let i in grabList) {
|
||||
const g = grabList[i] // 截图属性
|
||||
// 合法性检查
|
||||
if(g.imgID.startsWith("[")) {
|
||||
qmlapp.popup.message(errorTitle,
|
||||
qsTr("显示器: %1\n错误信息: %2").arg(g.screenName).arg(g.imgID), "error")
|
||||
callback()
|
||||
running = false
|
||||
return
|
||||
}
|
||||
const screen = Qt.application.screens[i] // 获取对应编号的屏幕
|
||||
if(screen.name !== g.screenName) {
|
||||
qmlapp.popup.message(errorTitle,
|
||||
qsTr("屏幕设备名称不相同:\n%1\n%2").arg(screen.name).arg(g.screenName), "error")
|
||||
callback()
|
||||
running = false
|
||||
return
|
||||
}
|
||||
const argd = {
|
||||
imgID: g.imgID,
|
||||
screenName: screen.name,
|
||||
screen: screen, // 为Window设定所属屏幕属性
|
||||
screenRatio: screen.devicePixelRatio, // 屏幕缩放比
|
||||
x: screen.virtualX,
|
||||
y: screen.virtualY,
|
||||
width: screen.width,
|
||||
height: screen.height,
|
||||
screenshotEnd: ssWinRoot.ssEnd // 关闭函数
|
||||
}
|
||||
argds.push(argd)
|
||||
}
|
||||
// 记录回调
|
||||
lastCallback = callback
|
||||
if(winDict === undefined) winDict = {}
|
||||
// 生成覆盖窗口
|
||||
for(let a in argds) {
|
||||
const obj = ssWinComp.createObject(this, argds[a])
|
||||
winDict[argds[a].imgID] = obj
|
||||
}
|
||||
// 注册esc事件监听
|
||||
qmlapp.pubSub.subscribeGroup("<<esc>>", ssWinRoot, "ssEsc", "ssEsc")
|
||||
}
|
||||
|
||||
// 重复上一次截图区域
|
||||
function reScreenshot(callback) {
|
||||
// 重复调用验证
|
||||
if(running) {
|
||||
qmlapp.popup.simple(errorTitle, errorRepeat)
|
||||
return
|
||||
}
|
||||
running = true
|
||||
if(!lastClipArgd) {
|
||||
qmlapp.popup.simple(qsTr("尚未记录截图区域"), "")
|
||||
callback()
|
||||
running = false
|
||||
return
|
||||
}
|
||||
// 获取所有屏幕的截图图像
|
||||
const grabList = getGrabList()
|
||||
let errorMsg = "" // 缓存报错信息
|
||||
// 在截图列表中,寻找上一次截图所在的屏幕
|
||||
for(let i in grabList) {
|
||||
const g = grabList[i] // 截图属性
|
||||
// 合法性检查
|
||||
if(g.imgID.startsWith("[")) {
|
||||
errorMsg = g.imgID // 记录失败,跳过本轮
|
||||
continue
|
||||
}
|
||||
// 找到对应屏幕
|
||||
if(lastClipArgd.screenName === g.screenName) {
|
||||
// 向py汇报,获取裁剪后的imgID
|
||||
const clipImgID = imageConn.getClipImgID(g.imgID,
|
||||
lastClipArgd.clipX, lastClipArgd.clipY, lastClipArgd.clipW, lastClipArgd.clipH)
|
||||
// 成功 调用回调
|
||||
runLastCallback(clipImgID)
|
||||
running = false
|
||||
return
|
||||
}
|
||||
}
|
||||
// 失败,未找到相同屏幕
|
||||
lastClipArgd = undefined
|
||||
if(!errorMsg) errorMsg = qsTr("未找到匹配的屏幕")
|
||||
qmlapp.popup.simple(qsTr("重复截图失败"), errorMsg)
|
||||
runLastCallback()
|
||||
running = false
|
||||
}
|
||||
|
||||
// 【同步】获取指定区域的截图ID,失败返回 "[Error]..."
|
||||
function getScreenshot(rect, screen=0) { // screen 屏幕编号
|
||||
// 无需验证 running
|
||||
// 获取所有屏幕的截图图像
|
||||
const grabList = getGrabList()
|
||||
// 参数检查
|
||||
if(!Number.isInteger(screen) || screen < 0 || screen >= grabList.length)
|
||||
return `[Error] Invalid screen=${screen}: must be an integer (0~${grabList.length-1})`
|
||||
if(rect.length != 4) // 不检查内部是否合法,getClipImgID会检查
|
||||
return `[Error] Invalid rect=${rect}: must be integers [x,y,w,h]`
|
||||
const grab = grabList[screen]
|
||||
const imgID = grab.imgID
|
||||
if(imgID.startsWith("[")) // 获取截图数据失败
|
||||
return imgID
|
||||
let [x, y, w, h] = rect
|
||||
// 补充缺省宽高
|
||||
if(w <= 0) w = grab.width - x
|
||||
if(h <= 0) h = grab.height - y
|
||||
// 返回裁剪后的imgID
|
||||
return imageConn.getClipImgID(imgID, x, y, w, h)
|
||||
}
|
||||
|
||||
// =================================================
|
||||
|
||||
// 获取所有屏幕的截图图像
|
||||
function getGrabList() {
|
||||
/*
|
||||
返回列表(不为空),每项为:\n
|
||||
{
|
||||
"imgID": 图片ID 或 报错信息 "[Error]开头" ,
|
||||
"screenName": 显示器名称 ,
|
||||
"width": 截图宽度 ,
|
||||
"height": 截图高度 ,
|
||||
}
|
||||
*/
|
||||
|
||||
// 截图前等待时间
|
||||
let wait = 0
|
||||
// 需要隐藏主窗口
|
||||
if(qmlapp.globalConfigs.getValue("screenshot.hideWindow")) {
|
||||
// 若主窗口可见,则记录位置,避免linux隐藏→显示主窗口后位置偏移。
|
||||
if(qmlapp.mainWin.getVisibility())
|
||||
qmlapp.mainWin.saveGeometry()
|
||||
qmlapp.mainWin.setVisibility(false)
|
||||
wait = qmlapp.globalConfigs.getValue("screenshot.hideWindowTime")
|
||||
}
|
||||
// 获取所有屏幕的截图
|
||||
const grabList = imageConn.getScreenshot(wait)
|
||||
return grabList
|
||||
}
|
||||
|
||||
// Esc退出截图
|
||||
function ssEsc() {
|
||||
const argd = {clipX: -1, clipY: -1, clipW: -1, clipH: -1}
|
||||
ssEnd(argd)
|
||||
}
|
||||
|
||||
// 截图窗口操作完毕的回调
|
||||
function ssEnd(argd) {
|
||||
// 注销esc事件监听
|
||||
qmlapp.pubSub.unsubscribeGroup("ssEsc")
|
||||
// 关闭所有覆盖窗口
|
||||
for (let key in winDict) {
|
||||
winDict[key].destroy()
|
||||
}
|
||||
winDict = {}
|
||||
// 检测是否有效。如果无效,可能是按Esc退出了截图流程
|
||||
if(argd.clipX<0 || argd.clipY<0 || argd.clipW<1 || argd.clipH<1 || !argd.imgID) {
|
||||
runLastCallback()
|
||||
lastClipArgd = undefined
|
||||
running = false
|
||||
return
|
||||
}
|
||||
// 记录当前截图信息
|
||||
lastClipArgd = argd
|
||||
// 向py汇报,获取裁剪后的imgID
|
||||
const clipImgID = imageConn.getClipImgID(argd.imgID, argd.clipX, argd.clipY, argd.clipW, argd.clipH)
|
||||
// 调用回调
|
||||
runLastCallback(clipImgID)
|
||||
running = false
|
||||
}
|
||||
|
||||
// 调用上级回调
|
||||
function runLastCallback(clipImgID) {
|
||||
if (lastCallback && typeof lastCallback === "function") {
|
||||
lastCallback(clipImgID)
|
||||
}
|
||||
}
|
||||
|
||||
property string errorTitle: qsTr("截图失败")
|
||||
property string errorRepeat: qsTr("上次截图操作未结束,不能进行新的截图!")
|
||||
property bool running: false // 当前是否正在截图
|
||||
property var lastClipArgd: undefined // 最后一次截图的信息
|
||||
property var lastCallback: undefined // 截图完毕的回调,得到 clipImgID
|
||||
property var winDict: {} // 存放当前已打开的窗口
|
||||
property QtObject imageConn: qmlapp.imageManager.imageConnector
|
||||
|
||||
Component {
|
||||
id: ssWinComp
|
||||
ScreenshotWindowComp { }
|
||||
}
|
||||
}
|
||||
204
UmiOCR-data/qt_res/qml/ImageManager/ScreenshotWindowComp.qml
Normal file
204
UmiOCR-data/qt_res/qml/ImageManager/ScreenshotWindowComp.qml
Normal file
@@ -0,0 +1,204 @@
|
||||
// =======================================
|
||||
// =============== 截图窗口 ===============
|
||||
// =======================================
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Window 2.15
|
||||
import QtGraphicalEffects 1.15
|
||||
import "../Widgets"
|
||||
|
||||
Window {
|
||||
id: win
|
||||
|
||||
property string imgID: "" // 图片id
|
||||
property string screenName: "" // 显示器名称
|
||||
property var screenRatio: 1 // 屏幕缩放比
|
||||
property var screenshotEnd // 关闭函数,外部传入
|
||||
|
||||
// 配置
|
||||
property int lineWidth: 1 // 线宽
|
||||
property color crossLineColor: "#00f91a" // 十字指示器的颜色
|
||||
property color clipBorderColor: "white" // 框选区边框的颜色
|
||||
property color darkLayerColor: "#73000000" // 深色背景层的颜色
|
||||
|
||||
// 鼠标状态, 0 等待 , 1 拖拽中
|
||||
property int mouseStatus: 0
|
||||
// status==0时为当前鼠标位置,status==1时为拖拽开始位置
|
||||
property int mouseX: -1
|
||||
property int mouseY: -1
|
||||
// 裁切区域的左上角坐标和宽高
|
||||
property int clipX: -1
|
||||
property int clipY: -1
|
||||
property int clipW: -1
|
||||
property int clipH: -1
|
||||
|
||||
flags: Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint // 无边框+置顶
|
||||
|
||||
Component.onCompleted: {
|
||||
image.showImgID(imgID)
|
||||
visible = true // 窗口可见
|
||||
// 窗口模式设置为全屏,避免Linux任务栏排斥窗口位置
|
||||
win.visibility = Window.FullScreen
|
||||
raise() // 弹到最前层
|
||||
requestActivate() // 激活窗口
|
||||
}
|
||||
|
||||
// 截图完毕,成功为true
|
||||
function ssEnd(okk) {
|
||||
visible = false // 先隐藏窗口
|
||||
let argd = {}
|
||||
if(okk) { // 成功
|
||||
// 乘以屏幕缩放比
|
||||
if(screenRatio !== 1) {
|
||||
clipX*=screenRatio; clipY*=screenRatio;
|
||||
clipW*=screenRatio; clipH*=screenRatio;
|
||||
}
|
||||
argd = {
|
||||
screenName: screenName,
|
||||
imgID: imgID,
|
||||
clipX: clipX,
|
||||
clipY: clipY,
|
||||
clipW: clipW,
|
||||
clipH: clipH,
|
||||
}
|
||||
}
|
||||
else {
|
||||
argd = {clipX:-1, clipY:-1, clipW:-1, clipH:-1}
|
||||
}
|
||||
// 向父级回报
|
||||
win.screenshotEnd(argd)
|
||||
}
|
||||
|
||||
// 底层,图片
|
||||
Image_ {
|
||||
id: image
|
||||
anchors.fill: parent
|
||||
}
|
||||
// 深色叠加层
|
||||
Rectangle {
|
||||
id: darkLayer
|
||||
anchors.fill: parent
|
||||
color: darkLayerColor
|
||||
// 遮罩,拖拽时扣除框选区域
|
||||
layer.enabled: mouseStatus==1
|
||||
layer.effect: OpacityMask {
|
||||
invert: true // 取反
|
||||
maskSource: Item {
|
||||
width: darkLayer.width
|
||||
height: darkLayer.height
|
||||
Rectangle {
|
||||
x: clipX
|
||||
y: clipY
|
||||
width: clipW
|
||||
height: clipH
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 框选区边框
|
||||
Rectangle {
|
||||
visible: mouseStatus==1
|
||||
x: clipX
|
||||
y: clipY
|
||||
width: clipW
|
||||
height: clipH
|
||||
color: "#00000000"
|
||||
border.width: lineWidth
|
||||
border.color: clipBorderColor
|
||||
}
|
||||
// 十字指示器, mouseStatus==0 时启用
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
visible: mouseArea.containsMouse && mouseStatus==0
|
||||
Rectangle { // 水平
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
color: crossLineColor
|
||||
height: lineWidth
|
||||
y: mouseY-lineWidth
|
||||
}
|
||||
Rectangle { // 垂直
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
color: crossLineColor
|
||||
width: lineWidth
|
||||
x: mouseX-lineWidth
|
||||
}
|
||||
}
|
||||
// 鼠标触控层
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton // 捕获左右键
|
||||
cursorShape: Qt.CrossCursor // 十字光标
|
||||
focus: true // 获取焦点
|
||||
|
||||
// 按下
|
||||
onPressed: {
|
||||
if (mouse.button === Qt.RightButton) {
|
||||
return
|
||||
}
|
||||
if(mouseStatus == 0) {
|
||||
mouseStatus = 1
|
||||
win.mouseX = mouse.x
|
||||
win.mouseY = mouse.y
|
||||
win.clipX = mouse.x
|
||||
win.clipY = mouse.y
|
||||
}
|
||||
}
|
||||
// 移动
|
||||
onPositionChanged: {
|
||||
// 正常移动
|
||||
if(mouseStatus == 0) {
|
||||
win.mouseX = mouse.x
|
||||
win.mouseY = mouse.y
|
||||
}
|
||||
// 拖拽
|
||||
else if(mouseStatus == 1) {
|
||||
// 右
|
||||
if(mouse.x > win.mouseX) {
|
||||
win.clipX = win.mouseX
|
||||
win.clipW = mouse.x - win.mouseX
|
||||
if(win.clipX + win.clipW > win.width) // 防右越界
|
||||
win.clipW = win.width - win.clipX
|
||||
}
|
||||
// 左
|
||||
else {
|
||||
win.clipX = mouse.x
|
||||
win.clipW = win.mouseX - mouse.x
|
||||
if(win.clipX < 0) { // 防左越界
|
||||
win.clipX = 0
|
||||
win.clipW = win.mouseX
|
||||
}
|
||||
}
|
||||
// 下
|
||||
if(mouse.y > win.mouseY) {
|
||||
win.clipY = win.mouseY
|
||||
win.clipH = mouse.y - win.mouseY
|
||||
if(win.clipY + win.clipH > win.height) // 防下越界
|
||||
win.clipH = win.height - win.clipY
|
||||
}
|
||||
// 上
|
||||
else {
|
||||
win.clipY = mouse.y
|
||||
win.clipH = win.mouseY - mouse.y
|
||||
if(win.clipY < 0) { // 防上越界
|
||||
win.clipY = 0
|
||||
win.clipH = win.mouseY
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 松开
|
||||
onReleased: {
|
||||
if (mouse.button === Qt.RightButton) {
|
||||
ssEnd(false)
|
||||
return
|
||||
}
|
||||
if(mouseStatus == 1) {
|
||||
ssEnd(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user