docs: 添加涉密文件自检工具实施计划

This commit is contained in:
2026-06-08 13:53:24 +08:00
commit 31161d9a5f
1838 changed files with 455407 additions and 0 deletions

View File

@@ -0,0 +1,234 @@
# ==========================================================
# =============== Python向Qml传输 Pixmap 图像 ===============
# ==========================================================
import os
from uuid import uuid4 # 唯一ID
from urllib.parse import unquote
from PySide2.QtCore import Qt, QByteArray, QBuffer
from PySide2.QtGui import QPixmap, QImage, QPainter, QClipboard
from PySide2.QtQuick import QQuickImageProvider
from umi_log import logger
from . import ImageQt
from ..platform import Platform
Clipboard = QClipboard() # 剪贴板
# Pixmap型图片提供器
class PixmapProviderClass(QQuickImageProvider):
def __init__(self):
super().__init__(QQuickImageProvider.Pixmap)
self.pixmapDict = {} # 缓存所有pixmap的字典
self.compDict = {} # 缓存所有组件的字典
# 空图占位符
self._noneImg = None
# 向qml返回图片imgID不存在时返回警告图
def requestPixmap(self, path, size=None, resSize=None):
if "/" in path:
compID, imgID = path.split("/", 1)
self._delCompCache(compID, imgID) # 先清缓存
if imgID in self.pixmapDict:
self.compDict[compID] = imgID # 记录缓存
return self.pixmapDict[imgID]
else: # 清空一个组件的缓存
self._delCompCache(path)
return self._getNoneImg() # 返回占位符
# 添加一个Pixmap图片到提供器返回imgID
def addPixmap(self, pixmap):
imgID = str(uuid4())
self.pixmapDict[imgID] = pixmap
return imgID
# 向py返回图片相当于requestPixmap但imgID不存在时返回None
def getPixmap(self, imgID):
return self.pixmapDict.get(imgID, None)
# 向py返回PIL对象
def getPilImage(self, imgID):
im = self.getPixmap(imgID)
if not im:
return None
try:
return ImageQt.fromqimage(im)
except Exception:
logger.error("QPixmap 转 PIL 失败。", exc_info=True, stack_info=True)
return None
# py将PIL对象写回pixmapDict。主要是记录预处理的图像
# imgID可以已存在也可以新添加
def setPilImage(self, img, imgID=""):
try:
pixmap = ImageQt.toqpixmap(img)
except Exception as e:
logger.error("PIL 转 QPixmap 失败。", exc_info=True, stack_info=True)
return f"[Error] PIL 转 QPixmap 失败:{e}"
if not imgID:
imgID = str(uuid4())
self.pixmapDict[imgID] = pixmap
return imgID
# 从pixmapDict缓存中删除一个或一批图片
# 一般无需手动调用此函数!缓存会自动管理、清除。
def delPixmap(self, imgIDs):
if isinstance(imgIDs, str):
imgIDs = [imgIDs]
for i in imgIDs:
if i in self.pixmapDict:
del self.pixmapDict[i]
logger.debug(f"删除图片缓存,剩余:{len(self.pixmapDict)}")
# 将 QPixmap 或 QImage 转换为字节
@staticmethod
def toBytes(image):
if isinstance(image, QPixmap):
image = image.toImage()
elif not isinstance(image, QImage):
raise ValueError(
f"[Error] Only QImage or QPixmap can toBytes(), no {str(type(image))}."
)
byteArray = QByteArray() # 创建一个字节数组
buffer = QBuffer(byteArray) # 创建一个缓冲区
buffer.open(QBuffer.WriteOnly)
image.save(buffer, "PNG") # 将 QImage 保存为字节数组
buffer.close()
bytesData = byteArray.data() # 获取字节数组的内容
return bytesData
# 清空一个组件的缓存。imgID可选该组件下一次更新的图片ID。
def _delCompCache(self, compID, imgID=""):
if compID in self.compDict:
last = self.compDict[compID]
if imgID and imgID == last:
logger.warning(f"图片组件异常清理: {compID} {imgID}")
return # 如果下一次更新的ID等于当前ID则为异常不进行清理
if last in self.pixmapDict:
del self.pixmapDict[last]
del self.compDict[compID]
# 返回空图占位符
def _getNoneImg(self):
if self._noneImg:
return self._noneImg
pixmap = QPixmap(1, 100)
pixmap.fill(Qt.blue)
painter = QPainter(pixmap) # 绘制警告条纹
painter.setPen(Qt.red)
painter.drawLine(0, 0, 0, 5)
painter.drawLine(0, 95, 0, 100)
self._noneImg = pixmap
return self._noneImg
# 图片提供器 单例
PixmapProvider = PixmapProviderClass()
# 读入一张图片,返回该图片
# type: pixmap / qimage / error
def _imread(path):
path = unquote(path) # 做一次URL解码
if path.startswith("image://pixmapprovider/"):
path = path[23:]
if "/" in path:
compID, imgID = path.split("/", 1)
if imgID in PixmapProvider.pixmapDict:
return {"type": "pixmap", "data": PixmapProvider.pixmapDict[imgID]}
else:
return {"type": "error", "data": f"[Warning] ID not in pixmapDict: {path}"}
elif path.startswith("file:///"):
path = path[8:]
if os.path.exists(path):
try:
image = QImage(path)
return {"type": "qimage", "data": image, "path": path}
except Exception as e:
return {
"type": "error",
"data": f"[Error] QImage cannot read path: {path}",
}
else:
return {"type": "error", "data": f"[Warning] Path {path} not exists."}
elif path in PixmapProvider.pixmapDict:
return {"type": "pixmap", "data": PixmapProvider.pixmapDict[path]}
elif os.path.exists(path):
try:
image = QImage(path)
return {"type": "qimage", "data": image, "path": path}
except Exception as e:
return {"type": "error", "data": f"[Error] QImage cannot read path: {path}"}
return {"type": "error", "data": f"[Warning] Unknow: {path}"}
# 复制一张图片到剪贴板
def copyImage(path):
im = _imread(path)
typ, data = im["type"], im["data"]
if typ == "error":
return data
try:
if typ == "pixmap":
Clipboard.setPixmap(data)
elif typ == "qimage":
Clipboard.setImage(data)
return "[Success]"
except Exception as e:
return f"[Error] can't copy: {e}\n{path}"
# 用系统默认应用打开图片
def openImage(path):
im = _imread(path)
typ, data = im["type"], im["data"]
if typ == "error":
return data
# 若原本为本地图片,则直接打开
if "path" in im:
path = im["path"]
# 若为内存数据,则创建缓存文件
else:
path = "umi_temp_image.png"
try:
if typ == "pixmap":
data = data.toImage()
data.save(path)
logger.debug(f"用系统默认应用打开图片时,缓存临时图片到 {path}")
except Exception as e:
logger.error(
f"用系统默认应用打开图片时,无法缓存临时图片到 {path}",
exc_info=True,
stack_info=True,
)
return f"[Error] can't save to temp file: {e}\n{path}"
# 打开文件
try:
Platform.startfile(path)
return "[Success]"
except Exception as e:
logger.error(
f"无法用系统默认应用打开图片 {path}",
exc_info=True,
stack_info=True,
)
return f"[Error] can't open image: {e}\n{path}"
# 保存一张图片
def saveImage(fromPath, toPath):
if toPath.startswith("file:///"):
toPath = toPath[8:]
im = _imread(fromPath)
typ, data = im["type"], im["data"]
if typ == "error":
return data
try:
if typ == "pixmap":
data.save(toPath)
elif typ == "qimage":
data.save(toPath)
return f"[Success] {toPath}"
except Exception as e:
return f"[Error] can't save: {e}\n{fromPath}\n{toPath}"