苦于不知如何高效添加图片水印?Pillow 加 Tkinter 帮你轻松搞定!

运行展示

经过测试,功能正常。
在这里插入图片描述

一、引言

在日常工作和生活中,我们经常需要对图片添加水印来保护版权或者标识信息。Python 作为一门功能强大且易于上手的编程语言,提供了丰富的库来实现图片处理功能,其中 Pillow 库就是一个非常实用的图片处理库。本文将详细介绍如何使用 Python 结合 Pillow 库实现图片文字水印的添加,并将添加水印后的图片保存到指定文件夹。

二、实现思路

我们的目标是开发一个具有图形用户界面(GUI)的程序,用户可以通过界面选择图片或文件夹,输入水印文字、字体大小和透明度,还能指定输出文件夹,程序会自动为图片添加文字水印并保存到指定位置。具体实现步骤如下:

  1. 输入验证:检查用户输入的字体大小和透明度是否为有效的数字。
  2. 水印添加:定义添加文字水印的函数,处理单张图片和批量图片添加水印的情况。
  3. GUI 设计:使用 tkinter 库创建一个简单易用的图形用户界面,方便用户操作。
  4. 输出保存:允许用户选择输出文件夹,将添加水印后的图片保存到该文件夹。

三、代码实现

1. 导入必要的库

from PIL import Image, ImageDraw, ImageFont
import os
import tkinter as tk
from tkinter import filedialog, messagebox

这里导入了 Pillow 库用于图片处理,os 库用于文件和文件夹操作,tkinter 库用于创建 GUI 界面,filedialogmessagebox 用于文件选择和消息提示。

2. 输入验证函数

# 检查输入是否为有效的数字
def is_valid_number(input_str):
    try:
        float(input_str)
        return True
    except ValueError:
        return False

该函数用于检查用户输入的字符串是否可以转换为浮点数,如果可以则返回 True,否则返回 False

3. 生成输出文件路径函数

# 生成输出文件路径
def generate_output_path(image_path, output_folder):
    file_name = os.path.splitext(os.path.basename(image_path))[0]
    file_extension = os.path.splitext(image_path)[1]
    return os.path.join(output_folder, file_name + "_watermarked" + file_extension)

该函数根据输入图片的路径和输出文件夹路径,生成添加水印后图片的保存路径。

4. 添加文字水印函数

# 添加文字水印函数
def add_text_watermark(image_path, output_folder, watermark_text, font_size, opacity):
    try:
        img = Image.open(image_path).convert("RGBA")
        # 尝试使用支持中文的字体文件
        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

        # 修改文字颜色为黑色
        text_color = (0, 0, 0, int(255 * opacity))
        draw = ImageDraw.Draw(img)

        # 使用 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 = img.size
        position = (img_width - text_width - 10, img_height - text_height - 10)  # 右下角位置

        text_layer = Image.new('RGBA', (text_width, text_height), (255, 255, 255, 0))
        draw_text = ImageDraw.Draw(text_layer)
        draw_text.text((0, 0), watermark_text, font=font, fill=text_color)

        img.paste(text_layer, position, text_layer)
        img = img.convert("RGB")
        output_path = generate_output_path(image_path, output_folder)
        img.save(output_path)
    except Exception as e:
        messagebox.showerror("错误", f"添加文字水印失败: {str(e)}")

该函数用于为单张图片添加文字水印。首先打开图片并转换为 RGBA 模式,然后尝试加载支持中文的字体文件 simhei.ttf,如果加载失败则使用系统默认字体。接着计算水印文字的大小和位置,创建一个透明的文本图层并绘制水印文字,最后将文本图层粘贴到图片上并保存到指定的输出文件夹。

5. 批量添加水印函数

# 批量添加水印函数
def batch_add_watermark(folder_path, output_folder, watermark_text, font_size, opacity):
    for root, 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(root, file)
                add_text_watermark(image_path, output_folder, watermark_text, font_size, opacity)

该函数用于批量处理指定文件夹中的图片。遍历文件夹中的所有文件,筛选出图片文件,然后调用 add_text_watermark 函数为每张图片添加水印。

6. GUI 界面类

# GUI界面
class WatermarkApp:
    def __init__(self, root):
        self.root = root
        self.root.title("文字水印处理工具")

        self.image_path = ""
        self.folder_path = ""
        self.output_folder = ""

        self.create_widgets()

    def create_widgets(self):
        # 添加水印部分
        self.add_watermark_frame = tk.LabelFrame(self.root, text="添加文字水印")
        self.add_watermark_frame.grid(row=0, column=0, padx=10, pady=10)

        tk.Label(self.add_watermark_frame, text="选择图片:").grid(row=0, column=0)
        self.image_button = tk.Button(self.add_watermark_frame, text="选择图片", command=self.select_image)
        self.image_button.grid(row=0, column=1)
        self.image_label = tk.Label(self.add_watermark_frame, text="")
        self.image_label.grid(row=0, column=2)

        tk.Label(self.add_watermark_frame, text="选择输出文件夹:").grid(row=1, column=0)
        self.output_folder_button = tk.Button(self.add_watermark_frame, text="选择输出文件夹",
                                              command=self.select_output_folder)
        self.output_folder_button.grid(row=1, column=1)
        self.output_folder_label = tk.Label(self.add_watermark_frame, text="")
        self.output_folder_label.grid(row=1, column=2)

        tk.Label(self.add_watermark_frame, text="输入水印文字:").grid(row=2, column=0)
        self.watermark_text = tk.Entry(self.add_watermark_frame)
        self.watermark_text.grid(row=2, column=1)

        tk.Label(self.add_watermark_frame, text="字体大小:").grid(row=3, column=0)
        self.font_size = tk.Entry(self.add_watermark_frame)
        self.font_size.grid(row=3, column=1)

        tk.Label(self.add_watermark_frame, text="透明度 (0 - 1):").grid(row=4, column=0)
        self.opacity = tk.Entry(self.add_watermark_frame)
        self.opacity.grid(row=4, column=1)

        self.add_watermark_button = tk.Button(self.add_watermark_frame, text="添加水印", command=self.add_watermark)
        self.add_watermark_button.grid(row=5, column=1)

        # 批量添加水印部分
        self.batch_add_watermark_frame = tk.LabelFrame(self.root, text="批量添加文字水印")
        self.batch_add_watermark_frame.grid(row=0, column=1, padx=10, pady=10)

        tk.Label(self.batch_add_watermark_frame, text="选择文件夹:").grid(row=0, column=0)
        self.batch_folder_button = tk.Button(self.batch_add_watermark_frame, text="选择文件夹",
                                             command=self.select_batch_folder)
        self.batch_folder_button.grid(row=0, column=1)
        self.batch_folder_label = tk.Label(self.batch_add_watermark_frame, text="")
        self.batch_folder_label.grid(row=0, column=2)

        tk.Label(self.batch_add_watermark_frame, text="选择输出文件夹:").grid(row=1, column=0)
        self.batch_output_folder_button = tk.Button(self.batch_add_watermark_frame, text="选择输出文件夹",
                                                    command=self.select_batch_output_folder)
        self.batch_output_folder_button.grid(row=1, column=1)
        self.batch_output_folder_label = tk.Label(self.batch_add_watermark_frame, text="")
        self.batch_output_folder_label.grid(row=1, column=2)

        tk.Label(self.batch_add_watermark_frame, text="输入水印文字:").grid(row=2, column=0)
        self.batch_watermark_text = tk.Entry(self.batch_add_watermark_frame)
        self.batch_watermark_text.grid(row=2, column=1)

        tk.Label(self.batch_add_watermark_frame, text="字体大小:").grid(row=3, column=0)
        self.batch_font_size = tk.Entry(self.batch_add_watermark_frame)
        self.batch_font_size.grid(row=3, column=1)

        tk.Label(self.batch_add_watermark_frame, text="透明度 (0 - 1):").grid(row=4, column=0)
        self.batch_opacity = tk.Entry(self.batch_add_watermark_frame)
        self.batch_opacity.grid(row=4, column=1)

        self.batch_add_watermark_button = tk.Button(self.batch_add_watermark_frame, text="批量添加水印",
                                                    command=self.batch_add_watermark_action)
        self.batch_add_watermark_button.grid(row=5, column=1)

    def select_image(self):
        self.image_path = filedialog.askopenfilename(title="选择图片",
                                                     filetypes=[("Image files", "*.png *.jpg *.jpeg *.bmp *.gif")])
        self.image_label.config(text=f"已选择图片: {self.image_path}")

    def select_output_folder(self):
        self.output_folder = filedialog.askdirectory(title="选择输出文件夹")
        self.output_folder_label.config(text=f"已选择输出文件夹: {self.output_folder}")

    def add_watermark(self):
        watermark_text = self.watermark_text.get()
        font_size_str = self.font_size.get()
        opacity_str = self.opacity.get()
        if not is_valid_number(font_size_str) or not is_valid_number(opacity_str):
            messagebox.showerror("错误", "字体大小和透明度必须为有效的数字!")
            return
        font_size = int(font_size_str)
        opacity = float(opacity_str)
        if self.image_path and self.output_folder:
            add_text_watermark(self.image_path, self.output_folder, watermark_text, font_size, opacity)
            messagebox.showinfo("提示", "水印添加成功!")
        else:
            messagebox.showerror("错误", "请先选择图片和输出文件夹!")

    def select_batch_folder(self):
        self.folder_path = filedialog.askdirectory(title="选择文件夹")
        self.batch_folder_label.config(text=f"已选择文件夹: {self.folder_path}")

    def select_batch_output_folder(self):
        self.output_folder = filedialog.askdirectory(title="选择输出文件夹")
        self.batch_output_folder_label.config(text=f"已选择输出文件夹: {self.output_folder}")

    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()
        if not is_valid_number(font_size_str) or not is_valid_number(opacity_str):
            messagebox.showerror("错误", "字体大小和透明度必须为有效的数字!")
            return
        font_size = int(font_size_str)
        opacity = float(opacity_str)
        if self.folder_path and self.output_folder:
            batch_add_watermark(self.folder_path, self.output_folder, watermark_text, font_size, opacity)
            messagebox.showinfo("提示", "批量水印添加成功!")
        else:
            messagebox.showerror("错误", "请先选择文件夹和输出文件夹!")

该类使用 tkinter 库创建了一个 GUI 界面,包含添加单张图片水印和批量添加水印两个部分。用户可以通过按钮选择图片、文件夹和输出文件夹,输入水印文字、字体大小和透明度,然后点击相应的按钮进行操作。

7. 主程序

if __name__ == "__main__":
    root = tk.Tk()
    app = WatermarkApp(root)
    root.mainloop()

在主程序中,创建 tkinter 的主窗口,实例化 WatermarkApp 类并启动主循环,使 GUI 界面保持运行状态。

四、使用方法

  1. 运行代码,弹出 GUI 界面
  2. 添加单张图片水印
    • 点击“选择图片”按钮,选择要添加水印的图片。
    • 点击“选择输出文件夹”按钮,选择保存添加水印后图片的文件夹。
    • 输入水印文字、字体大小和透明度。
    • 点击“添加水印”按钮,程序会自动为图片添加水印并保存到指定文件夹。
  3. 批量添加水印
    • 点击“选择文件夹”按钮,选择包含要添加水印图片的文件夹。
    • 点击“选择输出文件夹”按钮,选择保存添加水印后图片的文件夹。
    • 输入水印文字、字体大小和透明度。
    • 点击“批量添加水印”按钮,程序会遍历指定文件夹中的所有图片,为每张图片添加水印并保存到指定文件夹。

五、注意事项

  • 代码设置添加的水印文字颜色是黑色,如果要处理的图片背景颜色是黑色或者灰色之类,水印文字看不清,这时候就要更改水印文字的颜色。
  • 要确保你的 Python 脚本所在目录下有 simhei.ttf 字体文件,或者你可以根据实际情况修改字体文件的路径。
  • 不同操作系统的字体文件存放位置可能不同,若遇到字体文件找不到的问题,可以手动将字体文件复制到脚本所在目录,或者使用绝对路径指定字体文件。

(主要看能否正常显示中文水印,如果能正常显示就不用特意添加)

六、总结

通过本文的介绍,我们学习了如何使用 Python 的 Pillow 库和 tkinter 库实现图片文字水印的添加,并将添加水印后的图片保存到指定文件夹。这个程序不仅可以帮助我们保护图片版权,还可以方便地对大量图片进行批量处理。希望本文对你有所帮助,你可以根据自己的需求对代码进行扩展和优化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

数据攻城小狮子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值