#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
批量占位图像生成器
使用 Pillow 库生成纯色或带文字标注的占位图。
支持自定义尺寸、颜色、格式和输出目录。
依赖安装:
pip install Pillow
"""
import argparse
import os
import random
from PIL import Image, ImageDraw, ImageFont
# 常见颜色映射 (名称 -> RGB)
COLOR_MAP = {
'red': (255, 99, 71), # 番茄红
'blue': (70, 130, 180), # 钢蓝
'green': (60, 179, 113), # 海洋绿
'gray': (169, 169, 169),
'darkgray': (105, 105, 105),
'lightgray': (211, 211, 211),
'white': (255, 255, 255),
'black': (0, 0, 0),
'yellow': (255, 255, 0),
'purple': (147, 112, 219),
'orange': (255, 165, 0),
'pink': (255, 182, 193),
}
def parse_color(color_str):
"""将颜色字符串解析为 RGB 元组,支持 #hex 或预定义名称。"""
if color_str is None:
return None
s = color_str.strip().lower()
if s.startswith('#'):
try:
hex_val = s.lstrip('#')
if len(hex_val) != 6:
raise ValueError(f"无效的十六进制颜色: {color_str}")
return tuple(int(hex_val[i:i+2], 16) for i in (0, 2, 4))
except ValueError as e:
raise argparse.ArgumentTypeError(f"颜色格式错误: {e}")
if s in COLOR_MAP:
return COLOR_MAP[s]
# 尝试解析为纯数字 RGB,"255,0,0"
if ',' in s:
parts = s.split(',')
if len(parts) == 3:
try:
return tuple(max(0, min(255, int(p.strip()))) for p in parts)
except ValueError:
pass
raise argparse.ArgumentTypeError(f"无法识别的颜色: {color_str},支持 #RRGGBB 或名称 {list(COLOR_MAP.keys())}")
def create_placeholder_image(width, height, color, text=None, font_size=None):
"""生成单张占位图像并返回 PIL Image 对象。"""
if color is None:
# 随机生成较柔和颜色
color = (random.randint(100, 230), random.randint(100, 230), random.randint(100, 230))
image = Image.new('RGB', (width, height), color)
if text:
draw = ImageDraw.Draw(image)
if font_size is None:
# 根据图像大小自适应字号
font_size = max(12, int(min(width, height) * 0.12))
try:
# 尝试加载默认字体,若失败则使用默认
font = ImageFont.load_default()
# 简单放大字体(Pillow 10+ 支持 size 参数)
font = ImageFont.truetype("DejaVuSans.ttf", font_size) if os.path.exists("DejaVuSans.ttf") else ImageFont.load_default()
except:
font = ImageFont.load_default()
# 计算文字位置居中
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]
x = (width - text_width) / 2
y = (height - text_height) / 2 - text_bbox[1] # 调整基线
# 为了确保文字可读,在底部添加白色边框描边 (仅当颜色较深时)
draw.text((x, y), text, fill=(255, 255, 255), font=font, stroke_width=1, stroke_fill=(0,0,0))
return image
def main():
parser = argparse.ArgumentParser(
description="批量生成占位图,示例: python placeholder_gen.py --size 800x600 --count 10 --prefix banner --color #3498db --text 'Demo' --out ./images"
)
parser.add_argument('--size', '-s', type=str, default='800x600', help="图片尺寸 宽x高,800x600 或 1024x768")
parser.add_argument('--count', '-n', type=int, default=5, help="生成数量 (默认: 5)")
parser.add_argument('--out', '-o', type=str, default='./placeholder_images', help="输出目录 (默认: ./placeholder_images)")
parser.add_argument('--prefix', '-p', type=str, default='placeholder', help="文件名前缀 (默认: placeholder)")
parser.add_argument('--format', '-f', type=str, default='PNG', choices=['PNG', 'JPEG', 'WEBP', 'BMP'], help="图片格式 (默认: PNG)")
parser.add_argument('--color', '-c', type=str, default=None, help="背景颜色: 十六进制 #RRGGBB 或颜色名称,留空则随机")
parser.add_argument('--text', '-t', type=str, default=None, help="在图片中央显示的文本 (默认无)")
parser.add_argument('--font-size', type=int, default=None, help="文字字号 (默认自动)")
parser.add_argument('--seed', type=int, default=None, help="随机种子,固定颜色随机性")
parser.add_argument('--no-text', action='store_true', help="禁止文本,即使指定 --text 也忽略")
args = parser.parse_args()
# 解析尺寸
try:
w_str, h_str = args.size.lower().split('x')
width, height = int(w_str.strip()), int(h_str.strip())
if width <= 0 or height <= 0:
raise ValueError("宽高必须为正整数")
except ValueError as e:
parser.error(f"尺寸格式错误: {args.size},应类似 800x600")
if args.count <= 0:
parser.error("数量必须大于 0")
# 固定随机种子
if args.seed is not None:
random.seed(args.seed)
# 解析颜色
bg_color = None
if args.color:
try:
bg_color = parse_color(args.color)
except argparse.ArgumentTypeError as e:
parser.error(f"颜色参数错误: {e}")
# 创建输出目录
os.makedirs(args.out, exist_ok=True)
# 处理格式扩展名
ext = args.format.lower()
if ext == 'jpeg':
ext = 'jpg'
elif ext == 'webp':
ext = 'webp'
elif ext == 'bmp':
ext = 'bmp'
# 生成图片
generated = []
for i in range(1, args.count + 1):
filename = f"{args.prefix}_{i}.{ext}"
filepath = os.path.join(args.out, filename)
# 如果指定了文本且不禁用,则显示文本
text_content = args.text if (args.text and not args.no_text) else None
# 生成图像
img = create_placeholder_image(width, height, bg_color, text=text_content, font_size=args.font_size)
# 保存
try:
if ext == 'jpg':
img.save(filepath, quality=90)
else:
img.save(filepath)
generated.append(filepath)
except Exception as e:
print(f"[错误] 保存 {filepath} 失败: {e}")
# 打印结果
print(f"已生成 {len(generated)} 张占位图到: {os.path.abspath(args.out)}")
for p in generated:
print(f" - {p}")
if __name__ == '__main__':
main()
核心功能与使用场景
您可以通过命令行参数灵活控制生成图片的尺寸、数量、颜色和文字标注,适合用于前端开发、设计稿或数据填充。

- 基础用法:运行脚本时,通过
--size指定图片尺寸(如800x600),--count指定生成数量。 - 自定义外观:使用
--color设置背景色(支持#RRGGBB或颜色名称),使用--text在图片中央添加文字。 - 输出控制:通过
--out指定输出文件夹,--prefix设置文件名前缀,--format选择图片格式(PNG/JPEG等)。 - 高级选项:您可以设置
--seed固定随机颜色,或使用--no-text忽略文字参数,方便自动化测试。
版权声明: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直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播