# main.pyw
import sys
from designer.designer import Ui_Form
from PyQt5.QtWidgets import QApplication,QMainWindow
if __name__ == '__main__':
app = QApplication(sys.argv)
ui_components = Ui_Form()
ui_components.init_component()
ui_components.show()
sys.exit(app.exec_())
# ./designer/designer.py
from PyQt5 import QtCore,QtGui,QtWidgets
from PyQt5.QtGui import QKeySequence
from PyQt5.QtWidgets import QWidget,QShortcut,QGridLayout,QFrame,QPushButton,QLabel
from .PdfFunction import PdfQueue,PdfInfo
from PIL.ImageQt import toqpixmap
class Ui_Form(QWidget):
def __init__(self):
QWidget.__init__(self)
self.pdf_queue: PdfQueue=None
self.lastpdfinfo: PdfInfo=None
self.curpdfinfo: PdfInfo=None
def init_component(self):
# self.resize(640,480)
# 用来显示图片的label
self.lbl_pic=MyLabel(self)
self.lbl_pic.setMinimumSize(800,800)
# 用来显示当前文件名称的label
self.lbl_curfile=QtWidgets.QLabel()
# 用来显示上一个文件名称的label
self.lbl_lastfile=QtWidgets.QLabel()
# 文本框
self.lnedt_rename=QtWidgets.QLineEdit()
self.lnedt_rename.setMinimumSize(300,150)
self.lnedt_rename.setMaximumSize(300,150)
# 上一个按钮
self.btn_last=QtWidgets.QPushButton()
self.btn_last.setMinimumHeight(100)
# 下一个按钮
self.btn_next=QtWidgets.QPushButton()
self.btn_next.setMinimumHeight(100)
# 全图显示按钮
self.btn_full=QtWidgets.QPushButton()
self.btn_full.setMinimumHeight(100)
# 旋转按钮
self.btn_rotate=QtWidgets.QPushButton()
self.btn_rotate.setMinimumHeight(100)
self.btn_last.setStyleSheet('QPushButton{background:#dddddd}')
self.btn_next.setStyleSheet('QPushButton{background:#dddddd}')
self.btn_full.setStyleSheet('QPushButton{background:#dddddd}')
self.btn_rotate.setStyleSheet('QPushButton{background:#dddddd}')
QShortcut(QKeySequence("Up"),self).activated.connect(self.btn_last.click)
QShortcut(QKeySequence("Down"),self).activated.connect(self.btn_next.click)
QShortcut(QKeySequence("Ctrl+F"),self).activated.connect(self.btn_full.click)
QShortcut(QKeySequence("Ctrl+R"),self).activated.connect(self.btn_rotate.click)
grid_layout=QGridLayout(self)
grid_layout.setSpacing(5)
grid_layout.addWidget(self.lbl_pic,0,0,7,1)
grid_layout.addWidget(self.btn_last,0,1)
grid_layout.addWidget(self.btn_next,1,1)
grid_layout.addWidget(self.btn_rotate,2,1)
grid_layout.addWidget(self.btn_full,3,1)
grid_layout.addWidget(self.lbl_lastfile,4,1)
grid_layout.addWidget(self.lbl_curfile,5,1)
grid_layout.addWidget(self.lnedt_rename,6,1)
for lbl in self.findChildren(QLabel):
lbl.setFrameShape(QFrame.Box)
lbl.setFrameShadow(QFrame.Raised)
for btn in self.findChildren(QPushButton):
btn.setEnabled(False)
self.lnedt_rename.setEnabled(False)
self.AddMyEvent()
self.retranslateUi(self)
QtCore.QMetaObject.connectSlotsByName(self)
def AddMyEvent(self):
self.btn_last.clicked.connect(self.goto_last)
self.btn_next.clicked.connect(self.goto_next)
self.btn_rotate.clicked.connect(self.rotate_pic)
self.btn_full.clicked.connect(self.full_pic)
self.lnedt_rename.returnPressed.connect(self.rename_pdffile)
def pdf_queue_init(self):
for btn in self.findChildren(QPushButton):
btn.setEnabled(True)
self.btn_last.setEnabled(False)
self.lnedt_rename.setEnabled(True)
self.goto_next()
def rename_pdffile(self):
pdfinfo=self.pdf_queue.read_now()
string=self.lnedt_rename.text()
if string!='':
pdfinfo.rename(string)
def goto_next(self):
self.btn_next.setEnabled(False)
self.lastpdfinfo=self.pdf_queue.read_now() # 当index==-1时,返回None
self.curpdfinfo=self.pdf_queue.read_next()
self.set_change()
self.btn_next.setEnabled(True)
def goto_last(self):
self.btn_last.setEnabled(False)
self.lastpdfinfo=self.pdf_queue.read_now() # 当index==-1时,返回None
self.curpdfinfo=self.pdf_queue.read_last()
self.set_change()
self.btn_last.setEnabled(True)
def set_change(self):
if self.lastpdfinfo:
self.lbl_lastfile.setText('上一个:'+self.lastpdfinfo.file_name)
if self.curpdfinfo:
self.lbl_curfile.setText('当 前:'+self.curpdfinfo.file_name)
self.setWindowTitle(self.curpdfinfo.file_path)
self.set_pic()
if self.pdf_queue.has_last():
self.btn_last.setEnabled(True)
self.btn_last.setStyleSheet('QPushButton{background:#dddddd}')
else:
self.btn_last.setEnabled(False)
self.btn_last.setStyleSheet('QPushButton{background:#444444}')
if self.pdf_queue.has_next():
self.btn_next.setEnabled(True)
self.btn_next.setStyleSheet('QPushButton{background:#dddddd}')
else:
self.btn_next.setEnabled(False)
self.btn_next.setStyleSheet('QPushButton{background:#444444}')
self.lnedt_rename.setText('')
def full_pic(self):
self.btn_full.setEnabled(False)
self.pdf_queue.read_now().tick_full()
self.btn_full.setEnabled(True)
def rotate_pic(self):
self.btn_rotate.setEnabled(False)
self.pdf_queue.read_now().rotate_clockwise_90()
self.btn_rotate.setEnabled(True)
def set_pic(self):
self.lbl_pic.setPixmap(toqpixmap(self.curpdfinfo.get_image()))
def retranslateUi(self,Form):
_translate=QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form","Form"))
self.btn_rotate.setText(_translate("Form","旋转&Ctrl+R"))
self.btn_full.setText(_translate("Form","全图&Ctrl+F"))
self.btn_next.setText(_translate("Form","下一个&Down"))
self.btn_last.setText(_translate("Form","上一个&Up"))
class MyLabel(QtWidgets.QLabel):
def __init__(self,parent: Ui_Form):
super(MyLabel,self).__init__()
self.setAcceptDrops(True)
self.setScaledContents(True)
self.parent=parent
def dragEnterEvent(self,a0: QtGui.QDragEnterEvent) -> None:
if a0.mimeData().hasText():
a0.accept()
else:
a0.ignore()
def dropEvent(self,a0: QtGui.QDropEvent) -> None:
# 如果触发事件的文本资源以‘file:’开头,那么进行一下逻辑
# 将字符串中的'%23'替换成'#'
# 将'file:///'前缀(本地)和'file:'前缀(局域网)消除掉
text=a0.mimeData().text()
if text.startswith('file:'):
if text.find('\n')==-1:
text+='\n'
lines=text.split('\n')[:-1]
lines=[string.replace('%23','#') for string in lines]
lines=[string[5:] if string[7]!='/' else string[8:] for string in lines]
# 仅接受PDF
lines=[string for string in lines if string.lower().endswith('.pdf')]
if lines:
self.parent.pdf_queue=PdfQueue(lines,self.parent)
self.parent.pdf_queue.initilized.emit()
# ./designer/PdfFunction.py
import os
import fitz
from PIL import Image
from PyQt5.QtCore import pyqtSignal,QObject
def page2PIL_Image(page: fitz.Page,dpi=150,colorspace=fitz.csGRAY,clip=None,alpha=False,annots=False):
pixmap=page.get_pixmap(
matrix=fitz.IdentityMatrix,
dpi=dpi,
colorspace=colorspace,
clip=clip,
alpha=alpha,
annots=annots
)
return Image.frombuffer('L',(pixmap.width,pixmap.height),pixmap.samples)
def pdf2image(file_path,rotation,full_output):
w_clip=420
h_clip=630
try:
with fitz.open(file_path) as doc:
x0=doc[0].cropbox.x0
y0=doc[0].cropbox.y0
x1=doc[0].cropbox.x1
y1=doc[0].cropbox.y1
w,h=x1-x0,y1-y0
if rotation==90 or rotation==270:
w,h=h,w
doc[0].set_rotation(rotation)
if full_output:
return page2PIL_Image(doc[0])
return page2PIL_Image(
doc[0],clip=fitz.IRect(w-w_clip,h-h_clip,w-40,h-40))
except Exception as e:
print('pdf2image',e)
class PdfInfo(QObject):
current_name=['','','']
renameSignal=pyqtSignal()
rotateSignal=pyqtSignal()
fullSignal=pyqtSignal()
def __init__(self,file_path,parent):
QObject.__init__(self)
self.parent=parent
self.file_path=file_path
self.parent_path=os.path.dirname(self.file_path)
self.file_name=os.path.basename(self.file_path)
self.file_name_used_before=''
self.building=''
self.specility=''
self.number=''
self.rotation=0
with fitz.open(self.file_path) as doc:
x0=doc[0].cropbox.x0
y0=doc[0].cropbox.y0
x1=doc[0].cropbox.x1
y1=doc[0].cropbox.y1
w,h=x1-x0,y1-y0
if w<h:
self.rotation=90
self.is_full=False
self.renameSignal.connect(self.parent.goto_next)
self.rotateSignal.connect(self.parent.set_pic)
self.fullSignal.connect(self.parent.set_pic)
def rotate_clockwise_90(self):
self.rotation+=90
self.rotateSignal.emit()
def tick_full(self):
self.is_full = not self.is_full
self.fullSignal.emit()
def get_image(self):
return pdf2image(self.file_path,self.rotation,self.is_full)
@staticmethod
def Parse(string):
array=string.split(' ') # 参数用空格和不用参数,会有细微的差别,不用参数会忽略开的的空格
alen=len(array)
if array[0]=='':
PdfInfo.current_name[1]=array[1]
PdfInfo.current_name[2]=array[2]
else:
if alen==3:
PdfInfo.current_name=array
elif alen==2:
PdfInfo.current_name[0]=array[0]
PdfInfo.current_name[2]=array[1]
elif alen==1:
PdfInfo.current_name[2]=string
else:
return None
return PdfInfo.current_name
def rename(self,string):
# 得到了一个文档名三元祖
res=PdfInfo.Parse(string)
if res:
self.building,self.specility,self.number=res
# 如果res存在,就拼接一下
res_txt=''.join(res)
# 临时存放文件名的变量
name_new=res_txt+'.pdf'
# 如果该文件已存在,就在后面加上数字后缀
if self.file_path.replace('\\','/') != os.path.join(self.parent_path,name_new).replace('\\','/'):
if os.path.isfile(os.path.join(self.parent_path,name_new)):
count=2
name_new=f'{res_txt} ({count}).pdf'
while os.path.isfile(os.path.join(self.parent_path,name_new)):
count+=1
name_new=f'{res_txt} ({count}).pdf'
self.number=f'{self.number} ({count})'
self.file_name_used_before=self.file_name
self.file_name=name_new
os.rename(self.file_path,os.path.join(self.parent_path,self.file_name))
self.file_path=os.path.join(self.parent_path,name_new)
self.renameSignal.emit()
class PdfQueue(QObject):
initilized=pyqtSignal()
indexChanged=pyqtSignal()
def __init__(self,pdffiles,parent):
QObject.__init__(self)
self.parent=parent
self.initilized.connect(self.parent.pdf_queue_init)
self.indexChanged.connect(self.parent.set_change)
self.pdfObjects=[PdfInfo(f,self.parent) for f in pdffiles]
for pdfinfo in self.pdfObjects:
pdfinfo.renameSignal.connect(self.parent.goto_next)
self.index=-1
def has_next(self):
return self.index+1<len(self.pdfObjects)
def has_last(self):
return self.index>0
def read_next(self):
if self.has_next():
self.index+=1
self.indexChanged.emit()
return self.pdfObjects[self.index]
def read_last(self):
if self.has_last():
self.index-=1
self.indexChanged.emit()
return self.pdfObjects[self.index]
def read_now(self):
if self.index>-1:
return self.pdfObjects[self.index]