本文目录导读:

我来为您创建一个批量给图片添加文字说明的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
注意事项
-
中文字体:Windows系统默认有黑体(simhei.ttf)和微软雅黑(msyh.ttc),如果手动指定字体,请确保字体文件存在。
-
图片格式:支持JPG、PNG、BMP等常见格式,如果保存为JPG格式且图片有透明通道,会自动转换为白色背景。
-
文字位置:支持顶部、底部和居中三个位置。
-
批量处理:可以自动处理文件夹中的所有图片,支持递归处理子目录。
-
错误处理:脚本包含了基本的错误处理,如果某张图片处理失败不会影响其他图片。
这个脚本非常适合处理大量照片、创建带说明的图片集或添加水印文字等场景,您可以根据需要调整字体、颜色、位置等参数。