first commit

This commit is contained in:
褚宏光 2025-07-15 11:02:33 +08:00
commit 1b93218e56
425 changed files with 117 additions and 0 deletions

48
README.md Normal file
View File

@ -0,0 +1,48 @@
# 微信头像批量合成主界面图片——实现思路
## 需求拆解
1. **读取主界面截图**
- 路径:`./微信无头像主界面截图/`
- 每张图片尺寸2560x1527 px
2. **读取头像素材**
- 路径:`./微信头像素材/`
3. **确定头像合成区域**
- 区域基准点:左上角 (x=8, y=31)
- 区域尺寸宽75高70
4. **头像素材处理**
- 每张头像素材需缩放/裁剪为 54x54 px
5. **头像合成**
- 将处理后的头像粘贴到主界面截图的指定区域(左上角 x=8, y=31区域内随机偏移区域宽高为75x75
- 粘贴算法:
- 头像尺寸为54x54区域为75x75允许的偏移范围
- x: [8, 8+75-54] = [8, 29]
- y: [31, 31+75-54] = [31, 52]
- 每次随机生成x、y偏移值将头像贴到(x, y)处
- 合成后图片命名规则:
- `avatar_01_实际x-实际y_55x55.jpg`
- avatar_01头像文件名+序号
- 实际x-实际y本次随机偏移后的左上角坐标
- 55x55头像尺寸
6. **输出**
- 合成图片保存到 `./output/` 目录
## 实现流程
1. 遍历主界面截图文件夹,读取每张主界面图片
2. 遍历头像素材文件夹,读取每张头像图片
3. 对每张头像图片:
- 缩放/裁剪为 54x54 px
- 随机生成偏移坐标,将头像粘贴到每张主界面图片的 (8, 31, 75x75) 区域内
- 记录实际坐标,生成合成图片,按命名规则保存到 output 目录
4. 可选:批量处理,支持多线程/进度提示
## 技术选型
- 使用 Python 的 Pillow (PIL) 库进行图片读取、缩放、粘贴和保存
- 使用 os/pathlib 遍历文件夹
- 兼容 jpg/png 格式
## 注意事项
- 头像素材尺寸不一时,需等比缩放后居中裁剪为 54x54
- 合成区域如有特殊对齐需求可调整
- 文件命名需防止重名覆盖

69
main.py Normal file
View File

@ -0,0 +1,69 @@
import os
import random
from pathlib import Path
from PIL import Image
# 配置参数
MAIN_BG_DIR = './微信无头像主界面截图'
AVATAR_DIR = './微信头像素材'
OUTPUT_DIR = './output'
# 区域参数
REGION_X = 8
REGION_Y = 31
REGION_W = 75
REGION_H = 75
AVATAR_SIZE = 54 # 54x54 px
# 输出目录准备
def ensure_output_dir():
os.makedirs(OUTPUT_DIR, exist_ok=True)
def get_image_files(folder):
exts = ['.jpg', '.jpeg', '.png']
return [f for f in Path(folder).iterdir() if f.suffix.lower() in exts]
def process_avatar(avatar_path):
"""缩放/裁剪为54x54保持居中"""
img = Image.open(avatar_path).convert('RGBA')
# 等比缩放
min_side = min(img.width, img.height)
# 居中裁剪为正方形
left = (img.width - min_side) // 2
top = (img.height - min_side) // 2
img = img.crop((left, top, left + min_side, top + min_side))
img = img.resize((AVATAR_SIZE, AVATAR_SIZE), Image.LANCZOS)
return img
def random_offset():
x = random.randint(REGION_X, REGION_X + REGION_W - AVATAR_SIZE)
y = random.randint(REGION_Y, REGION_Y + REGION_H - AVATAR_SIZE)
return x, y
def main():
ensure_output_dir()
main_imgs = get_image_files(MAIN_BG_DIR)
avatar_imgs = get_image_files(AVATAR_DIR)
if not main_imgs or not avatar_imgs:
print('未找到主界面或头像素材图片')
return
avatar_count = 0
for avatar_idx, avatar_path in enumerate(avatar_imgs, 1):
avatar_img = process_avatar(avatar_path)
avatar_name = avatar_path.stem
for main_idx, main_path in enumerate(main_imgs, 1):
with Image.open(main_path).convert('RGBA') as main_img:
x, y = random_offset()
composed = main_img.copy()
composed.paste(avatar_img, (x, y), avatar_img)
# 命名规则
out_name = f"avatar_{avatar_idx:02d}_{x}-{y}_{AVATAR_SIZE}x{AVATAR_SIZE}.jpg"
out_path = os.path.join(OUTPUT_DIR, out_name)
# 转为RGB再保存为jpg
composed.convert('RGB').save(out_path, 'JPEG', quality=95)
print(f"保存: {out_path}")
avatar_count += 1
print(f"共生成{avatar_count}张合成图片。")
if __name__ == '__main__':
main()

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 311 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 311 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 309 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 311 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 273 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 272 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 KiB

Some files were not shown because too many files have changed in this diff Show More