docs: 添加涉密文件自检工具实施计划
This commit is contained in:
229
UmiOCR-data/qt_res/qml/Widgets/ImageViewer/ImageScale.qml
Normal file
229
UmiOCR-data/qt_res/qml/Widgets/ImageViewer/ImageScale.qml
Normal file
@@ -0,0 +1,229 @@
|
||||
// ==================================================
|
||||
// =============== 可缩放的图片预览组件 ===============
|
||||
// ==================================================
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
|
||||
import ".."
|
||||
|
||||
Rectangle {
|
||||
id: iRoot
|
||||
// ========================= 【接口】 =========================
|
||||
|
||||
// 可设置
|
||||
property real scaleMax: 2.0 // 比例上下限
|
||||
property real scaleMin: 0.1 // 比例上下限
|
||||
property QtObject overlayLayer // 图片叠加层
|
||||
property var border: bRect.border // 边框
|
||||
// 只读
|
||||
property alias showImage: showImage // 图片组件
|
||||
property real scale: 1.0 // 图片缩放比例
|
||||
property int imageSW: 0 // 图片原始宽高
|
||||
property int imageSH: 0
|
||||
// 子类重写
|
||||
property var beforeShow: undefined // 展示图片之前执行的操作
|
||||
|
||||
// 设置图片源,展示一张图片
|
||||
function setSource(source) {
|
||||
if(source) {
|
||||
// 特殊字符#替换为%23
|
||||
if(source.startsWith("file:///") && source.includes("#"))
|
||||
source = source.replace(new RegExp("#", "g"), "%23");
|
||||
showImage.source = source // 设置源
|
||||
}
|
||||
else
|
||||
showImage.source = ""
|
||||
}
|
||||
|
||||
// 传入路径,展示图片
|
||||
function showPath(path) {
|
||||
if(beforeShow) beforeShow()
|
||||
showImage.showPath(path)
|
||||
}
|
||||
|
||||
// 传入imgID,展示图片
|
||||
function showImgID(imgID) {
|
||||
if(beforeShow) beforeShow()
|
||||
showImage.showImgID(imgID)
|
||||
}
|
||||
|
||||
// 清空展示
|
||||
function clear() {
|
||||
if(beforeShow) beforeShow()
|
||||
// showImage.clear()
|
||||
showImage.source = ""
|
||||
imageSW = imageSH = 0
|
||||
}
|
||||
|
||||
// 复制当前图片
|
||||
function copyImage() {
|
||||
if(showImage.source == "") return
|
||||
const res = qmlapp.imageManager.copyImage(showImage.source)
|
||||
if(res === "[Success]")
|
||||
qmlapp.popup.simple(qsTr("复制图片"), "")
|
||||
else
|
||||
qmlapp.popup.simple(qsTr("复制图片失败"), res)
|
||||
}
|
||||
|
||||
// 用系统默认应用打开图片
|
||||
function openImage() {
|
||||
if(showImage.source == "") return
|
||||
const res = qmlapp.imageManager.openImage(showImage.source)
|
||||
if(res === "[Success]")
|
||||
qmlapp.popup.simple(qsTr("打开图片"), "")
|
||||
else
|
||||
qmlapp.popup.simple(qsTr("打开图片失败"), res)
|
||||
}
|
||||
|
||||
// 保存当前图片
|
||||
function saveImage() {
|
||||
if(showImage.source == "") return
|
||||
saveDialog.open()
|
||||
}
|
||||
|
||||
FileDialog_ {
|
||||
id: saveDialog
|
||||
title: qsTr("保存图片")
|
||||
selectExisting: false
|
||||
selectFolder: false
|
||||
folder: shortcuts.desktop // 默认放桌面
|
||||
nameFilters: ["*.png", "*.jpg"]
|
||||
onAccepted: {
|
||||
if(!fileUrl) {
|
||||
console.log("文件对话框:未选择任何文件")
|
||||
return
|
||||
}
|
||||
let filePath = fileUrl
|
||||
const res = qmlapp.imageManager.saveImage(showImage.source, filePath)
|
||||
if(res.startsWith("[Success]"))
|
||||
qmlapp.popup.simple(qsTr("保存图片"), res)
|
||||
else
|
||||
qmlapp.popup.simple(qsTr("保存图片失败"), res)
|
||||
}
|
||||
}
|
||||
|
||||
// ========================= 【处理】 =========================
|
||||
|
||||
Component.onCompleted: {
|
||||
// 叠加层挂父级
|
||||
if(overlayLayer && overlayLayer.hasOwnProperty("parent"))
|
||||
overlayLayer.parent = showImage
|
||||
}
|
||||
|
||||
|
||||
// 图片组件的状态改变
|
||||
function imageStatusChanged(s) {
|
||||
// 已就绪
|
||||
if(s == Image.Ready) {
|
||||
imageSW = showImage.sourceSize.width // 记录图片原始宽高
|
||||
imageSH = showImage.sourceSize.height
|
||||
imageFullFit() // 初始大小
|
||||
}
|
||||
else {
|
||||
imageSW = imageSH = 0
|
||||
iRoot.scale = 1
|
||||
}
|
||||
}
|
||||
|
||||
// 缩放,传入 flag>0 放大, <0 缩小 ,0回归100%。以相框中心为锚点。
|
||||
function imageScaleAddSub(flag=0, step=0.1) {
|
||||
if(showImage.status != Image.Ready) return
|
||||
// 计算缩放比例
|
||||
let s = 1.0 // flag==0 时复原
|
||||
if (flag > 0) { // 放大
|
||||
s = (iRoot.scale + step).toFixed(1)
|
||||
// 禁止大于上限 或 图片填满大小(裁切)
|
||||
const max = Math.max(flickable.width/imageSW, flickable.height/imageSH, scaleMax)
|
||||
if(s > max) s = max
|
||||
}
|
||||
else if(flag < 0) { // 缩小
|
||||
s = (iRoot.scale - step).toFixed(1)
|
||||
// 禁止小于下限 或 图片填满大小(不裁切)
|
||||
const min = Math.min(flickable.width/imageSW, flickable.height/imageSH, scaleMin)
|
||||
if(s < min) s = min
|
||||
}
|
||||
|
||||
// 目标锚点
|
||||
let gx = -flickable.width/2
|
||||
let gy = -flickable.height/2
|
||||
// 目标锚点在图片中的原比例
|
||||
let s1x = (flickable.contentX-gx)/showImageContainer.width
|
||||
let s1y = (flickable.contentY-gy)/showImageContainer.height
|
||||
// 目标锚点在图片中的新比例,及差值
|
||||
iRoot.scale = s // 更新缩放
|
||||
let s2x = (flickable.contentX-gx)/showImageContainer.width
|
||||
let s2y = (flickable.contentY-gy)/showImageContainer.height
|
||||
let sx = s2x-s1x
|
||||
let sy = s2y-s1y
|
||||
// 实际长度差值
|
||||
let lx = sx*showImageContainer.width
|
||||
let ly = sy*showImageContainer.height
|
||||
// 偏移
|
||||
flickable.contentX -= lx
|
||||
flickable.contentY -= ly
|
||||
}
|
||||
|
||||
// 图片填满组件,不裁切
|
||||
function imageFullFit() {
|
||||
if(showImage.source == "" || imageSW <= 0) return
|
||||
iRoot.scale = Math.min(flickable.width/imageSW, flickable.height/imageSH)
|
||||
// 图片中心对齐相框
|
||||
flickable.contentY = - (flickable.height - showImageContainer.height)/2
|
||||
flickable.contentX = - (flickable.width - showImageContainer.width)/2
|
||||
}
|
||||
|
||||
// ======================== 【布局】 =========================
|
||||
color: theme.bgColor
|
||||
|
||||
|
||||
// 滑动区域,显示图片,监听左键拖拽
|
||||
Flickable {
|
||||
id: flickable
|
||||
anchors.fill: parent
|
||||
contentWidth: showImageContainer.width
|
||||
contentHeight: showImageContainer.height
|
||||
clip: true
|
||||
|
||||
// 图片容器,大小不小于滑动区域
|
||||
Item {
|
||||
id: showImageContainer
|
||||
width: Math.max( imageSW * iRoot.scale , flickable.width )
|
||||
height: Math.max( imageSH * iRoot.scale , flickable.height )
|
||||
Image_ {
|
||||
id: showImage
|
||||
anchors.centerIn: parent
|
||||
scale: iRoot.scale
|
||||
onStatusChanged: imageStatusChanged(status)
|
||||
}
|
||||
}
|
||||
|
||||
// 滚动条
|
||||
ScrollBar.vertical: ScrollBar { }
|
||||
ScrollBar.horizontal: ScrollBar { }
|
||||
}
|
||||
|
||||
// 监听滚轮缩放
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.NoButton
|
||||
// 滚轮缩放
|
||||
onWheel: {
|
||||
if (wheel.angleDelta.y > 0) {
|
||||
imageScaleAddSub(1) // 放大
|
||||
}
|
||||
else {
|
||||
imageScaleAddSub(-1) // 缩小
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 边框
|
||||
Rectangle {
|
||||
id: bRect
|
||||
anchors.fill: parent
|
||||
color: "#00000000"
|
||||
border.width: 1
|
||||
border.color: theme.coverColor4
|
||||
}
|
||||
}
|
||||
300
UmiOCR-data/qt_res/qml/Widgets/ImageViewer/ImageWithText.qml
Normal file
300
UmiOCR-data/qt_res/qml/Widgets/ImageViewer/ImageWithText.qml
Normal file
@@ -0,0 +1,300 @@
|
||||
// ==========================================================
|
||||
// =============== 可显示OCR文本的增强Image组件 ===============
|
||||
// ==========================================================
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import ".."
|
||||
|
||||
ImageScale {
|
||||
id: iRoot
|
||||
property bool showOverlay: true // 显示叠加层
|
||||
|
||||
Component.onCompleted: {
|
||||
// 默认显示/关闭叠加层
|
||||
showOverlay = qmlapp.globalConfigs.getValue("ui.imgShowOverlay")
|
||||
}
|
||||
|
||||
beforeShow: () => {
|
||||
mouseArea.initIndex() // 清空选字参数
|
||||
textBoxes = [] // 清空旧文本块
|
||||
}
|
||||
|
||||
// 展示文本块
|
||||
function showTextBoxes(res) {
|
||||
beforeShow()
|
||||
// 提取文本框
|
||||
if(res.code == 100 && res.data.length > 0) {
|
||||
let tbs = []
|
||||
for(let i in res.data) {
|
||||
const d = res.data[i]
|
||||
const info = {
|
||||
x: d.box[0][0],
|
||||
y: d.box[0][1],
|
||||
width: d.box[2][0] - d.box[0][0],
|
||||
height: d.box[2][1] - d.box[0][1],
|
||||
text: d.text,
|
||||
end: d.end || "", // 行尾间隔符
|
||||
}
|
||||
tbs.push(info)
|
||||
}
|
||||
textBoxes = tbs
|
||||
}
|
||||
}
|
||||
|
||||
// 弹出菜单
|
||||
function popupMenu() {
|
||||
selectMenu.popup()
|
||||
}
|
||||
// 显示/隐藏叠加层
|
||||
function switchOverlay() {
|
||||
showOverlay = !showOverlay
|
||||
if(!showOverlay)
|
||||
mouseArea.cursorShape = Qt.OpenHandCursor
|
||||
}
|
||||
|
||||
property var textBoxes: [] // 文本块列表
|
||||
|
||||
// 文本块叠加层
|
||||
overlayLayer: Item {
|
||||
id: oRoot
|
||||
anchors.fill: parent
|
||||
visible: showOverlay
|
||||
|
||||
Repeater {
|
||||
id: textBoxRepeater
|
||||
model: textBoxes
|
||||
TextBox {
|
||||
text: modelData.text
|
||||
x: modelData.x
|
||||
y: modelData.y
|
||||
end: modelData.end // 结尾间隔符
|
||||
|
||||
Component.onCompleted: {
|
||||
width = modelData.width
|
||||
height = modelData.height
|
||||
resetSize() // 自适应字体和组件大小
|
||||
textBoxes[index].width = width // 记录修改后的组件大小
|
||||
textBoxes[index].height = height
|
||||
textBoxes[index].obj = this
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
property int startIndex: -1 // 拖拽开始时,文本框序号
|
||||
property int startTextIndex: -1 // 拖拽开始时,字符序号
|
||||
property int endIndex: -1 // 拖拽结束时,文本框序号
|
||||
property int endTextIndex: -1 // 拖拽结束时,字符序号
|
||||
property int selectUpdate: 0
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
|
||||
// 清除index
|
||||
function initIndex() {
|
||||
startIndex = startTextIndex = endIndex = endTextIndex = -1
|
||||
}
|
||||
// 检测当前鼠标点,位于哪一个tb内
|
||||
function mouseInTextBox() {
|
||||
const localPoint = oRoot.mapFromItem(mouseArea, mouseX, mouseY)
|
||||
const x = localPoint.x, y = localPoint.y
|
||||
for (let i=0,l=textBoxes.length; i<l; i++) {
|
||||
const rect = textBoxes[i]
|
||||
if (x >= rect.x && x <= rect.x + rect.width &&
|
||||
y >= rect.y && y <= rect.y + rect.height) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1
|
||||
}
|
||||
// 检测当前鼠标点,在index tb内的哪一个字符处
|
||||
function mouseInTextIndex(index) {
|
||||
return textBoxes[index].obj.where(mouseArea, mouseX, mouseY)
|
||||
}
|
||||
// 获取Index正确顺序。返回: [li 起始块, lt 起始块选区左侧, ri 结束块, rt 结束块选区右侧]
|
||||
function getIndexes() {
|
||||
let li, lt, ri, rt
|
||||
if(startIndex < endIndex) {
|
||||
li=startIndex; lt=startTextIndex; ri=endIndex; rt=endTextIndex;
|
||||
}
|
||||
else if(startIndex > endIndex) {
|
||||
li=endIndex; lt=endTextIndex; ri=startIndex; rt=startTextIndex;
|
||||
}
|
||||
else {
|
||||
li = ri = startIndex
|
||||
if(startTextIndex < endTextIndex) {
|
||||
lt=startTextIndex; rt=endTextIndex;
|
||||
}
|
||||
else if(startTextIndex > endTextIndex) {
|
||||
lt=endTextIndex; rt=startTextIndex;
|
||||
}
|
||||
else { // 单击,未选中
|
||||
lt = rt = -1
|
||||
}
|
||||
}
|
||||
return [li, lt, ri, rt]
|
||||
}
|
||||
// 根据 Index 的参数,选择对应文本。
|
||||
function selectIndex() {
|
||||
const [li, lt, ri, rt] = getIndexes()
|
||||
// 遍历每个文本框数据
|
||||
for (let i = 0, l=textBoxes.length; i < l; i++) {
|
||||
const tEdit = textBoxes[i].obj.textEdit
|
||||
if( li<0 || ri<0 || i<li || i>ri ) { // 未被选中
|
||||
tEdit.deselect()
|
||||
}
|
||||
else if(i === li && i === ri) { // 单个块
|
||||
if(lt === rt) // 无有效选中
|
||||
tEdit.deselect()
|
||||
else
|
||||
tEdit.select(lt, rt)
|
||||
}
|
||||
else if(i === li) { // 多个块的起始
|
||||
const len = textBoxes[i].text.length
|
||||
tEdit.select(lt, len)
|
||||
}
|
||||
else if(i === ri) { // 多个块的结束
|
||||
tEdit.select(0, rt)
|
||||
}
|
||||
else { // 多个块的中间
|
||||
tEdit.selectAll(0, rt)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 全选
|
||||
function selectAll() {
|
||||
const l = textBoxes.length
|
||||
if(l === 0) return
|
||||
startIndex = startTextIndex = 0
|
||||
endIndex = l-1
|
||||
endTextIndex = textBoxes[endIndex].text.length
|
||||
selectIndex()
|
||||
}
|
||||
// 复制已选中的内容
|
||||
function selectCopy() {
|
||||
let [li, lt, ri, rt] = getIndexes()
|
||||
// 没有有效选中,则复制全部
|
||||
if(li<0 || ri<0 || (li===ri && lt===rt)) {
|
||||
selectAllCopy()
|
||||
return
|
||||
}
|
||||
let copyText = ""
|
||||
// 选中单个文本块
|
||||
if(li === ri) {
|
||||
copyText = textBoxes[li].text.substring(lt, rt)
|
||||
}
|
||||
// 选中多个块,则遍历多个块,提取各自的文本
|
||||
else {
|
||||
for(let i = li; i <= ri; i++) {
|
||||
const text = textBoxes[i].text
|
||||
const end = textBoxes[i].end
|
||||
if(i === li) // 多个块的起始
|
||||
copyText = text.substring(lt) + end
|
||||
else if(i === ri) // 多个块的结束
|
||||
copyText += text.substring(0, rt)
|
||||
else // 多个块的中间
|
||||
copyText += text + end
|
||||
}
|
||||
}
|
||||
if(copyText && copyText.length > 0) {
|
||||
qmlapp.utilsConnector.copyText(copyText)
|
||||
qmlapp.popup.simple(qsTr("图片:复制%1字").arg(copyText.length), "")
|
||||
}
|
||||
else {
|
||||
qmlapp.popup.simple(qsTr("图片:无选中文字"), "")
|
||||
}
|
||||
}
|
||||
// 复制所有
|
||||
function selectAllCopy() {
|
||||
let copyText = ""
|
||||
for (let i = 0, l=textBoxes.length; i < l; i++) {
|
||||
copyText += textBoxes[i].text
|
||||
if(i < l-1) copyText += textBoxes[i].end
|
||||
}
|
||||
qmlapp.utilsConnector.copyText(copyText)
|
||||
qmlapp.popup.simple(qsTr("图片:复制全部%1字").arg(copyText.length), "")
|
||||
selectAll()
|
||||
}
|
||||
|
||||
// 按下
|
||||
onPressed: {
|
||||
mouseArea.forceActiveFocus()
|
||||
if (mouse.button === Qt.RightButton) {
|
||||
selectMenu.popup()
|
||||
return
|
||||
}
|
||||
if(!showOverlay) {
|
||||
mouse.accepted = false
|
||||
return
|
||||
}
|
||||
initIndex()
|
||||
const tbi = mouseInTextBox()
|
||||
cursorShape = tbi < 0 ? Qt.ClosedHandCursor : Qt.IBeamCursor
|
||||
if(tbi >= 0) { // 选择文本
|
||||
startIndex = tbi
|
||||
startTextIndex = mouseInTextIndex(tbi)
|
||||
}
|
||||
else {
|
||||
mouse.accepted = false
|
||||
}
|
||||
}
|
||||
// 移动
|
||||
onPositionChanged: {
|
||||
if(!showOverlay) return
|
||||
const tbi = mouseInTextBox()
|
||||
if(pressed) { // 拖拽中
|
||||
if(tbi >= 0) { // 选择文本
|
||||
endIndex = tbi
|
||||
endTextIndex = mouseInTextIndex(tbi)
|
||||
selectIndex()
|
||||
}
|
||||
}
|
||||
else { // 悬停中
|
||||
cursorShape = tbi < 0 ? Qt.OpenHandCursor : Qt.IBeamCursor
|
||||
}
|
||||
}
|
||||
// 抬起
|
||||
onReleased: {
|
||||
if(!showOverlay) return
|
||||
if (mouse.button === Qt.RightButton) return
|
||||
const tbi = mouseInTextBox()
|
||||
cursorShape = tbi < 0 ? Qt.OpenHandCursor : Qt.IBeamCursor
|
||||
if(startIndex === -1) return
|
||||
if(tbi >= 0) {
|
||||
endIndex = tbi
|
||||
endTextIndex = mouseInTextIndex(tbi)
|
||||
}
|
||||
selectIndex()
|
||||
}
|
||||
// 菜单
|
||||
Menu_ {
|
||||
id: selectMenu
|
||||
menuList: [
|
||||
[mouseArea.selectCopy, qsTr("复制 (Ctrl+C)")],
|
||||
[mouseArea.selectAll, qsTr("全选 (Ctrl+A)")],
|
||||
[iRoot.copyImage, qsTr("复制图片(Ctrl+X)")],
|
||||
[iRoot.saveImage, qsTr("保存图片(Ctrl+S)")],
|
||||
[iRoot.switchOverlay, qsTr("显示/隐藏文字(Tab)")],
|
||||
[iRoot.openImage, qsTr("用默认应用打开图片")],
|
||||
[iRoot.clear, qsTr("删除图片(Ctrl+D)"), "noColor"],
|
||||
]
|
||||
}
|
||||
// 按键事件
|
||||
Keys.onPressed: {
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
event.key===Qt.Key_A && selectAll()
|
||||
event.key===Qt.Key_C && selectCopy()
|
||||
event.key===Qt.Key_X && iRoot.copyImage()
|
||||
event.key===Qt.Key_S && iRoot.saveImage()
|
||||
event.key===Qt.Key_D && iRoot.clear()
|
||||
}
|
||||
if (event.key === Qt.Key_Tab) {
|
||||
iRoot.switchOverlay()
|
||||
Qt.callLater(mouseArea.forceActiveFocus)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
87
UmiOCR-data/qt_res/qml/Widgets/ImageViewer/TextBox.qml
Normal file
87
UmiOCR-data/qt_res/qml/Widgets/ImageViewer/TextBox.qml
Normal file
@@ -0,0 +1,87 @@
|
||||
// =============================================
|
||||
// =============== 单个文本块组件 ===============
|
||||
// =============================================
|
||||
|
||||
import QtQuick 2.15
|
||||
import QtQuick.Controls 2.15
|
||||
import ".."
|
||||
|
||||
Item {
|
||||
id: tRoot
|
||||
property string text: ""
|
||||
|
||||
// 颜色固定,不受主题影响
|
||||
property color bgColor: "#99000000"
|
||||
property color textColor: "#FFFFFF"
|
||||
|
||||
// 外部接口,重设字体和组件大小
|
||||
property var resetSize: textEdit.resetFontSize
|
||||
property alias textEdit: textEdit // 文本组件
|
||||
property string end: "" // 结尾间隔符
|
||||
|
||||
// 传入一个相对于item的坐标,返回该坐标的文本序号。
|
||||
function where(item, mx, my) {
|
||||
const textPoint = textEdit.mapFromItem(item, mx, my)
|
||||
const textPos = textEdit.positionAt(textPoint.x, textPoint.y)
|
||||
return textPos
|
||||
}
|
||||
|
||||
// 背景
|
||||
Rectangle {
|
||||
id: bgRect
|
||||
anchors.fill: parent
|
||||
color: bgColor
|
||||
}
|
||||
// 结尾标识
|
||||
Icon_ {
|
||||
icon: "line_feed"
|
||||
visible: end == "\n" // 标记换行符
|
||||
anchors.left: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.leftMargin: 1
|
||||
height: Math.min(tRoot.height * 0.8 ,tRoot.width * 0.8 , size_.line * 2)
|
||||
width: height
|
||||
color: theme.subTextColor
|
||||
}
|
||||
// 文本
|
||||
TextEdit_ {
|
||||
id: textEdit
|
||||
anchors.fill: parent
|
||||
color: textColor
|
||||
readOnly: true // 只读
|
||||
selectByMouse: false // 禁止选择文本
|
||||
selectByKeyboard: false
|
||||
persistentSelection: true // 丢失焦点时,保留选区
|
||||
font.pixelSize: 10 // 初始:10像素
|
||||
|
||||
// 重设字体大小,以适合组件大小
|
||||
function resetFontSize() {
|
||||
text = tRoot.text
|
||||
// 初次调整,利用初始文字面积与容器面积的比值,计算字体大小
|
||||
let s = 1
|
||||
if(contentWidth>0 && contentHeight>0)
|
||||
s = (width * height) / (contentWidth * contentHeight)
|
||||
let ps = font.pixelSize * Math.sqrt(s)
|
||||
font.pixelSize = ps
|
||||
// 二次调整:如果文本比容器高出至少半行,则减小字体大小,直到不高于容器
|
||||
if(contentHeight >= height+(ps*0.5)) {
|
||||
// 为了保持性能,限定调整的最大次数
|
||||
for(let i=0; i<10 && contentHeight > height; i++) {
|
||||
font.pixelSize--
|
||||
}
|
||||
}
|
||||
// 二次调整:如果当前只有一行,则优化字间距
|
||||
if(lineCount === 1 && text.length > 0) {
|
||||
const s = (tRoot.width - contentWidth) / text.length
|
||||
if(s > 0) {
|
||||
font.letterSpacing = s
|
||||
}
|
||||
}
|
||||
// 优化整体宽高
|
||||
if(contentWidth > tRoot.width)
|
||||
tRoot.width = contentWidth
|
||||
if(contentHeight > tRoot.height)
|
||||
tRoot.height = contentHeight
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user