把这几张图片写入代码"""
图片批量处理器 - 单文件整合版(PyQt6)
功能:批量添加文字/图片水印、批量重命名(大写/小写/编号)
依赖:pip install PyQt6 Pillow
"""
import os
import sys
from PyQt6 import QtCore, QtGui, QtWidgets
from PyQt6.QtWidgets import QApplication, QMainWindow, QMessageBox, QFileDialog, QFontDialog
from PIL import Image, ImageDraw, ImageFont, ImageEnhance
class ImageProcessorApp(QMainWindow):
def __init__(self):
super().__init__()
self.setup_ui()
self.init_values()
def init_values(self):
self.img_path = ""
self.waterimg = ""
self.dir_path = ""
self.waterfont = None
self.fontInfo = None
self.fontSize = None
def setup_ui(self):
# 主窗口设置
self.resize(800, 600)
self.setFixedSize(800, 600)
self.setWindowTitle("图片批量处理器")
# 菜单栏
self.menubar = QtWidgets.QMenuBar(self)
self.menu = QtWidgets.QMenu("主菜单", self.menubar)
self.menu_2 = QtWidgets.QMenu("关于", self.menubar)
self.actionMark = QtGui.QAction("添加水印", self)
self.actionMark.setIcon(QtGui.QIcon("img/mark.ico"))
self.actionRename = QtGui.QAction("批量重命名", self)
self.actionRename.setIcon(QtGui.QIcon("img/rename.ico"))
self.actionAbout = QtGui.QAction("关于本软件", self)
self.actionAbout.setIcon(QtGui.QIcon("img/about.ico"))
self.menu.addAction(self.actionMark)
self.menu.addAction(self.actionRename)
self.menubar.addAction(self.menu.menuAction())
self.menu_2.addAction(self.actionAbout)
self.menubar.addAction(self.menu_2.menuAction())
self.setMenuBar(self.menubar)
# 状态栏
self.statusbar = QtWidgets.QStatusBar()
self.statusbar.showMessage("准备就绪......")
self.setStatusBar(self.statusbar)
# 背景图(可选)
palette = self.palette()
try:
pixmap = QtGui.QPixmap("img/back.png")
scaled = pixmap.scaled(self.size(), QtCore.Qt.AspectRatioMode.IgnoreAspectRatio,
QtCore.Qt.TransformationMode.SmoothTransformation)
palette.setBrush(QtGui.QPalette.ColorRole.Window, QtGui.QBrush(scaled))
self.setPalette(palette)
self.setAutoFillBackground(True)
except:
pass # 忽略背景图不存在的情况
# 绑定菜单事件
self.actionMark.triggered.connect(self.open_mark_window)
self.actionRename.triggered.connect(self.open_rename_window)
self.actionAbout.triggered.connect(self.about_software)
# 子窗口引用
self.mark_window = None
self.rename_window = None
def open_mark_window(self):
self.mark_window = MarkWindow()
self.mark_window.show()
def open_rename_window(self):
self.rename_window = RenameWindow()
self.rename_window.show()
def about_software(self):
QMessageBox.information(None, "关于本软件",
"图片批量处理器是一款提供日常工作的工具软件,通过该软件,您可以方便地为图片添加文字水印和图片水印,"
"而且可以自定义添加位置,以及透明度;另外,您还可以通过该软件对图片文件进行重命名,"
"支持文件名大写、小写,以及根据自定义模板对图片文件进行编号。",
QMessageBox.StandardButton.Ok)
class MarkWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setup_ui()
self.init_ui_elements()
def setup_ui(self):
self.resize(600, 500)
self.setWindowTitle("批量添加水印")
# 图片列表
self.listWidget = QtWidgets.QListWidget(self)
self.listWidget.setGeometry(QtCore.QRect(0, 0, 141, 391))
self.pushButton = QtWidgets.QPushButton("加载图片", self)
self.pushButton.setGeometry(QtCore.QRect(150, 0, 75, 23))
self.pushButton.clicked.connect(self.get_files)
# 水印设置组
self.groupBox = QtWidgets.QGroupBox("水印设置", self)
self.groupBox.setGeometry(QtCore.QRect(150, 30, 421, 151))
self.radioButton = QtWidgets.QRadioButton("添加文字水印", self.groupBox)
self.radioButton.setGeometry(QtCore.QRect(20, 20, 101, 16))
self.radioButton.setChecked(True)
self.lineEdit = QtWidgets.QLineEdit(self.groupBox)
self.lineEdit.setGeometry(QtCore.QRect(90, 50, 241, 20))
self.lineEdit.setPlaceholderText("请输入水印文字")
self.pushButton_2 = QtWidgets.QPushButton("字体设置", self.groupBox)
self.pushButton_2.setGeometry(QtCore.QRect(340, 50, 75, 23))
self.pushButton_2.clicked.connect(self.set_font)
self.radioButton_2 = QtWidgets.QRadioButton("添加图片水印", self.groupBox)
self.radioButton_2.setGeometry(QtCore.QRect(20, 80, 91, 16))
self.lineEdit_2 = QtWidgets.QLineEdit(self.groupBox)
self.lineEdit_2.setGeometry(QtCore.QRect(90, 110, 241, 20))
self.pushButton_3 = QtWidgets.QPushButton("浏览", self.groupBox)
self.pushButton_3.setGeometry(QtCore.QRect(340, 110, 75, 23))
self.pushButton_3.clicked.connect(self.set_img)
# 透明度与位置
self.groupBox_2 = QtWidgets.QGroupBox("透明度及位置设置", self)
self.groupBox_2.setGeometry(QtCore.QRect(150, 190, 421, 71))
self.horizontalSlider = QtWidgets.QSlider(QtCore.Qt.Orientation.Horizontal, self.groupBox_2)
self.horizontalSlider.setGeometry(QtCore.QRect(70, 30, 181, 22))
self.horizontalSlider.setMinimum(1)
self.horizontalSlider.setMaximum(10)
self.comboBox = QtWidgets.QComboBox(self.groupBox_2)
self.comboBox.setGeometry(QtCore.QRect(330, 30, 71, 22))
for pos in ["左上角", "右上角", "左下角", "右下角", "居中位置"]:
self.comboBox.addItem(pos)
self.comboBox.setCurrentIndex(0)
# 保存路径
self.groupBox_3 = QtWidgets.QGroupBox("路径设置", self)
self.groupBox_3.setGeometry(QtCore.QRect(150, 270, 421, 71))
self.lineEdit_3 = QtWidgets.QLineEdit(self.groupBox_3)
self.lineEdit_3.setGeometry(QtCore.QRect(80, 30, 241, 20))
self.pushButton_4 = QtWidgets.QPushButton("浏览", self.groupBox_3)
self.pushButton_4.setGeometry(QtCore.QRect(330, 30, 75, 23))
self.pushButton_4.clicked.connect(self.msg)
# 执行按钮
self.pushButton_5 = QtWidgets.QPushButton("执行", self)
self.pushButton_5.setGeometry(QtCore.QRect(480, 350, 75, 23))
self.pushButton_5.clicked.connect(self.add_mark)
# 状态栏
self.statusBar = QtWidgets.QStatusBar()
self.statusBar.showMessage("准备就绪......")
self.setStatusBar(self.statusBar)
def init_ui_elements(self):
self.img_path = ""
self.list = []
self.waterfont = None
self.fontInfo = None
self.fontSize = None
def isImg(self, ext):
return ext.lower() in ['.png', '.jpg', '.jpeg', '.bmp', '.gif']
def get_files(self):
dir_path = QFileDialog.getExistingDirectory(None, "选择图片文件夹路径", os.getcwd())
if not dir_path:
return
self.img_path = dir_path
self.listWidget.clear()
num = 0
files = os.listdir(self.img_path)
for f in files:
fp = os.path.join(self.img_path, f)
if os.path.isfile(fp) and self.isImg(os.path.splitext(fp)[1]):
num += 1
item = QtWidgets.QListWidgetItem(f)
self.listWidget.addItem(item)
self.statusBar.showMessage(f"共有图片{num}张")
self.listWidget.itemClicked.connect(self.preview_image)
def preview_image(self, item):
os.startfile(os.path.join(self.img_path, item.text()))
def set_font(self):
font, ok = QFontDialog.getFont()
if ok:
self.waterfont = font
self.lineEdit.setFont(font)
self.fontSize = QtGui.QFontMetrics(font)
self.fontInfo = QtGui.QFontInfo(font)
def set_img(self):
path, _ = QFileDialog.getOpenFileName(None, "选择水印图片", "C:\\", "图片文件(*.jpeg;*.png;*.jpg;*.bmp)")
if path:
self.lineEdit_2.setText(path)
def msg(self):
path = QFileDialog.getExistingDirectory(None, "选择保存路径", os.getcwd())
if path:
self.lineEdit_3.setText(path)
def textMark(self, img, newImgPath):
try:
im = Image.open(img).convert('RGBA')
newImg = Image.new('RGBA', im.size, (255, 255, 255, 0))
font_size = self.fontInfo.pointSize() if self.fontInfo else 20
try:
font = ImageFont.truetype("simkai.ttf", font_size)
except:
font = ImageFont.load_default()
draw = ImageDraw.Draw(newImg)
w, h = im.size
txt = self.lineEdit.text()
txt_w = self.fontSize.boundingRect(txt).width() * 1.5 if self.fontSize else 10 * len(txt)
txt_h = self.fontSize.height() if self.fontSize else 20
pos_text = self.comboBox.currentText()
position = {
"左上角": (0, 0),
"右上角": (w - txt_w, 0),
"左下角": (0, h - txt_h),
"右下角": (w - txt_w, h - txt_h),
"居中位置": (w // 2, h // 2)
}.get(pos_text, (0, 0))
draw.text(position, txt, font=font, fill="#FCA454")
alpha = newImg.split()[3]
alpha = ImageEnhance.Brightness(alpha).enhance(self.horizontalSlider.value() / 10.0)
newImg.putalpha(alpha)
result = Image.alpha_composite(im, newImg)
result.save(newImgPath, "PNG")
except Exception as e:
print(e)
QMessageBox.warning(None, "错误", "图片格式有误,请重新选择...", QMessageBox.StandardButton.Ok)
def imgMark(self, img, newImgPath):
try:
im = Image.open(img).convert("RGBA")
mark = Image.open(self.lineEdit_2.text()).convert("RGBA")
w, h = im.size
mw, mh = mark.size
scale = max(w / (10 * mw), h / (10 * mh))
new_size = (int(mw * scale), int(mh * scale))
mark = mark.resize(new_size, Image.Resampling.LANCZOS)
mw, mh = mark.size
pos_text = self.comboBox.currentText()
px, py = {
"左上角": (0, 0),
"右上角": (w - mw, 0),
"左下角": (0, h - mh),
"右下角": (w - mw, h - mh),
"居中位置": ((w - mw) // 2, (h - mh) // 2)
}.get(pos_text, (0, 0))
alpha = mark.split()[3]
alpha = ImageEnhance.Brightness(alpha).enhance(self.horizontalSlider.value() / 10.0)
mark.putalpha(alpha)
im.paste(mark, (px, py), mark)
im.save(newImgPath)
except Exception as e:
print(e)
QMessageBox.warning(None, "错误", "请选择有效的水印图片...", QMessageBox.StandardButton.Ok)
def add_mark(self):
save_dir = self.lineEdit_3.text()
if not save_dir:
QMessageBox.warning(None, "警告", "请选择保存路径", QMessageBox.StandardButton.Ok)
return
if not os.path.exists(save_dir):
os.makedirs(save_dir)
num = 0
for i in range(self.listWidget.count()):
item = self.listWidget.item(i)
src = os.path.join(self.img_path, item.text())
dst = os.path.join(save_dir, item.text())
if self.radioButton.isChecked():
if not self.lineEdit.text().strip():
QMessageBox.warning(None, "警告", "请输入水印文字", QMessageBox.StandardButton.Ok)
return
self.textMark(src, dst)
elif self.radioButton_2.isChecked():
if not self.lineEdit_2.text().strip():
QMessageBox.warning(None, "警告", "请选择水印图片", QMessageBox.StandardButton.Ok)
return
self.imgMark(src, dst)
num += 1
self.statusBar.showMessage(f"任务完成,此次共处理 {num} 张图片")
class RenameWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setup_ui()
self.init_values()
def setup_ui(self):
self.resize(600, 500)
self.setWindowTitle("批量重命名")
self.groupBox = QtWidgets.QGroupBox("重命名设置", self)
self.groupBox.setGeometry(QtCore.QRect(10, 10, 491, 141))
self.radioButton = QtWidgets.QRadioButton("文件名大写", self.groupBox)
self.radioButton.setGeometry(QtCore.QRect(20, 30, 89, 16))
self.radioButton.setChecked(True)
self.radioButton_2 = QtWidgets.QRadioButton("文件名小写", self.groupBox)
self.radioButton_2.setGeometry(QtCore.QRect(130, 30, 89, 16))
self.radioButton_3 = QtWidgets.QRadioButton("文件名编号", self.groupBox)
self.radioButton_3.setGeometry(QtCore.QRect(20, 60, 89, 16))
self.comboBox = QtWidgets.QComboBox(self.groupBox)
self.comboBox.setGeometry(QtCore.QRect(90, 90, 101, 22))
self.comboBox.addItems(["img_***", "fil_***", "pic_***"])
self.comboBox.setCurrentIndex(0)
self.lineEdit_2 = QtWidgets.QLineEdit("1", self.groupBox)
self.lineEdit_2.setGeometry(QtCore.QRect(280, 90, 61, 21))
self.lineEdit_3 = QtWidgets.QLineEdit("1", self.groupBox)
self.lineEdit_3.setGeometry(QtCore.QRect(420, 90, 61, 21))
self.groupBox_2 = QtWidgets.QGroupBox("图片设置", self)
self.groupBox_2.setGeometry(QtCore.QRect(10, 160, 491, 51))
self.lineEdit_4 = QtWidgets.QLineEdit(self.groupBox_2)
self.lineEdit_4.setGeometry(QtCore.QRect(110, 20, 201, 21))
self.pushButton = QtWidgets.QPushButton("选择", self.groupBox_2)
self.pushButton.setGeometry(QtCore.QRect(320, 20, 75, 23))
self.pushButton.clicked.connect(self.get_files)
self.pushButton_2 = QtWidgets.QPushButton("重命名", self.groupBox_2)
self.pushButton_2.setGeometry(QtCore.QRect(410, 20, 75, 23))
self.pushButton_2.clicked.connect(self.re_name)
self.tableWidget = QtWidgets.QTableWidget(self)
self.tableWidget.setGeometry(QtCore.QRect(10, 210, 491, 191))
self.tableWidget.setColumnCount(2)
self.tableWidget.setHorizontalHeaderLabels(["图片名", "图片路径"])
header = self.tableWidget.horizontalHeader()
header.setStretchLastSection(True)
self.tableWidget.setColumnWidth(0, 130)
self.statusbar = QtWidgets.QStatusBar()
self.statusbar.showMessage("准备就绪......")
self.setStatusBar(self.statusbar)
def init_values(self):
self.img_path = ""
self.list = []
def isImg(self, ext):
return ext.lower() in ['.png', '.jpg', '.jpeg', '.bmp', '.gif']
def get_files(self):
path = QFileDialog.getExistingDirectory(None, "选择图片文件夹路径", os.getcwd())
if not path:
return
self.lineEdit_4.setText(path)
self.img_path = path
self.tableWidget.setRowCount(0)
self.tableWidget.clearContents()
files = os.listdir(path)
num = 0
for f in files:
fp = os.path.join(path, f)
if os.path.isfile(fp) and self.isImg(os.path.splitext(fp)[1]):
row = self.tableWidget.rowCount()
self.tableWidget.insertRow(row)
self.tableWidget.setItem(row, 0, QtWidgets.QTableWidgetItem(f))
self.tableWidget.setItem(row, 1, QtWidgets.QTableWidgetItem(path))
num += 1
self.statusbar.showMessage(f"共有图片{num}张")
def re_name(self):
num = 0
try:
for i in range(self.tableWidget.rowCount()):
old_name = self.tableWidget.item(i, 0).text()
path = self.tableWidget.item(i, 1).text()
full_old = os.path.join(path, old_name)
ext = os.path.splitext(old_name)[1]
if self.radioButton.isChecked():
new_name = old_name.upper()
elif self.radioButton_2.isChecked():
new_name = old_name.lower()
elif self.radioButton_3.isChecked():
template = self.comboBox.currentText().replace("*", "{}")
idx = int(self.lineEdit_2.text()) + i * int(self.lineEdit_3.text())
new_name = template.format(idx) + ext
else:
continue
full_new = os.path.join(path, new_name)
os.replace(full_old, full_new) # 更安全的重命名
self.tableWidget.setItem(i, 0, QtWidgets.QTableWidgetItem(new_name))
num += 1
self.statusbar.showMessage(f"批量重命名完成,共处理图片{num}张")
except Exception as e:
print(e)
QMessageBox.warning(None, "警告", "重命名失败,请检查权限或输入!", QMessageBox.StandardButton.Ok)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = ImageProcessorApp()
window.show()
sys.exit(app.exec())
完成pdf效果