本文目录导读:

我来为您创建一个批量给图片添加文字说明的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格式且图片有透明通道,会自动转换为白色背景。
-
文字位置:支持顶部、底部和居中三个位置。
-
批量处理:可以自动处理文件夹中的所有图片,支持递归处理子目录。
-
错误处理:脚本包含了基本的错误处理,如果某张图片处理失败不会影响其他图片。
这个脚本非常适合处理大量照片、创建带说明的图片集或添加水印文字等场景,您可以根据需要调整字体、颜色、位置等参数。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播