Add files via upload

This commit is contained in:
cocolight
2024-03-24 15:48:14 +08:00
committed by GitHub
parent 068a1accf2
commit 5590add680
12 changed files with 821 additions and 0 deletions

15
src/docx.py Normal file
View File

@@ -0,0 +1,15 @@
def a():
try:
m
except Exception as e:
raise Exception("拷贝 pptx 文件错误") from e
def b():
try:
a()
except Exception as e:
print('捕获到异常:{}'.format(e))
b()

91
src/excel.py Normal file
View File

@@ -0,0 +1,91 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@文件 :excel.py
@时间 :2023/07/20 14:02:21
@作者 :aliha
@版本 :1.0
@依赖 :无
@说明 :移除限制xlsx的限制密码
'''
from lxml import etree
import shutil
import os
from util import delDirs, filterFiles, unZip, zipDir, mkdir
keyNode = ['sheetProtection', 'workbookProtection']
def unlockFile(fpath:str):
fname = os.path.basename(fpath)
fnamef, ftype = fname.rsplit(".",1)
parent_path = os.path.dirname(fpath)
tmpdir_path = os.path.join(parent_path, 'tmp')
copyed_tar_fpath = os.path.join(tmpdir_path, fname)
old_zip_fpath = tmpdir_path + '\\' + fnamef + '.zip'
extractalldir_path = os.path.join(tmpdir_path, fnamef)
new_zip_path = os.path.join(tmpdir_path, fnamef + '_removedPwd.zip')
new_zip_fnamef = os.path.basename(new_zip_path)
removedPwd_fpath = os.path.join(tmpdir_path, new_zip_fnamef + ftype)
new_fpath = os.path.join(parent_path, fnamef + '_removedPwd.' + ftype)
try:
if os.path.exists(tmpdir_path):
os.remove(tmpdir_path)
mkdir(tmpdir_path)
shutil.copyfile(fpath, copyed_tar_fpath)
os.rename(copyed_tar_fpath, old_zip_fpath)
except FileExistsError as e:
raise Exception("文件已存在,无法创建") from e
except Exception as e:
raise Exception("拷贝 pptx 文件错误") from e
# 解压文件
unZip(old_zip_fpath, extractalldir_path)
xmls = filterFiles(extractalldir_path, 'xml')
for xml in xmls:
if('styles' not in xml and 'app' not in xml and 'core' not in xml and 'custom' not in xml):
for kwd in keyNode:
removeNode(xml, xml, kwd)
zipDir(extractalldir_path, new_zip_path) # 重新压缩
try: # 重命名为 pptx,拷贝到原目录
os.rename(new_zip_path, removedPwd_fpath)
shutil.copyfile(removedPwd_fpath, new_fpath)
except Exception as e:
raise Exception("拷贝文件错误") from e
# 删除tmp下所有文件
delDirs(tmpdir_path,root=True)
def removeNode(fpath:str, sfPath, keyNode:str):
"""移除xml节点并且存储
Args:
fpath (str): 源xml路径
sfpath (str): 移除节点后的xml路径
keyNode (str): 要移除节点
"""
try:
tree = etree.parse(fpath)
for child in tree.iter():
if(keyNode in child.tag):
child.getparent().remove(child)
tree.write(sfPath)
break
except Exception as e:
raise Exception("移除节点失败") from e

BIN
src/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 448 KiB

37
src/pdf.py Normal file
View File

@@ -0,0 +1,37 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@文件 :pdf.py
@时间 :2023/07/20 14:01:58
@作者 :aliha
@版本 :1.0
@依赖 :无
@说明 :移除PDF限制密码
'''
import pikepdf
def unlockFile(fpath:str):
"""移除pdf限制编辑并且存储
Args:
fpath (str): 带限制的pdf路径
sfpath (str): 移除限制的pdf路径
Returns:
str: 移除成功的提示话语
"""
try:
pdf = pikepdf.open(fpath, allow_overwriting_input=True)
except Exception as e:
print('打开pdf出错')
try:
sfpath = fpath.rsplit('.',1)[0] +"_removepwd."+ fpath.rsplit('.',1)[1]
pdf.save(sfpath)
except Exception as e:
print('写入pdf失败')
return 'ヾ(≧▽≦*)o 恭喜你,移除成功'

16
src/pic.py Normal file

File diff suppressed because one or more lines are too long

95
src/pptx.py Normal file
View File

@@ -0,0 +1,95 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@文件 :pptx.py
@时间 :2023/07/20 14:00:53
@作者 :aliha
@版本 :1.0
@依赖 :util.py
@说明 :移除PPTX限制密码
'''
from lxml import etree
import shutil
import os
from util import delDirs, filterFiles, unZip, zipDir, mkdir
keyNode = ['modifyVerifier']
def unlockFile(fpath:str):
fname = os.path.basename(fpath)
fnamef, ftype = fname.rsplit(".",1)
parent_path = os.path.dirname(fpath)
tmpdir_path = os.path.join(parent_path, 'tmp')
copyed_tar_fpath = os.path.join(tmpdir_path, fname)
old_zip_fpath = tmpdir_path + '\\' + fnamef + '.zip'
extractalldir_path = os.path.join(tmpdir_path, fnamef)
new_zip_path = os.path.join(tmpdir_path, fnamef + '_removedPwd.zip')
new_zip_fnamef = os.path.basename(new_zip_path)
removedPwd_fpath = os.path.join(tmpdir_path, new_zip_fnamef + ftype)
new_fpath = os.path.join(parent_path, fnamef + '_removedPwd.' + ftype)
try:
if os.path.exists(tmpdir_path):
os.remove(tmpdir_path)
mkdir(tmpdir_path)
shutil.copyfile(fpath, copyed_tar_fpath)
os.rename(copyed_tar_fpath, old_zip_fpath)
except FileExistsError as e:
raise Exception("文件已存在,无法创建") from e
except Exception as e:
raise Exception("拷贝 pptx 文件错误") from e
# 解压文件
unZip(old_zip_fpath, extractalldir_path)
xmls = filterFiles(extractalldir_path, 'xml')
for xml in xmls:
if('Styles' not in xml and 'Props' not in xml and 'theme' not in xml and 'tag' not in xml and 'slide' not in xml):
for kwd in keyNode:
removeNode(xml, xml, kwd)
zipDir(extractalldir_path, new_zip_path) # 重新压缩
try: # 重命名为 pptx,拷贝到原目录
os.rename(new_zip_path, removedPwd_fpath)
shutil.copyfile(removedPwd_fpath, new_fpath)
except Exception as e:
raise Exception("拷贝文件错误") from e
# 删除tmp下所有文件
delDirs(tmpdir_path,root=True)
def removeNode(fpath:str, sfPath, keyNode:str):
"""移除xml节点并且存储
Args:
fpath (str): 源xml路径
sfpath (str): 移除节点后的xml路径
keyNode (str): 要移除节点
"""
try:
tree = etree.parse(fpath)
for child in tree.iter():
if(keyNode in child.tag):
child.getparent().remove(child)
tree.write(sfPath)
break
except Exception as e:
raise Exception("移除节点失败") from e

62
src/readme.py Normal file
View File

@@ -0,0 +1,62 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@文件 :readme.py
@时间 :2023/07/20 14:00:28
@作者 :aliha
@版本 :1.0
@依赖 :无
@说明 :软件的介绍说明
'''
__updateLog = '''
<h4><span style="color:red">V 0.3.1 </span></h4>
<p>更新日期2023-7-21</p>
<p>修复:错误路径导致程序卡死</p>
<hr />
<h4><span style="color:red">V 0.3.0 </span></h4>
<p>更新日期2023-7-20</p>
<p>新增:拖拽文件或者文件夹打开的功能</p>
<p>新增:批量移除限制密码的功能</p>
<p>变更:更改 GUI 框架为 Pyside6 ,更漂亮的 UI</p>
<p>修复:无法重复点击【开始处理】按钮,需要重新打开的 BUG</p>
<hr />
<h4><span style="color:red">V 0.2.1 </span></h4>
<p>更新日期2023-7-17</p>
<p>1. 增加移除限制 pptx 文档编辑的密码</p>
<p>2. 修复 bug :启动软件直接点击【开始】按钮会退出软件</p>
<hr />
<h4><span style="color:red">V 0.2.0 </span></h4>
<p>更新日期2023-7-13</p>
<p>1. 增加移除限制 xlsx 文档编辑的密码,包括工作簿和工作表保护密码</p>
<hr />
<h4><span style="color:red">V 0.1.0 </span></h4>
<p>更新日期2022-10-24</p>
<p>1. 移除限制pdf文档编辑的密码</p>
<hr />
'''
__info = """
<p>批量移除限制编辑密码</p>
<p>移除PDF、xlsx、pptx限制密码输出文件在源路径结果名称带_removepwd</p>
<p>只能移除文档限制编辑的密码解密不了加密文件</p>
"""
info = {
'author': 'aliha',
'version': '0.3.1',
'updateDate': '2023-07-21',
'userWeb': 'https://www.52pojie.cn/home.php?mod=space&uid=1873109',
'info': __info,
'updateLog': __updateLog
}
# <p style="font-size:30px;color:orange">p标签设置字体颜色</p>
# nuitka --enable-plugin=pyside6 --standalone --onefile --remove-output --windows-disable-console --windows-icon-from-ico=icon.ico RemovePwd.py

239
src/removePwd.py Normal file
View File

@@ -0,0 +1,239 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@文件 :removePwd.py
@时间 :2023/07/20 10:42:17
@作者 :aliha
@版本 :1.0
@依赖 :thread.py, styleSheet.py, readme.py, pic.py
@说明 :文档密码移除工具主界面
'''
from PySide6.QtWidgets import QApplication, QLabel, QVBoxLayout, QWidget, QTabWidget, QPushButton, QHBoxLayout, QTextEdit, QTextBrowser, QSizePolicy, QSpacerItem
from PySide6.QtGui import QDragEnterEvent, QDropEvent, QDragMoveEvent, QPixmap, QPainter, QCursor, QCloseEvent, QFont
from PySide6.QtCore import Qt, QByteArray, QThread, Signal
import sys
import base64
import os
from styleSheet import styleSheet
from readme import info
from pic import imgstr
from thread import WorkThread
class FileDropLabel(QLabel):
def __init__(self, parent):
super().__init__(parent)
self.setObjectName("label") # 添加该行
self.setAcceptDrops(True)
self.setAlignment(Qt.AlignCenter)
self.setText("拖拽文件或文件夹到这里")
self.setStyleSheet("QLabel { border: 2px dashed #aaa; padding: 5px; color: #555; }")
def dragEnterEvent(self, event: QDragEnterEvent):
if event.mimeData().hasUrls():
event.acceptProposedAction()
def dragMoveEvent(self, event: QDragMoveEvent):
if event.mimeData().hasUrls():
event.acceptProposedAction()
event.setDropAction(Qt.CopyAction)
pixmap = QPixmap(100, 100)
pixmap.fill(Qt.transparent)
painter = QPainter(pixmap)
painter.setOpacity(0.7)
painter.drawPixmap(0, 0, self.grab())
painter.end()
cursor = QCursor(pixmap)
event.accept()
self.setCursor(cursor)
else:
event.ignore()
def dropEvent(self, event: QDropEvent):
if event.mimeData().hasUrls():
urls = event.mimeData().urls()
file_path = urls[0].toLocalFile()
self.setText("已选择: " + file_path)
self.setCursor(Qt.CursorShape.ArrowCursor)
# 调用MainWindow的方法将选定的文件路径传递过去
main_window = self.window() # 使用 window() 方法获取父级窗口MainWindow
if isinstance(main_window, MainWindow):
main_window.setSelectedFilePath(file_path)
else:
event.ignore()
class ClickableLabel(QLabel):
def __init__(self, text, url=None):
super().__init__()
self.url = url
self.text = text
if self.url is not None:
self.setText(f'<a href="{url}">{text}</a>')
self.setOpenExternalLinks(True) # 打开链接时在外部浏览器中打开
self.setStyleSheet("color: blue; text-decoration: underline;") # 设置颜色和下划线效果
else:
self.setText(f'<p >{text}</>')
font = QFont("Arial", 12, QFont.Bold)
self.setFont(font)
class AboutUsTab(QWidget):
def __init__(self):
super().__init__()
layout = QHBoxLayout(self)
left_layout = QVBoxLayout()
# Create labels for displaying software information
author_label = ClickableLabel("作者信息:\t{}".format(info['author']),info['userWeb'])
version_label = ClickableLabel("软件版本信息:\t{}".format(info['version']))
update_label = ClickableLabel("更新日期:\t{}".format(info['updateDate']))
# Create a layout for the QR code
qr_code_layout = QHBoxLayout()
qr_code_label = QLabel(self)
png = self.base64ToByte()
qr_code_image = QPixmap()
qr_code_image.loadFromData(png)
# qr_code_image = QPixmap("QR.png")
qr_code_image = qr_code_image.scaled(250, 250, Qt.KeepAspectRatio)
qr_code_label.setPixmap(qr_code_image)
qr_code_layout.addWidget(qr_code_label)
left_layout.addWidget(author_label)
left_layout.addWidget(version_label)
left_layout.addWidget(update_label)
left_layout.addLayout(qr_code_layout)
left_layout.addStretch()
funcInfo_label = QTextBrowser(self)
funcInfo_label.setOpenExternalLinks(True)
funcInfo_label.setLineWrapMode(QTextBrowser.WidgetWidth)
func_info_html = """
<h3>功能简介:</h3>
{}
<h3>更新日志</h3>
{}
""".format(info['info'],info['updateLog'])
funcInfo_label.setHtml(func_info_html)
layout.addLayout(left_layout)
layout.addWidget(funcInfo_label)
self.setLayout(layout)
def base64ToByte(self):
# Step 1: Decode the base64 data to obtain the raw image data
decoded_data = base64.b64decode(imgstr)
# Step 2: Create a QByteArray from the decoded image data
byte_array = QByteArray(decoded_data)
# Step 3: Load the image data into a QPixmap
# pixmap = QPixmap()
# pixmap.loadFromData(byte_array)
return byte_array
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("文档密码移除工具")
self.resize(600, 280)
self.thread = None
self.selected_file_path = None
# def rendererWindow(self):
layout = QVBoxLayout(self)
tab_widget = QTabWidget(self)
# Tab 1: Password Removal
tab1 = QWidget(self)
tab1_layout = QVBoxLayout(tab1)
label = FileDropLabel(tab1)
tab1_layout.addWidget(label)
self.progress_output = QTextEdit(tab1)
self.progress_output.setReadOnly(True)
tab1_layout.addWidget(self.progress_output)
self.button = QPushButton("开始处理", tab1)
self.button.clicked.connect(self.startWorkerThread)
tab1_layout.addWidget(self.button)
tab1.setLayout(tab1_layout)
tab_widget.addTab(tab1, "限制密码移除")
# Tab 2: Software Settings
tab2 = QWidget(self)
tab_widget.addTab(tab2, "批量加密解密")
tab2_layout = QVBoxLayout(tab2)
development_label = QLabel("正在开发中,请耐心等待", tab2)
development_label.setAlignment(Qt.AlignCenter)
tab2_layout.addWidget(development_label)
tab2.setLayout(tab2_layout)
# Create the third tab (About Us)
tab3 = AboutUsTab()
tab_widget.addTab(tab3, "关于我们")
layout.addWidget(tab_widget)
self.setStyleSheet(styleSheet)
layout.setContentsMargins(0, 1, 0, 0)
self.setLayout(layout)
def closeEvent(self, event: QCloseEvent) -> None:
return super().closeEvent(event)
def startWorkerThread(self):
if self.selected_file_path is not None:
if os.path.isdir(self.selected_file_path) or os.path.isfile(self.selected_file_path):
self.worker = WorkThread()
self.thread = QThread()
self.worker.moveToThread(self.thread)
self.worker.setFilePath(self.selected_file_path)
self.worker.progressSignal.connect(self.updateProgressBar)
self.thread.started.connect(self.progress_output.clear)
self.thread.started.connect(self.worker.work)
self.thread.finished.connect(self.thread.quit)
self.thread.finished.connect(self.unlockStartButtom)
self.thread.finished.connect(self.thread.deleteLater)
self.thread.start()
self.button.setEnabled(False)
self.button.setStyleSheet('background-color: #e0e0e0;')
label = self.findChild(FileDropLabel, "label")
if label:
label.setEnabled(False)
else:
self.progress_output.clear()
self.progress_output.append('请输入正确的路径')
def unlockStartButtom(self):
self.button.setEnabled(True)
self.button.setStyleSheet('background-color: #4caf50;')
label = self.findChild(FileDropLabel, "label")
if label:
label.setEnabled(True)
def setSelectedFilePath(self, file_path):
self.selected_file_path = file_path
def updateProgressBar(self, value):
self.progress_output.append(value)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MainWindow()
# window.rendererWindow()
window.show()
sys.exit(app.exec())

BIN
src/requirements.txt Normal file

Binary file not shown.

56
src/styleSheet.py Normal file
View File

@@ -0,0 +1,56 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@文件 :styleSheet.py
@时间 :2023/07/20 14:00:10
@作者 :aliha
@版本 :1.0
@依赖 :无
@说明 :窗口的样式文件
'''
styleSheet = """
QPushButton {
background-color: #4caf50;
color: white;
padding: 10px;
border: none;
border-radius: 5px;
}
QPushButton:hover {
background-color: #45a049;
}
QPushButton:pressed {
background-color: #2980b9;
}
QTextEdit {
background-color: #fff;
border: 2px solid #aaa;
padding: 5px;
font-family: Arial, sans-serif;
font-size: 14px;
color: #333;
}
QTabWidget::pane {
border: 1px solid #aaa;
background-color: #f0f0f0;
padding: 0px;
}
QTabBar::tab {
background-color: #4caf50;
color: white;
padding: 8px;
border: none;
font-family: Arial, sans-serif;
font-size: 14px;
font-weight: bold;
}
QTabBar::tab:hover {
background-color: #45a049;
}
QTabBar::tab:selected {
background-color: #fff;
color: #4caf50;
}
"""

97
src/thread.py Normal file
View File

@@ -0,0 +1,97 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@文件 :thread.py
@时间 :2023/07/20 10:41:04
@作者 :aliha
@版本 :1.0
@依赖 :excel.py, pdf.py, pptx.py
@说明 :移除密码的多线程处理
'''
from PySide6.QtCore import QObject, QThread, Signal
from pdf import unlockFile as pdfUnlock
from excel import unlockFile as xlsxUnlock
from pptx import unlockFile as pptxUnlock
import time
import os
class WorkThread(QObject):
count = (0)
# countSignal = Signal(int)
progressSignal = Signal(str)
tipsSignal = Signal(str)
def __init__(self):
super(WorkThread, self).__init__()
self.file_path = None
def setFilePath(self, file_path):
self.file_path = file_path
# def work(self):
# self.flag = True
# while self.flag:
# self.count += 1
# self.progressSignal.emit(self.count)
# time.sleep(0.1)
# if(self.count == 100):
# QThread.currentThread().quit()
# break
def work(self):
if os.path.isfile(self.file_path ):
self.progressSignal.emit('#=>[1/1]: {}'.format(self.file_path))
self.unlockFile(self.file_path)
if os.path.isdir(self.file_path ):
file_lists = os.listdir(self.file_path)
for file in file_lists:
self.count += 1
child_path = os.path.join(self.file_path, file)
try:
self.unlockFile(child_path)
except Exception as e:
self.progressSignal.emit('捕获到异常信息: {}'.format(e))
self.progressSignal.emit('#=>[{}/{}]: {}'.format(self.count, len(file_lists), file))
self.progressSignal.emit('ヾ(≧▽≦*)o 恭喜你,移除成功 \r\n 解密的文件保存在原目录下哦名称带“removedPwd')
QThread.currentThread().quit()
def unlockFile(self, file):
try:
if('xlsx' in os.path.basename(file)):
xlsxUnlock(file)
if('pdf' in os.path.basename(file)):
pdfUnlock(file)
if('pptx' in os.path.basename(file)):
pptxUnlock(file)
except Exception as e:
raise Exception("程序错误,请联系作者") from e
# 上述代码的启动方式如下:
# class main():
# def runIt(self):
# self.worker = WorkThread()
# self.thread = QThread()
# self.worker.moveToThread(self.thread)
# self.worker.countSignal.connect(self.flush)
# self.thread.started.connect(self.worker.work)
# self.finished.connect(self.worker.quit)
# self.finished.connect(self.worker.deleteLater)
# self.thread.start()
# def flush(self):
# print('flush ing')

113
src/util.py Normal file
View File

@@ -0,0 +1,113 @@
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@文件 :util.py
@时间 :2023/07/20 13:59:26
@作者 :aliha
@版本 :1.0
@依赖 :无
@说明 :常用的文件处理的工具函数抽取到了这里
'''
import shutil
import os
import zipfile
def delDirs(dirpath:str, root=False):
"""删除路径文件下所有的文件root=true 时包括根文件夹
Args:
dirpath (str): 文件夹路径
root (boolean): 是否删除根目录
"""
try:
filelists = os.listdir(dirpath) # 获取目录下所有文件列表
for mydir in filelists: # 遍历文件列表
filepath = os.path.join(dirpath, mydir) # 将文件名进行拼接
if os.path.isfile(filepath): # 判断该文件是否为文件
os.remove(filepath) # 若为文件,则直接删除
elif os.path.isdir(filepath): # 判断该文件是否为文件夹
shutil.rmtree(filepath, True) # 若为文件夹,则删除该文件夹及文件夹内所有文件
if(root):
shutil.rmtree(dirpath, True) # 最后删除根文件夹
except Exception as e:
print('删除缓存文件失败')
def filterFiles(folder_path:str, file_extension:str):
"""获取指定路径下,符合扩展名条件的文件路径
Args:
folder_path (str): 根目录
file_extension (str): 扩展名
Returns:
_type_: 查找结果组成的数组
"""
files = []
def filter(folder:str, extension:str):
try:
file_lists = os.listdir(folder)
for child in file_lists:
child_path = os.path.join(folder, child)
if(os.path.isfile(child_path)):
frname, ftype = os.path.basename(child_path).rsplit('.',1)
if(extension in ftype):
files.append(child_path)
continue
elif(os.path.isdir(child_path)):
filter(child_path, extension)
except Exception as e:
print('遍历文件错误')
raise e
filter(folder_path, file_extension)
return files
def unZip(zip_file:str, extractall_path:str):
"""解压缩zip文件
Args:
zip_file (str): zip文件路径
extractall_path (str): 解压路径
"""
try:
if(zipfile.is_zipfile(zip_file)):
zin = zipfile.ZipFile(zip_file, 'r') # 以只读方式打开压缩包
zin.extractall(path=extractall_path)
zin.close()
except Exception as e:
print('解压失败')
raise e
def zipDir(dirpath:str, outFullName:str):
"""
压缩指定文件夹
:param dirpath: 目标文件夹路径
:param outFullName: 压缩文件保存路径+xxxx.zip
:return: 无
"""
zip = zipfile.ZipFile(outFullName, "w", zipfile.ZIP_DEFLATED)
for path, dirnames, filenames in os.walk(dirpath):
# 去掉目标跟路径,只对目标文件夹下边的文件及文件夹进行压缩
fpath = path.replace(dirpath, '')
for filename in filenames:
zip.write(os.path.join(path, filename), os.path.join(fpath, filename))
zip.close()
def mkdir(dirpath:str):
try:
if( not os.path.exists(dirpath)):
os.makedirs(dirpath)
except Exception as e:
print('创建缓存文件错误')