在日常工作和生活中,我们经常需要对图片添加水印。通过在图片中添加水印,可以有效保护图片的版权。在前面的教程中,我们已经介绍了如何通过给单个图片添加水印。在实际运用中,我们经常需要批量对多张图片添加水印,如果手动一张一张地添加水印效率极低,既费时又费力,利用Python的Pillow库和Tkinter库可以轻松实现批量添加水印的功能。
批量添加水印程序的效果图如下所示:
1、批量添加水印过程分析
程序通过Python的PIL(Pillow)库和Tkinter图形用户界面(GUI)创建一个应用,用户可以通过简单的界面选择单张图片或目标图片文件夹,输入水印文字、字体大小、不透明度、水印位置和水印字体颜色,处理后的图片还能保存到指定的文件夹中。点击“添加水印”或“批量添加水印”按钮后,程序会自动为图片添加文字水印,并保存到指定文件夹中。
具体实现步骤如下:
输入验证:验证用户输入的字体大小和不透明度是否为整数。
水印添加:定义添加文字水印的函数,可以选择处理单张图片或选择批量图片添加水印的情况。
总的GUI界面设计:使用Tkinter库创建一个操作简单的图形用户界面,方便用户操作。
输出保存:允许用户选择输出文件夹,将添加水印后的图片保存到指定文件夹中。
2、代码实现
(1) 导入必要的库
首先,确保你已经安装了Pillow库。如果还没有安装,可以通过pip安装:
pip install pillow
(2) 导入必要的库
import os
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
from tkinter.colorchooser import askcolor
from PIL import Image, ImageDraw, ImageFont
这里导入了PIL(Pillow)库用于图片处理,os库用于操作系统文件和文件夹,Tkinter库用于创建(GUI)图形用户界面,filedialog和messagebox分别用于文件选择和消息提示,askcolor用于颜色选择对话框,允许用户通过颜色对话框选择所需的颜色对象,支持使用预定义的颜色样本或者通过设置RGB值选择自定义颜色。用户选择颜色后,对话框会返回一个包含所选颜色RGB值和十六进制值的元组。
(3)显示十六进制的RGB值颜色
# 显示十六进制的RGB值颜色
def rgb_to_hex(rgb):
return "#%02x%02x%02x" % rgb
该函数用于确保输出十六进制数的RGB值颜色,
(4)验证函数
# 判断输入的内容是否为整数
def is_int_number(input_str):
try:
int(input_str)
return True
except ValueError:
return False
该函数用于验证用户输入的字符是否为整数,如果是整数则返回True,否则返回False。
(5)创建输出文件路径
# 创建输出文件路径
def create_output_path(image_path, output_path):
file_name = os.path.splitext(os.path.basename(image_path))[0]
file_extension = os.path.splitext(image_path)[1]
return os.path.join(output_path, file_name + "_watermarked" + file_extension)
通过该函数获取输入图片的路径和输出文件夹路径,生成添加水印后图片的保存路径。
(6)文字水印制作函数
# 文字水印制作函数
def add_text_watermark(image_path, output_path, watermark_text, font_size, opacity, position, color):
try:
# 打开原始图片
base_image = Image.open(image_path).convert("RGBA")
# 尝试使用Windows系统预装的黑体字体
try:
font = ImageFont.truetype("simhei.ttf", font_size)
except OSError:
try:
# 尝试使用系统默认字体
font = ImageFont.load_default()
except Exception as e:
# 如果字体加载失败,则抛出错误提示
messagebox.showerror("错误", f"无法加载字体: {str(e)}")
return
# 根据颜色选择和不透明度值创建RGBA元组
opacity_tuple = ((round(opacity * 2.55)),)
text_color = color + opacity_tuple
# 创建一个ImageDraw对象,用来绘制图像
draw = ImageDraw.Draw(base_image)
# 使用textbbox方法计算水印文本尺寸
bbox = draw.textbbox((0, 0), watermark_text, font=font)
text_width = bbox[2] - bbox[0]
text_height = bbox[3] - bbox[1]
# 获取原始图片尺寸
img_width, img_height = base_image.size
# 根据选择的位置调整水印位置
if position == "左上":
paste_position = (0, 0)
elif position == "右上":
paste_position = (img_width - text_width, 0)
elif position == "居中":
paste_position = (int((img_width - text_width)/2), int((img_height - text_height)/2))
elif position == "左下":
paste_position = (0, img_height - text_height)
elif position == "右下":
paste_position = (img_width - text_width, img_height - text_height)
else:
paste_position = (0, 0)
# 创建一个新的透明度为0的白色背景图片
text_image = Image.new('RGBA', (text_width, text_height), (255, 255, 255, 0))
# 创建一个ImageDraw对象,用来绘制文本内容
draw_text = ImageDraw.Draw(text_image)
# 在白色背景的图片上写入文本内容
draw_text.text((0, 0), watermark_text, font=font, fill=text_color)
# 将文本图片粘贴到原始图片上
base_image.paste(text_image, paste_position, text_image)
base_image = base_image.convert("RGB")
output_file = create_output_path(image_path, output_path)
# 保存结果图片,压缩质量为95%最高质量
base_image.save(output_file, quality=95)
except Exception as e:
messagebox.showerror("错误", f"添加文字水印失败: {str(e)}")
(7)批量文字水印制作函数
def batch_add_watermark(folder_path, output_path, watermark_text, font_size, opacity, position, color):
# 遍历文件夹中的所有图片文件
for app, dirs, files in os.walk(folder_path):
for file in files:
file_extension = os.path.splitext(file)[1].lower()
if file_extension in [".png", ".jpg", ".jpeg", ".bmp", ".gif"]:
image_path = os.path.join(app, file)
add_text_watermark(image_path, output_path, watermark_text, font_size, opacity, position, color)
该函数用于批量处理指定文件夹中的所有图片。通过for循环遍历文件夹中的所有文件,筛选出图片格式的文件,最后调用add_text_watermark()水印制作函数为每张图片添加水印。
(8)GUI界面设计
# GUI界面设计
class WatermarkApp:
def __init__(self, app):
self.app = app
self.app.title("添加文字水印工具")
self.image_path = ""
self.folder_path = ""
self.output_path = ""
self.create_widgets()
def create_widgets(self):
# 添加水印部分(非批量)
self.edit_watermark_frame = tk.LabelFrame(self.app, text="添加文字水印(非批量)", labelanchor='n')
self.edit_watermark_frame.grid(row=0, column=0, padx=10, pady=10)
tk.Label(self.edit_watermark_frame, text="选择待加水印图片:").grid(row=0, column=0)
self.open_image_entry = tk.Entry(self.edit_watermark_frame, width=30)
self.open_image_entry.grid(row=0, column=1, pady=5, padx=2)
self.image_button = tk.Button(self.edit_watermark_frame, text="选择图片", command=self.select_image)
self.image_button.grid(row=0, column=2)
tk.Label(self.edit_watermark_frame, text="选择输出文件夹:").grid(row=1, column=0)
self.output_entry = tk.Entry(self.edit_watermark_frame, width=30)
self.output_entry.grid(row=1, column=1, pady=5, padx=2)
self.output_path_button = tk.Button(self.edit_watermark_frame, text="选择输出文件夹",
command=self.select_output_path)
self.output_path_button.grid(row=1, column=2, pady=5, padx=5)
# 水印文字内容
tk.Label(self.edit_watermark_frame, text="输入水印文字: ", width=12, anchor="w").grid(row=2, column=0, pady=5, padx=2)
self.default_value = tk.StringVar()
self.default_value.set("水印文字内容")
self.watermark_text = tk.Entry(self.edit_watermark_frame, textvariable=self.default_value, width=30)
self.watermark_text.grid(row=2, column=1, pady=5, padx=2, sticky="w")
# 水印字体大小
self.current_font_size = tk.IntVar(value=50)
tk.Label(self.edit_watermark_frame, text="字体大小: ", width=12, anchor="w").grid(row=3, column=0, pady=5, padx=2)
self.font_size = tk.Spinbox(self.edit_watermark_frame,
from_=8,
to=250,
wrap=True,
textvariable=self.current_font_size,)
self.font_size.grid(column=1, row=3, pady=5, padx=2, sticky="w")
# 水印不透明度
self.current_opacity = tk.IntVar(value=100)
tk.Label(self.edit_watermark_frame, text="不透明度", width=12, anchor="w").grid(row=4, column=0, pady=5, padx=2)
self.opacity = tk.Spinbox(self.edit_watermark_frame,
from_=0,
to=100,
textvariable=self.current_opacity,
wrap=False,
)
self.opacity.grid(row=4, column=1, pady=5, padx=2, sticky="w")
# 水印位置选择
self.position_label = tk.Label(self.edit_watermark_frame, pady=5, padx=2, text="水印位置:", width=12, anchor="w")
self.position_label.grid(column=0, row=5)
self.position_var = tk.StringVar()
self.position_option = ttk.Combobox(
self.edit_watermark_frame,
textvariable=self.position_var,
values=["左上", "右上", "居中", "左下", "右下"],
width=10,
state="readonly",
)
self.position_option.current(2)
self.position_option.grid(column=1, row=5, pady=5, padx=2, sticky="w")
# 水印颜色
self.text_color = (0, 0, 0)
self.color_selection = tk.Canvas(self.edit_watermark_frame,
bg=rgb_to_hex(self.text_color),
width=80,
height=15)
self.color_selection.grid(column=0, row=6, pady=5, padx=2)
self.color_button = tk.Button(self.edit_watermark_frame,
text="更改字体颜色",
command=self.change_text_color,
width=18)
self.color_button.grid(column=1, row=6, columnspan=1, pady=5, padx=2, sticky="w")
self.add_watermark_button = tk.Button(self.edit_watermark_frame, text="添加水印", command=self.add_watermark)
self.add_watermark_button.grid(row=7, column=1, pady=5, padx=5)
# 批量添加水印部分
self.batch_edit_watermark_frame = tk.LabelFrame(self.app, text="批量添加文字水印", labelanchor='n')
self.batch_edit_watermark_frame.grid(row=0, column=1, padx=10, pady=10)
tk.Label(self.batch_edit_watermark_frame, text="选择文件夹:").grid(row=0, column=0)
self.batch_folder_entry = tk.Entry(self.batch_edit_watermark_frame, width=30)
self.batch_folder_entry.grid(row=0, column=1, pady=5, padx=2)
self.batch_folder_button = tk.Button(self.batch_edit_watermark_frame, text="选择文件夹",
command=self.select_batch_folder)
self.batch_folder_button.grid(row=0, column=2)
tk.Label(self.batch_edit_watermark_frame, text="选择输出文件夹:").grid(row=1, column=0)
self.batch_output_path_entry = tk.Entry(self.batch_edit_watermark_frame, width=30)
self.batch_output_path_entry.grid(row=1, column=1, pady=5, padx=2)
self.batch_output_path_button = tk.Button(self.batch_edit_watermark_frame, text="选择输出文件夹",
command=self.select_batch_output_path)
self.batch_output_path_button.grid(row=1, column=2, pady=5, padx=5)
# 水印文字内容
tk.Label(self.batch_edit_watermark_frame, text="输入水印文字: ", width=12, anchor="w").grid(row=2, column=0, pady=5, padx=2)
self.default_value = tk.StringVar()
self.default_value.set("水印文字内容")
self.batch_watermark_text = tk.Entry(self.batch_edit_watermark_frame, textvariable=self.default_value, width=30)
self.batch_watermark_text.grid(row=2, column=1, pady=5, padx=2, sticky="w")
# 水印字体大小
self.current_font_size = tk.IntVar(value=50)
tk.Label(self.batch_edit_watermark_frame, text="字体大小: ", width=12, anchor="w").grid(row=3, column=0, pady=5, padx=2)
self.batch_font_size = tk.Spinbox(self.batch_edit_watermark_frame,
from_=8,
to=250,
wrap=True,
textvariable=self.current_font_size,)
self.batch_font_size.grid(column=1, row=3, pady=5, padx=2, sticky="w")
# 水印不透明度
self.current_opacity = tk.IntVar(value=100)
tk.Label(self.batch_edit_watermark_frame, text="不透明度", width=12, anchor="w").grid(row=4, column=0, pady=5, padx=2)
self.batch_opacity = tk.Spinbox(self.batch_edit_watermark_frame,
from_=0,
to=100,
textvariable=self.current_opacity,
wrap=False,
)
self.batch_opacity.grid(row=4, column=1, pady=5, padx=2, sticky="w")
# 水印位置选择
self.batch_position_label = tk.Label(self.batch_edit_watermark_frame, pady=5, padx=2, text="水印位置:", width=12, anchor="w")
self.batch_position_label.grid(column=0, row=5)
self.batch_position_var = tk.StringVar()
self.batch_position_option = ttk.Combobox(
self.batch_edit_watermark_frame,
textvariable=self.batch_position_var,
values=["左上", "右上", "居中", "左下", "右下"],
width=10,
state="readonly",
)
self.batch_position_option.current(2)
self.batch_position_option.grid(column=1, row=5, pady=5, padx=2, sticky="w")
# 水印颜色
self.batch_text_color = (0, 0, 0)
self.batch_color_selection = tk.Canvas(self.batch_edit_watermark_frame,
bg=rgb_to_hex(self.batch_text_color),
width=80,
height=15)
self.batch_color_selection.grid(column=0, row=6, pady=5, padx=2)
self.batch_color_button = tk.Button(self.batch_edit_watermark_frame,
text="更改字体颜色",
command=self.batch_change_text_color,
width=18)
self.batch_color_button.grid(column=1, row=6, columnspan=1, pady=5, padx=2, sticky="w")
self.batch_add_watermark_button = tk.Button(self.batch_edit_watermark_frame, text="批量添加水印",
command=self.batch_add_watermark_action)
self.batch_add_watermark_button.grid(row=7, column=1, pady=5, padx=5)
# 打开一个文件选择对话框,允许用户选择一个图片文件
def select_image(self):
# 支持多种格式
self.image_path = filedialog.askopenfilename(title="选择图片",
filetypes=[("Image files", "*.png *.jpg *.jpeg *.bmp *.gif")])
if self.image_path:
self.open_image_entry.delete(0, tk.END)
self.open_image_entry.insert(0, self.image_path)
# 选择输出文件夹路径,用于存放添加水印后的图片
def select_output_path(self):
self.output_path = filedialog.askdirectory(title="选择输出文件夹")
if self.output_path:
self.output_entry.delete(0, tk.END)
self.output_entry.insert(0, self.output_path)
# 文字水印颜色选择器(非批量)
def change_text_color(self):
self.colors = askcolor(title="水印颜色选择器")
self.text_color = self.colors[0] # colors[0]是RGB值
self.color_selection.configure(bg=self.colors[1]) # colors[1]是十六进制值
# 文字水印颜色选择器(批量)
def batch_change_text_color(self):
self.colors = askcolor(title="水印颜色选择器")
self.batch_text_color = self.colors[0] # colors[0]是RGB值
self.batch_color_selection.configure(bg=self.colors[1]) # colors[1]是十六进制值
# 添加文字水印函数(非批量)
def add_watermark(self):
watermark_text = self.watermark_text.get()
font_size_str = self.font_size.get()
opacity_str = self.opacity.get()
position = self.position_var.get()
color = self.text_color
if not is_int_number(font_size_str) or not is_int_number(opacity_str):
messagebox.showerror("错误", "字体大小和透明度必须为有效的整数!")
return
font_size = int(font_size_str)
opacity = int(opacity_str)
if self.image_path and self.output_path:
add_text_watermark(self.image_path, self.output_path, watermark_text, font_size, opacity, position, color)
messagebox.showinfo("提示", "水印添加成功!")
else:
messagebox.showerror("错误", "请先选择图片和输出文件夹!")
# 选择文件夹路径,包含原图片
def select_batch_folder(self):
self.folder_path = filedialog.askdirectory(title="选择文件夹")
if self.folder_path:
self.batch_folder_entry.delete(0, tk.END)
self.batch_folder_entry.insert(0, self.folder_path)
# 选择输出文件夹路径,用于存放添加水印后的图片
def select_batch_output_path(self):
self.output_path = filedialog.askdirectory(title="选择输出文件夹")
if self.output_path:
self.batch_output_path_entry.delete(0, tk.END)
self.batch_output_path_entry.insert(0, self.output_path)
# 批量添加文字水印函数
def batch_add_watermark_action(self):
watermark_text = self.batch_watermark_text.get()
font_size_str = self.batch_font_size.get()
opacity_str = self.batch_opacity.get()
position = self.batch_position_var.get()
color = self.batch_text_color
if not is_int_number(font_size_str) or not is_int_number(opacity_str):
messagebox.showerror("错误", "字体大小和透明度必须为有效的整数!")
return
font_size = int(font_size_str)
opacity = int(opacity_str)
if self.folder_path and self.output_path:
batch_add_watermark(self.folder_path, self.output_path, watermark_text, font_size, opacity, position, color)
messagebox.showinfo("提示", "批量水印添加成功!")
else:
messagebox.showerror("错误", "请先选择文件夹和输出文件夹!")
该WatermarkApp类使用Tkinter库创建了一个简单的GUI界面,主要分为两个部分,左边的框架可以添加单张图片水印,右边的框架可以批量添加水印。用户可以通过按钮选择图片、文件夹和输出文件夹,输入水印文字、字体大小、不透明度、水印位置和水印字体颜色,然后点击相应的按钮进行操作。
(9)主程序
# 当前模块直接被执行
if __name__ == "__main__":
# 创建程序主窗口
app = tk.Tk()
window = WatermarkApp(app)
# 运行主循环
app.mainloop()
在主程序中,创建Tkinter程序的主窗口,通过实例化WatermarkApp类运行主循环,使图形GUI界面保持运行状态。
(10)批量给图片添加文字水印的完整代码如下所示:
import os
import tkinter as tk
from tkinter import filedialog, messagebox, ttk
from tkinter.colorchooser import askcolor
from PIL import Image, ImageDraw, ImageFont
# 显示十六进制的RGB值颜色
def rgb_to_hex(rgb):
return "#%02x%02x%02x" % rgb
# 判断输入的内容是否为整数
def is_int_number(input_str):
try:
int(input_str)
return True
except ValueError:
return False
# 创建输出文件路径
def create_output_path(image_path, output_path):
file_name = os.path.splitext(os.path.basename(image_path))[0]
file_extension = os.path.splitext(image_path)[1]
return os.path.join(output_path, file_name + "_watermarked" + file_extension)
# 文字水印制作函数
def add_text_watermark(image_path, output_path, watermark_text, font_size, opacity, position, color):
try:
# 打开原始图片
base_image = Image.open(image_path).convert("RGBA")
# 尝试使用Windows系统预装的黑体字体
try:
font = ImageFont.truetype("simhei.ttf", font_size)
except OSError:
try:
# 尝试使用系统默认字体
font = ImageFont.load_default()
except Exception as e:
# 如果字体加载失败,则抛出错误提示
messagebox.showerror("错误", f"无法加载字体: {str(e)}")
return
# 根据颜色选择和不透明度值创建RGBA元组
opacity_tuple = ((round(opacity * 2.55)),)
text_color = color + opacity_tuple
# 创建一个ImageDraw对象,用来绘制图像
draw = ImageDraw.Draw(base_image)
# 使用textbbox方法计算水印文本尺寸
bbox = draw.textbbox((0, 0), watermark_text, font=font)
text_width = bbox[2] - bbox[0]
text_height = bbox[3] - bbox[1]
# 获取原始图片尺寸
img_width, img_height = base_image.size
# 根据选择的位置调整水印位置
if position == "左上":
paste_position = (0, 0)
elif position == "右上":
paste_position = (img_width - text_width, 0)
elif position == "居中":
paste_position = (int((img_width - text_width)/2), int((img_height - text_height)/2))
elif position == "左下":
paste_position = (0, img_height - text_height)
elif position == "右下":
paste_position = (img_width - text_width, img_height - text_height)
else:
paste_position = (0, 0)
# 创建一个新的透明度为0的白色背景图片
text_image = Image.new('RGBA', (text_width, text_height), (255, 255, 255, 0))
# 创建一个ImageDraw对象,用来绘制文本内容
draw_text = ImageDraw.Draw(text_image)
# 在白色背景的图片上写入文本内容
draw_text.text((0, 0), watermark_text, font=font, fill=text_color)
# 将文本图片粘贴到原始图片上
base_image.paste(text_image, paste_position, text_image)
base_image = base_image.convert("RGB")
output_file = create_output_path(image_path, output_path)
# 保存结果图片,压缩质量为95%最高质量
base_image.save(output_file, quality=95)
except Exception as e:
messagebox.showerror("错误", f"添加文字水印失败: {str(e)}")
# 批量文字水印制作函数
def batch_add_watermark(folder_path, output_path, watermark_text, font_size, opacity, position, color):
# 遍历文件夹中的所有图片文件
for app, dirs, files in os.walk(folder_path):
for file in files:
file_extension = os.path.splitext(file)[1].lower()
if file_extension in [".png", ".jpg", ".jpeg", ".bmp", ".gif"]:
image_path = os.path.join(app, file)
add_text_watermark(image_path, output_path, watermark_text, font_size, opacity, position, color)
# GUI界面设计
class WatermarkApp:
def __init__(self, app):
self.app = app
self.app.title("添加文字水印工具")
self.image_path = ""
self.folder_path = ""
self.output_path = ""
self.create_widgets()
def create_widgets(self):
# 添加水印部分(非批量)
self.edit_watermark_frame = tk.LabelFrame(self.app, text="添加文字水印(非批量)", labelanchor='n')
self.edit_watermark_frame.grid(row=0, column=0, padx=10, pady=10)
tk.Label(self.edit_watermark_frame, text="选择待加水印图片:").grid(row=0, column=0)
self.open_image_entry = tk.Entry(self.edit_watermark_frame, width=30)
self.open_image_entry.grid(row=0, column=1, pady=5, padx=2)
self.image_button = tk.Button(self.edit_watermark_frame, text="选择图片", command=self.select_image)
self.image_button.grid(row=0, column=2)
tk.Label(self.edit_watermark_frame, text="选择输出文件夹:").grid(row=1, column=0)
self.output_entry = tk.Entry(self.edit_watermark_frame, width=30)
self.output_entry.grid(row=1, column=1, pady=5, padx=2)
self.output_path_button = tk.Button(self.edit_watermark_frame, text="选择输出文件夹",
command=self.select_output_path)
self.output_path_button.grid(row=1, column=2, pady=5, padx=5)
# 水印文字内容
tk.Label(self.edit_watermark_frame, text="输入水印文字: ", width=12, anchor="w").grid(row=2, column=0, pady=5, padx=2)
self.default_value = tk.StringVar()
self.default_value.set("水印文字内容")
self.watermark_text = tk.Entry(self.edit_watermark_frame, textvariable=self.default_value, width=30)
self.watermark_text.grid(row=2, column=1, pady=5, padx=2, sticky="w")
# 水印字体大小
self.current_font_size = tk.IntVar(value=50)
tk.Label(self.edit_watermark_frame, text="字体大小: ", width=12, anchor="w").grid(row=3, column=0, pady=5, padx=2)
self.font_size = tk.Spinbox(self.edit_watermark_frame,
from_=8,
to=250,
wrap=True,
textvariable=self.current_font_size,)
self.font_size.grid(column=1, row=3, pady=5, padx=2, sticky="w")
# 水印不透明度
self.current_opacity = tk.IntVar(value=100)
tk.Label(self.edit_watermark_frame, text="不透明度", width=12, anchor="w").grid(row=4, column=0, pady=5, padx=2)
self.opacity = tk.Spinbox(self.edit_watermark_frame,
from_=0,
to=100,
textvariable=self.current_opacity,
wrap=False,
)
self.opacity.grid(row=4, column=1, pady=5, padx=2, sticky="w")
# 水印位置选择
self.position_label = tk.Label(self.edit_watermark_frame, pady=5, padx=2, text="水印位置:", width=12, anchor="w")
self.position_label.grid(column=0, row=5)
self.position_var = tk.StringVar()
self.position_option = ttk.Combobox(
self.edit_watermark_frame,
textvariable=self.position_var,
values=["左上", "右上", "居中", "左下", "右下"],
width=10,
state="readonly",
)
self.position_option.current(2)
self.position_option.grid(column=1, row=5, pady=5, padx=2, sticky="w")
# 水印颜色
self.text_color = (0, 0, 0)
self.color_selection = tk.Canvas(self.edit_watermark_frame,
bg=rgb_to_hex(self.text_color),
width=80,
height=15)
self.color_selection.grid(column=0, row=6, pady=5, padx=2)
self.color_button = tk.Button(self.edit_watermark_frame,
text="更改字体颜色",
command=self.change_text_color,
width=18)
self.color_button.grid(column=1, row=6, columnspan=1, pady=5, padx=2, sticky="w")
self.add_watermark_button = tk.Button(self.edit_watermark_frame, text="添加水印", command=self.add_watermark)
self.add_watermark_button.grid(row=7, column=1, pady=5, padx=5)
# 批量添加水印部分
self.batch_edit_watermark_frame = tk.LabelFrame(self.app, text="批量添加文字水印", labelanchor='n')
self.batch_edit_watermark_frame.grid(row=0, column=1, padx=10, pady=10)
tk.Label(self.batch_edit_watermark_frame, text="选择文件夹:").grid(row=0, column=0)
self.batch_folder_entry = tk.Entry(self.batch_edit_watermark_frame, width=30)
self.batch_folder_entry.grid(row=0, column=1, pady=5, padx=2)
self.batch_folder_button = tk.Button(self.batch_edit_watermark_frame, text="选择文件夹",
command=self.select_batch_folder)
self.batch_folder_button.grid(row=0, column=2)
tk.Label(self.batch_edit_watermark_frame, text="选择输出文件夹:").grid(row=1, column=0)
self.batch_output_path_entry = tk.Entry(self.batch_edit_watermark_frame, width=30)
self.batch_output_path_entry.grid(row=1, column=1, pady=5, padx=2)
self.batch_output_path_button = tk.Button(self.batch_edit_watermark_frame, text="选择输出文件夹",
command=self.select_batch_output_path)
self.batch_output_path_button.grid(row=1, column=2, pady=5, padx=5)
# 水印文字内容
tk.Label(self.batch_edit_watermark_frame, text="输入水印文字: ", width=12, anchor="w").grid(row=2, column=0, pady=5, padx=2)
self.default_value = tk.StringVar()
self.default_value.set("水印文字内容")
self.batch_watermark_text = tk.Entry(self.batch_edit_watermark_frame, textvariable=self.default_value, width=30)
self.batch_watermark_text.grid(row=2, column=1, pady=5, padx=2, sticky="w")
# 水印字体大小
self.current_font_size = tk.IntVar(value=50)
tk.Label(self.batch_edit_watermark_frame, text="字体大小: ", width=12, anchor="w").grid(row=3, column=0, pady=5, padx=2)
self.batch_font_size = tk.Spinbox(self.batch_edit_watermark_frame,
from_=8,
to=250,
wrap=True,
textvariable=self.current_font_size,)
self.batch_font_size.grid(column=1, row=3, pady=5, padx=2, sticky="w")
# 水印不透明度
self.current_opacity = tk.IntVar(value=100)
tk.Label(self.batch_edit_watermark_frame, text="不透明度", width=12, anchor="w").grid(row=4, column=0, pady=5, padx=2)
self.batch_opacity = tk.Spinbox(self.batch_edit_watermark_frame,
from_=0,
to=100,
textvariable=self.current_opacity,
wrap=False,
)
self.batch_opacity.grid(row=4, column=1, pady=5, padx=2, sticky="w")
# 水印位置选择
self.batch_position_label = tk.Label(self.batch_edit_watermark_frame, pady=5, padx=2, text="水印位置:", width=12, anchor="w")
self.batch_position_label.grid(column=0, row=5)
self.batch_position_var = tk.StringVar()
self.batch_position_option = ttk.Combobox(
self.batch_edit_watermark_frame,
textvariable=self.batch_position_var,
values=["左上", "右上", "居中", "左下", "右下"],
width=10,
state="readonly",
)
self.batch_position_option.current(2)
self.batch_position_option.grid(column=1, row=5, pady=5, padx=2, sticky="w")
# 水印颜色
self.batch_text_color = (0, 0, 0)
self.batch_color_selection = tk.Canvas(self.batch_edit_watermark_frame,
bg=rgb_to_hex(self.batch_text_color),
width=80,
height=15)
self.batch_color_selection.grid(column=0, row=6, pady=5, padx=2)
self.batch_color_button = tk.Button(self.batch_edit_watermark_frame,
text="更改字体颜色",
command=self.batch_change_text_color,
width=18)
self.batch_color_button.grid(column=1, row=6, columnspan=1, pady=5, padx=2, sticky="w")
self.batch_add_watermark_button = tk.Button(self.batch_edit_watermark_frame, text="批量添加水印",
command=self.batch_add_watermark_action)
self.batch_add_watermark_button.grid(row=7, column=1, pady=5, padx=5)
# 打开一个文件选择对话框,允许用户选择一个图片文件
def select_image(self):
# 支持多种格式
self.image_path = filedialog.askopenfilename(title="选择图片",
filetypes=[("Image files", "*.png *.jpg *.jpeg *.bmp *.gif")])
if self.image_path:
self.open_image_entry.delete(0, tk.END)
self.open_image_entry.insert(0, self.image_path)
# 选择输出文件夹路径,用于存放添加水印后的图片
def select_output_path(self):
self.output_path = filedialog.askdirectory(title="选择输出文件夹")
if self.output_path:
self.output_entry.delete(0, tk.END)
self.output_entry.insert(0, self.output_path)
# 文字水印颜色选择器(非批量)
def change_text_color(self):
self.colors = askcolor(title="水印颜色选择器")
self.text_color = self.colors[0] # colors[0]是RGB值
self.color_selection.configure(bg=self.colors[1]) # colors[1]是十六进制值
# 文字水印颜色选择器(批量)
def batch_change_text_color(self):
self.colors = askcolor(title="水印颜色选择器")
self.batch_text_color = self.colors[0] # colors[0]是RGB值
self.batch_color_selection.configure(bg=self.colors[1]) # colors[1]是十六进制值
# 添加文字水印函数(非批量)
def add_watermark(self):
watermark_text = self.watermark_text.get()
font_size_str = self.font_size.get()
opacity_str = self.opacity.get()
position = self.position_var.get()
color = self.text_color
if not is_int_number(font_size_str) or not is_int_number(opacity_str):
messagebox.showerror("错误", "字体大小和透明度必须为有效的整数!")
return
font_size = int(font_size_str)
opacity = int(opacity_str)
if self.image_path and self.output_path:
add_text_watermark(self.image_path, self.output_path, watermark_text, font_size, opacity, position, color)
messagebox.showinfo("提示", "水印添加成功!")
else:
messagebox.showerror("错误", "请先选择图片和输出文件夹!")
# 选择文件夹路径,包含原图片
def select_batch_folder(self):
self.folder_path = filedialog.askdirectory(title="选择文件夹")
if self.folder_path:
self.batch_folder_entry.delete(0, tk.END)
self.batch_folder_entry.insert(0, self.folder_path)
# 选择输出文件夹路径,用于存放添加水印后的图片
def select_batch_output_path(self):
self.output_path = filedialog.askdirectory(title="选择输出文件夹")
if self.output_path:
self.batch_output_path_entry.delete(0, tk.END)
self.batch_output_path_entry.insert(0, self.output_path)
# 批量添加文字水印函数
def batch_add_watermark_action(self):
watermark_text = self.batch_watermark_text.get()
font_size_str = self.batch_font_size.get()
opacity_str = self.batch_opacity.get()
position = self.batch_position_var.get()
color = self.batch_text_color
if not is_int_number(font_size_str) or not is_int_number(opacity_str):
messagebox.showerror("错误", "字体大小和透明度必须为有效的整数!")
return
font_size = int(font_size_str)
opacity = int(opacity_str)
if self.folder_path and self.output_path:
batch_add_watermark(self.folder_path, self.output_path, watermark_text, font_size, opacity, position, color)
messagebox.showinfo("提示", "批量水印添加成功!")
else:
messagebox.showerror("错误", "请先选择文件夹和输出文件夹!")
# 当前模块直接被执行
if __name__ == "__main__":
# 创建程序主窗口
app = tk.Tk()
window = WatermarkApp(app)
# 运行主循环
app.mainloop()