base.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506
  1. import os
  2. import copy
  3. import configparser
  4. # from module.base_mode.module_aes import Aes
  5. import exifread
  6. from natsort import ns, natsorted
  7. import shutil
  8. from hashlib import sha256, md5
  9. import requests
  10. from datetime import datetime
  11. # 获取digicam的路径
  12. def check_install_path(other):
  13. path_list = []
  14. path_list.append(other)
  15. path_list.append(r"D:\Program Files (x86)\digiCamControl\CameraControl.exe")
  16. path_list.append(r"C:\Program Files (x86)\digiCamControl\CameraControl.exe")
  17. path_list.append(r"D:\Program Files\digiCamControl\CameraControl.exe")
  18. path_list.append(r"C:\Program Files\digiCamControl\CameraControl.exe")
  19. for i in path_list:
  20. if os.path.exists(i):
  21. return i
  22. return ""
  23. # 输入文件夹,并检查是否是一个正常的图片文件夹。
  24. def check_goods_folder(folder_path):
  25. all_files = os.listdir(folder_path)
  26. for file in all_files:
  27. file_path = "{}/{}".format(folder_path, file)
  28. if not os.path.isdir(file_path):
  29. continue
  30. if "原始图" in os.listdir(file_path):
  31. return folder_path
  32. # 上述检查不通过,可能是选择目录错误
  33. if "原始图" in all_files:
  34. root_path, _ = os.path.split(folder_path)
  35. return root_path
  36. return None
  37. def download_file(url, file_path):
  38. try:
  39. root_path, file_name = os.path.split(file_path)
  40. check_path(root_path)
  41. response = requests.get(url)
  42. _content = response.content
  43. with open(file_path, 'wb') as f:
  44. f.write(_content)
  45. print("下载成功:{}".format(file_path))
  46. except:
  47. print("下载失败:{}".format(file_path))
  48. def calculate_sha256(file_path):
  49. """Calculate the sha256 hash of the given file."""
  50. sha256_hash = sha256()
  51. try:
  52. with open(file_path, "rb") as f:
  53. # Read and update hash string value in blocks of 4K
  54. for byte_block in iter(lambda: f.read(4096), b""):
  55. sha256_hash.update(byte_block)
  56. return sha256_hash.hexdigest()
  57. except FileNotFoundError:
  58. print(f"The file {file_path} does not exist.")
  59. return None
  60. except Exception as e:
  61. print(f"An error occurred: {e}")
  62. return None
  63. def get_modified_time(file_path):
  64. # 获取文件最后修改的时间戳
  65. timestamp = os.path.getmtime(file_path)
  66. # 将时间戳转换为datetime对象,并格式化为指定格式的字符串
  67. modified_time = datetime.fromtimestamp(timestamp).strftime('%Y-%m-%d %H:%M:%S')
  68. return modified_time
  69. def download_file_to_io(url):
  70. try:
  71. # 发送GET请求
  72. response = requests.get(url)
  73. # 检查请求是否成功
  74. response.raise_for_status() # 如果响应状态码不是200,会抛出HTTPError异常
  75. # 返回响应内容,以文本形式(对于HTML、JSON等文本内容)
  76. return response.text
  77. # 或者返回原始的二进制内容(对于图片、文件等非文本内容)
  78. # return response.content
  79. except requests.RequestException as e:
  80. print(f"An error occurred: {e}")
  81. return None
  82. def get_md5(file_path):
  83. data_md5 = None
  84. if os.path.isfile(file_path):
  85. f = open(file_path, 'rb')
  86. md5_obj = md5()
  87. md5_obj.update(f.read())
  88. hash_code = md5_obj.hexdigest()
  89. f.close()
  90. data_md5 = str(hash_code).lower()
  91. return data_md5
  92. def list_dir(path):
  93. listdir = os.listdir(path)
  94. return natsorted(listdir, alg=ns.PATH)
  95. # 通用串口数据解析器
  96. def get_data_from_receive_data(receive_data, start, len_data, data_magnification=1):
  97. # data_magnification 数据放大倍数,或缩小倍数,默认为1
  98. try:
  99. if len_data == 1:
  100. data = receive_data[start]
  101. return data * data_magnification
  102. elif len_data == 2:
  103. data = receive_data[start] << 8 | receive_data[start + 1]
  104. return data * data_magnification
  105. elif len_data == 4:
  106. data = receive_data[start] << 24 | receive_data[start + 1] << 16 | receive_data[start + 2] << 8 | \
  107. receive_data[start + 3]
  108. return data * data_magnification
  109. return None
  110. except:
  111. return None
  112. def get_images(path):
  113. _Type = [".png", ".PNG", ".jpg", ".JPG", ".gif", ".GIF", ".jpge", ".JPGE", ".CR2"]
  114. image_list = [] # 过滤非图片数据
  115. for _file in list_dir(path):
  116. file_name, e = os.path.splitext(_file)
  117. file_path = "{}/{}".format(path, _file)
  118. if os.path.isdir(file_path):
  119. continue
  120. if e in _Type and "mask" not in file_name:
  121. image_list.append(
  122. {
  123. "file_path": file_path,
  124. "file_name": file_name,
  125. "file": _file,
  126. "root_path": path,
  127. "e": e,
  128. }
  129. )
  130. return image_list
  131. def get_image_mask(path):
  132. _Type = [".png", ".PNG", ".jpg", ".JPG", ".gif", ".GIF", ".jpge", ".JPGE", ".CR2"]
  133. image_list = [] # 过滤非图片数据
  134. for _file in list_dir(path):
  135. file_name, e = os.path.splitext(_file)
  136. file_path = "{}/{}".format(path, _file)
  137. if os.path.isdir(file_path):
  138. continue
  139. if e in _Type and file_name == "mask":
  140. image_list.append(
  141. {
  142. "file_path": file_path,
  143. "file_name": file_name,
  144. "file": _file,
  145. "root_path": path,
  146. "e": e,
  147. }
  148. )
  149. return image_list
  150. # 删除文件夹下的所有文件
  151. def remove_all_file(directory):
  152. try:
  153. shutil.rmtree(directory)
  154. os.makedirs(directory)
  155. except Exception as e:
  156. print(f'Failed to clear directory {directory}. Reason: {e}')
  157. # 删除文件
  158. def remove_files(file_path):
  159. try:
  160. if os.path.exists(file_path):
  161. os.remove(file_path)
  162. return True
  163. except BaseException as e:
  164. print("base 188", e)
  165. return False
  166. def get_folder(path):
  167. folder_list = []
  168. for _file in list_dir(path):
  169. file_path = "{}/{}".format(path, _file)
  170. if os.path.isdir(file_path):
  171. folder_list.append(
  172. {"folder_path": file_path,
  173. "folder_name": _file,
  174. "root_path": path,
  175. "label": "待处理", # 是否需要继续处理
  176. }
  177. )
  178. return folder_list
  179. # 获取所有货号颜色 文件夹
  180. def get_all_goods_art_no_folder(path, goods_art_nos):
  181. folder_list = []
  182. if not os.path.exists(path):
  183. return folder_list
  184. if os.path.isfile(path):
  185. return folder_list
  186. temp_folder_list = get_folder(path)
  187. # for goods_art_no in goods_art_nos:
  188. for folder_data in temp_folder_list:
  189. folder_path = folder_data["folder_path"]
  190. _p = "{}/原始图".format(folder_path)
  191. if os.path.exists(_p):
  192. folder_data["folder_path"] = f"{folder_path}"
  193. folder_list.append(folder_data)
  194. return folder_list
  195. def check_move_goods_art_no_folder(path, goods_art_nos,limit_folder):
  196. """
  197. 检查目录是否存在,如果存在,直接移动到当前日期下的目录
  198. """
  199. folder_list = {}
  200. if not os.path.exists(path):
  201. print("path不存在", path)
  202. return folder_list
  203. if os.path.isfile(path):
  204. print("path是文件", path)
  205. return folder_list
  206. temp_folder_list = get_folder(path)
  207. for goods_art_no in goods_art_nos:
  208. for folder_data in temp_folder_list:
  209. # folder_path = folder_data["folder_path"]
  210. folder_name = folder_data["folder_name"]
  211. _p = "output/{}/{}/原始图".format(folder_name, goods_art_no)
  212. if os.path.exists(_p):
  213. folder_data["folder_path"] = f"output/{folder_name}/{goods_art_no}"
  214. # 整个目录移动到目标目录
  215. folder_list[goods_art_no] = folder_data
  216. if not os.path.exists(f"{limit_folder}/{goods_art_no}"):
  217. # 目标不存在
  218. folder_list[goods_art_no] = folder_data
  219. shutil.move(folder_data["folder_path"], limit_folder)
  220. else:
  221. # 如果希望覆盖
  222. print(f"目标目录 {limit_folder}/{goods_art_no} 已存在,跳过移动")
  223. return folder_list
  224. def get_date_time_original(file_path):
  225. with open(file_path, "rb") as file_data:
  226. tags = exifread.process_file(file_data)
  227. if "EXIF DateTimeOriginal" in tags:
  228. return str(tags["EXIF DateTimeOriginal"])
  229. else:
  230. return False
  231. def get_data_from_hqt(goods_number_list, get_online_data_ins):
  232. _goods_number_list = copy.deepcopy(goods_number_list)
  233. _list = []
  234. # 单次请求数少于20个
  235. goods_number_dict = {}
  236. while _goods_number_list:
  237. goods_art_no = _goods_number_list.pop()
  238. if "NUM" in goods_art_no:
  239. goods_art_no = goods_art_no.replace("NUM", "")
  240. _list.append(goods_art_no)
  241. if len(_list) == 20 or len(_goods_number_list) == 0:
  242. online_goods_art_data = get_online_data_ins.get_goods_art_no_info(
  243. numbers_list=_list
  244. )
  245. if online_goods_art_data:
  246. for number in online_goods_art_data:
  247. goods_number_dict["NUM" + number] = online_goods_art_data[number]
  248. _list = []
  249. return goods_number_dict
  250. def get_data_from_hqt_with_goods_art_no(goods_art_no_list, get_online_data_ins):
  251. _goods_art_no_list = copy.deepcopy(goods_art_no_list)
  252. _list = []
  253. # 单次请求数少于20个
  254. goods_art_no_dict = {}
  255. while _goods_art_no_list:
  256. goods_art_no = _goods_art_no_list.pop()
  257. _list.append(goods_art_no)
  258. if len(_list) == 20 or len(_goods_art_no_list) == 0:
  259. online_goods_art_data = get_online_data_ins.get_goods_art_no_info(
  260. goods_art_list=_list
  261. )
  262. if online_goods_art_data:
  263. for _goods_art_no in online_goods_art_data:
  264. goods_art_no_dict[_goods_art_no] = online_goods_art_data[
  265. _goods_art_no
  266. ]
  267. _list = []
  268. return goods_art_no_dict
  269. def load_config_form_ini(config_path):
  270. config = configparser.ConfigParser()
  271. if os.path.exists(config_path):
  272. try:
  273. config.read(config_path, encoding="utf-8")
  274. except:
  275. config.read(config_path)
  276. return config
  277. def set_config_to_int(config_ins, config_path, data_dict, section="basicSetup"):
  278. for i in data_dict:
  279. config_ins.set(section=section, option=i, value=data_dict[i])
  280. try:
  281. config_ins.write(open(config_path, "w", encoding="utf-8"))
  282. except:
  283. config_ins.write(open(config_path, "w"))
  284. # try:
  285. # config_ins.read(config_path, encoding="utf-8")
  286. # except:
  287. # config_ins.read(config_path)
  288. return config_ins
  289. def get_config(config_ins, key, section="basicSetup"):
  290. config_dict1 = config_ins.items(section)
  291. __config_dict = {}
  292. for i, k in config_dict1:
  293. __config_dict[i] = k
  294. if key in __config_dict:
  295. return __config_dict[key]
  296. else:
  297. return None
  298. def get_config_by_items(config_dict):
  299. __config_dict = {}
  300. for i, k in config_dict:
  301. __config_dict[i] = k
  302. return __config_dict
  303. def get_dict_value(_dict, key, default=None):
  304. if key in _dict:
  305. return _dict[key]
  306. else:
  307. return default
  308. # def set_key(authorization, SecretKey, SecretIv):
  309. # # --------------------用户身份--------------
  310. # if authorization:
  311. # authorization = Aes().get_key(authorization, SecretKey, SecretIv)
  312. # with open("key", "w") as f:
  313. # f.write(authorization)
  314. # return authorization
  315. def print_dic(_dict):
  316. for i, v in _dict.items():
  317. print("{}:{}".format(i, v))
  318. print("\n")
  319. def check_path(_path):
  320. if not os.path.exists(_path):
  321. # 创建多级目录
  322. os.makedirs(_path, exist_ok=True)
  323. # os.mkdir(_path)
  324. return True
  325. def move_folders(path_list, target_folder):
  326. if not os.path.exists(target_folder):
  327. os.makedirs(target_folder)
  328. for source_folder in path_list:
  329. shutil.move(source_folder, target_folder)
  330. # 给定一个图片路径,如果 是原始图下的则返回对应已扣图等信息。否则只返回基础信息
  331. def get_cutout_image_info(source_image_path):
  332. if not os.path.exists(source_image_path):
  333. return None
  334. if os.path.isdir(source_image_path):
  335. return None
  336. data = {}
  337. source_root_path, source_file = os.path.split(source_image_path)
  338. source_file_name, source_file_extension = os.path.splitext(source_file)
  339. print("---------------source_root_path--------------------")
  340. print(source_root_path)
  341. print(source_root_path[-3:])
  342. # if source_root_path[-3:] != "原始图":
  343. # return None
  344. data["source_image_path"] = source_image_path
  345. data["source_root_path"] = source_root_path
  346. data["source_file"] = source_file
  347. data["source_file_name"] = source_file_name
  348. data["source_file_extension"] = source_file_extension
  349. cutout_image_path = "{}/原始图_已抠图/{}.png".format(source_root_path[:-3], source_file_name)
  350. if not os.path.exists(cutout_image_path):
  351. data["cutout_image_path"] = None
  352. return data
  353. cutout_image_root_path, cutout_image_file = os.path.split(cutout_image_path)
  354. cutout_image_file_name, cutout_image_file_extension = os.path.splitext(cutout_image_file)
  355. data["cutout_image_path"] = cutout_image_path
  356. data["cutout_image_root_path"] = cutout_image_root_path
  357. data["cutout_image_file"] = cutout_image_file
  358. data["cutout_image_file_name"] = cutout_image_file_name
  359. data["cutout_image_file_extension"] = cutout_image_file_extension
  360. return data
  361. # 指定一个列表,指定一个需要移动的数据列表,移动到指定列表中的位置
  362. def move_elements_inplace(lst, indices, target_index, is_real_same_folder=False):
  363. """
  364. 在原地将列表中指定位置的两个元素移动到目标位置。
  365. :param lst: 要操作的列表
  366. :param indices: 一个包含两个整数的元组或列表,表示要移动的元素的索引
  367. :param target_index: 目标插入位置的索引
  368. """
  369. if not isinstance(indices, (list, tuple)) or len(indices) == 0:
  370. raise ValueError("Indices must be a non-empty list or tuple of integers.")
  371. # 添加到末尾
  372. if target_index == len(lst):
  373. if is_real_same_folder:
  374. # 倒序取出所有内容,并添加到末尾
  375. indices.sort(reverse=True)
  376. temp = []
  377. for i in indices:
  378. temp.append(lst.pop(i))
  379. while temp:
  380. lst.append(temp.pop(-1))
  381. # 重新写入索引
  382. for index, image_label in enumerate(lst):
  383. image_label.image_index = index
  384. return
  385. # 检查索引是否有效,并排序以确保按照正确的顺序处理
  386. valid_indices = sorted(set(indices)) # 去重并排序
  387. if not all(0 <= idx < len(lst) for idx in valid_indices):
  388. raise IndexError("One or more indices are out of range.")
  389. if not (0 <= target_index <= len(lst)):
  390. raise IndexError("Target index is out of range.")
  391. elements_to_move = [lst[idx] for idx in valid_indices]
  392. # 如果目标位置在所有待移动元素的最大索引之后,则不需要调整目标位置
  393. max_idx = max(valid_indices)
  394. if max_idx < target_index:
  395. pass
  396. else:
  397. # 计算需要减少的位置数(因为删除元素后,后续元素会向前移动)
  398. shift_count = sum(1 for idx in valid_indices if idx < target_index)
  399. target_index -= shift_count
  400. # 移除元素(从大索引开始以避免影响小索引处的元素)
  401. for idx in reversed(valid_indices):
  402. del lst[idx]
  403. # 插入元素到目标位置,保持它们原来的相对顺序
  404. for i, element in enumerate(elements_to_move):
  405. lst.insert(target_index + i, element)
  406. # 重新写入索引
  407. for index, image_label in enumerate(lst):
  408. image_label.image_index = index
  409. # 比较两个相同格式的时间字符串
  410. def compare_two_times(time_str1, time_str2):
  411. # 定义时间格式
  412. time_format = "%Y-%m-%d %H:%M:%S"
  413. # 将时间字符串解析为datetime对象
  414. time1 = datetime.strptime(time_str1, time_format)
  415. time2 = datetime.strptime(time_str2, time_format)
  416. # 比较两个时间
  417. if time1 > time2:
  418. # print(f"{time_str1} 比 {time_str2} 新。")
  419. return "left_new"
  420. elif time1 < time2:
  421. # print(f"{time_str2} 比 {time_str1} 新。")
  422. return "right_new"
  423. else:
  424. # print("两个时间相等。")
  425. return "is_same"