Bladeren bron

```
feat(image-processing): 添加图片处理功能和颜色转换工具

- 引入PictureProcessing插件用于高级图片处理
- 添加十六进制到RGB颜色转换功能到settings模块
- 实现多颜色正片叠底混合处理功能
- 支持用户自定义背景颜色配置参数
- 优化图片生成流程中的背景处理逻辑
- 移除过时的代码注释和无用配置
```

rambo 1 maand geleden
bovenliggende
commit
a91e263c8d
3 gewijzigde bestanden met toevoegingen van 252 en 35 verwijderingen
  1. 20 29
      python/service/grenerate_main_image_test.py
  2. 41 1
      python/settings.py
  3. 191 5
      python/temp.py

+ 20 - 29
python/service/grenerate_main_image_test.py

@@ -12,6 +12,7 @@ from .multi_threaded_image_saving import ImageSaver
 from .get_mask_by_green import GetMask
 from middleware import UnicornException
 from logger import logger
+from custom_plugins.plugins_mode.pic_deal import PictureProcessing
 def time_it(func):
     @wraps(func)  # 使用wraps来保留原始函数的元数据信息
     def wrapper(*args, **kwargs):
@@ -470,6 +471,10 @@ class GeneratePic(object):
         padding_800image = settings.getSysConfigs(
             "basic_configs", "padding_800image", 100
         )
+        color_800image = settings.getSysConfigs(
+            "basic_configs", "color_800image", "#FFFFFF"
+        )
+        rgb_color = settings.hex_to_rgb(color_800image)
         # ==========先进行剪切原图
         _s = time.time()
         with Image.open(image_path) as orign_im:
@@ -620,42 +625,33 @@ class GeneratePic(object):
                         im_shadow = to_resize(_im=im_shadow, high=1400)
                         cut_image = to_resize(_im=cut_image, high=1400)
 
-                    # if im_shadow.height <= im_shadow.width * 1.2:
-                    #     im_shadow = to_resize(_im=im_shadow, width=650)
-                    #     cut_image = to_resize(_im=cut_image, width=650)
-                    # else:
-                    #     im_shadow = to_resize(_im=im_shadow, high=1400)
-                    #     cut_image = to_resize(_im=cut_image, high=1400)
-
 
         # 创建底层背景
-        image_bg = Image.new("RGB", bg_size, (255, 255, 255))
-        image_bg = self.paste_img(image=image_bg, top_img=im_shadow, base="cc", value=(_offset_x * -1, _offset_y * -1))
-        image_bg = self.paste_img(image=image_bg, top_img=cut_image, base="cc", value=(_offset_x * -1, _offset_y * -1))
+        # 用户可设置的颜色值参数
+        # image_bg = Image.new("RGB", bg_size, rgb_color)
+        # image_bg = self.paste_img(image=image_bg, top_img=im_shadow, base="cc", value=(_offset_x * -1, _offset_y * -1))
+        # image_bg = self.paste_img(image=image_bg, top_img=cut_image, base="cc", value=(_offset_x * -1, _offset_y * -1))
+        image_bg = PictureProcessing("RGB", bg_size, rgb_color)
+        image_bg = image_bg.to_overlay_pic_advance(mode="pixel",
+                                                    top_img=PictureProcessing(im=im_shadow),
+                                                    base="cc",
+                                                    value=(_offset_x * -1, _offset_y * -1),
+                                                    top_png_img=PictureProcessing(im=cut_image),)
+        image_bg = image_bg.im
         image_bg_x, image_bg_y = image_bg.size
         image_x, image_y = im_shadow.size
 
         _x = int((image_bg_x - image_x) / 2)
         _y = int((image_bg_y - image_y) / 2)
 
-        image_bg.paste(im_shadow, (_x, _y))
-        image_bg.paste(cut_image, (_x, _y), cut_image)  # 再叠加原图避免色差
+        # image_bg.paste(im_shadow, (_x, _y))
+        # image_bg.paste(cut_image, (_x, _y), cut_image)  # 再叠加原图避免色差
 
         if "小苏" in settings.Company:
             # 所有主图加logo
             is_logo = True
 
         if is_logo:
-            # logo_path = ""
-            # if settings.PROJECT == "红蜻蜓":
-            #     logo_path = r"resources\LOGO\HQT\logo.png"
-            # elif settings.PROJECT == "惠利玛":
-            #     if "小苏" in settings.Company:
-            #         logo_path = r"resources\LOGO\xiaosushuoxie\logo.png"
-            #     elif "惠利玛" in settings.Company:
-            #         logo_path = r"resources\LOGO\HLM\logo.png"
-            #     else:
-            #         pass
             if not logo_path:
                 logo_im = Image.new("RGBA", (1600, 1600), (0, 0, 0, 0))
             else:
@@ -676,7 +672,6 @@ class GeneratePic(object):
             if settings.getSysConfigs("basic_configs", "image_sharpening", "1") == ""
             else settings.getSysConfigs("basic_configs", "image_sharpening", "1")
         )
-        # image_bg = image_bg.resize((out_pic_size, out_pic_size), Image.BICUBIC)
         if out_pci_factor > 1.0:
             print("图片锐化处理")
             image_bg = sharpen_image(image_bg, factor=out_pci_factor)
@@ -696,10 +691,10 @@ class GeneratePic(object):
             image_size_int = int(imageSize)
             image_size_str = str(imageSize)
             new_file_path = f"{file_without_suffix}_{image_size_str}.{suffix}"
-            if image_size_int < 3000:
-                image_bg = image_bg.resize(
+            image_bg = image_bg.resize(
                     (image_size_int, image_size_int), resample=settings.RESIZE_IMAGE_MODE
                 )
+            if image_size_int < 3000:
                 if out_pci_mode == ".jpg":
                     self.saver.save_image(
                         image=image_bg,
@@ -709,8 +704,6 @@ class GeneratePic(object):
                         dpi=(350, 350),
                         _format="JPEG",
                     )
-                    # save_image_by_thread(image_bg, out_path, save_mode="jpg", quality=None, dpi=None, _format="JPEG")
-                    # image_bg.save(out_path, format="JPEG")
                 elif out_pci_mode == ".png":
                     self.saver.save_image(
                         image=image_bg,
@@ -729,8 +722,6 @@ class GeneratePic(object):
                         dpi=(350, 350),
                         _format=new_format,
                     )
-                    # save_image_by_thread(image_bg, out_path, save_mode="jpg", quality=100, dpi=(300, 300), _format="JPEG")
-                    # image_bg.save(out_path, quality=100, dpi=(300, 300), format="JPEG")
             else:
                 new_format = out_pci_mode.split(".")[-1]
                 self.saver.save_image(

+ 41 - 1
python/settings.py

@@ -330,4 +330,44 @@ def handle_remove_readonly(func, path, exc):
     func(path)
 
 
-CUSTOMER_TEMPLATE_URL = config.get("customer_template", "template_url")
+CUSTOMER_TEMPLATE_URL = config.get("customer_template", "template_url")
+
+
+
+
+def hex_to_rgb(hex_color):
+    """
+    将十六进制颜色值转换为RGB颜色值
+    :param hex_color: 十六进制颜色值,例如 "#FF0000" 或 "FF0000"
+    :return: RGB元组,例如 (255, 0, 0)
+    """
+    # 移除可能存在的 # 符号
+    hex_color = hex_color.lstrip('#')
+    
+    # 确保是有效的十六进制字符串
+    if len(hex_color) != 6:
+        raise ValueError("十六进制颜色值格式不正确,应为6位十六进制数")
+    
+    # 将十六进制字符串转换为RGB值
+    try:
+        r = int(hex_color[0:2], 16)
+        g = int(hex_color[2:4], 16)
+        b = int(hex_color[4:6], 16)
+        return (r, g, b)
+    except ValueError:
+        return (255, 255, 255)
+
+
+def rgb_to_hex(r, g, b):
+    """
+    将RGB颜色值转换为十六进制颜色值
+    :param r: 红色分量 (0-255)
+    :param g: 绿色分量 (0-255)
+    :param b: 蓝色分量 (0-255)
+    :return: 十六进制颜色值,例如 "#FF0000"
+    """
+    # 验证RGB值在有效范围内
+    if not all(0 <= val <= 255 for val in [r, g, b]):
+        return "#FFFFFF"
+    
+    return "#{:02X}{:02X}{:02X}".format(r, g, b)

+ 191 - 5
python/temp.py

@@ -3,6 +3,8 @@
 import time,json
 import requests
 from PIL import Image
+import numpy as np
+from blend_modes import multiply
 from service.online_request.module_online_data import OnlineDataRequest,AIGCDataRequest
 # aigc = OnlineDataRequest("Bearer f99e72d818b504d23e0581ef1b1a2b4bb687c683")
 # aigc.uploadGoods2ThirdParty("",["惠利玛@拼多多"])
@@ -12,9 +14,193 @@ from service.online_request.module_online_data import OnlineDataRequest,AIGCData
 # print(js)
 
 
-from service.customer_template_service import CustomerTemplateService
+# 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,'test-template',r"C:/Development/project/output/2025-12-05/详情图-测试")
+# 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/详情图-测试")
+
+def hex_to_rgb(hex_color):
+    """
+    将十六进制颜色值转换为RGB值
+    """
+    hex_color = hex_color.lstrip('#')
+    if len(hex_color) == 6:
+        return tuple(int(hex_color[i:i+2], 16) for i in (0, 2, 4))
+    elif len(hex_color) == 3:
+        return tuple(int(hex_color[i:i+1]*2, 16) for i in (0, 1, 2))
+    else:
+        raise ValueError("无效的十六进制颜色值")
+
+
+def color_name_to_rgb(color_name):
+    """
+    将颜色名称转换为RGB值
+    """
+    color_map = {
+        'red': (255, 0, 0),
+        'green': (0, 255, 0),
+        'blue': (0, 0, 255),
+        'white': (255, 255, 255),
+        'black': (0, 0, 0),
+        'yellow': (255, 255, 0),
+        'cyan': (0, 255, 255),
+        'magenta': (255, 0, 255),
+        'orange': (255, 165, 0),
+        'purple': (128, 0, 128),
+        'pink': (255, 192, 203),
+        'brown': (165, 42, 42),
+        'gray': (128, 128, 128),
+        'grey': (128, 128, 128),
+        'lightgray': (211, 211, 211),
+        'darkgray': (169, 169, 169),
+        'lightblue': (173, 216, 230),
+        'lightgreen': (144, 238, 144),
+        'lightyellow': (255, 255, 224)
+    }
+    
+    if color_name.lower() in color_map:
+        return color_map[color_name.lower()]
+    else:
+        raise ValueError(f"未找到颜色名称: {color_name}")
+def create_color_overlay(size, color):
+    """
+    创建指定颜色的覆盖层
+    
+    :param size: 图片尺寸 (width, height)
+    :param color: 颜色值,可以是以下格式之一:
+                  - RGB元组: (R, G, B) 如 (255, 0, 0) 表示红色
+                  - RGBA元组: (R, G, B, A) 如 (255, 0, 0, 128)
+                  - 十六进制字符串: "#FF0000" 表示红色
+                  - 颜色名称: "red", "blue", "green" 等
+    :return: PIL Image对象
+    """
+    # 如果是十六进制颜色值,转换为RGB
+    if isinstance(color, str):
+        if color.startswith('#'):
+            color = hex_to_rgb(color)
+        else:
+            # 使用预定义的颜色名称
+            color = color_name_to_rgb(color)
+    
+    # 如果是RGB或RGBA元组
+    if isinstance(color, (tuple, list)):
+        if len(color) == 3:  # RGB
+            overlay = Image.new('RGBA', size, color + (255,))
+        elif len(color) == 4:  # RGBA
+            overlay = Image.new('RGBA', size, tuple(map(int, color)))
+        else:
+            raise ValueError("颜色元组应包含3个(RGB)或4个(RGBA)值")
+    else:
+        raise ValueError("颜色值格式不正确")
+    
+    return overlay
+def multiply_blend_multiple_colors(img1_path, img2_path, output_path, 
+                                 colors=None, positions=None, blend_opacity=1.0):
+    """
+    对两张图片进行正片叠底处理,可以应用多个颜色区域
+    
+    :param img1_path: 第一张图片路径(底层图片)
+    :param img2_path: 第二张图片路径(顶层图片)
+    :param output_path: 输出图片路径
+    :param colors: 颜色列表,每个颜色可以是RGB元组、十六进制颜色或颜色名称
+    :param positions: 位置列表,每个位置是 (x, y, width, height) 的元组
+    :param blend_opacity: 混合透明度 (0.0-1.0)
+    """
+    
+    # 打开图片
+    img1 = Image.open(img1_path).convert('RGBA')
+    img2 = Image.open(img2_path).convert('RGBA')
+    
+    # 调整图片大小
+    if img1.size != img2.size:
+        img2 = img2.resize(img1.size, Image.LANCZOS)
+    
+    # 转换为numpy数组
+    img1_array = np.array(img1, dtype=np.float64)
+    img2_array = np.array(img2, dtype=np.float64)
+    
+    # 如果提供了颜色和位置信息
+    if colors and positions:
+        for color, pos in zip(colors, positions):
+            # 创建颜色覆盖层
+            color_size = (pos[2], pos[3])  # width, height
+            color_overlay = create_color_overlay(color_size, color)
+            
+            # 将颜色覆盖层应用到指定位置
+            img2_array[pos[1]:pos[1]+pos[3], pos[0]:pos[0]+pos[2]] = \
+                np.array(color_overlay, dtype=np.float64)
+    
+    # 使用blend_modes库进行正片叠底
+    blended_img = multiply(img1_array, img2_array, blend_opacity)
+    
+    # 转换回PIL Image对象
+    blended_img = np.clip(blended_img, 0, 255).astype(np.uint8)
+    result = Image.fromarray(blended_img, mode='RGBA')
+    
+    # 保存结果
+    result.save(output_path)
+    print(f"多颜色正片叠底完成,结果保存至: {output_path}")
+    
+    return result
+def multiply_blend_with_color(imagePng,imageJpg, output_path, color=None, 
+                             color_opacity=0.5, blend_opacity=1.0):
+    """
+    对两张图片进行正片叠底处理,可以应用指定颜色
+    
+    :param img1_path: 第一张图片路径(底层图片)
+    :param img2_path: 第二张图片路径(顶层图片)
+    :param output_path: 输出图片路径
+    :param color: 要应用的颜色,可以是RGB元组、十六进制颜色或颜色名称
+    :param color_opacity: 颜色层的透明度 (0.0-1.0)
+    :param blend_opacity: 正片叠底层的透明度 (0.0-1.0)
+    """
+    imagePng:Image
+    imageJpg:Image
+    # 调整图片大小
+    if imagePng.size != imageJpg.size:
+        imageJpg = imageJpg.resize(imagePng.size, Image.LANCZOS)
+    
+    # 如果指定了颜色,创建颜色覆盖层
+    if color is not None:
+        # 创建颜色覆盖层
+        color_overlay = create_color_overlay(imageJpg.size, color)
+        
+        # 将颜色层与第二张图片混合
+        imageJpg_array = np.array(imageJpg, dtype=np.float64)
+        color_array = np.array(color_overlay, dtype=np.float64)
+        
+        # 混合颜色层与图片
+        mixed_array = imageJpg_array * (1 - color_opacity) + color_array * color_opacity
+        imageJpg = Image.fromarray(np.clip(mixed_array, 0, 255).astype(np.uint8), mode='RGBA')
+    
+    # 转换为numpy数组
+    imagePng_array = np.array(imagePng, dtype=np.float64)
+    imageJpg_array = np.array(imageJpg, dtype=np.float64)
+    
+    # 使用blend_modes库进行正片叠底
+    blended_img = multiply(imagePng_array, imageJpg_array, blend_opacity)
+    
+    # 转换回PIL Image对象
+    blended_img = np.clip(blended_img, 0, 255).astype(np.uint8)
+    result = Image.fromarray(blended_img, mode='RGBA')
+    
+    # 保存结果
+    result.save(output_path)
+    print(f"正片叠底完成,结果保存至: {output_path}")
+    
+    return result
+# 示例用法
+if __name__ == "__main__":
+    # 示例1:使用RGB颜色值
+    imagePng = Image.open("C:/Development/project/output/2025-12-24/AQG1411283/阴影图处理/AQG1411283(1)_俯视_抠图.png")
+    imageJpg = Image.open("C:/Development/project/output/2025-12-24/AQG1411283/阴影图处理/AQG1411283(1)_俯视_阴影.png")
+    multiply_blend_with_color(
+        imagePng=imagePng,  # 替换为您的图片路径
+        imageJpg=imageJpg,  # 替换为您的图片路径
+        output_path="output_rgb.png",
+        color="#FF00AA",  # 红色
+        color_opacity=1,  # 颜色透明度
+        blend_opacity=0.8   # 正片叠底透明度
+    )