python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python图片添加水印

Python Pillow库批量为图片添加文字水印或图片水印

作者:小庄-Python办公

这篇文章主要为大家详细介绍了如何使用Python的Pillow库批量添加图片水印,适用于员工工牌或产品图片处理,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下

场景引入

公司有 5000 张产品图片需要加上公司 Logo 水印,或 2000 张员工工牌照片需要加盖"仅限内部使用"的文字水印。用 Photoshop 一张一张处理,一个人都要干半天。

本节教你用 Python 的 Pillow 库,批量为图片添加文字水印或图片水印,每秒处理几十张。

技术原理

使用 Pillow(PIL Fork)库操作图片:

水印类型实现方式
文字水印ImageDraw.text()
图片水印(Logo)Image.paste()Image.alpha_composite()
半透明水印创建透明图层 + Image.blend()
倾斜水印Image.rotate()

原图 → 创建透明图层 → 绘制水印 → 叠加到原图 → 保存

环境准备

pip install Pillow

完整代码

from PIL import Image, ImageDraw, ImageFont, ImageEnhance
import os
from pathlib import Path

# ==================== 方案 1:文字水印 ====================
def add_text_watermark(input_image, output_image, text="内部资料",
                       position="center", font_size=40, color=(255, 255, 255, 128),
                       angle=0):
    """
    为图片添加文字水印

    参数:
        input_image: 输入图片路径
        output_image: 输出图片路径
        text: 水印文字
        position: 位置 'center'/'bottom-right'/'bottom-left'/'top-right'/'top-left'
        font_size: 字体大小
        color: 字体颜色 (R, G, B, A)
        angle: 旋转角度(0=水平,-30=左倾斜)
    """
    # 打开图片
    img = Image.open(input_image).convert('RGBA')

    # 创建透明图层
    txt_layer = Image.new('RGBA', img.size, (255, 255, 255, 0))
    draw = ImageDraw.Draw(txt_layer)

    # 获取字体
    try:
        font = ImageFont.truetype("C:/Windows/Fonts/msyh.ttc", font_size)  # 微软雅黑
    except:
        font = ImageFont.load_default()

    # 计算文字大小和位置
    bbox = draw.textbbox((0, 0), text, font=font)
    text_width = bbox[2] - bbox[0]
    text_height = bbox[3] - bbox[1]

    img_width, img_height = img.size

    positions = {
        'center': ((img_width - text_width) // 2, (img_height - text_height) // 2),
        'bottom-right': (img_width - text_width - 20, img_height - text_height - 20),
        'bottom-left': (20, img_height - text_height - 20),
        'top-right': (img_width - text_width - 20, 20),
        'top-left': (20, 20),
    }

    x, y = positions.get(position, positions['center'])

    # 如果需要旋转
    if angle != 0:
        # 创建更大的图层以容纳旋转后的文字
        big_layer = Image.new('RGBA', (img_width * 2, img_height * 2), (255, 255, 255, 0))
        big_draw = ImageDraw.Draw(big_layer)
        big_draw.text((img_width // 2, img_height // 2), text, font=font, fill=color)
        big_layer = big_layer.rotate(angle, expand=0)
        txt_layer = big_layer.crop((img_width // 2, img_height // 2,
                                     img_width // 2 + img_width,
                                     img_height // 2 + img_height))
    else:
        draw.text((x, y), text, font=font, fill=color)

    # 叠加
    result = Image.alpha_composite(img, txt_layer)

    # 保存(转回 RGB 以便保存为 JPEG)
    result = result.convert('RGB')
    result.save(output_image, quality=95)
    print(f"文字水印: {os.path.basename(input_image)}")


# ==================== 方案 2:图片水印(Logo) ====================
def add_image_watermark(input_image, output_image, logo_path,
                       position="bottom-right", opacity=0.5, scale=0.15):
    """
    为图片添加 Logo 水印

    参数:
        input_image: 输入图片
        output_image: 输出图片
        logo_path: Logo 图片路径(建议 PNG 透明背景)
        position: 位置
        opacity: 透明度(0-1,1=完全不透明)
        scale: Logo 相对原图大小的比例(0.15=15%)
    """
    img = Image.open(input_image).convert('RGBA')

    # 打开 Logo
    logo = Image.open(logo_path).convert('RGBA')

    # 缩放 Logo
    new_logo_size = (int(img.width * scale), int(img.height * scale * logo.height / logo.width))
    logo = logo.resize(new_logo_size, Image.LANCZOS)

    # 设置 Logo 透明度
    if opacity < 1:
        # 调整 alpha 通道
        r, g, b, a = logo.split()
        a = a.point(lambda x: int(x * opacity))
        logo = Image.merge('RGBA', (r, g, b, a))

    # 计算位置
    positions = {
        'center': ((img.width - logo.width) // 2, (img.height - logo.height) // 2),
        'bottom-right': (img.width - logo.width - 20, img.height - logo.height - 20),
        'bottom-left': (20, img.height - logo.height - 20),
        'top-right': (img.width - logo.width - 20, 20),
        'top-left': (20, 20),
    }

    x, y = positions.get(position, positions['bottom-right'])

    # 创建透明图层并粘贴 Logo
    watermark_layer = Image.new('RGBA', img.size, (0, 0, 0, 0))
    watermark_layer.paste(logo, (x, y))

    # 叠加
    result = Image.alpha_composite(img, watermark_layer)
    result = result.convert('RGB')
    result.save(output_image, quality=95)
    print(f"Logo水印: {os.path.basename(input_image)}")


# ==================== 方案 3:平铺水印(全屏重复) ====================
def add_tiled_watermark(input_image, output_image, text="内部资料",
                        font_size=30, color=(255, 255, 255, 50), angle=-30, spacing=150):
    """
    添加平铺水印(全屏重复文字)
    """
    img = Image.open(input_image).convert('RGBA')
    txt_layer = Image.new('RGBA', img.size, (255, 255, 255, 0))
    draw = ImageDraw.Draw(txt_layer)

    try:
        font = ImageFont.truetype("C:/Windows/Fonts/msyh.ttc", font_size)
    except:
        font = ImageFont.load_default()

    # 计算文字大小
    bbox = draw.textbbox((0, 0), text, font=font)
    text_width = bbox[2] - bbox[0]
    text_height = bbox[3] - bbox[1]

    # 平铺
    y = 0
    while y < img.height:
        x = 0
        row_offset = (y // spacing) % 2 * (spacing // 2)  # 错行排列
        while x < img.width:
            draw.text((x + row_offset, y), text, font=font, fill=color)
            x += text_width + spacing
        y += text_height + spacing

    result = Image.alpha_composite(img, txt_layer)
    result = result.convert('RGB')
    result.save(output_image, quality=95)
    print(f"平铺水印: {os.path.basename(input_image)}")


# ==================== 批量处理 ====================
def batch_add_watermark(input_dir, output_dir, watermark_func, **kwargs):
    """
    批量为文件夹中的所有图片添加水印
    """
    input_path = Path(input_dir)
    output_path = Path(output_dir)
    output_path.mkdir(parents=True, exist_ok=True)

    image_extensions = {'.jpg', '.jpeg', '.png', '.bmp', '.webp', '.tiff'}
    count = 0

    for file_path in input_path.iterdir():
        if file_path.is_file() and file_path.suffix.lower() in image_extensions:
            output_file = output_path / file_path.name
            watermark_func(str(file_path), str(output_file), **kwargs)
            count += 1

    print(f"\n批量水印完成: {count} 张图片")


# ==================== 使用示例 ====================
if __name__ == "__main__":
    # 单个文件
    # add_text_watermark("工牌照片.jpg", "工牌_水印.jpg", text="内部资料", position="center", font_size=50)

    # 批量文字水印
    batch_add_watermark(
        input_dir="原始工牌照片",
        output_dir="已加水印",
        watermark_func=add_text_watermark,
        text="仅限内部使用",
        position="center",
        font_size=40,
    )

    # 批量 Logo 水印
    # batch_add_watermark(
    #     input_dir="产品图片",
    #     output_dir="已加Logo",
    #     watermark_func=add_image_watermark,
    #     logo_path="company_logo.png",
    #     position="bottom-right",
    #     opacity=0.7,
    #     scale=0.1
    # )

    # 平铺水印(防截图)
    # batch_add_watermark(
    #     input_dir="机密文档截图",
    #     output_dir="平铺水印",
    #     watermark_func=add_tiled_watermark,
    #     text="机密文件",
    #     font_size=25,
    #     angle=-30,
    # )

常见问题

Q1:中文水印显示为方框?

需要指定中文字体路径:

font = ImageFont.truetype("C:/Windows/Fonts/msyh.ttc", font_size)  # 微软雅黑
# 或
font = ImageFont.truetype("C:/Windows/Fonts/simsun.ttc", font_size)  # 宋体

Q2:水印太显眼覆盖了图片内容?

调整 color 的 alpha 值(第四个参数):

color=(255, 255, 255, 50)  # alpha=50,更透明

Q3:保存 PNG 后水印不见了?

确保保存时使用 RGBA 模式并指定 PNG 格式:

result.save(output_image, 'PNG')

总结

水印类型函数适用场景
文字水印add_text_watermark()版权声明
Logo 水印add_image_watermark()品牌标识
平铺水印add_tiled_watermark()防泄漏标记

本节掌握了为图片批量添加水印的能力。

到此这篇关于Python Pillow库批量为图片添加文字水印或图片水印的文章就介绍到这了,更多相关Python图片添加水印内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文