detail_generate_base.py 33 KB

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