| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574 |
- import json
- import os
- from module.view_control.generate_goods_no_detail_pic.pic_deal import PictureProcessing
- from PIL import Image
- import shutil
- from module.base_mode.base import get_images, check_path, get_image_mask
- from natsort import ns, natsorted
- import math
- from PIL import ImageFont
- import settings
- class DetailBase(object):
- def __init__(self, goods_no, goods_no_value: dict, out_put_dir, windows=None, excel_data=None,
- assigned_page_list=None):
- self.goods_no = goods_no
- self.out_put_dir = out_put_dir
- self.deal_pic_func_list = []
- self.goods_no_value = goods_no_value
- self.root = ""
- self.windows = windows
- print(goods_no_value)
- # 重新解析为新的数据结构
- self.data = {}
- self.detailed_images = []
- self.assigned_page_list = assigned_page_list
- self.overlay_pic_dict = {}
- self.init()
- # for goods_art_no_dict in self.goods_no_value["货号资料"]:
- # print(goods_art_no_dict)
- #
- # raise 1
- if excel_data:
- ig_keys = ["模板名称"]
- for k, v in excel_data.items():
- if k not in ig_keys:
- self.goods_no_value[k] = v
- def run_all(self):
- print("===================detailed_images=================")
- detailed_images = self.deal_details()
- self.create_folder(self.out_put_dir)
- detail_path = "{out_put_dir}/{goods_no}/details".format(out_put_dir=self.out_put_dir, goods_no=self.goods_no)
- self.create_folder(detail_path)
- self.save_to_png(detailed_images=detailed_images, detail_path=detail_path)
- # 生成拼接图
- self.generate_spliced_picture()
- # ------------移动其他图片---------------------
- # 获取主图模板列表
- main_pic_path_list = DetailBase.get_temp_pic_info(root=self.root)["main_pic_path_list"]
- if not main_pic_path_list:
- self.move_other_pic(move_main_pic=True)
- else:
- self.move_other_pic(move_main_pic=True)
- if not self.assigned_page_list:
- self.deal_all_main_pic()
- else:
- if "主图" in self.assigned_page_list:
- self.deal_all_main_pic()
- return True
- # 生成各个详情图切片
- def deal_details(self):
- detailed_images = []
- for index, func in enumerate(self.deal_pic_func_list):
- if not self.assigned_page_list:
- self.image_list_append(detailed_images, func())
- else:
- index = "{}".format(index + 1)
- if index in self.assigned_page_list:
- self.image_list_append(detailed_images, func())
- else:
- self.image_list_append(detailed_images, {"mes": "不生成"})
- return [x for x in detailed_images if x]
- # 生成拼接的图片
- def generate_spliced_picture(self):
- detail_path = "{out_put_dir}/{goods_no}/details".format(out_put_dir=self.out_put_dir, goods_no=self.goods_no)
- if not os.path.exists(detail_path):
- return
- detailed_images = []
- for image_data in get_images(detail_path):
- detailed_images.append(PictureProcessing(image_data["file_path"]))
- # 生成拼接图
- img = self.add_pic(detailed_images)
- join_path = "{out_put_dir}/{goods_no}/拼接图".format(out_put_dir=self.out_put_dir, goods_no=self.goods_no)
- self.create_folder(join_path)
- img.save("{}/1.jpg".format(join_path), format="JPEG")
- def image_list_append(self, image_list: list, data):
- self.check_state_end()
- image_list.append(data)
- def save_to_png(self, detailed_images, detail_path):
- self.check_state_end()
- for index, pp in enumerate(detailed_images):
- if isinstance(pp, dict):
- continue
- pp.im.save("{}/{}({}).png".format(detail_path, self.goods_no, str(index + 11).zfill(2)))
- def check_state_end(self):
- if self.windows is not None:
- if self.windows.state == 99:
- raise "用户主动取消"
- @classmethod
- def get_temp_pic_info(cls, root):
- """
- 获取详情页模板中的信息
- """
- main_pic_list = []
- mask_pic_list = []
- if os.path.exists(r"{}\main_image".format(root)):
- for _name in os.listdir(r"{}\main_image".format(root)):
- _path = r"{}\main_image\{}".format(root, _name)
- if os.path.isdir(_path):
- main_pic_list.append([x["file_path"] for x in get_images(_path)])
- mask_pic_list.append(
- [x["file_path"] for x in get_image_mask(_path)]
- )
- _l = get_images(r"{}\show".format(root))
- temp_pic_path = _l[0]["file_path"] if _l else None
- other_pic_list = [x["file_path"] for x in get_images(r"{}".format(root))]
- return {
- "main_pic_path_list": main_pic_list,
- "temp_pic_path": temp_pic_path,
- "mask_pic_list": mask_pic_list,
- "other_pic_path_list": other_pic_list,
- }
- def init(self):
- for goods_art_no_value in self.goods_no_value["货号资料"]:
- self.data[goods_art_no_value["货号"]] = {"pics": goods_art_no_value["pics"],
- "pic_is_deal": {}
- }
- def get_text_value(self, key, subsection_len=0):
- text = ""
- if key in self.goods_no_value:
- if self.goods_no_value[key]:
- text = str(self.goods_no_value[key])
- text = text.replace(r"\n", "\n")
- if key in ["跟高", "鞋宽", "帮高", "脚掌围", "鞋长"]:
- if text:
- text = text.split(".")[0]
- if subsection_len != 0:
- text = text.split("\n")
- text = [x for x in text if x]
- if len(text) == 2:
- text_1 = text[0]
- text_2 = text[1]
- return text_1, text_2
- else:
- if text:
- text_1 = text[0]
- else:
- text_1 = ""
- text_2 = ""
- return text_1, text_2
- return text
- def create_folder(self, path):
- if not os.path.exists(path):
- os.makedirs(path)
- def get_all_process_pics(self):
- """
- 获取所有颜色的过程图片
- data = [
- {"货号": "",
- "素材": [{
- "名称": "俯视",
- "抠图": "路径1",
- "阴影": "路径2"
- }, ]},
- ]
- """
- return_data = []
- for goods_art_no in self.data:
- goods_art_no_dict = {"货号": goods_art_no,
- "素材": [],
- }
- # 图片数据重新排序
- pic_data = []
- for pic_name, pic_path in self.data[goods_art_no]["pics"].items():
- root_path, file_name = os.path.split(pic_path)
- pic_data.append(file_name)
- pic_data = natsorted(pic_data, alg=ns.PATH)
- for file_name in pic_data:
- if "阴影" in file_name:
- _, action_name, _ = file_name.split("_")
- pic_path = self.data[goods_art_no]["pics"]["{}-阴影".format(action_name)]
- pic_cutout_path = self.data[goods_art_no]["pics"]["{}-抠图".format(action_name)]
- if os.path.exists(pic_path) and os.path.exists(pic_cutout_path):
- goods_art_no_dict["素材"].append({"名称": action_name, "抠图": pic_cutout_path, "阴影": pic_path})
- return_data.append(goods_art_no_dict)
- return return_data
- def get_overlay_pic_from_dict(self, goods_art_no, color_name, bg_color) -> PictureProcessing:
- self.check_state_end()
- # 增加逻辑,获取任意货号下的组合图
- if "组合" in color_name:
- goods_art_no, color_name = self.get_all_scene_list(goods_art_no, color_name)
- key = "{}-{}-{}".format(goods_art_no, color_name, bg_color)
- if key in self.overlay_pic_dict:
- return self.overlay_pic_dict[key]
- if goods_art_no in self.data:
- for pic_name, pic_path in self.data[goods_art_no]["pics"].items():
- if "阴影" in pic_name:
- action_name = pic_name.replace("-阴影", "")
- if action_name == color_name:
- pp1 = PictureProcessing(pic_path)
- pp2 = PictureProcessing(self.data[goods_art_no]["pics"]["{}-抠图".format(action_name)])
- pp1 = pp1.get_overlay_pic(top_img=pp2, color=bg_color).resize(mode="pixel", base="width",
- value=1600)
- self.overlay_pic_dict[key] = pp1
- if key in self.overlay_pic_dict:
- return self.overlay_pic_dict[key]
- def image_init(self, bg_color=(246, 246, 246)):
- # 制作一批素材图,添加背景色,并保留阴影,以及处理成最小尺寸
- for goods_art_no in self.data:
- for pic_name, pic_path in self.data[goods_art_no]["pics"].items():
- if "阴影" in pic_name:
- action_name = pic_name.replace("-阴影", "")
- pp1 = PictureProcessing(pic_path)
- pp2 = PictureProcessing(self.data[goods_art_no]["pics"]["{}-抠图".format(action_name)])
- pp1 = pp1.get_overlay_pic(top_img=pp2, color=bg_color).resize(mode="pixel", base="width",
- value=1600)
- self.data[goods_art_no]["pic_is_deal"][action_name] = pp1
- # 获取任意货号的场景图,优先取指定货号;
- # 调整,按顺序从货号列表中提取所有组合图
- def get_all_scene_info(self, goods_art_no):
- data = []
- # 收集所有组合图
- # 找任意一个有组合图的货号
- for goods_art_no_dict in self.goods_no_value["货号资料"]:
- _goods_art_no = goods_art_no_dict["货号"]
- _view_name_list = set([x.split("-")[0] for x in goods_art_no_dict["pics"]])
- for _view_name in _view_name_list:
- if "组合" not in _view_name:
- continue
- return _goods_art_no
- return goods_art_no
- def get_all_scene_list(self, goods_art_no, view_name: str):
- if "组合" == view_name:
- view_name = "组合1"
- try:
- view_index = int(view_name.replace("组合", "")) - 1
- except:
- return goods_art_no, "无法匹配"
- data = []
- # 收集所有组合图
- # 找任意一个有组合图的货号
- for goods_art_no_dict in self.goods_no_value["货号资料"]:
- _goods_art_no = goods_art_no_dict["货号"]
- _view_name_list = set([x.split("-")[0] for x in goods_art_no_dict["pics"]])
- for _view_name in _view_name_list:
- if "组合" not in _view_name:
- continue
- data.append(
- {"goods_art_no": _goods_art_no,
- "view_name": _view_name
- }
- )
- if len(data) <= view_index:
- return goods_art_no, "无法匹配"
- else:
- return data[view_index]["goods_art_no"], data[view_index]["view_name"]
- def image_one_pic(self, goods_art_no, name, bg_color=None, return_orign=None):
- # 增加逻辑,获取任意货号下的组合图
- if "组合" in name:
- goods_art_no, name = self.get_all_scene_list(goods_art_no, name)
- # 制作一批素材图,添加背景色,并保留阴影,以及处理成最小尺寸
- for pic_name, pic_path in self.data[goods_art_no]["pics"].items():
- if "阴影" in pic_name:
- action_name = pic_name.replace("-阴影", "")
- if name != action_name:
- continue
- pp1 = PictureProcessing(pic_path)
- pp2 = PictureProcessing(self.data[goods_art_no]["pics"]["{}-抠图".format(action_name)])
- if not return_orign:
- pp1 = pp1.get_overlay_pic(top_img=pp2, color=bg_color).resize(mode="pixel", base="width",
- value=1600)
- return pp1
- else:
- return pp1, pp2
- if not return_orign:
- return None
- else:
- return None, None
- def move_other_pic(self, move_main_pic=True):
- # ------------------------------移动其他图片------------------------------
- goods_no_main_pic_number = 0
- for goods_art_no_dict in self.goods_no_value["货号资料"]:
- if "800x800" not in goods_art_no_dict:
- continue
- if not goods_art_no_dict["800x800"]:
- continue
- goods_art_no = ""
- if "编号" in goods_art_no_dict:
- if goods_art_no_dict["编号"]:
- goods_art_no = goods_art_no_dict["编号"]
- if not goods_art_no:
- goods_art_no = goods_art_no_dict["货号"]
- # print("goods_art_no:", goods_art_no)
- # 移动颜色图=====================
- goods_art_no_f = "{}/{}/{}".format(self.out_put_dir, self.goods_no, goods_art_no)
- self.create_folder(goods_art_no_f)
- # 放入一张主图
- old_pic_path_1 = goods_art_no_dict["800x800"][0]
- shutil.copy(old_pic_path_1,
- "{}/{}{}".format(goods_art_no_f, goods_art_no, os.path.splitext(old_pic_path_1)[1]))
- # 把其他主图放入作为款号图=====================
- if move_main_pic:
- for pic_path in goods_art_no_dict["800x800"]:
- goods_no_main_pic_number += 1
- e = os.path.splitext(pic_path)[1]
- shutil.copy(pic_path,
- "{out_put_dir}/{goods_no}/{goods_no}({goods_no_main_pic_number}){e}".format(
- out_put_dir=self.out_put_dir, goods_no=self.goods_no,
- goods_no_main_pic_number=str(goods_no_main_pic_number + 10).zfill(2),
- e=e))
- def deal_all_main_pic(self):
- """
- 处理主图模板,如存在出图模板则进行对应处理
- """
- # 获取主图模板列表
- all_main_pic_path_list = DetailBase.get_temp_pic_info(root=self.root)["main_pic_path_list"]
- if not all_main_pic_path_list:
- return
- mask_pic_list = DetailBase.get_temp_pic_info(root=self.root)["mask_pic_list"]
- data = self.get_all_process_pics()
- print("========deal_all_main_pic=========主图相关素材:")
- view_list = ["组合", "组合2", "组合3", "组合4", "组合5", "组合6", "俯视", "侧视", "后跟", "鞋底", "内里", ]
- for _index, main_pic_path_list in enumerate(all_main_pic_path_list):
- self.check_state_end()
- out_path_root = "{out_put_dir}/{goods_no}/main_image_{_index}".format(
- out_put_dir=self.out_put_dir,
- goods_no=self.goods_no,
- _index=_index
- )
- check_path(out_path_root)
- if mask_pic_list[_index]:
- mask_pic = mask_pic_list[_index][0]
- else:
- mask_pic = None
- goods_no_main_pic_number = 10
- # g_index 为第几个颜色货号
- for g_index, goods_art_no_dict in enumerate(data):
- goods_art_no = goods_art_no_dict["货号"]
- # =====================重新指定=================================
- _material_sort_dict = {}
- for index, material_dict in enumerate(goods_art_no_dict["素材"]):
- name = material_dict["名称"]
- _material_sort_dict[name] = material_dict
- # ======================================================
- file_name_index = -1
- for view_name in view_list:
- # 组合图比较特殊,为全局获取
- if g_index != 0:
- if "组合" in view_name:
- continue
- if view_name not in _material_sort_dict:
- continue
- self.check_state_end()
- pp_jpg, pp_png = self.image_one_pic(goods_art_no, view_name, bg_color=None, return_orign=True)
- if not pp_jpg:
- continue
- file_name_index += 1
- # 获取对应主图模板
- if len(main_pic_path_list) < file_name_index + 1:
- main_pic_path = main_pic_path_list[-1]
- else:
- main_pic_path = main_pic_path_list[file_name_index]
- pp_bg = PictureProcessing(main_pic_path)
- original_width = pp_bg.width
- if original_width != 1600:
- pp_bg = pp_bg.resize(value=1600)
- if mask_pic:
- mask_bg = PictureProcessing(mask_pic)
- mask_bg = mask_bg.resize(value=1600)
- mask_box_im = mask_bg.get_im()
- box_size = mask_box_im.getbbox()
- result_image = mask_box_im.crop(box_size)
- mask_width, mask_height = result_image.size
- mask_x, mask_y = box_size[0], box_size[1]
- else:
- mask_width, mask_height = pp_bg.size
- mask_width, mask_height = int(mask_width * 12 / 16), int(mask_height * 12 / 16)
- mask_x, mask_y = int((pp_bg.size[0] - mask_width) / 2), int((pp_bg.size[1] - mask_height) / 2)
- if view_name != "后跟":
- pp_jpg = pp_jpg.resize(base_by_box=(mask_width, mask_height))
- pp_png = pp_png.resize(base_by_box=(mask_width, mask_height))
- # 计算粘贴的位置 mask的位置+图片在mask中的位置
- p_x = mask_x + int((mask_width - pp_jpg.width) / 2)
- p_y = mask_y + int((mask_height - pp_jpg.height) / 2)
- pp_bg = pp_bg.to_overlay_pic_advance(mode="pixel", top_img=pp_jpg, base="nw",
- value=(p_x, p_y), top_png_img=pp_png)
- else:
- new_mask_width, new_mask_height = int(mask_width / 1.6), int(mask_height / 1.6)
- pp_jpg = pp_jpg.resize(base_by_box=(new_mask_width, new_mask_height))
- pp_png = pp_png.resize(base_by_box=(new_mask_width, new_mask_height))
- new_mask_x = int((mask_width - new_mask_width) / 2 + mask_x)
- new_mask_y = int((mask_height - new_mask_height) / 2 + mask_y)
- # 计算粘贴的位置 mask的位置+图片在mask中的位置
- p_x = new_mask_x + int((new_mask_width - pp_jpg.width) / 2)
- p_y = new_mask_y + int((new_mask_height - pp_jpg.height) / 2)
- pp_bg = pp_bg.to_overlay_pic_advance(mode="pixel", top_img=pp_jpg, base="nw", value=(p_x, p_y),
- top_png_img=pp_png)
- goods_no_main_pic_number += 1
- out_pic_path = "{out_path_root}/{goods_no}({goods_no_main_pic_number}){pic_mode}".format(
- out_path_root=out_path_root,
- goods_no=self.goods_no,
- goods_no_main_pic_number=goods_no_main_pic_number,
- pic_mode=settings.OUT_PIC_MODE,
- )
- if settings.OUT_PIC_FACTOR > 1.0:
- print("图片锐化处理")
- pp_bg = pp_bg.sharpen_image(factor=settings.OUT_PIC_FACTOR)
- if original_width < 1600:
- pp_bg = pp_bg.resize(value=original_width)
- print("392 out_pic_path", out_pic_path)
- if settings.OUT_PIC_MODE == ".jpg":
- pp_bg.save_as_rgb(out_pic_path)
- else:
- pp_bg.save_as_png(out_pic_path)
- def add_pic(self, detailed_images):
- self.check_state_end()
- detailed_images = [x for x in detailed_images if x]
- if not detailed_images:
- return
- page_len = 0
- for index, pp in enumerate(detailed_images):
- page_len += pp.height
- bg_im = Image.new("RGB", (pp.width, page_len), (255, 255, 255))
- n = 0
- for index, pp in enumerate(detailed_images):
- bg_im.paste(pp.im, (0, n))
- n += pp.height
- return bg_im
- # 通用方法,用于写文字
- def add_text_list(self, text_list, spacing=5, base="wn"):
- text_list = [x for x in text_list if x["text"]]
- # print(text_list)
- # spacing 行间距
- text_image_list = []
- max_w = 0
- total_h = 0
- for text_data in text_list:
- _pp = PictureProcessing("RGBA", (1200, 800), (255, 255, 255, 0))
- if base == "wn" or base == "nw":
- align = "left"
- anchor = None
- value = (0, 200)
- if base == "cn" or base == "nc":
- align = "center"
- anchor = "mm"
- value = (600, 200)
- if base == "en" or base == "ne":
- align = "right"
- anchor = "rs"
- value = (1200, 200)
- _pp = _pp.get_text_image_advanced(
- value=value,
- font=text_data["font"],
- text=text_data["text"],
- align=align,
- anchor=anchor,
- spacing=5,
- fill=text_data["fill"],
- return_mode="min_image",
- margins=(0, 0, 0, 0)
- )
- text_image_list.append(_pp)
- if _pp.width > max_w:
- max_w = _pp.width
- total_h += _pp.height
- if "spacing" in text_data:
- total_h += text_data["spacing"]
- if not text_image_list:
- return None
- #
- bg = PictureProcessing("RGBA", (max_w, total_h * 3), (0, 0, 0, 0))
- y = 0
- for text_image, text_data in zip(text_image_list, text_list):
- bg = bg.paste_img(top_img=text_image, value=(0, y), base=base)
- y += spacing + text_image.height
- if "spacing" in text_data:
- y += text_data["spacing"]
- bg = bg.crop(mode="min")
- # _ = bg.paste_img_invert(top_img=PictureProcessing("RGB", (bg.width,bg.height), (255, 255, 255)))
- # _.show()
- return bg
- def generate_font_list_to_pic(self):
- font_path_list = [r"resources\ttf\puhui\Bold.ttf",
- r"resources\ttf\puhui\Medium.ttf",
- r"resources\ttf\puhui\Heavy.ttf",
- r"resources\ttf\puhui\Light.ttf",
- r"resources\ttf\puhui\Regular.ttf",
- ]
- text_v_list = [
- "这是一段话Bold",
- "这是一段话Medium",
- "这是一段话Heavy",
- "这是一段话Light",
- "这是一段话Regular",
- ]
- detailed_images = []
- for font_path, text in zip(font_path_list, text_v_list):
- text_list = []
- for size in range(26, 80, 2):
- font = ImageFont.truetype(font_path, size)
- text_list.append({"text": "{}-字号{}".format(text, size),
- "font": font,
- "fill": (110, 110, 110),
- })
- text_image = self.add_text_list(text_list, spacing=15, base="nw")
- text_image = text_image.crop(mode="min")
- text_image = text_image.paste_img_invert(top_img=PictureProcessing("RGB", text_image.size, (255, 255, 255)))
- detailed_images.append(text_image)
- return PictureProcessing(im=self.add_pic(detailed_images))
|