批量给图片添加文字说明脚本

wen 实用脚本 1

本文目录导读:

批量给图片添加文字说明脚本

  1. 基础版本 - 单张图片添加文字
  2. 高级版本 - 支持更多功能
  3. 命令行版本
  4. 使用方法

我来为您创建一个批量给图片添加文字说明的Python脚本,这个脚本使用PIL(Pillow)库来处理图片。

基础版本 - 单张图片添加文字

from PIL import Image, ImageDraw, ImageFont
import os
def add_text_to_image(image_path, text, output_path, 
                     position='bottom', font_size=40, 
                     text_color=(255, 255, 255), 
                     background_color=(0, 0, 0, 128)):
    """
    给单张图片添加文字说明
    参数:
    - image_path: 原始图片路径
    - text: 要添加的文字
    - output_path: 输出图片路径
    - position: 文字位置 ('top', 'bottom', 'center')
    - font_size: 字体大小
    - text_color: 文字颜色
    - background_color: 背景颜色 (带透明度)
    """
    # 打开图片
    image = Image.open(image_path)
    # 如果图片有透明通道,转换为RGB
    if image.mode in ('RGBA', 'LA') or (image.mode == 'P' and 'transparency' in image.info):
        image = image.convert('RGBA')
    else:
        image = image.convert('RGB')
    # 创建画布
    draw = ImageDraw.Draw(image)
    # 加载字体(中文需要指定字体文件)
    try:
        # Windows系统字体路径
        font_path = "C:/Windows/Fonts/simhei.ttf"  # 黑体
        if not os.path.exists(font_path):
            font_path = "C:/Windows/Fonts/msyh.ttc"  # 微软雅黑
        font = ImageFont.truetype(font_path, font_size)
    except:
        # 如果找不到中文字体,使用默认字体
        font = ImageFont.load_default()
        print("警告:使用默认字体,中文可能无法正常显示")
    # 获取文字边界框
    text_bbox = draw.textbbox((0, 0), text, font=font)
    text_width = text_bbox[2] - text_bbox[0]
    text_height = text_bbox[3] - text_bbox[1]
    # 计算图片尺寸
    image_width, image_height = image.size
    # 计算文字位置
    padding = 20
    text_x = (image_width - text_width) // 2
    if position == 'bottom':
        text_y = image_height - text_height - padding
    elif position == 'top':
        text_y = padding
    elif position == 'center':
        text_y = (image_height - text_height) // 2
    else:
        text_y = image_height - text_height - padding
    # 创建半透明背景
    overlay = Image.new('RGBA', image.size, (0, 0, 0, 0))
    overlay_draw = ImageDraw.Draw(overlay)
    # 绘制文字背景
    background_bbox = [
        text_x - padding, 
        text_y - padding//2, 
        text_x + text_width + padding, 
        text_y + text_height + padding
    ]
    # 只在有背景色时绘制
    if background_color[3] > 0:
        overlay_draw.rectangle(background_bbox, fill=background_color)
    # 将覆盖层合并到原始图片
    image = image.convert('RGBA')
    image = Image.alpha_composite(image, overlay)
    # 创建新的画布(因为原始画布已被替换)
    draw = ImageDraw.Draw(image)
    # 绘制文字
    draw.text((text_x, text_y), text, fill=text_color, font=font)
    # 保存图片
    if image.mode == 'RGBA':
        # 如果需要保存为JPG,转换为RGB
        if output_path.lower().endswith('.jpg') or output_path.lower().endswith('.jpeg'):
            image = image.convert('RGB')
    image.save(output_path)
    print(f"已保存: {output_path}")
def batch_add_text(images_dict, output_dir='output'):
    """
    批量处理多张图片
    参数:
    - images_dict: 字典,键为图片路径,值为对应的文字说明
    - output_dir: 输出目录
    """
    # 创建输出目录
    os.makedirs(output_dir, exist_ok=True)
    for img_path, text in images_dict.items():
        if not os.path.exists(img_path):
            print(f"图片不存在: {img_path}")
            continue
        # 构建输出路径
        filename = os.path.basename(img_path)
        name, ext = os.path.splitext(filename)
        output_path = os.path.join(output_dir, f"{name}_texted{ext}")
        try:
            add_text_to_image(img_path, text, output_path)
        except Exception as e:
            print(f"处理 {img_path} 时出错: {e}")
# 使用示例
if __name__ == "__main__":
    # 方法1:单张图片
    add_text_to_image(
        image_path="example.jpg",
        text="这是一张示例图片",
        output_path="example_texted.jpg",
        position="bottom",
        font_size=40
    )
    # 方法2:批量处理
    images_text = {
        "photo1.jpg": "第一张照片 - 海边风光",
        "photo2.jpg": "第二张照片 - 城市夜景",
        "photo3.jpg": "第三张照片 - 山间风景"
    }
    batch_add_text(images_text, output_dir="output_images")

高级版本 - 支持更多功能

from PIL import Image, ImageDraw, ImageFont, ImageEnhance, ImageFilter
import os
import glob
from datetime import datetime
class ImageTextAdder:
    """高级图片文字添加器"""
    def __init__(self, font_size=40, font_path=None):
        self.font_size = font_size
        self.font_path = font_path or self._get_default_font()
        self.font = None
        self._load_font()
    def _get_default_font(self):
        """获取系统默认字体"""
        font_candidates = [
            "C:/Windows/Fonts/simhei.ttf",      # 黑体
            "C:/Windows/Fonts/msyh.ttc",        # 微软雅黑
            "C:/Windows/Fonts/arial.ttf",       # Arial
            "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",  # Linux
            "/System/Library/Fonts/Helvetica.ttc"  # Mac
        ]
        for font_path in font_candidates:
            if os.path.exists(font_path):
                return font_path
        return None
    def _load_font(self):
        """加载字体"""
        try:
            if self.font_path and os.path.exists(self.font_path):
                self.font = ImageFont.truetype(self.font_path, self.font_size)
            else:
                self.font = ImageFont.load_default()
                print("警告:使用默认字体")
        except Exception as e:
            print(f"字体加载失败: {e}")
            self.font = ImageFont.load_default()
    def add_text_with_style(self, image_path, text, output_path,
                           position='bottom', font_size=None,
                           text_color=(255, 255, 255),
                           bg_color=(0, 0, 0, 150),
                           padding=20, border_radius=10,
                           text_align='center', line_spacing=1.5):
        """
        添加带样式的文字
        参数:
        - border_radius: 背景边框圆角
        - text_align: 文字对齐方式
        - line_spacing: 行间距倍数
        """
        if font_size:
            self.font_size = font_size
            self._load_font()
        # 打开图片
        image = Image.open(image_path)
        if image.mode in ('RGBA', 'LA'):
            image = image.convert('RGBA')
        else:
            image = image.convert('RGB')
        # 创建绘图对象
        draw = ImageDraw.Draw(image)
        # 处理多行文字
        lines = text.split('\n')
        text_bboxes = []
        total_height = 0
        max_width = 0
        for line in lines:
            bbox = draw.textbbox((0, 0), line, font=self.font)
            width = bbox[2] - bbox[0]
            height = bbox[3] - bbox[1]
            max_width = max(max_width, width)
            total_height += height * line_spacing
            text_bboxes.append((width, height))
        # 计算位置
        image_width, image_height = image.size
        if position == 'bottom':
            text_y = image_height - total_height - padding
        elif position == 'top':
            text_y = padding
        elif position == 'center':
            text_y = (image_height - total_height) // 2
        else:
            text_y = image_height - total_height - padding
        # 创建半透明背景
        if bg_color[3] > 0:
            bg_padding = 15
            bg_bbox = [
                padding - bg_padding,
                text_y - bg_padding,
                image_width - padding + bg_padding,
                text_y + total_height + bg_padding
            ]
            # 绘制圆角背景
            overlay = Image.new('RGBA', image.size, (0, 0, 0, 0))
            overlay_draw = ImageDraw.Draw(overlay)
            overlay_draw.rounded_rectangle(
                bg_bbox, 
                radius=border_radius, 
                fill=bg_color
            )
            image = Image.alpha_composite(image.convert('RGBA'), overlay)
            draw = ImageDraw.Draw(image)
        # 绘制每行文字
        current_y = text_y
        for i, line in enumerate(lines):
            width, height = text_bboxes[i]
            if text_align == 'center':
                text_x = (image_width - width) // 2
            elif text_align == 'left':
                text_x = padding
            elif text_align == 'right':
                text_x = image_width - padding - width
            # 添加文字阴影增强可读性
            if bg_color[3] == 0:  # 无背景时添加阴影
                shadow_color = (0, 0, 0, 180)
                draw.text((text_x + 2, current_y + 2), line, 
                         fill=shadow_color, font=self.font)
            draw.text((text_x, current_y), line, 
                     fill=text_color, font=self.font)
            current_y += height * line_spacing
        # 保存
        if output_path.lower().endswith(('.jpg', '.jpeg')):
            image = image.convert('RGB')
        image.save(output_path)
        print(f"已保存: {output_path}")
    def batch_process_folder(self, input_folder, output_folder, 
                            text_template="{filename}",
                            **kwargs):
        """
        批量处理文件夹中的所有图片
        参数:
        - text_template: 文字模板,支持 {filename}, {date}, {number}
        """
        # 创建输出目录
        os.makedirs(output_folder, exist_ok=True)
        # 支持的图片格式
        image_extensions = ['.jpg', '.jpeg', '.png', '.bmp', '.gif', '.webp']
        # 获取所有图片
        image_files = []
        for ext in image_extensions:
            image_files.extend(glob.glob(os.path.join(input_folder, f"*{ext}")))
            image_files.extend(glob.glob(os.path.join(input_folder, f"*{ext.upper()}")))
        if not image_files:
            print(f"在 {input_folder} 中没有找到图片")
            return
        print(f"找到 {len(image_files)} 张图片")
        current_date = datetime.now().strftime("%Y-%m-%d")
        for idx, img_path in enumerate(sorted(image_files), 1):
            try:
                filename = os.path.splitext(os.path.basename(img_path))[0]
                # 根据模板生成文字
                text = text_template.format(
                    filename=filename,
                    date=current_date,
                    number=idx,
                    total=len(image_files)
                )
                # 构建输出路径
                ext = os.path.splitext(img_path)[1]
                output_path = os.path.join(output_folder, f"{filename}_text{ext}")
                # 添加文字
                self.add_text_with_style(img_path, text, output_path, **kwargs)
            except Exception as e:
                print(f"处理 {img_path} 时出错: {e}")
# 使用示例
if __name__ == "__main__":
    # 创建实例
    adder = ImageTextAdder(font_size=36)
    # 单张图片
    adder.add_text_with_style(
        image_path="example.jpg",
        text="美丽的风景\n拍摄于2024年",
        output_path="example_styled.jpg",
        position="bottom",
        bg_color=(0, 0, 0, 150),
        border_radius=15
    )
    # 批量处理文件夹(自动为每张图片添加文件名作为文字)
    adder.batch_process_folder(
        input_folder="原始图片",
        output_folder="带文字图片",
        text_template="图片:{filename}\n编号:{number}/{total}",
        position="bottom",
        bg_color=(0, 0, 0, 120)
    )

命令行版本

创建 batch_add_text.py

#!/usr/bin/env python3
import argparse
import os
from PIL import Image, ImageDraw, ImageFont
import glob
def batch_process(input_dir, output_dir, text, font_size=40, 
                 position='bottom', font_path=None, recursive=False):
    """命令行批量处理函数"""
    # 设置字体
    if not font_path:
        # 尝试加载中文字体
        candidates = [
            "C:/Windows/Fonts/simhei.ttf",
            "C:/Windows/Fonts/msyh.ttc",
            "/usr/share/fonts/truetype/wqy/wqy-microhei.ttc"
        ]
        for candidate in candidates:
            if os.path.exists(candidate):
                font_path = candidate
                break
    try:
        font = ImageFont.truetype(font_path, font_size)
    except:
        font = ImageFont.load_default()
    # 获取图片列表
    extensions = ['*.jpg', '*.jpeg', '*.png', '*.bmp', '*.webp']
    image_files = []
    if recursive:
        for root, dirs, files in os.walk(input_dir):
            for ext in extensions:
                image_files.extend(glob.glob(os.path.join(root, ext)))
    else:
        for ext in extensions:
            image_files.extend(glob.glob(os.path.join(input_dir, ext)))
    # 创建输出目录
    os.makedirs(output_dir, exist_ok=True)
    # 处理每张图片
    for img_path in image_files:
        try:
            # 打开图片
            img = Image.open(img_path)
            # 获取文件名
            filename = os.path.basename(img_path)
            name, ext = os.path.splitext(filename)
            # 创建绘图对象
            draw = ImageDraw.Draw(img)
            # 计算文字大小
            text_bbox = draw.textbbox((0, 0), text, font=font)
            text_width = text_bbox[2] - text_bbox[0]
            text_height = text_bbox[3] - text_bbox[1]
            # 计算位置
            img_width, img_height = img.size
            x = (img_width - text_width) // 2
            if position == 'bottom':
                y = img_height - text_height - 20
            elif position == 'top':
                y = 20
            else:
                y = (img_height - text_height) // 2
            # 添加半透明背景
            if img.mode != 'RGBA':
                img = img.convert('RGBA')
            overlay = Image.new('RGBA', img.size, (0, 0, 0, 0))
            overlay_draw = ImageDraw.Draw(overlay)
            overlay_draw.rectangle(
                [x-10, y-5, x+text_width+10, y+text_height+5],
                fill=(0, 0, 0, 100)
            )
            img = Image.alpha_composite(img, overlay)
            # 重新创建绘图对象
            draw = ImageDraw.Draw(img)
            # 绘制文字
            draw.text((x, y), text, fill=(255, 255, 255), font=font)
            # 保存
            output_path = os.path.join(output_dir, f"{name}_texted{ext}")
            if img.mode == 'RGBA' and ext.lower() in ['.jpg', '.jpeg']:
                img = img.convert('RGB')
            img.save(output_path)
            print(f"✓ {filename} -> {os.path.basename(output_path)}")
        except Exception as e:
            print(f"✗ {img_path}: {e}")
def main():
    parser = argparse.ArgumentParser(description='批量给图片添加文字说明')
    parser.add_argument('input_dir', help='输入图片目录')
    parser.add_argument('output_dir', help='输出图片目录')
    parser.add_argument('--text', '-t', help='要添加的文字', default='')
    parser.add_argument('--size', '-s', type=int, default=40, help='字体大小')
    parser.add_argument('--position', '-p', default='bottom', 
                       choices=['top', 'bottom', 'center'], help='文字位置')
    parser.add_argument('--font', '-f', help='字体文件路径', default=None)
    parser.add_argument('--recursive', '-r', action='store_true', 
                       help='递归处理子目录')
    args = parser.parse_args()
    if not args.text:
        args.text = "示例文字"  # 默认文字
    batch_process(
        args.input_dir,
        args.output_dir,
        args.text,
        args.size,
        args.position,
        args.font,
        args.recursive
    )
if __name__ == "__main__":
    main()

使用方法

安装依赖

pip install Pillow

使用命令行版本

# 基本使用
python batch_add_text.py 输入目录 输出目录 --text "我的图片说明"
# 指定字体大小和位置
python batch_add_text.py input output -t "风景照" -s 50 -p bottom
# 使用自定义字体
python batch_add_text.py input output -t "测试" -f "C:/MY_FONT.TTF"
# 递归处理子文件夹
python batch_add_text.py input output -t "测试" -r

注意事项

  1. 中文字体:Windows系统默认有黑体(simhei.ttf)和微软雅黑(msyh.ttc),如果手动指定字体,请确保字体文件存在。

  2. 图片格式:支持JPG、PNG、BMP等常见格式,如果保存为JPG格式且图片有透明通道,会自动转换为白色背景。

  3. 文字位置:支持顶部、底部和居中三个位置。

  4. 批量处理:可以自动处理文件夹中的所有图片,支持递归处理子目录。

  5. 错误处理:脚本包含了基本的错误处理,如果某张图片处理失败不会影响其他图片。

这个脚本非常适合处理大量照片、创建带说明的图片集或添加水印文字等场景,您可以根据需要调整字体、颜色、位置等参数。

抱歉,评论功能暂时关闭!