diff --git a/README.md b/README.md index 2b2a346..8f05602 100644 --- a/README.md +++ b/README.md @@ -20,4 +20,23 @@ python generate_layout.py ``` - 该脚本会自动调用 DeepSeek API 生成 React 组件代码,并将其保存到指定路径。 - 默认为``output/generated_code.jsx``,可以根据需要修改。 \ No newline at end of file + 默认为``output/generated_code.jsx``,可以根据需要修改。 + +## 图层叠加和PSD导出部分 +### 功能组件 +- **图层合成**:根据生成的布局配置,将各个图层叠加在一起,生成完整的海报图像。 +- **PSD导出**:将合成的海报图像保存为标准的PSD格式,同时保留各个图层的独立性,方便后续编辑。 +### 如何调用 +1. **环境准备**: +```bash +conda create -n ai_service python=3.8 +conda activate ai_service +pip install -r requirements.txt +``` +2. **运行脚本**: +```bash +python export_psd.py #简单生成 +python export_psd_from_json.py #从json文件加载布局并生成 +python PSD_test.py #在run_pipline.py中的调用方法 +``` +该脚本会自动调用图层合成模块生成完整海报图像,并将其保存为标准PSD格式。 \ No newline at end of file diff --git a/configs/example.json b/configs/example.json new file mode 100644 index 0000000..7b2764e --- /dev/null +++ b/configs/example.json @@ -0,0 +1,40 @@ +{ + "canvas": { + "width": 1000, + "height": 800, + "mode": "RGB" + }, + "layers": [ + { + "image_path": "../images/background.jpg", + "name": "background", + "position": { + "left": 0, + "top": 0 + }, + "visible": true + }, + { + "image_path": "../images/nankai.jpg", + "name": "middle", + "position": { + "left": 100, + "top": 100 + }, + "visible": true + }, + { + "image_path": "../images/aaai.png", + "name": "top", + "position": { + "left": 200, + "top": 200 + }, + "visible": true + } + ], + "output": { + "path": "../outputs/configured_output.psd", + "generate_preview": true + } +} \ No newline at end of file diff --git a/outputs/.DS_Store b/outputs/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/outputs/.DS_Store differ diff --git a/outputs/combined_output.psd b/outputs/combined_output.psd new file mode 100644 index 0000000..8f291e4 Binary files /dev/null and b/outputs/combined_output.psd differ diff --git a/outputs/combined_output_预览.png b/outputs/combined_output_预览.png new file mode 100644 index 0000000..2ca34af Binary files /dev/null and b/outputs/combined_output_预览.png differ diff --git a/scripts/PSD_test1.py b/scripts/PSD_test1.py new file mode 100644 index 0000000..8556279 --- /dev/null +++ b/scripts/PSD_test1.py @@ -0,0 +1,14 @@ +from export_psd import create_psd_from_images + +if __name__ == "__main__": + image_list = [ + '../images/background.jpg', + '../images/nankai.jpg', + '../images/aaai.png', + # Add more images as needed + ] + + create_psd_from_images( + image_paths=image_list, + output_path='../outputs/combined_output.psd' + ) \ No newline at end of file diff --git a/scripts/export_psd.py b/scripts/export_psd.py new file mode 100644 index 0000000..0e1dbda --- /dev/null +++ b/scripts/export_psd.py @@ -0,0 +1,100 @@ +""" +测试文件:从多个图片创建PSD文件 +将图片列表作为输入,从底到顶添加为PSD图层,并将图片居中放置 +""" + +from psd_tools import PSDImage +from PIL import Image +from psd_tools.constants import Compression +import os +from typing import List, Tuple + +# 导入PixelLayer类,用于从PIL图像创建图层 +from psd_tools.api.layers import PixelLayer + + +def create_psd_from_images( + image_paths: List[str], + output_path: str, + canvas_size: Tuple[int, int] = (1000, 800), + mode: str = 'RGB' +) -> None: + """ + 从图片列表创建PSD文件,将图片从底到顶堆叠 + + 参数: + image_paths: 图片路径列表 + output_path: 保存PSD文件的路径 + canvas_size: PSD画布大小,格式为(宽度, 高度) + mode: PSD文件的颜色模式 + """ + # 确保输出目录存在 + os.makedirs(os.path.dirname(os.path.abspath(output_path)), exist_ok=True) + + try: + # 1. 创建一个新的PSD文件 + psd = PSDImage.new(mode, canvas_size) + + # 2. 打开并添加每个图片作为图层 + for i, img_path in enumerate(image_paths): + # 打开图片 + image = Image.open(img_path) + + # 计算居中位置 + left = (canvas_size[0] - image.width) // 2 + top = (canvas_size[1] - image.height) // 2 + + # 根据图片文件名创建图层名称 + layer_name = f"layer {i+1} - {os.path.basename(img_path)}" + + # 创建并添加图层 + layer = PixelLayer.frompil(image, psd, layer_name, top, left, Compression.RLE) + # 确保图层可见 + layer.visible = True + psd.append(layer) + + # 确保所有图层都是可见的 + for layer in psd: + if not layer.visible: + print(f"图层 {layer.name} 不可见,正在设置为可见") + layer.visible = True + + # 生成合成图像 + composite_image = psd.composite(force=True) + + # 更新PSD文件的图像数据 + psd._record.image_data.set_data([channel.tobytes() for channel in composite_image.split()], psd._record.header) + + # 3. 保存PSD文件 + psd.save(output_path) + print(f"PSD文件已成功创建,保存在: {output_path}") + + # 4. 生成并保存预览 + preview_path = os.path.splitext(output_path)[0] + "_预览.png" + composite_image.save(preview_path) + print(f"预览已保存在: {preview_path}") + + # 5. 验证PSD文件结构 + saved_psd = PSDImage.open(output_path) + print(f"PSD文件信息: {saved_psd}") + print(f"图层数量: {len(saved_psd)}") + for i, layer in enumerate(saved_psd): + print(f"图层 {i}: {layer.name}, 位置: ({layer.left}, {layer.top}), 大小: {layer.width}x{layer.height}") + + except Exception as e: + print(f"创建PSD文件时出错: {e}") + + +if __name__ == "__main__": + # 示例用法 + image_list = [ + '../images/background.jpg', # 底层图片 + '../images/nankai.jpg', # 中间图片 + '../images/aaai.png', # 顶层图片 + # 可以根据需要添加更多图片 + ] + + create_psd_from_images( + image_paths=image_list, + output_path='../outputs/combined_output.psd' + ) \ No newline at end of file diff --git a/scripts/export_psd_from_json.py b/scripts/export_psd_from_json.py new file mode 100644 index 0000000..3796568 --- /dev/null +++ b/scripts/export_psd_from_json.py @@ -0,0 +1,197 @@ + + +""" +测试文件:从JSON配置文件创建PSD文件 +支持通过配置文件精确控制图层位置和属性 +""" + +import json +from psd_tools import PSDImage +from PIL import Image +from psd_tools.constants import Compression +import os +from typing import List, Tuple + +# 导入PixelLayer类,用于从PIL图像创建图层 +from psd_tools.api.layers import PixelLayer + + +def create_psd_from_config(config_file: str) -> None: + """ + 从JSON配置文件创建PSD文件 + + 参数: + config_file: JSON配置文件路径 + """ + # 确保配置文件存在 + if not os.path.exists(config_file): + raise FileNotFoundError(f"配置文件不存在: {config_file}") + + # 读取JSON配置文件 + with open(config_file, 'r', encoding='utf-8') as f: + config = json.load(f) + + try: + # 1. 从配置创建PSD文件 + canvas = config['canvas'] + psd = PSDImage.new( + canvas['mode'], + (canvas['width'], canvas['height']) + ) + + # 2. 根据配置添加图层 + for layer_config in config['layers']: + # 打开图片 + image = Image.open(layer_config['image_path']) + + # 获取位置信息 + position = layer_config['position'] + left = position['left'] + top = position['top'] + + # 创建图层 + layer = PixelLayer.frompil( + image, + psd, + layer_config['name'], + top, + left, + Compression.RLE + ) + + # 设置图层可见性 + layer.visible = layer_config.get('visible', True) + psd.append(layer) + + # 3. 确保所有图层都是可见的 + for layer in psd: + if not layer.visible: + print(f"图层 {layer.name} 不可见,正在设置为可见") + layer.visible = True + + # 4. 生成合成图像并更新PSD文件的图像数据 + composite_image = psd.composite(force=True) + psd._record.image_data.set_data( + [channel.tobytes() for channel in composite_image.split()], + psd._record.header + ) + + # 5. 保存PSD文件 + output_config = config['output'] + output_path = output_config['path'] + + # 确保输出目录存在 + os.makedirs(os.path.dirname(os.path.abspath(output_path)), exist_ok=True) + + psd.save(output_path) + print(f"PSD文件已成功创建,保存在: {output_path}") + + # 6. 生成预览(如果配置中启用) + if output_config.get('generate_preview', False): + preview_path = os.path.splitext(output_path)[0] + "_预览.png" + composite_image.save(preview_path) + print(f"预览已保存在: {preview_path}") + + # 7. 验证PSD文件结构 + saved_psd = PSDImage.open(output_path) + print(f"PSD文件信息: {saved_psd}") + print(f"图层数量: {len(saved_psd)}") + for i, layer in enumerate(saved_psd): + print(f"图层 {i}: {layer.name}, 位置: ({layer.left}, {layer.top}), 大小: {layer.width}x{layer.height}") + + except Exception as e: + print(f"创建PSD文件时出错: {e}") + + +def create_psd_from_images( + image_paths: List[str], + output_path: str, + canvas_size: Tuple[int, int] = (1000, 800), + mode: str = 'RGB' +) -> None: + """ + 从图片列表创建PSD文件,将图片从底到顶堆叠(保留原有功能) + + 参数: + image_paths: 图片路径列表 + output_path: 保存PSD文件的路径 + canvas_size: PSD画布大小,格式为(宽度, 高度) + mode: PSD文件的颜色模式 + """ + # 确保输出目录存在 + os.makedirs(os.path.dirname(os.path.abspath(output_path)), exist_ok=True) + + try: + # 1. 创建一个新的PSD文件 + psd = PSDImage.new(mode, canvas_size) + + # 2. 打开并添加每个图片作为图层 + for i, img_path in enumerate(image_paths): + # 打开图片 + image = Image.open(img_path) + + # 计算居中位置 + left = (canvas_size[0] - image.width) // 2 + top = (canvas_size[1] - image.height) // 2 + + # 根据图片文件名创建图层名称 + layer_name = f"layer {i+1} - {os.path.basename(img_path)}" + + # 创建并添加图层 + layer = PixelLayer.frompil(image, psd, layer_name, top, left, Compression.RLE) + # 确保图层可见 + layer.visible = True + psd.append(layer) + + # 确保所有图层都是可见的 + for layer in psd: + if not layer.visible: + print(f"图层 {layer.name} 不可见,正在设置为可见") + layer.visible = True + + # 生成合成图像 + composite_image = psd.composite(force=True) + + # 更新PSD文件的图像数据 + psd._record.image_data.set_data([channel.tobytes() for channel in composite_image.split()], psd._record.header) + + # 3. 保存PSD文件 + psd.save(output_path) + print(f"PSD文件已成功创建,保存在: {output_path}") + + # 4. 生成并保存预览 + preview_path = os.path.splitext(output_path)[0] + "_预览.png" + composite_image.save(preview_path) + print(f"预览已保存在: {preview_path}") + + # 5. 验证PSD文件结构 + saved_psd = PSDImage.open(output_path) + print(f"PSD文件信息: {saved_psd}") + print(f"图层数量: {len(saved_psd)}") + for i, layer in enumerate(saved_psd): + print(f"图层 {i}: {layer.name}, 位置: ({layer.left}, {layer.top}), 大小: {layer.width}x{layer.height}") + + except Exception as e: + print(f"创建PSD文件时出错: {e}") + + +if __name__ == "__main__": + # 方法1: 使用JSON配置文件 + print("=== 使用JSON配置文件创建PSD ===") + create_psd_from_config('../configs/example.json') + + print("\n" + "="*50 + "\n") + + # 方法2: 使用原有的图片列表方法(保留兼容性) + print("=== 使用图片列表创建PSD(居中布局)===") + image_list = [ + '../images/background.jpg', # 底层图片 + '../images/nankai.jpg', # 中间图片 + '../images/aaai.png', # 顶层图片 + # 可以根据需要添加更多图片 + ] + + create_psd_from_images( + image_paths=image_list, + output_path='../outputs/combined_output.psd' + ) \ No newline at end of file