实现导出PSD,通过测试
This commit is contained in:
parent
cf0990d22d
commit
4cd8eec947
@ -1,8 +1,14 @@
|
|||||||
from export_psd import export_to_psd
|
from export_psd import create_psd_from_images
|
||||||
|
|
||||||
# 将多个图层导出为PSD文件
|
if __name__ == "__main__":
|
||||||
export_to_psd(
|
image_list = [
|
||||||
['background.jpg','aaai.png', 'nankai.jpg'],
|
'../images/background.jpg',
|
||||||
'output.psd',
|
'../images/nankai.jpg',
|
||||||
['background', 'middle', 'front'] # 可选的图层名称
|
'../images/aaai.png',
|
||||||
)
|
# Add more images as needed
|
||||||
|
]
|
||||||
|
|
||||||
|
create_psd_from_images(
|
||||||
|
image_paths=image_list,
|
||||||
|
output_path='../outputs/combined_output.psd'
|
||||||
|
)
|
Binary file not shown.
BIN
scripts/__pycache__/export_psd2.cpython-38.pyc
Normal file
BIN
scripts/__pycache__/export_psd2.cpython-38.pyc
Normal file
Binary file not shown.
@ -1,84 +0,0 @@
|
|||||||
# compose_poster.py - 合成图层
|
|
||||||
import os
|
|
||||||
from PIL import Image
|
|
||||||
import logging
|
|
||||||
|
|
||||||
# 设置日志
|
|
||||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
# 设置默认图片目录
|
|
||||||
DEFAULT_IMAGE_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'images')
|
|
||||||
|
|
||||||
def compose_layers(layers, output_path, canvas_size=(1080, 1920)):
|
|
||||||
"""
|
|
||||||
合成多个图层为一个图像
|
|
||||||
|
|
||||||
Args:
|
|
||||||
layers: 图层文件名列表,从底到顶排序
|
|
||||||
output_path: 输出文件路径
|
|
||||||
canvas_size: 画布大小,默认为(1080, 1920)
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
str: 输出文件的路径
|
|
||||||
"""
|
|
||||||
logger.info(f"开始合成{len(layers)}个图层...")
|
|
||||||
|
|
||||||
# 创建空白画布
|
|
||||||
canvas = Image.new('RGBA', canvas_size, (0, 0, 0, 0))
|
|
||||||
|
|
||||||
# 逐个添加图层
|
|
||||||
for i, layer_name in enumerate(layers):
|
|
||||||
try:
|
|
||||||
# 构建完整的图层路径
|
|
||||||
layer_path = os.path.join(DEFAULT_IMAGE_DIR, layer_name)
|
|
||||||
|
|
||||||
if os.path.exists(layer_path):
|
|
||||||
# 打开图层图像
|
|
||||||
layer = Image.open(layer_path).convert('RGBA')
|
|
||||||
|
|
||||||
# 调整图层大小以适应画布
|
|
||||||
# 如果图层尺寸与画布不同,将其居中
|
|
||||||
if layer.size != canvas_size:
|
|
||||||
new_layer = Image.new('RGBA', canvas_size, (0, 0, 0, 0))
|
|
||||||
paste_x = (canvas_size[0] - layer.width) // 2
|
|
||||||
paste_y = (canvas_size[1] - layer.height) // 2
|
|
||||||
new_layer.paste(layer, (paste_x, paste_y), layer)
|
|
||||||
layer = new_layer
|
|
||||||
|
|
||||||
# 合成图层
|
|
||||||
canvas = Image.alpha_composite(canvas, layer)
|
|
||||||
logger.info(f"已添加第{i+1}个图层: {layer_path}")
|
|
||||||
else:
|
|
||||||
logger.error(f"图层文件不存在: {layer_path}")
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"处理图层{layer_path}时出错: {str(e)}")
|
|
||||||
|
|
||||||
# 设置默认输出目录
|
|
||||||
default_output_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'outputs')
|
|
||||||
|
|
||||||
# 确保输出目录存在
|
|
||||||
if not os.path.exists(default_output_dir):
|
|
||||||
os.makedirs(default_output_dir)
|
|
||||||
|
|
||||||
# 构建输出文件的完整路径
|
|
||||||
output_path = os.path.join(default_output_dir, os.path.basename(output_path))
|
|
||||||
|
|
||||||
# 保存合成图像
|
|
||||||
canvas.save(output_path)
|
|
||||||
logger.info(f"图层合成完成,已保存到: {output_path}")
|
|
||||||
|
|
||||||
return output_path
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
# 简单测试
|
|
||||||
from sys import argv
|
|
||||||
|
|
||||||
if len(argv) >= 3:
|
|
||||||
# 从命令行接收参数
|
|
||||||
layers = argv[1:-1] # 现在只需要提供文件名,不需要完整路径
|
|
||||||
output = argv[-1]
|
|
||||||
compose_layers(layers, output)
|
|
||||||
else:
|
|
||||||
print("用法: python compose_poster.py layer1.png layer2.png ... output.png")
|
|
||||||
print(f"图片将从默认目录加载: {DEFAULT_IMAGE_DIR}")
|
|
@ -1,7 +0,0 @@
|
|||||||
from compose_poster import compose_layers
|
|
||||||
|
|
||||||
# 将多个图层合成为一个图像
|
|
||||||
compose_layers(
|
|
||||||
['background.jpg','aaai.png', 'nankai.jpg'],
|
|
||||||
|
|
||||||
)
|
|
@ -1,91 +1,100 @@
|
|||||||
# export_psd.py - PSD导出 (适配psd-tools 1.10.0 API)
|
"""
|
||||||
import os
|
测试文件:从多个图片创建PSD文件
|
||||||
|
将图片列表作为输入,从底到顶添加为PSD图层,并将图片居中放置
|
||||||
|
"""
|
||||||
|
|
||||||
|
from psd_tools import PSDImage
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
import logging
|
from psd_tools.constants import Compression
|
||||||
|
import os
|
||||||
|
from typing import List, Tuple
|
||||||
|
|
||||||
# 设置日志
|
# 导入PixelLayer类,用于从PIL图像创建图层
|
||||||
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
from psd_tools.api.layers import PixelLayer
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
# 设置默认目录路径
|
|
||||||
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
||||||
DEFAULT_INPUT_DIR = os.path.join(project_root, 'images')
|
|
||||||
DEFAULT_OUTPUT_DIR = os.path.join(project_root, 'outputs')
|
|
||||||
|
|
||||||
def export_to_psd(layers, output_path, layer_names=None, canvas_size=(1080, 1920)):
|
def create_psd_from_images(
|
||||||
# 先导入compose_poster中的函数
|
image_paths: List[str],
|
||||||
from compose_poster import compose_layers
|
output_path: str,
|
||||||
|
canvas_size: Tuple[int, int] = (1000, 800),
|
||||||
try:
|
mode: str = 'RGB'
|
||||||
# 导入psd-tools相关模块
|
) -> None:
|
||||||
from psd_tools import PSDImage
|
"""
|
||||||
from psd_tools.api.layers import PixelLayer
|
从图片列表创建PSD文件,将图片从底到顶堆叠
|
||||||
from psd_tools.constants import Compression
|
|
||||||
except ImportError:
|
|
||||||
logger.error("未安装psd-tools库,无法导出PSD。请安装:pip install psd-tools>=1.10.0")
|
|
||||||
return ""
|
|
||||||
|
|
||||||
logger.info(f"开始创建PSD文件,包含{len(layers)}个图层...")
|
|
||||||
|
|
||||||
# 1. 先使用compose_layers合成图层
|
|
||||||
temp_output = os.path.join(DEFAULT_OUTPUT_DIR, "temp_composed.png")
|
|
||||||
composed_path = compose_layers(layers, temp_output, canvas_size)
|
|
||||||
|
|
||||||
if not composed_path:
|
|
||||||
logger.error("图层合成失败")
|
|
||||||
return ""
|
|
||||||
|
|
||||||
# 2. 处理输出路径
|
|
||||||
if not os.path.isabs(output_path):
|
|
||||||
output_path = os.path.join(DEFAULT_OUTPUT_DIR, output_path)
|
|
||||||
|
|
||||||
if not output_path.lower().endswith('.psd'):
|
|
||||||
output_path += '.psd'
|
|
||||||
|
|
||||||
|
参数:
|
||||||
|
image_paths: 图片路径列表
|
||||||
|
output_path: 保存PSD文件的路径
|
||||||
|
canvas_size: PSD画布大小,格式为(宽度, 高度)
|
||||||
|
mode: PSD文件的颜色模式
|
||||||
|
"""
|
||||||
# 确保输出目录存在
|
# 确保输出目录存在
|
||||||
output_dir = os.path.dirname(output_path)
|
os.makedirs(os.path.dirname(os.path.abspath(output_path)), exist_ok=True)
|
||||||
if output_dir and not os.path.exists(output_dir):
|
|
||||||
os.makedirs(output_dir)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# 3. 创建PSD文件
|
# 1. 创建一个新的PSD文件
|
||||||
psd = PSDImage.new('RGB', canvas_size)
|
psd = PSDImage.new(mode, canvas_size)
|
||||||
|
|
||||||
# 4. 添加合成后的图层
|
# 2. 打开并添加每个图片作为图层
|
||||||
composed_image = Image.open(composed_path).convert('RGBA')
|
for i, img_path in enumerate(image_paths):
|
||||||
pixel_layer = PixelLayer.frompil(composed_image, psd, "Composed_Layer")
|
# 打开图片
|
||||||
psd.append(pixel_layer)
|
image = Image.open(img_path)
|
||||||
|
|
||||||
# 5. 保存PSD文件
|
# 计算居中位置
|
||||||
|
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)
|
psd.save(output_path)
|
||||||
logger.info(f"PSD文件已成功创建并保存到: {output_path}")
|
print(f"PSD文件已成功创建,保存在: {output_path}")
|
||||||
|
|
||||||
# 6. 清理临时文件
|
# 4. 生成并保存预览
|
||||||
if os.path.exists(temp_output):
|
preview_path = os.path.splitext(output_path)[0] + "_预览.png"
|
||||||
os.remove(temp_output)
|
composite_image.save(preview_path)
|
||||||
|
print(f"预览已保存在: {preview_path}")
|
||||||
|
|
||||||
return output_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:
|
except Exception as e:
|
||||||
logger.error(f"创建PSD文件时出错: {str(e)}")
|
print(f"创建PSD文件时出错: {e}")
|
||||||
logger.exception(e)
|
|
||||||
return ""
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
# 简单测试
|
# 示例用法
|
||||||
from sys import argv
|
image_list = [
|
||||||
|
'../images/background.jpg', # 底层图片
|
||||||
|
'../images/nankai.jpg', # 中间图片
|
||||||
|
'../images/aaai.png', # 顶层图片
|
||||||
|
# 可以根据需要添加更多图片
|
||||||
|
]
|
||||||
|
|
||||||
if len(argv) >= 3:
|
create_psd_from_images(
|
||||||
# 从命令行接收参数
|
image_paths=image_list,
|
||||||
layers = argv[1:-1]
|
output_path='../outputs/combined_output.psd'
|
||||||
output = argv[-1]
|
)
|
||||||
result = export_to_psd(layers, output)
|
|
||||||
if result:
|
|
||||||
print(f"PSD文件已成功导出到: {result}")
|
|
||||||
else:
|
|
||||||
print("PSD文件导出失败")
|
|
||||||
else:
|
|
||||||
print("用法: python export_psd.py layer1.png layer2.png ... output.psd")
|
|
||||||
print(f"默认输入目录: {DEFAULT_INPUT_DIR}")
|
|
||||||
print(f"默认输出目录: {DEFAULT_OUTPUT_DIR}")
|
|
||||||
print("注意:如果只提供文件名,将从默认输入目录查找图片文件")
|
|
Loading…
Reference in New Issue
Block a user