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

432 lines
18 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.
// ===========================================
// =============== 文档预览面板 ===============
// ===========================================
import QtQuick 2.15
import QtQuick.Controls 2.15
import DocPreviewConnector 1.0
import "../../Widgets"
import "../../Widgets/IgnoreArea"
ModalLayer {
id: pRoot
property var updateInfo // 更新信息函数
property var configsComp: undefined // 设置组件
property string previewPath: ""
property string password: ""
property bool isEncrypted: false // 已加密
property bool isAuthenticate: false // 密码正确
property int previewPage: -1
property int pageCount: -1
property int rangeStart: -1
property int rangeEnd: -1
property int ignoreRangeStart: 1
property int ignoreRangeEnd: -1
property bool previewOCR: false // 是否预览OCR
property bool ocrRunning: false // 是否预览OCR正在执行
// 展示文档
// info: path, page_count, range_start, range_end, is_encrypted, password, is_authenticate
function show(info) {
imgViewer.clear()
visible = true
previewPath = info.path
pageCount = info.page_count
previewPage = info.range_start
rangeStart = info.range_start
rangeEnd = info.range_end
password = info.password
isEncrypted = info.is_encrypted
isAuthenticate = info.is_authenticate
// 读取忽略区域设置
let initArea = configsComp.getValue("tbpu.ignoreArea")
if(initArea && initArea.length>0) {
// 读取设置,反格式化
let ig1 = []
for(let i=0,l=initArea.length; i<l; i++) {
const b = initArea[i]
ig1.push({
"x": b[0][0],
"y": b[0][1],
"width": b[2][0] - b[0][0],
"height": b[2][1] - b[0][1],
})
}
imgViewer.ig1Boxes = ig1
}
ignoreRangeStart = configsComp.getValue("tbpu.ignoreRangeStart")
ignoreRangeEnd = configsComp.getValue("tbpu.ignoreRangeEnd")
toPreview()
}
// 返回上层,更新信息
onVisibleChanged: {
if(visible) return
// 负数转倒数
if(rangeStart < 0) rangeStart += pageCount + 1
if(rangeEnd < 0) rangeEnd += pageCount + 1
// 范围检查
if(rangeStart < 1) rangeStart = 1
if(rangeStart > pageCount) rangeStart = pageCount
if(rangeEnd < rangeStart) rangeEnd = rangeStart
if(rangeEnd > pageCount) rangeEnd = pageCount
let pages_ = `${pageCount}` // 如果范围为整本,只显示总页数。否则显示 起始-结束
if(rangeEnd - rangeStart + 1 < pageCount)
pages_ = `${rangeStart}-${rangeEnd}`
if(updateInfo) {
updateInfo(previewPath, {
pages: pages_,
state: isAuthenticate ? "" : qsTr("加密"),
range_start: rangeStart,
range_end: rangeEnd,
password: password,
is_authenticate: isAuthenticate,
})
}
// 更新忽略区域
if(imgViewer.ig1Boxes.length > 0) {
// 格式化,存入设置
let ig1 = []
for(let i=0,l=imgViewer.ig1Boxes.length; i<l; i++) {
const b = imgViewer.ig1Boxes[i]
const x = Math.round(b.x)
const y = Math.round(b.y)
const w = Math.round(b.width)
const h = Math.round(b.height)
ig1.push([[x, y], [x+w, y], [x+w, y+h], [x, y+h]])
}
configsComp.setValue("tbpu.ignoreArea", ig1)
}
else {
configsComp.setValue("tbpu.ignoreArea", undefined)
}
configsComp.setValue("tbpu.ignoreRangeStart", ignoreRangeStart)
configsComp.setValue("tbpu.ignoreRangeEnd", ignoreRangeEnd)
imgViewer.clear()
prevConn.clear() // 清除文档缓存
previewPath = ""
}
// 翻页。to直接翻页flag加减页。
function changePage(to, flag=0) {
if (typeof to === "string") {
to = parseInt(to, 10)
}
if(flag != 0) {
to = previewPage + flag
}
if(previewPage != to && to > 0 && to <= pageCount) {
previewPage = to
toPreview()
}
}
Keys.onLeftPressed: changePage(-1, -1) // 上一页
Keys.onUpPressed: changePage(-1, -1)
Keys.onRightPressed: changePage(-1, 1) // 下一页
Keys.onDownPressed: changePage(-1, 1)
// 预览一页文档
function toPreview() {
if(!previewPath) return
if(previewPage < 1) previewPage = 1
if(previewPage > pageCount) previewPage = pageCount
prevConn.preview(previewPath, previewPage, password)
if(previewOCR) { // 预览OCR
ocrRunning = true
const argd = configsComp.getValueDict()
argd["tbpu.parser"] = "None" // 去除排版解析
prevConn.ocr(previewPath, previewPage, password, argd)
}
}
// 预览连接器
DocPreviewConnector {
id: prevConn
// 图片渲染的回调
onPreviewImg: function(imgID) {
const title = qsTr("打开文档失败")
if(imgID === "[Warning] is_encrypted") {
qmlapp.popup.simple(title, qsTr("请填写正确的密码"))
isAuthenticate = false
}
else if(imgID.startsWith("[Error]")) {
qmlapp.popup.message(title, imgID, "error")
}
else {
imgViewer.showImgID(imgID)
if(!isAuthenticate) {
qmlapp.popup.simple(qsTr("密码正确"), password)
isAuthenticate = true
}
}
}
// ocr预览的回调
onPreviewOcr: function(info) {
let path = info[0], page = info[1], res = info[2]
if(res.code!=100&&res.code!=101) { // 遇到异常
qmlapp.popup.message(qsTr("文档预览异常"), res.data, "error")
return
}
if(path != previewPath || page != previewPage) {
console.warn("文档OCR预览回调不匹配")
return
}
ocrRunning = false
imgViewer.showTextBoxes(res)
}
}
property string ignoreTips: qsTr("忽略区域说明:\n右键拖拽绘制矩形区域包含在区域内的文字框将被忽略。可用于排除水印、页眉页脚。\n范围允许填写负数表示倒数第x页。如-1表示最后一页-2表示倒数第2页。\n忽略区域的设置对所有文档生效。")
contentItem: DoubleRowLayout {
anchors.fill: parent
initSplitterX: size_.line * 13
// 左:控制面板
leftItem: Panel {
anchors.fill: parent
ScrollView {
anchors.fill: parent
contentWidth: width // 内容宽度
clip: true // 溢出隐藏
Column {
anchors.left: parent.left
anchors.right: parent.right
anchors.margins: size_.spacing
spacing: size_.smallSpacing
// ===== 文件名 =====
Text_ {
text: previewPath
anchors.left: parent.left
anchors.right: parent.right
wrapMode: TextEdit.WrapAnywhere // 任意换行
maximumLineCount: 4 // 限制行数
color: theme.subTextColor
font.pixelSize: size_.smallText
}
// ===== 密码 =====
Row {
visible: isEncrypted && !isAuthenticate // 已加密,未填密码,才显示
spacing: size_.spacing
height: size_.line + size_.spacing * 2
Text_ {
color: theme.noColor
anchors.verticalCenter: parent.verticalCenter
text: qsTr("密码:")
}
TextField_ {
width: size_.line * 6
anchors.top: parent.top
anchors.bottom: parent.bottom
text: password
onTextChanged: password = text
}
IconButton {
anchors.top: parent.top
anchors.bottom: parent.bottom
width: height
icon_: "yes"
onClicked: toPreview()
}
}
// ===== 控制项 =====
Column {
visible: !isEncrypted || isAuthenticate
spacing: size_.smallSpacing
anchors.left: parent.left
anchors.right: parent.right
// ===== 页数 =====
Rectangle {
anchors.left: parent.left
anchors.right: parent.right
height: 1
color: theme.coverColor4
}
Row {
spacing: size_.line
height: size_.line
Text_ {
text: qsTr("预览页面")
anchors.verticalCenter: parent.verticalCenter
}
CheckButton {
anchors.verticalCenter: parent.verticalCenter
height: size_.line
enabledAnime: true
checked: previewOCR
textColor_: theme.subTextColor
onCheckedChanged: {
if(!previewOCR&&checked) {
previewOCR = true
toPreview()
}
else {
previewOCR = ocrRunning = false
}
}
text_: "OCR"
toolTip: qsTr("预览PDF时是否预览OCR结果")
}
}
Row {
spacing: size_.spacing
height: size_.line + size_.smallSpacing * 2
Button_ {
anchors.top: parent.top
anchors.bottom: parent.bottom
text_: "<"
onClicked: changePage(0, -1)
}
Button_ {
anchors.top: parent.top
anchors.bottom: parent.bottom
text_: ">"
onClicked: changePage(0, 1)
}
TextField_ {
width: size_.line * 3
anchors.top: parent.top
anchors.bottom: parent.bottom
validator: IntValidator{bottom: 1; top: pageCount;}
text: previewPage
onTextChanged: changePage(text)
}
Text_ {
anchors.verticalCenter: parent.verticalCenter
text: "/ "+pageCount
}
}
// ===== OCR范围 =====
Rectangle {
anchors.left: parent.left
anchors.right: parent.right
height: 1
color: theme.coverColor4
}
Text_ {
text: qsTr("OCR页数")
}
Row {
height: size_.line + size_.smallSpacing * 2
spacing: size_.spacing
Text_ {
font.pixelSize: size_.smallText
anchors.verticalCenter: parent.verticalCenter
text: qsTr("范围")
}
TextField_ {
width: size_.line * 3
anchors.top: parent.top
anchors.bottom: parent.bottom
validator: IntValidator{bottom: -pageCount; top: pageCount;}
text: rangeStart
onTextChanged: {
if(text !== "" && text !== "-") rangeStart = text
}
}
Text_ {
anchors.verticalCenter: parent.verticalCenter
text: "-"
}
TextField_ {
width: size_.line * 3
anchors.top: parent.top
anchors.bottom: parent.bottom
validator: IntValidator{bottom: -pageCount; top: pageCount;}
text: rangeEnd
onTextChanged: {
if(text !== "" && text !== "-") rangeEnd = text
}
}
}
// ===== 忽略区域 =====
Rectangle {
anchors.left: parent.left
anchors.right: parent.right
height: 1
color: theme.coverColor4
}
Text_ {
text: qsTr("忽略区域页数(全局)")
}
Row {
height: size_.line + size_.smallSpacing * 2
spacing: size_.spacing
Text_ {
font.pixelSize: size_.smallText
anchors.verticalCenter: parent.verticalCenter
text: qsTr("范围")
}
TextField_ {
width: size_.line * 3
anchors.top: parent.top
anchors.bottom: parent.bottom
validator: IntValidator {}
text: ignoreRangeStart
onTextChanged: {
if(text !== "" && text !== "-") ignoreRangeStart = text
}
}
Text_ {
anchors.verticalCenter: parent.verticalCenter
text: "-"
}
TextField_ {
width: size_.line * 3
anchors.top: parent.top
anchors.bottom: parent.bottom
validator: IntValidator {}
text: ignoreRangeEnd
onTextChanged: {
if(text !== "" && text !== "-") ignoreRangeEnd = text
}
}
}
Row {
spacing: size_.spacing
height: size_.smallLine + size_.smallSpacing * 2
Button_ {
anchors.verticalCenter: parent.verticalCenter
height: size_.smallLine + size_.smallSpacing
bgColor_: theme.coverColor1
text_: qsTr("撤销")
onClicked: imgViewer.revokeIg()
textSize: size_.smallText
}
Button_ {
anchors.verticalCenter: parent.verticalCenter
height: size_.smallLine + size_.smallSpacing
bgColor_: theme.coverColor1
textColor_: theme.noColor
text_: qsTr("清空")
onClicked: imgViewer.clearIg()
textSize: size_.smallText
}
}
Text_ {
text: ignoreTips
color: theme.subTextColor
font.pixelSize: size_.smallText
anchors.left: parent.left
anchors.right: parent.right
wrapMode: TextEdit.Wrap
}
}
}
}
}
// 右:图片查看面板
rightItem: ImageWithIgnore {
id: imgViewer
anchors.fill: parent
// 加载中 动态图标
Loading {
visible: ocrRunning
anchors.centerIn: parent
}
}
}
}