rambo пре 1 месец
родитељ
комит
7fd96ff27c

+ 21 - 21
python/detail_template_test_xinnuo.json

@@ -8,22 +8,22 @@
                 "编号": "AC51016112",
                 "颜色名称": "枪色",
                 "pics": {
-                   "俯视": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(1)_俯视_抠图.png",
-                "俯视-阴影": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(1)_俯视_阴影.png",
-                "侧视": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(2)_侧视_抠图.png",
-                "侧视-阴影": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(2)_侧视_阴影.png",
-                "后跟": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(3)_后跟_抠图.png",
-                "后跟-阴影": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(3)_后跟_阴影.png",
-                "鞋底": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(4)_鞋底_抠图.png",
-                "鞋底-阴影": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(4)_鞋底_阴影.png",
-                "内里": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(5)_内里_抠图.png",
-                "内里-阴影": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(5)_内里_阴影.png",
-                "组合": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(6)_组合_抠图.png",
-                "组合-阴影": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(6)_组合_阴影.png",
-                "组合2": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(7)_组合2_抠图.png",
-                "组合2-阴影": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(7)_组合2_阴影.png",
-                "组合3": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(8)_组合3_抠图.png",
-                "组合3-阴影": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(8)_组合3_阴影.png"
+                    "俯视-抠图": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(1)_俯视_抠图.png",
+                    "俯视-阴影": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(1)_俯视_阴影.png",
+                    "侧视-抠图": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(2)_侧视_抠图.png",
+                    "侧视-阴影": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(2)_侧视_阴影.png",
+                    "后跟-抠图": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(3)_后跟_抠图.png",
+                    "后跟-阴影": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(3)_后跟_阴影.png",
+                    "鞋底-抠图": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(4)_鞋底_抠图.png",
+                    "鞋底-阴影": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(4)_鞋底_阴影.png",
+                    "内里-抠图": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(5)_内里_抠图.png",
+                    "内里-阴影": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(5)_内里_阴影.png",
+                    "组合-抠图": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(6)_组合_抠图.png",
+                    "组合-阴影": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(6)_组合_阴影.png",
+                    "组合2-抠图": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(7)_组合2_抠图.png",
+                    "组合2-阴影": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(7)_组合2_阴影.png",
+                    "组合3-抠图": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(8)_组合3_抠图.png",
+                    "组合3-阴影": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(8)_组合3_阴影.png"
                 },
                 "800x800": [
                     "C:/Users/15001/Desktop/测试文件夹/AC51016112/800x800/AC51016112(1).jpg",
@@ -39,15 +39,15 @@
                 "编号": "AC51209131",
                 "颜色名称": "白色",
                 "pics": {
-                    "俯视": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(1)_俯视_抠图.png",
+                    "俯视-抠图": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(1)_俯视_抠图.png",
                     "俯视-阴影": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(1)_俯视_阴影.png",
-                    "侧视": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(2)_侧视_抠图.png",
+                    "侧视-抠图": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(2)_侧视_抠图.png",
                     "侧视-阴影": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(2)_侧视_阴影.png",
-                    "后跟": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(3)_后跟_抠图.png",
+                    "后跟-抠图": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(3)_后跟_抠图.png",
                     "后跟-阴影": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(3)_后跟_阴影.png",
-                    "鞋底": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(4)_鞋底_抠图.png",
+                    "鞋底-抠图": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(4)_鞋底_抠图.png",
                     "鞋底-阴影": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(4)_鞋底_阴影.png",
-                    "内里": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(5)_内里_抠图.png",
+                    "内里-抠图": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(5)_内里_抠图.png",
                     "内里-阴影": "C:/Users/15001/Desktop/2025-06-11/A333/阴影图处理/A333(5)_内里_阴影.png"
                 },
                 "800x800": [

+ 135 - 17
python/service/customer_template_service.py

@@ -5,24 +5,27 @@ import copy
 import requests
 from PIL import Image
 from io import BytesIO
-import base64
+import base64,shutil
+from logger import logger
+'''前端生图接口'''
 generate_templace = "/generate"
-# CUSTOMER_TEMPLATE_URL
 class CustomerTemplateService:
     def __init__(self):
         pass
-    def generateTemplate(self,config_data,template_json):
+    def generateTemplate(self,config_data,template_json,template_name,save_path):
         '''
         参数:
         config_data: 配置数据
         template_json: 模板数据
+        template_name: 模板名称
+        save_path: 保存路径
         '''
         print("开始生成模板")
         # print("config_data",config_data)
-        handler_config_data = self.__handler_config_data(config_data)
-        print("handler_config_data",handler_config_data)
+        handler_config_data,model_image,scene_image = self.__handler_config_data(config_data)
+        goods_no = list(handler_config_data.keys())[0]
         headers = {"Content-Type": "application/json"}
-        json_data = {"goodsList":handler_config_data,"canvasList":template_json}
+        json_data = {"goodsList":[handler_config_data],"canvasList":template_json}
         json_data = json.dumps(json_data,ensure_ascii=False)
         # print("json_data",json_data)
         template_result = requests.post(CUSTOMER_TEMPLATE_URL+generate_templace,data=json_data,headers=headers)
@@ -32,31 +35,80 @@ class CustomerTemplateService:
         images = resultJson.get("images",[])
         if code != 0:
             raise UnicornException(f"详情页生成失败,请检查模板数据是否正确:{msg}")
+        concat_images_array = []
         for image in images:
             canvasIndex = image.get("canvasIndex")
             dataUrl = image.get("dataUrl")
-            path = r"C:/Development/project/output/2025-12-05/详情图-测试"
-            save_name = f"{path}/切片图-自定义-1/{int(canvasIndex)+1}.png"
+            save_name = f"{save_path}/切片图-{template_name}/{goods_no}({int(canvasIndex)+1}).png"
             match dataUrl:
                 case "model":
                     # 复制模特图进行拼接
-                    pass
+                    if model_image:
+                        model_copy_res = self.copyImage(model_image,save_name)
+                        if model_copy_res:
+                            model_image_pil = Image.open(model_image)
+                            concat_images_array.append(model_image_pil)
                 case "scene":
                     # 复制场景图进行拼接
-                    pass
+                    if scene_image:
+                        scene_copy_res = self.copyImage(scene_image,save_name)
+                        if scene_copy_res:
+                            scene_image_pil = Image.open(scene_image)
+                            concat_images_array.append(scene_image_pil)
                 case _:
-                    self.save_base64_image(dataUrl,save_name)
+                    pillowImage = self.save_base64_image(dataUrl,save_name)
+                    concat_images_array.append(pillowImage)
         print("模板生成成功")
+    
+    def concat_images_vertically(image_array, custom_width=None):
+        """
+        按照顺序将图片数组拼接成长图,并统一图片宽度
+
+        参数:
+        - image_array: list,存放 Pillow 图片对象的数组
+        - custom_width: int,可选参数,指定统一的图片宽度(默认为第一张图的宽度)
+
+        返回:
+        - concatenated_image: PIL.Image,拼接后的长图对象
+        """
+        if not image_array:
+            raise ValueError("图片数组为空,无法拼接")
+
+        # 1. 确定统一宽度
+        base_width = custom_width or image_array[0].width
+
+        # 2. 计算总高度和调整图片尺寸
+        total_height = 0
+        resized_images = []
+        for img in image_array:
+            # 调整图片宽度并保持宽高比
+            width_ratio = base_width / img.width
+            new_height = int(img.height * width_ratio)
+            resized_img = img.resize((base_width, new_height), Image.ANTIALIAS)
+            resized_images.append(resized_img)
+            total_height += new_height
+
+        # 3. 创建空白画布
+        concatenated_image = Image.new("RGB", (base_width, total_height))
+
+        # 4. 按顺序拼接图片
+        y_offset = 0
+        for resized_img in resized_images:
+            concatenated_image.paste(resized_img, (0, y_offset))
+            y_offset += resized_img.height
+
+        return concatenated_image
     def __handler_config_data(self,config_data):
         '''
         处理配置数据,返回一个新的数据对象
         '''
         # 深拷贝原始数据,确保不改变原数据对象
         new_config_data = copy.deepcopy(config_data)
-        
+        model_image = None
+        scene_image = None
         # 如果输入是字典,则将其转换为目标结构
         if isinstance(new_config_data, dict):
-            result = []
+            # result = []
             for key, item in new_config_data.items():
                 # 提取需要添加的数据
                 additional_data = {k: v for k, v in item.items() if k not in ["款号", "货号资料"]}
@@ -64,12 +116,35 @@ class CustomerTemplateService:
                 # 遍历货号资料,将额外数据添加到每个货号对象中
                 for product in item.get("货号资料", []):
                     product.update(additional_data)
+                    # 处理 pics 字段中的 xx-抠图 转换为 Base64 并新增字段
+                    pics = product.get("pics", {})
+                    if not model_image:
+                        model_image = product.get("模特图", None)
+                    if not scene_image:
+                        scene_image = product.get("场景图", None)
+                    new_pics = {}
+                    for pic_key, pic_path in pics.items():
+                        if "-抠图" in pic_key:
+                            # 读取图片并转换为 Base64
+                            try:
+                                # base64_data = self.crop_image_and_convert_to_base64(pic_path)
+                                # 新增字段(去除 -抠图)
+                                new_key = pic_key.replace("-抠图", "")
+                                new_pics[new_key] = pic_path
+                            except Exception as e:
+                                print(f"读取图片失败: {pic_path}, 错误: {e}")
+                        else:
+                            # 非 -抠图 字段保持不变
+                            new_pics[pic_key] = pic_path
+                    
+                    # 更新 pics 字段
+                    product["pics"] = new_pics
                 
                 # 构建目标结构
-                result.append({key: item})
-            return result
+            #     result.append({key: item})
+            # return result
         
-        return new_config_data
+        return new_config_data,model_image,scene_image
     def save_base64_image(self,base64_data, output_path):
         """
         将 Base64 编码的图像保存到本地文件
@@ -94,6 +169,49 @@ class CustomerTemplateService:
             # 4. 保存图像到本地
             image.save(output_path)
             print(f"图像已成功保存到 {output_path}")
+            return image
         except Exception as e:
             print(f"保存图像失败: {e}")
-            print(f"Base64 数据前 100 字符: {base64_data[:100]}")
+            print(f"Base64 数据前 100 字符: {base64_data[:100]}")
+            return None
+            
+    def crop_image_and_convert_to_base64(self,pic_path):
+        """
+        使用 Pillow 裁剪图片并生成带有前缀的 Base64 图片
+
+        参数:
+        - pic_path: str,图片文件路径
+
+        返回:
+        - base64_data_with_prefix: str,带有前缀的 Base64 编码图片数据
+        """
+        try:
+            # 1. 加载图片
+            with Image.open(pic_path) as image:
+                # 2. 获取图片的非透明区域边界框 (bounding box)
+                bbox = image.getbbox()
+                if not bbox:
+                    raise ValueError("图片可能是完全透明的,无法获取边界框")
+                
+                # 3. 裁剪图片
+                cropped_image = image.crop(bbox)
+                
+                # 4. 将裁剪后的图片转换为 Base64
+                buffered = BytesIO()
+                cropped_image.save(buffered, format="PNG")  # 保存为 PNG 格式
+                base64_data = base64.b64encode(buffered.getvalue()).decode("utf-8")
+                
+                # 5. 添加 Base64 前缀
+                base64_data_with_prefix = f"data:image/png;base64,{base64_data}"
+                return base64_data_with_prefix
+
+        except Exception as e:
+            print(f"处理图片失败: {pic_path}, 错误: {e}")
+            return None
+    def copyImage(self,src_path,limit_path):
+        try:
+          shutil.copy(src_path, limit_path)
+          return True
+        except Exception as e:
+            logger.info(f"copyImage 复制模特图/场景图出错:{str(e)}",src_path,limit_path)
+            return False

+ 5 - 5
python/service/grenerate_main_image_test.py

@@ -705,8 +705,8 @@ class GeneratePic(object):
                         image=image_bg,
                         file_path=new_file_path,
                         save_mode="jpg",
-                        quality=None,
-                        dpi=None,
+                        quality=100,
+                        dpi=(350, 350),
                         _format="JPEG",
                     )
                     # save_image_by_thread(image_bg, out_path, save_mode="jpg", quality=None, dpi=None, _format="JPEG")
@@ -717,8 +717,8 @@ class GeneratePic(object):
                         file_path=new_file_path,
                         save_mode="jpg",
                         quality=100,
-                        dpi=(300, 300),
-                        _format="JPEG",
+                        dpi=(350, 350),
+                        _format="PNG",
                     )
                 else:
                     new_format = out_pci_mode.split(".")[-1]
@@ -727,7 +727,7 @@ class GeneratePic(object):
                         file_path=new_file_path,
                         save_mode=new_format,
                         quality=100,
-                        dpi=(300, 300),
+                        # dpi=(300, 300),
                         _format=new_format,
                     )
                     # save_image_by_thread(image_bg, out_path, save_mode="jpg", quality=100, dpi=(300, 300), _format="JPEG")

+ 8 - 4
python/temp.py

@@ -2,6 +2,7 @@
 # from settings import recordDataPoint
 import time,json
 import requests
+from PIL import Image
 from service.online_request.module_online_data import OnlineDataRequest,AIGCDataRequest
 # aigc = OnlineDataRequest("Bearer f99e72d818b504d23e0581ef1b1a2b4bb687c683")
 # aigc.uploadGoods2ThirdParty("",["惠利玛@拼多多"])
@@ -13,7 +14,10 @@ from service.online_request.module_online_data import OnlineDataRequest,AIGCData
 
 from service.customer_template_service import CustomerTemplateService
 
-service = CustomerTemplateService()
-config_data = json.load(open("detail_template_test_xinnuo.json", mode="r", encoding="utf-8"))
-canvas_json = json.load(open("canvas_json.json", mode="r", encoding="utf-8"))
-service.generateTemplate(config_data,canvas_json)
+# service = CustomerTemplateService()
+# config_data = json.load(open("detail_template_test_xinnuo.json", mode="r", encoding="utf-8"))
+# canvas_json = json.load(open("canvas_json.json", mode="r", encoding="utf-8"))
+# service.generateTemplate(config_data,canvas_json,'test-template',r"C:/Development/project/output/2025-12-05/详情图-测试")
+pilImage = Image.open("C:/Users/15001/Documents/xwechat_files/lyb383409060_36ab/msg/file/2025-12/2025-12-16/123/原始图_已抠图/123(1).png")
+# pilImage = pilImage.convert("RGB")
+pilImage.save("test_image.png",format="PNG",dpi=(350,350))