330 lines
11 KiB
Python
330 lines
11 KiB
Python
|
|
#!/usr/bin/env python3
|
|||
|
|
"""
|
|||
|
|
整理 data/订单班文档资料 目录下所有订单班的图片
|
|||
|
|
1. 统一图片格式为jpg
|
|||
|
|
2. 规范化图片命名
|
|||
|
|
3. 更新Markdown中的图片引用
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import os
|
|||
|
|
import re
|
|||
|
|
import shutil
|
|||
|
|
import json
|
|||
|
|
from pathlib import Path
|
|||
|
|
from PIL import Image
|
|||
|
|
from typing import Dict, List, Tuple
|
|||
|
|
|
|||
|
|
def main():
|
|||
|
|
"""主函数"""
|
|||
|
|
base_path = Path("/Users/xiaoqi/Documents/Dev/Project/2025-09-08_n8nDEMO演示/data/订单班文档资料")
|
|||
|
|
|
|||
|
|
# 订单班列表
|
|||
|
|
order_classes = [
|
|||
|
|
"文旅", "财经商贸", "食品", "智能开发", "智能制造",
|
|||
|
|
"视觉设计", "交通物流", "土木", "大健康", "能源",
|
|||
|
|
"化工", "环保"
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
print("=" * 60)
|
|||
|
|
print("开始整理订单班图片资源")
|
|||
|
|
print("=" * 60)
|
|||
|
|
|
|||
|
|
total_processed = 0
|
|||
|
|
|
|||
|
|
for order_class in order_classes:
|
|||
|
|
order_dir = base_path / order_class
|
|||
|
|
|
|||
|
|
if not order_dir.exists():
|
|||
|
|
print(f"\n⚠ 跳过:{order_class} 目录不存在")
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
notion_dir = order_dir / "notion文稿"
|
|||
|
|
if not notion_dir.exists():
|
|||
|
|
print(f"\n⚠ 跳过:{order_class}/notion文稿 目录不存在")
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
# 处理该订单班
|
|||
|
|
count = process_order_class(order_class, notion_dir)
|
|||
|
|
total_processed += count
|
|||
|
|
|
|||
|
|
print("\n" + "=" * 60)
|
|||
|
|
print(f"✅ 完成!共处理 {total_processed} 张图片")
|
|||
|
|
print("=" * 60)
|
|||
|
|
|
|||
|
|
def process_order_class(order_class: str, notion_dir: Path) -> int:
|
|||
|
|
"""处理单个订单班的图片"""
|
|||
|
|
print(f"\n{'='*50}")
|
|||
|
|
print(f"处理订单班: {order_class}")
|
|||
|
|
print(f"{'='*50}")
|
|||
|
|
|
|||
|
|
# 确保image目录存在
|
|||
|
|
image_dir = notion_dir / "image"
|
|||
|
|
image_dir.mkdir(exist_ok=True)
|
|||
|
|
|
|||
|
|
# 收集所有图片文件(包括各种格式)
|
|||
|
|
all_images = []
|
|||
|
|
|
|||
|
|
# 在notion文稿目录查找散落的图片
|
|||
|
|
for ext in ['*.jpg', '*.jpeg', '*.png', '*.gif', '*.bmp', '*.webp']:
|
|||
|
|
all_images.extend(notion_dir.glob(ext))
|
|||
|
|
all_images.extend(notion_dir.glob(ext.upper()))
|
|||
|
|
|
|||
|
|
# 在image子目录查找图片
|
|||
|
|
if image_dir.exists():
|
|||
|
|
for ext in ['*.jpg', '*.jpeg', '*.png', '*.gif', '*.bmp', '*.webp']:
|
|||
|
|
all_images.extend(image_dir.glob(ext))
|
|||
|
|
all_images.extend(image_dir.glob(ext.upper()))
|
|||
|
|
|
|||
|
|
if not all_images:
|
|||
|
|
print(f" 没有找到图片文件")
|
|||
|
|
return 0
|
|||
|
|
|
|||
|
|
print(f" 找到 {len(all_images)} 张图片")
|
|||
|
|
|
|||
|
|
# 记录映射关系
|
|||
|
|
image_mapping = {}
|
|||
|
|
processed_count = 0
|
|||
|
|
|
|||
|
|
# 分类计数器
|
|||
|
|
counters = {
|
|||
|
|
"设计图": 0,
|
|||
|
|
"展示图": 0,
|
|||
|
|
"效果图": 0,
|
|||
|
|
"流程图": 0,
|
|||
|
|
"场景图": 0,
|
|||
|
|
"图片": 0 # 通用图片
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
# 处理每张图片
|
|||
|
|
for img_path in sorted(set(all_images)):
|
|||
|
|
if not img_path.exists():
|
|||
|
|
continue
|
|||
|
|
|
|||
|
|
old_name = img_path.name
|
|||
|
|
|
|||
|
|
# 生成新名称
|
|||
|
|
new_name = generate_standard_name(old_name, order_class, counters)
|
|||
|
|
|
|||
|
|
# 确保是jpg格式
|
|||
|
|
if not new_name.endswith('.jpg'):
|
|||
|
|
new_name = new_name.rsplit('.', 1)[0] + '.jpg'
|
|||
|
|
|
|||
|
|
# 目标路径
|
|||
|
|
new_path = image_dir / new_name
|
|||
|
|
|
|||
|
|
# 如果需要移动或转换
|
|||
|
|
if img_path != new_path:
|
|||
|
|
try:
|
|||
|
|
# 转换图片格式并移动到image目录
|
|||
|
|
convert_and_move_image(img_path, new_path)
|
|||
|
|
image_mapping[old_name] = new_name
|
|||
|
|
processed_count += 1
|
|||
|
|
print(f" ✓ {old_name} -> {new_name}")
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f" ✗ 处理失败 {old_name}: {e}")
|
|||
|
|
|
|||
|
|
# 更新Markdown文件中的引用
|
|||
|
|
if image_mapping:
|
|||
|
|
update_markdown_files(notion_dir, image_mapping)
|
|||
|
|
save_mapping(notion_dir, image_mapping)
|
|||
|
|
|
|||
|
|
# 创建图片索引
|
|||
|
|
create_image_index(order_class, image_dir)
|
|||
|
|
|
|||
|
|
print(f" 完成:处理了 {processed_count} 张图片")
|
|||
|
|
return processed_count
|
|||
|
|
|
|||
|
|
def generate_standard_name(filename: str, order_class: str, counters: Dict[str, int]) -> str:
|
|||
|
|
"""生成标准化的文件名"""
|
|||
|
|
name = Path(filename).stem.lower()
|
|||
|
|
|
|||
|
|
# 特殊处理文旅订单班的Whisk图片
|
|||
|
|
if order_class == "文旅" and 'whisk' in name:
|
|||
|
|
counters["设计图"] += 1
|
|||
|
|
return f"设计图_{counters['设计图']:02d}.jpg"
|
|||
|
|
|
|||
|
|
# 根据文件名特征分类
|
|||
|
|
if any(keyword in name for keyword in ['设计', 'design', 'whisk', 'cad', '3d', '三维', '渲染']):
|
|||
|
|
counters["设计图"] += 1
|
|||
|
|
return f"设计图_{counters['设计图']:02d}.jpg"
|
|||
|
|
|
|||
|
|
elif any(keyword in name for keyword in ['展示', 'display', 'show', '展台', '展位', '展览']):
|
|||
|
|
counters["展示图"] += 1
|
|||
|
|
return f"展示图_{counters['展示图']:02d}.jpg"
|
|||
|
|
|
|||
|
|
elif any(keyword in name for keyword in ['效果', 'effect', 'render', '成品', '最终']):
|
|||
|
|
counters["效果图"] += 1
|
|||
|
|
return f"效果图_{counters['效果图']:02d}.jpg"
|
|||
|
|
|
|||
|
|
elif any(keyword in name for keyword in ['流程', 'flow', 'process', '步骤', '架构', 'diagram']):
|
|||
|
|
counters["流程图"] += 1
|
|||
|
|
return f"流程图_{counters['流程图']:02d}.jpg"
|
|||
|
|
|
|||
|
|
elif any(keyword in name for keyword in ['场景', 'scene', '展会', '博览', '会场', '现场', '签到']):
|
|||
|
|
counters["场景图"] += 1
|
|||
|
|
return f"场景图_{counters['场景图']:02d}.jpg"
|
|||
|
|
|
|||
|
|
else:
|
|||
|
|
# 默认命名
|
|||
|
|
counters["图片"] += 1
|
|||
|
|
return f"图片_{counters['图片']:02d}.jpg"
|
|||
|
|
|
|||
|
|
def convert_and_move_image(source_path: Path, target_path: Path):
|
|||
|
|
"""转换图片格式并移动到目标位置"""
|
|||
|
|
try:
|
|||
|
|
# 如果已经是jpg且只需要移动
|
|||
|
|
if source_path.suffix.lower() == '.jpg' and source_path.parent == target_path.parent:
|
|||
|
|
if source_path != target_path:
|
|||
|
|
shutil.move(str(source_path), str(target_path))
|
|||
|
|
else:
|
|||
|
|
# 需要转换格式
|
|||
|
|
img = Image.open(source_path)
|
|||
|
|
|
|||
|
|
# 如果是RGBA模式,转换为RGB
|
|||
|
|
if img.mode in ('RGBA', 'LA', 'P'):
|
|||
|
|
# 创建白色背景
|
|||
|
|
background = Image.new('RGB', img.size, (255, 255, 255))
|
|||
|
|
if img.mode == 'P':
|
|||
|
|
img = img.convert('RGBA')
|
|||
|
|
background.paste(img, mask=img.split()[-1] if img.mode == 'RGBA' else None)
|
|||
|
|
img = background
|
|||
|
|
elif img.mode != 'RGB':
|
|||
|
|
img = img.convert('RGB')
|
|||
|
|
|
|||
|
|
# 保存为jpg
|
|||
|
|
img.save(target_path, 'JPEG', quality=95, optimize=True)
|
|||
|
|
|
|||
|
|
# 删除原文件(如果不同)
|
|||
|
|
if source_path != target_path:
|
|||
|
|
source_path.unlink()
|
|||
|
|
except Exception as e:
|
|||
|
|
# 如果转换失败,尝试直接复制
|
|||
|
|
print(f" 转换失败,尝试直接复制: {e}")
|
|||
|
|
shutil.copy2(source_path, target_path)
|
|||
|
|
if source_path != target_path:
|
|||
|
|
source_path.unlink()
|
|||
|
|
|
|||
|
|
def update_markdown_files(notion_dir: Path, image_mapping: Dict[str, str]):
|
|||
|
|
"""更新Markdown文件中的图片引用"""
|
|||
|
|
md_files = list(notion_dir.glob("*.md"))
|
|||
|
|
|
|||
|
|
for md_file in md_files:
|
|||
|
|
try:
|
|||
|
|
content = md_file.read_text(encoding='utf-8')
|
|||
|
|
original_content = content
|
|||
|
|
|
|||
|
|
for old_name, new_name in image_mapping.items():
|
|||
|
|
# 准备各种可能的引用格式
|
|||
|
|
old_name_no_ext = Path(old_name).stem
|
|||
|
|
|
|||
|
|
# 替换各种可能的图片引用格式
|
|||
|
|
patterns = [
|
|||
|
|
# 标准Markdown格式
|
|||
|
|
(f"!\\[([^\\]]*)\\]\\({re.escape(old_name)}\\)", f""),
|
|||
|
|
(f"!\\[([^\\]]*)\\]\\(\\./image/{re.escape(old_name)}\\)", f""),
|
|||
|
|
(f"!\\[([^\\]]*)\\]\\(image/{re.escape(old_name)}\\)", f""),
|
|||
|
|
# 可能的其他路径格式
|
|||
|
|
(f"!\\[([^\\]]*)\\]\\([^)]*/{re.escape(old_name)}\\)", f""),
|
|||
|
|
# HTML格式
|
|||
|
|
(f'src="[^"]*{re.escape(old_name)}"', f'src="./image/{new_name}"'),
|
|||
|
|
(f"src='[^']*{re.escape(old_name)}'", f"src='./image/{new_name}'"),
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
for pattern, replacement in patterns:
|
|||
|
|
content = re.sub(pattern, replacement, content, flags=re.IGNORECASE)
|
|||
|
|
|
|||
|
|
# 修正所有图片引用路径,确保都指向./image/目录
|
|||
|
|
content = re.sub(
|
|||
|
|
r'!\[([^\]]*)\]\((?!\.?/image/)([^)]+\.(jpg|jpeg|png|gif|bmp|webp))\)',
|
|||
|
|
r'',
|
|||
|
|
content,
|
|||
|
|
flags=re.IGNORECASE
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 如果内容有变化,保存文件
|
|||
|
|
if content != original_content:
|
|||
|
|
md_file.write_text(content, encoding='utf-8')
|
|||
|
|
print(f" ✓ 更新Markdown: {md_file.name}")
|
|||
|
|
except Exception as e:
|
|||
|
|
print(f" ✗ 更新Markdown失败 {md_file.name}: {e}")
|
|||
|
|
|
|||
|
|
def save_mapping(notion_dir: Path, image_mapping: Dict[str, str]):
|
|||
|
|
"""保存图片映射文件"""
|
|||
|
|
mapping_file = notion_dir / "图片映射.json"
|
|||
|
|
|
|||
|
|
with open(mapping_file, 'w', encoding='utf-8') as f:
|
|||
|
|
json.dump(image_mapping, f, ensure_ascii=False, indent=2)
|
|||
|
|
|
|||
|
|
print(f" ✓ 保存映射文件")
|
|||
|
|
|
|||
|
|
def create_image_index(order_class: str, image_dir: Path):
|
|||
|
|
"""创建图片索引文档"""
|
|||
|
|
if not image_dir.exists():
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
images = sorted(image_dir.glob("*.jpg"))
|
|||
|
|
|
|||
|
|
if not images:
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
# 分类统计
|
|||
|
|
categories = {
|
|||
|
|
"设计图": [],
|
|||
|
|
"展示图": [],
|
|||
|
|
"效果图": [],
|
|||
|
|
"流程图": [],
|
|||
|
|
"场景图": [],
|
|||
|
|
"其他": []
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for img in images:
|
|||
|
|
name = img.name
|
|||
|
|
categorized = False
|
|||
|
|
for category in ["设计图", "展示图", "效果图", "流程图", "场景图"]:
|
|||
|
|
if name.startswith(category):
|
|||
|
|
categories[category].append(name)
|
|||
|
|
categorized = True
|
|||
|
|
break
|
|||
|
|
if not categorized:
|
|||
|
|
categories["其他"].append(name)
|
|||
|
|
|
|||
|
|
# 生成索引内容
|
|||
|
|
content = f"# {order_class}订单班 - 图片资源索引\n\n"
|
|||
|
|
content += f"**图片总数**: {len(images)} 张\n"
|
|||
|
|
content += f"**更新时间**: 2025-09-28\n\n"
|
|||
|
|
|
|||
|
|
for category, files in categories.items():
|
|||
|
|
if files:
|
|||
|
|
content += f"## {category} ({len(files)}张)\n\n"
|
|||
|
|
for file in files:
|
|||
|
|
content += f"- {file}\n"
|
|||
|
|
content += "\n"
|
|||
|
|
|
|||
|
|
content += """## 图片引用说明
|
|||
|
|
|
|||
|
|
### Markdown中的引用格式
|
|||
|
|
```markdown
|
|||
|
|

|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 路径说明
|
|||
|
|
- 所有图片都在 `notion文稿/image/` 目录下
|
|||
|
|
- Markdown文件中使用相对路径 `./image/` 引用
|
|||
|
|
- 图片格式已统一为 `.jpg`
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
# 保存索引文件
|
|||
|
|
index_file = image_dir.parent / "图片索引.md"
|
|||
|
|
index_file.write_text(content, encoding='utf-8')
|
|||
|
|
print(f" ✓ 创建图片索引")
|
|||
|
|
|
|||
|
|
if __name__ == "__main__":
|
|||
|
|
# 检查是否安装了Pillow
|
|||
|
|
try:
|
|||
|
|
from PIL import Image
|
|||
|
|
except ImportError:
|
|||
|
|
print("需要安装Pillow库来处理图片格式转换")
|
|||
|
|
print("请运行: pip3 install Pillow")
|
|||
|
|
exit(1)
|
|||
|
|
|
|||
|
|
main()
|