detail_generate_base.py 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814
  1. import settings
  2. import os
  3. try:
  4. is_test_plugins = settings.is_test_plugins
  5. except:
  6. is_test_plugins = False
  7. if is_test_plugins:
  8. from custom_plugins.plugins_mode.pic_deal import PictureProcessing
  9. else:
  10. from plugins_mode.pic_deal import PictureProcessing
  11. from PIL import Image
  12. import shutil
  13. from service.base import get_images, check_path, get_image_mask
  14. from natsort import ns, natsorted
  15. # import math
  16. from PIL import ImageFont
  17. import settings
  18. class DetailBase(object):
  19. def __init__(
  20. self,
  21. goods_no,
  22. goods_no_value: dict,
  23. out_put_dir,
  24. windows=None,
  25. excel_data=None,
  26. assigned_page_list=None,
  27. output_queue=None,
  28. ):
  29. self.goods_no = goods_no
  30. self.output_queue = output_queue
  31. self.out_put_dir = out_put_dir
  32. self.deal_pic_func_list = []
  33. self.goods_no_value = goods_no_value
  34. self.root = ""
  35. self.windows = windows
  36. self.template_name = None
  37. print(goods_no_value)
  38. # 重新解析为新的数据结构
  39. self.data = {}
  40. self.detailed_images = []
  41. self.assigned_page_list = assigned_page_list
  42. self.overlay_pic_dict = {}
  43. self.init()
  44. # for goods_art_no_dict in self.goods_no_value["货号资料"]:
  45. # print(goods_art_no_dict)
  46. #
  47. # raise 1
  48. if excel_data:
  49. ig_keys = ["模板名称"]
  50. for k, v in excel_data.items():
  51. if k not in ig_keys:
  52. self.goods_no_value[k] = v
  53. def check_shoe_is_right_by_pixel(self, im=None, image_path=None):
  54. if im is None:
  55. im = Image.open(image_path)
  56. # 注意,只支持透明图
  57. # 打开图像文件
  58. im = im.crop(im.getbbox())
  59. # image.show()
  60. # 获取图像第一行的像素数据
  61. pixel_data = im.load()
  62. pix_list = []
  63. h = int(im.height / 20)
  64. for i in range(im.width):
  65. _r, _g, _b, _a = pixel_data[i, h]
  66. if _a > 10:
  67. pix_list.append(i)
  68. left_f_num = 0
  69. middle_w = int(im.width / 2)
  70. for i in pix_list:
  71. if i < middle_w:
  72. left_f_num += 1
  73. else:
  74. left_f_num -= 1
  75. if left_f_num > 0:
  76. return True
  77. else:
  78. return False
  79. def del_detail_folder(self):
  80. out_path = "{out_put_dir}/{goods_no}".format(
  81. out_put_dir=self.out_put_dir, goods_no=self.goods_no
  82. )
  83. if not os.path.exists(out_path):
  84. return
  85. try:
  86. shutil.rmtree(out_path)
  87. except BaseException as e:
  88. print("删除文件夹失败", e)
  89. def run_all(self):
  90. if self.template_name:
  91. self.out_put_dir = "{}/{}".format(self.out_put_dir, self.template_name)
  92. print("===================detailed_images=================")
  93. # 如果没有指定页面,则删除指定目录下的对应的详情文件夹
  94. if not self.assigned_page_list:
  95. self.del_detail_folder()
  96. detailed_images = self.deal_details()
  97. self.create_folder(self.out_put_dir)
  98. detail_path = "{out_put_dir}/{goods_no}/details".format(
  99. out_put_dir=self.out_put_dir, goods_no=self.goods_no
  100. )
  101. self.create_folder(detail_path)
  102. self.save_to_png(detailed_images=detailed_images, detail_path=detail_path)
  103. # 生成拼接图
  104. self.generate_spliced_picture()
  105. # ------------移动其他图片---------------------
  106. # 获取主图模板列表
  107. main_pic_path_list = DetailBase.get_temp_pic_info(root=self.root)[
  108. "main_pic_path_list"
  109. ]
  110. if not main_pic_path_list:
  111. self.move_other_pic(move_main_pic=True)
  112. else:
  113. self.move_other_pic(move_main_pic=True)
  114. if not self.assigned_page_list:
  115. self.deal_all_main_pic()
  116. else:
  117. if "主图" in self.assigned_page_list:
  118. self.deal_all_main_pic()
  119. # ----------如果是红蜻蜓则创建同颜色下的其他货号颜色文件夹---------------
  120. if settings.PROJECT == "红蜻蜓":
  121. if "data_all_goods_art_info" in self.goods_no_value:
  122. # 数据格式:[{'number': '14250232', 'goods_art_no': 'AC52001173', 'color': '杏色'}, ]
  123. for pic_data in self.goods_no_value["货号资料"]:
  124. if "颜色名称" not in pic_data:
  125. continue
  126. color_name = pic_data["颜色名称"]
  127. color_file_path = "{out_put_dir}/{goods_no}/{goods_number}".format(
  128. out_put_dir=self.out_put_dir,
  129. goods_no=self.goods_no,
  130. goods_number=pic_data["编号"],
  131. )
  132. for i in self.goods_no_value["data_all_goods_art_info"]:
  133. if color_name in i["color"]:
  134. new_path = "{out_put_dir}/{goods_no}/{goods_number}".format(
  135. out_put_dir=self.out_put_dir,
  136. goods_no=self.goods_no,
  137. goods_number="NUM{}".format(i["number"]),
  138. )
  139. if not os.path.exists(new_path):
  140. # 创建文件夹
  141. os.makedirs(new_path)
  142. self.move_one_pic(
  143. color_file_path,
  144. new_path,
  145. "NUM{}".format(i["number"]),
  146. )
  147. return True
  148. # 移动一张图片到新的文件夹
  149. def move_one_pic(self, old_path, new_path, new_name):
  150. image_file = os.listdir(old_path)[0]
  151. old_image_path = "{}/{}".format(old_path, image_file)
  152. image_e = os.path.splitext(image_file)[1]
  153. new_image_path = "{}/{}{}".format(new_path, new_name, image_e)
  154. shutil.copy(old_image_path, new_image_path)
  155. # 生成各个详情图切片
  156. def deal_details(self):
  157. detailed_images = []
  158. for index, func in enumerate(self.deal_pic_func_list):
  159. image_pp = func()
  160. if not self.assigned_page_list:
  161. self.image_list_append(detailed_images, image_pp)
  162. else:
  163. index = "{}".format(index + 1)
  164. if index in self.assigned_page_list:
  165. self.image_list_append(detailed_images, image_pp)
  166. else:
  167. self.image_list_append(detailed_images, {"mes": "不生成"})
  168. return [x for x in detailed_images if x]
  169. # 生成拼接的图片
  170. def generate_spliced_picture(self):
  171. detail_path = "{out_put_dir}/{goods_no}/details".format(
  172. out_put_dir=self.out_put_dir, goods_no=self.goods_no
  173. )
  174. if not os.path.exists(detail_path):
  175. return
  176. detailed_images = []
  177. for image_data in get_images(detail_path):
  178. detailed_images.append(PictureProcessing(image_data["file_path"]))
  179. # 生成拼接图
  180. img = self.add_pic(detailed_images)
  181. join_path = "{out_put_dir}/{goods_no}/拼接图".format(
  182. out_put_dir=self.out_put_dir, goods_no=self.goods_no
  183. )
  184. self.create_folder(join_path)
  185. img.save("{}/1.jpg".format(join_path), format="JPEG")
  186. def image_list_append(self, image_list: list, data):
  187. self.check_state_end()
  188. if isinstance(data, list):
  189. image_list.extend(data)
  190. else:
  191. image_list.append(data)
  192. def save_to_png(self, detailed_images, detail_path):
  193. self.check_state_end()
  194. for index, pp in enumerate(detailed_images):
  195. if isinstance(pp, dict):
  196. continue
  197. pp.im.save(
  198. "{}/{}({}).png".format(
  199. detail_path, self.goods_no, str(index + 11).zfill(2)
  200. )
  201. )
  202. def check_state_end(self):
  203. if self.windows is not None:
  204. if self.windows.state == 99:
  205. raise "用户主动取消"
  206. @classmethod
  207. def get_temp_pic_info(cls, root):
  208. """
  209. 获取详情页模板中的信息
  210. """
  211. main_pic_list = []
  212. mask_pic_list = []
  213. if os.path.exists(r"{}\main_image".format(root)):
  214. for _name in os.listdir(r"{}\main_image".format(root)):
  215. _path = r"{}\main_image\{}".format(root, _name)
  216. if os.path.isdir(_path):
  217. main_pic_list.append([x["file_path"] for x in get_images(_path)])
  218. mask_pic_list.append(
  219. [x["file_path"] for x in get_image_mask(_path)]
  220. )
  221. _l = get_images(r"{}\show".format(root))
  222. temp_pic_path = _l[0]["file_path"] if _l else None
  223. other_pic_list = [x["file_path"] for x in get_images(r"{}".format(root))]
  224. return {
  225. "main_pic_path_list": main_pic_list,
  226. "temp_pic_path": temp_pic_path,
  227. "mask_pic_list": mask_pic_list,
  228. "other_pic_path_list": other_pic_list,
  229. }
  230. def init(self):
  231. for goods_art_no_value in self.goods_no_value["货号资料"]:
  232. self.data[goods_art_no_value["货号"]] = {
  233. "pics": goods_art_no_value["pics"],
  234. "pic_is_deal": {},
  235. }
  236. def get_text_value(self, key, subsection_len=0):
  237. text = ""
  238. if key in self.goods_no_value:
  239. if self.goods_no_value[key]:
  240. text = str(self.goods_no_value[key])
  241. text = text.replace(r"\n", "\n")
  242. # if key in ["跟高", "鞋宽", "帮高", "脚掌围", "鞋长"]:
  243. # if text:
  244. # text = text.split(".")[0]
  245. if subsection_len != 0:
  246. text = text.split("\n")
  247. text = [x for x in text if x]
  248. if len(text) == 2:
  249. text_1 = text[0]
  250. text_2 = text[1]
  251. return text_1, text_2
  252. else:
  253. if text:
  254. text_1 = text[0]
  255. else:
  256. text_1 = ""
  257. text_2 = ""
  258. return text_1, text_2
  259. return text
  260. def create_folder(self, path):
  261. if not os.path.exists(path):
  262. os.makedirs(path)
  263. def get_all_process_pics(self):
  264. """
  265. 获取所有颜色的过程图片
  266. data = [
  267. {"货号": "",
  268. "素材": [{
  269. "名称": "俯视",
  270. "抠图": "路径1",
  271. "阴影": "路径2"
  272. }, ]},
  273. ]
  274. """
  275. return_data = []
  276. for goods_art_no in self.data:
  277. goods_art_no_dict = {
  278. "货号": goods_art_no,
  279. "素材": [],
  280. }
  281. # 图片数据重新排序
  282. pic_data = []
  283. for pic_name, pic_path in self.data[goods_art_no]["pics"].items():
  284. root_path, file_name = os.path.split(pic_path)
  285. pic_data.append(file_name)
  286. pic_data = natsorted(pic_data, alg=ns.PATH)
  287. for file_name in pic_data:
  288. if "阴影" in file_name:
  289. _, action_name, _ = file_name.split("_")
  290. pic_path = self.data[goods_art_no]["pics"][
  291. "{}-阴影".format(action_name)
  292. ]
  293. pic_cutout_path = self.data[goods_art_no]["pics"][
  294. "{}-抠图".format(action_name)
  295. ]
  296. if os.path.exists(pic_path) and os.path.exists(pic_cutout_path):
  297. goods_art_no_dict["素材"].append(
  298. {
  299. "名称": action_name,
  300. "抠图": pic_cutout_path,
  301. "阴影": pic_path,
  302. }
  303. )
  304. return_data.append(goods_art_no_dict)
  305. return return_data
  306. def get_overlay_pic_from_dict(
  307. self, goods_art_no, color_name, bg_color
  308. ) -> PictureProcessing:
  309. self.check_state_end()
  310. # 增加逻辑,获取任意货号下的组合图
  311. if "组合" in color_name:
  312. goods_art_no, color_name = self.get_all_scene_list(goods_art_no, color_name)
  313. key = "{}-{}-{}".format(goods_art_no, color_name, bg_color)
  314. if key in self.overlay_pic_dict:
  315. return self.overlay_pic_dict[key]
  316. if goods_art_no in self.data:
  317. for pic_name, pic_path in self.data[goods_art_no]["pics"].items():
  318. if "阴影" in pic_name:
  319. action_name = pic_name.replace("-阴影", "")
  320. if action_name == color_name:
  321. pp1 = PictureProcessing(pic_path)
  322. pp2 = PictureProcessing(
  323. self.data[goods_art_no]["pics"][
  324. "{}-抠图".format(action_name)
  325. ]
  326. )
  327. pp1 = pp1.get_overlay_pic(top_img=pp2, color=bg_color).resize(
  328. mode="pixel", base="width", value=1600
  329. )
  330. self.overlay_pic_dict[key] = pp1
  331. if key in self.overlay_pic_dict:
  332. return self.overlay_pic_dict[key]
  333. def image_init(self, bg_color=(246, 246, 246)):
  334. # 制作一批素材图,添加背景色,并保留阴影,以及处理成最小尺寸
  335. for goods_art_no in self.data:
  336. for pic_name, pic_path in self.data[goods_art_no]["pics"].items():
  337. if "阴影" in pic_name:
  338. action_name = pic_name.replace("-阴影", "")
  339. pp1 = PictureProcessing(pic_path)
  340. pp2 = PictureProcessing(
  341. self.data[goods_art_no]["pics"]["{}-抠图".format(action_name)]
  342. )
  343. pp1 = pp1.get_overlay_pic(top_img=pp2, color=bg_color).resize(
  344. mode="pixel", base="width", value=1600
  345. )
  346. self.data[goods_art_no]["pic_is_deal"][action_name] = pp1
  347. # 获取任意货号的场景图,优先取指定货号;
  348. # 调整,按顺序从货号列表中提取所有组合图
  349. def get_all_scene_info(self, goods_art_no):
  350. data = []
  351. # 收集所有组合图
  352. # 找任意一个有组合图的货号
  353. for goods_art_no_dict in self.goods_no_value["货号资料"]:
  354. _goods_art_no = goods_art_no_dict["货号"]
  355. _view_name_list = set([x.split("-")[0] for x in goods_art_no_dict["pics"]])
  356. for _view_name in _view_name_list:
  357. if "组合" not in _view_name:
  358. continue
  359. return _goods_art_no
  360. return goods_art_no
  361. def get_all_scene_list(self, goods_art_no, view_name: str):
  362. if "组合" == view_name:
  363. view_name = "组合1"
  364. try:
  365. view_index = int(view_name.replace("组合", "")) - 1
  366. except:
  367. return goods_art_no, "无法匹配"
  368. data = []
  369. # 收集所有组合图
  370. # 找任意一个有组合图的货号
  371. for goods_art_no_dict in self.goods_no_value["货号资料"]:
  372. _goods_art_no = goods_art_no_dict["货号"]
  373. if _goods_art_no != goods_art_no:
  374. continue
  375. _view_name_list = set([x.split("-")[0] for x in goods_art_no_dict["pics"]])
  376. for _view_name in _view_name_list:
  377. if "组合" not in _view_name:
  378. continue
  379. data.append(
  380. {
  381. "goods_art_no": _goods_art_no,
  382. "view_name": _view_name,
  383. "real_view_name": (
  384. "组合1" if _view_name == "组合" else _view_name
  385. ),
  386. }
  387. )
  388. if len(data) <= view_index:
  389. return goods_art_no, "无法匹配"
  390. else:
  391. data.sort(key=lambda x: x["real_view_name"], reverse=False)
  392. return data[view_index]["goods_art_no"], data[view_index]["view_name"]
  393. def image_one_pic(self, goods_art_no, name, bg_color=None, return_orign=None):
  394. # 增加逻辑,获取任意货号下的组合图
  395. if "组合" in name:
  396. print("324==== goods_art_no, name", goods_art_no, name)
  397. goods_art_no, name = self.get_all_scene_list(goods_art_no, name)
  398. print("324 goods_art_no, name", goods_art_no, name)
  399. # 制作一批素材图,添加背景色,并保留阴影,以及处理成最小尺寸
  400. for pic_name, pic_path in self.data[goods_art_no]["pics"].items():
  401. if "阴影" in pic_name:
  402. action_name = pic_name.replace("-阴影", "")
  403. if name != action_name:
  404. continue
  405. pp1 = PictureProcessing(pic_path)
  406. pp2 = PictureProcessing(
  407. self.data[goods_art_no]["pics"]["{}-抠图".format(action_name)]
  408. )
  409. if not return_orign:
  410. pp1 = pp1.get_overlay_pic(top_img=pp2, color=bg_color).resize(
  411. mode="pixel", base="width", value=1600
  412. )
  413. return pp1
  414. else:
  415. return pp1, pp2
  416. if not return_orign:
  417. return None
  418. else:
  419. return None, None
  420. def move_other_pic(self, move_main_pic=True):
  421. # ------------------------------移动其他图片------------------------------
  422. goods_no_main_pic_number = 0
  423. for goods_art_no_dict in self.goods_no_value["货号资料"]:
  424. if "800x800" not in goods_art_no_dict:
  425. continue
  426. if not goods_art_no_dict["800x800"]:
  427. continue
  428. goods_art_no = ""
  429. if "编号" in goods_art_no_dict:
  430. if goods_art_no_dict["编号"]:
  431. goods_art_no = goods_art_no_dict["编号"]
  432. if not goods_art_no:
  433. goods_art_no = goods_art_no_dict["货号"]
  434. # print("goods_art_no:", goods_art_no)
  435. # 移动颜色图=====================
  436. goods_art_no_f = "{}/{}/{}".format(
  437. self.out_put_dir, self.goods_no, goods_art_no
  438. )
  439. self.create_folder(goods_art_no_f)
  440. # 放入一张主图
  441. old_pic_path_1 = goods_art_no_dict["800x800"][0]
  442. shutil.copy(
  443. old_pic_path_1,
  444. "{}/{}{}".format(
  445. goods_art_no_f, goods_art_no, os.path.splitext(old_pic_path_1)[1]
  446. ),
  447. )
  448. # 把其他主图放入作为款号图=====================
  449. if move_main_pic:
  450. for pic_path in goods_art_no_dict["800x800"]:
  451. goods_no_main_pic_number += 1
  452. e = os.path.splitext(pic_path)[1]
  453. shutil.copy(
  454. pic_path,
  455. "{out_put_dir}/{goods_no}/{goods_no}({goods_no_main_pic_number}){e}".format(
  456. out_put_dir=self.out_put_dir,
  457. goods_no=self.goods_no,
  458. goods_no_main_pic_number=str(
  459. goods_no_main_pic_number + 10
  460. ).zfill(2),
  461. e=e,
  462. ),
  463. )
  464. def deal_all_main_pic(self):
  465. """
  466. 处理主图模板,如存在出图模板则进行对应处理
  467. """
  468. # 获取主图模板列表
  469. all_main_pic_path_list = DetailBase.get_temp_pic_info(root=self.root)[
  470. "main_pic_path_list"
  471. ]
  472. if not all_main_pic_path_list:
  473. return
  474. mask_pic_list = DetailBase.get_temp_pic_info(root=self.root)["mask_pic_list"]
  475. data = self.get_all_process_pics()
  476. print("========deal_all_main_pic=========主图相关素材:")
  477. view_list = [
  478. "组合",
  479. "组合2",
  480. "组合3",
  481. "组合4",
  482. "组合5",
  483. "组合6",
  484. "俯视",
  485. "侧视",
  486. "后跟",
  487. "鞋底",
  488. "内里",
  489. ]
  490. for _index, main_pic_path_list in enumerate(all_main_pic_path_list):
  491. self.check_state_end()
  492. out_path_root = "{out_put_dir}/{goods_no}/main_image_{_index}".format(
  493. out_put_dir=self.out_put_dir, goods_no=self.goods_no, _index=_index
  494. )
  495. check_path(out_path_root)
  496. if mask_pic_list[_index]:
  497. mask_pic = mask_pic_list[_index][0]
  498. else:
  499. mask_pic = None
  500. goods_no_main_pic_number = 10
  501. # g_index 为第几个颜色货号
  502. for g_index, goods_art_no_dict in enumerate(data):
  503. goods_art_no = goods_art_no_dict["货号"]
  504. # =====================重新指定=================================
  505. _material_sort_dict = {}
  506. for index, material_dict in enumerate(goods_art_no_dict["素材"]):
  507. name = material_dict["名称"]
  508. _material_sort_dict[name] = material_dict
  509. # ======================================================
  510. file_name_index = -1
  511. for view_name in view_list:
  512. # 组合图比较特殊,为全局获取
  513. if g_index != 0:
  514. if "组合" in view_name:
  515. continue
  516. if view_name not in _material_sort_dict:
  517. continue
  518. self.check_state_end()
  519. pp_jpg, pp_png = self.image_one_pic(
  520. goods_art_no, view_name, bg_color=None, return_orign=True
  521. )
  522. if not pp_jpg:
  523. continue
  524. file_name_index += 1
  525. # 获取对应主图模板
  526. if len(main_pic_path_list) < file_name_index + 1:
  527. main_pic_path = main_pic_path_list[-1]
  528. else:
  529. main_pic_path = main_pic_path_list[file_name_index]
  530. pp_bg = PictureProcessing(main_pic_path)
  531. original_width = pp_bg.width
  532. if original_width != 1600:
  533. pp_bg = pp_bg.resize(value=1600)
  534. if mask_pic:
  535. mask_bg = PictureProcessing(mask_pic)
  536. mask_bg = mask_bg.resize(value=1600)
  537. mask_box_im = mask_bg.get_im()
  538. box_size = mask_box_im.getbbox()
  539. result_image = mask_box_im.crop(box_size)
  540. mask_width, mask_height = result_image.size
  541. mask_x, mask_y = box_size[0], box_size[1]
  542. else:
  543. mask_width, mask_height = pp_bg.size
  544. mask_width, mask_height = int(mask_width * 12 / 16), int(
  545. mask_height * 12 / 16
  546. )
  547. mask_x, mask_y = int((pp_bg.size[0] - mask_width) / 2), int(
  548. (pp_bg.size[1] - mask_height) / 2
  549. )
  550. if view_name != "后跟":
  551. pp_jpg = pp_jpg.resize(base_by_box=(mask_width, mask_height))
  552. pp_png = pp_png.resize(base_by_box=(mask_width, mask_height))
  553. # 计算粘贴的位置 mask的位置+图片在mask中的位置
  554. p_x = mask_x + int((mask_width - pp_jpg.width) / 2)
  555. p_y = mask_y + int((mask_height - pp_jpg.height) / 2)
  556. pp_bg = pp_bg.to_overlay_pic_advance(
  557. mode="pixel",
  558. top_img=pp_jpg,
  559. base="nw",
  560. value=(p_x, p_y),
  561. top_png_img=pp_png,
  562. )
  563. else:
  564. new_mask_width, new_mask_height = int(mask_width / 1.6), int(
  565. mask_height / 1.6
  566. )
  567. pp_jpg = pp_jpg.resize(
  568. base_by_box=(new_mask_width, new_mask_height)
  569. )
  570. pp_png = pp_png.resize(
  571. base_by_box=(new_mask_width, new_mask_height)
  572. )
  573. new_mask_x = int((mask_width - new_mask_width) / 2 + mask_x)
  574. new_mask_y = int((mask_height - new_mask_height) / 2 + mask_y)
  575. # 计算粘贴的位置 mask的位置+图片在mask中的位置
  576. p_x = new_mask_x + int((new_mask_width - pp_jpg.width) / 2)
  577. p_y = new_mask_y + int((new_mask_height - pp_jpg.height) / 2)
  578. pp_bg = pp_bg.to_overlay_pic_advance(
  579. mode="pixel",
  580. top_img=pp_jpg,
  581. base="nw",
  582. value=(p_x, p_y),
  583. top_png_img=pp_png,
  584. )
  585. goods_no_main_pic_number += 1
  586. out_pic_path = "{out_path_root}/{goods_no}({goods_no_main_pic_number}){pic_mode}".format(
  587. out_path_root=out_path_root,
  588. goods_no=self.goods_no,
  589. goods_no_main_pic_number=goods_no_main_pic_number,
  590. pic_mode=settings.OUT_PIC_MODE,
  591. )
  592. if settings.OUT_PIC_FACTOR > 1.0:
  593. print("图片锐化处理")
  594. pp_bg = pp_bg.sharpen_image(factor=settings.OUT_PIC_FACTOR)
  595. if original_width < 1600:
  596. pp_bg = pp_bg.resize(value=original_width)
  597. print("392 out_pic_path", out_pic_path)
  598. if settings.OUT_PIC_MODE == ".jpg":
  599. pp_bg.save_as_rgb(out_pic_path)
  600. elif settings.OUT_PIC_MODE == ".png":
  601. pp_bg.save_as_png(out_pic_path)
  602. else:
  603. pp_bg.save_as_other(
  604. out_pic_path, settings.OUT_PIC_MODE.split(".")[-1]
  605. )
  606. def add_pic(self, detailed_images):
  607. self.check_state_end()
  608. todo_detailed_images = []
  609. detailed_images = [x for x in detailed_images if x]
  610. if not detailed_images:
  611. return
  612. for i in detailed_images:
  613. if isinstance(i, list):
  614. for n in i:
  615. todo_detailed_images.append(n)
  616. else:
  617. todo_detailed_images.append(i)
  618. page_len = 0
  619. for index, pp in enumerate(todo_detailed_images):
  620. page_len += pp.height
  621. bg_im = Image.new("RGB", (pp.width, page_len), (255, 255, 255))
  622. n = 0
  623. for index, pp in enumerate(todo_detailed_images):
  624. bg_im.paste(pp.im, (0, n))
  625. n += pp.height
  626. return bg_im
  627. # 通用方法,用于写文字
  628. def add_text_list(self, text_list, spacing=5, base="wn", base_width=1600):
  629. text_list = [x for x in text_list if x["text"]]
  630. # print(text_list)
  631. # spacing 行间距
  632. text_image_list = []
  633. max_w = 0
  634. total_h = 0
  635. for text_data in text_list:
  636. _pp = PictureProcessing("RGBA", (base_width, 1200), (255, 255, 255, 0))
  637. if base == "wn" or base == "nw":
  638. align = "left"
  639. anchor = None
  640. value = (0, 250)
  641. if base == "cn" or base == "nc":
  642. align = "center"
  643. anchor = "mm"
  644. value = (int(base_width / 2), 250)
  645. if base == "en" or base == "ne":
  646. align = "right"
  647. anchor = "rs"
  648. value = (base_width - 10, 250)
  649. _pp = _pp.get_text_image_advanced(
  650. value=value,
  651. font=text_data["font"],
  652. text=text_data["text"],
  653. align=align,
  654. anchor=anchor,
  655. spacing=5,
  656. fill=text_data["fill"],
  657. return_mode="min_image",
  658. margins=(0, 0, 0, 0),
  659. )
  660. text_image_list.append(_pp)
  661. if _pp.width > max_w:
  662. max_w = _pp.width
  663. total_h += _pp.height
  664. if "spacing" in text_data:
  665. total_h += text_data["spacing"]
  666. if not text_image_list:
  667. return None
  668. #
  669. bg = PictureProcessing("RGBA", (max_w, total_h * 3), (0, 0, 0, 0))
  670. y = 0
  671. for text_image, text_data in zip(text_image_list, text_list):
  672. bg = bg.paste_img(top_img=text_image, value=(0, y), base=base)
  673. y += spacing + text_image.height
  674. if "spacing" in text_data:
  675. y += text_data["spacing"]
  676. bg = bg.crop(mode="min")
  677. # _ = bg.paste_img_invert(top_img=PictureProcessing("RGB", (bg.width,bg.height), (255, 255, 255)))
  678. # _.show()
  679. return bg
  680. def generate_font_list_to_pic(self):
  681. font_path_list = [
  682. r"resources\ttf\puhui\Bold.ttf",
  683. r"resources\ttf\puhui\Medium.ttf",
  684. r"resources\ttf\puhui\Heavy.ttf",
  685. r"resources\ttf\puhui\Light.ttf",
  686. r"resources\ttf\puhui\Regular.ttf",
  687. ]
  688. text_v_list = [
  689. "这是一段话Bold",
  690. "这是一段话Medium",
  691. "这是一段话Heavy",
  692. "这是一段话Light",
  693. "这是一段话Regular",
  694. ]
  695. detailed_images = []
  696. for font_path, text in zip(font_path_list, text_v_list):
  697. text_list = []
  698. for size in range(26, 80, 2):
  699. font = ImageFont.truetype(font_path, size)
  700. text_list.append(
  701. {
  702. "text": "{}-字号{}".format(text, size),
  703. "font": font,
  704. "fill": (110, 110, 110),
  705. }
  706. )
  707. text_image = self.add_text_list(text_list, spacing=15, base="nw")
  708. text_image = text_image.crop(mode="min")
  709. text_image = text_image.paste_img_invert(
  710. top_img=PictureProcessing("RGB", text_image.size, (255, 255, 255))
  711. )
  712. detailed_images.append(text_image)
  713. return PictureProcessing(im=self.add_pic(detailed_images))
  714. # 图片分段,每段至少大于N长度
  715. def pp_pic_subsection(self, pp: PictureProcessing, one_height=3200):
  716. total_height = pp.height
  717. now_height = 0
  718. detailed_images = []
  719. while 1:
  720. if now_height + one_height < total_height:
  721. h1 = now_height
  722. h2 = now_height + one_height
  723. bbox = (0, h1, pp.width, h2)
  724. # print("bbox1", bbox)
  725. detailed_images.append(pp.crop(bbox=bbox))
  726. now_height = now_height + one_height
  727. continue
  728. if now_height + one_height >= total_height:
  729. h1 = now_height
  730. h2 = total_height
  731. bbox = (0, h1, pp.width, h2)
  732. # print("bbox2", bbox)
  733. detailed_images.append(pp.crop(bbox=bbox))
  734. break
  735. return detailed_images