image_label.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. import json
  2. import os.path
  3. from import_qt_mode import *
  4. from UI.manual_image_matching.image_items import Ui_Form as Ui_Image_Items
  5. from PIL import Image
  6. import rawpy, io
  7. class ImageLabel(QLabel, Ui_Image_Items):
  8. drop_sign = Signal(dict) # 粘贴的位置
  9. drop_from_sign = Signal(dict) # 粘贴来源的位置
  10. select_clearn_all_sign = Signal()
  11. selected_sign = Signal() # 有选中
  12. delete_image_sign = Signal(list) # 删除通知
  13. def __init__(self, text, image_index, image_path, image_name, root_path, is_goods_list, parent=None, windows=None,
  14. top_windows=None):
  15. super().__init__(parent)
  16. self.setupUi(self)
  17. # self.setFixedSize(150, 160)
  18. # self.ui_image.setFixedSize(150, 150)
  19. self.windows = windows
  20. self.top_windows = top_windows
  21. self.parent = parent
  22. self.text = image_name
  23. self.image_index = image_index
  24. self.image_path = image_path
  25. self.image_name = image_name
  26. self.root_path = root_path
  27. self.ui_text.setText(self.text)
  28. # 是图片列表还是普通列表
  29. self.is_goods_list = is_goods_list
  30. self.icon = None
  31. self.set_label_image()
  32. self.setMouseTracking(True)
  33. self.drag_start_position = None
  34. self.selected = False
  35. self.setAcceptDrops(True)
  36. def set_image_label_windows(self,windows):
  37. self.windows = windows
  38. def show_text(self):
  39. self.ui_text.setText(self.text)
  40. def crop_to_square(self, img):
  41. # 打开图片
  42. width, height = img.size # 获取原始图片的宽度和高度
  43. if width == height:
  44. return img
  45. if width > height:
  46. _x = int((width - height) / 2)
  47. img = img.crop((_x, 0, width - _x, height))
  48. else:
  49. _y = int((height - width) / 2)
  50. img = img.crop((0, _y, width, height - _y))
  51. return img
  52. def set_new_parent(self, parent):
  53. self.parent = parent
  54. self.setParent(parent)
  55. def show_big_image(self):
  56. if self.top_windows is not None:
  57. if self.icon:
  58. self.top_windows.show_big_image(self.icon)
  59. def set_label_image2(self):
  60. try:
  61. w, h = self.ui_image.width() * 2, self.ui_image.height() * 2
  62. if "CR2" == self.image_path[-3:]:
  63. _img_raw = Image.open(self.image_path)
  64. else:
  65. if "jpg" == self.image_path[-3:] or "png" == self.image_path[-3:]:
  66. _img_raw = Image.open(self.image_path)
  67. else:
  68. with rawpy.imread(self.image_path) as raw:
  69. raw_image = raw.postprocess()
  70. _img_raw = Image.fromarray(raw_image)
  71. size = (w, int(_img_raw.height * w / _img_raw.width))
  72. _img_raw = _img_raw.resize(size)
  73. _img_raw = _img_raw.convert("RGB")
  74. bytes_io = io.BytesIO()
  75. _img_raw.save(bytes_io, "JPEG")
  76. icon = QPixmap()
  77. icon.loadFromData(bytes_io.getvalue())
  78. self.icon = icon
  79. icon = icon.scaled(
  80. self.ui_image.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation
  81. )
  82. self.ui_image.setPixmap(icon)
  83. except:
  84. pass
  85. def set_label_image(self):
  86. try:
  87. w, h = self.ui_image.width() * 2, self.ui_image.height() * 2
  88. if "CR2" == self.image_path[-3:]:
  89. _img_raw = Image.open(self.image_path)
  90. else:
  91. if "jpg" == self.image_path[-3:] or "png" == self.image_path[-3:]:
  92. _img_raw = Image.open(self.image_path)
  93. else:
  94. with rawpy.imread(self.image_path) as raw:
  95. raw_image = raw.postprocess()
  96. _img_raw = Image.fromarray(raw_image)
  97. # 取缩略图
  98. _img_raw.thumbnail((w, int(_img_raw.height * w / _img_raw.width)))
  99. size = (w, int(_img_raw.height * w / _img_raw.width))
  100. _img_raw = _img_raw.resize(size)
  101. _img_raw = _img_raw.convert("RGB")
  102. bytes_io = io.BytesIO()
  103. _img_raw.save(bytes_io, "JPEG")
  104. icon = QPixmap()
  105. icon.loadFromData(bytes_io.getvalue())
  106. self.icon = icon
  107. icon = icon.scaled(
  108. self.ui_image.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation
  109. )
  110. self.ui_image.setPixmap(icon)
  111. except:
  112. pass
  113. def get_image_orientation(self, img):
  114. # 获取EXIF数据
  115. exif = img._getexif()
  116. if exif is not None:
  117. # EXIF标签274对应的是Orientation
  118. orientation = exif.get(0x0112)
  119. if orientation == 2:
  120. # 水平翻转
  121. img = img.transpose(Image.FLIP_LEFT_RIGHT)
  122. elif orientation == 3:
  123. # 旋转180度
  124. img = img.rotate(180, expand=True)
  125. elif orientation == 4:
  126. # 垂直翻转
  127. img = img.transpose(Image.FLIP_TOP_BOTTOM)
  128. elif orientation == 5:
  129. # 水平翻转后顺时针旋转90度
  130. img = img.transpose(Image.FLIP_LEFT_RIGHT).transpose(Image.ROTATE_270)
  131. elif orientation == 6:
  132. # 顺时针旋转90度
  133. img = img.transpose(Image.ROTATE_270)
  134. elif orientation == 7:
  135. # 水平翻转后逆时针旋转90度
  136. img = img.transpose(Image.FLIP_LEFT_RIGHT).transpose(Image.ROTATE_90)
  137. elif orientation == 8:
  138. # 逆时针旋转90度
  139. img = img.transpose(Image.ROTATE_90)
  140. else:
  141. pass
  142. return img
  143. def set_selected(self, selected):
  144. self.selected = selected
  145. self.setStyleSheet("background-color: yellow;" if selected else "background-color: white;")
  146. def mouseMoveEvent(self, event):
  147. if not (event.buttons() & Qt.LeftButton) or self.drag_start_position is None:
  148. return
  149. if (event.pos() - self.drag_start_position).manhattanLength() < QApplication.startDragDistance():
  150. return
  151. print("Starting drag...{}".format(self.image_name)) # 调试信息
  152. # 创建拖拽任务
  153. drag = QDrag(self)
  154. mime_data = QMimeData()
  155. # 收集所有选中的控件的数据
  156. data = QByteArray()
  157. stream = QDataStream(data, QIODevice.WriteOnly)
  158. # 写入图片索引
  159. for widget in self.parent.findChildren(ImageLabel):
  160. if widget.selected:
  161. if widget != self:
  162. stream.writeInt32(widget.image_index)
  163. # 设置当前为选中
  164. self.set_selected(True)
  165. stream.writeInt32(self.image_index)
  166. mime_data.setData('application/x-draggable-labels', data)
  167. drag.setMimeData(mime_data)
  168. # 可选:设置一个图标或快照来表示正在拖拽的对象
  169. pixmap = QPixmap(self.size())
  170. self.render(pixmap)
  171. drag.setPixmap(pixmap)
  172. # 设置热点为鼠标点击位置相对窗口的位置
  173. hot_spot = event.position().toPoint()
  174. drag.setHotSpot(hot_spot)
  175. # 开始拖拽操作
  176. result = drag.exec(Qt.MoveAction)
  177. if result == Qt.MoveAction:
  178. self.setParent(None) # 如果成功移动,则从原位置移除
  179. self.hide()
  180. self.drag_start_position = None
  181. print("end drag...{}".format(self.image_name)) # 调试信息
  182. def mouseReleaseEvent(self, event):
  183. super().mouseReleaseEvent(event)
  184. # print("Mouse released.") # 调试信息
  185. self.drag_start_position = None
  186. # 清除所有已选
  187. def clear_all(self):
  188. self.select_clearn_all_sign.emit()
  189. def mousePressEvent(self, event):
  190. if event.button() == Qt.LeftButton:
  191. self.show_big_image()
  192. self.drag_start_position = event.pos()
  193. self.selected_sign.emit() # 发送单击事件给父窗口
  194. if event.modifiers() & Qt.ControlModifier:
  195. # 如果按下了 Ctrl 键,则进行复选
  196. self.set_selected(not self.selected)
  197. else:
  198. self.clear_all()
  199. self.set_selected(not self.selected)
  200. def dragEnterEvent(self, event):
  201. event.acceptProposedAction()
  202. def dragMoveEvent(self, event):
  203. event.acceptProposedAction()
  204. # 粘贴来源的位置,发送信号
  205. def drop_from_event(self, return_data):
  206. self.drop_from_sign.emit(return_data)
  207. def dropEvent(self, event):
  208. mime = event.mimeData()
  209. if mime.hasFormat('application/x-draggable-labels'):
  210. return_data = {"is_same_folder": True,
  211. "from_image_index_list": [],
  212. "from_source": "",
  213. "to_image_index": 0,
  214. "to_source": "",
  215. }
  216. byte_array = mime.data('application/x-draggable-labels')
  217. stream = QDataStream(byte_array, QIODevice.ReadOnly)
  218. while not stream.atEnd():
  219. image_index = stream.readInt32()
  220. return_data["from_image_index_list"].append(image_index)
  221. from_source = event.source()
  222. return_data["from_source"] = from_source.windows
  223. return_data["to_source"] = self.windows
  224. return_data["to_image_index"] = self.image_index
  225. if from_source.windows == self.windows:
  226. return_data["is_same_folder"] = True
  227. print("同文件夹")
  228. else:
  229. return_data["is_same_folder"] = False
  230. print("不同文件夹")
  231. if return_data["is_same_folder"] is False:
  232. # 不同文件夹处理,处理发送到来源文件夹的操作
  233. from_source.drop_from_event(return_data)
  234. else:
  235. # 同文件夹处理,发送粘贴的信号
  236. self.drop_sign.emit(return_data)
  237. def contextMenuEvent(self, event):
  238. # 创建一个QMenu对象
  239. menu = QMenu(self)
  240. # 添加菜单项
  241. delete_action = menu.addAction("删除图片")
  242. # 连接菜单项到槽函数
  243. action = menu.exec(self.mapToGlobal(event.pos()))
  244. if action == delete_action:
  245. self.delete_selected_item()
  246. def delete_selected_item(self):
  247. # 获取当前选中的项并删除它
  248. print("delete_selected_item")
  249. image_index_list = [self.image_index]
  250. # 写入图片索引
  251. for widget in self.parent.findChildren(ImageLabel):
  252. if widget.selected:
  253. if widget != self:
  254. image_index_list.append(widget.image_index)
  255. if image_index_list:
  256. self.delete_image_sign.emit(image_index_list)
  257. def del_image(self):
  258. """
  259. 删除图片
  260. """
  261. parentPath, _ = os.path.split(self.root_path)
  262. cutImagePath = "{}/原始图_已抠图/{}.png".format(parentPath, self.image_name)
  263. f = False
  264. try:
  265. if os.path.exists(self.image_path):
  266. os.remove(self.image_path)
  267. f = True
  268. if os.path.exists(cutImagePath):
  269. os.remove(cutImagePath)
  270. f = True
  271. except FileNotFoundError:
  272. print(f"删除文件失败.")
  273. except Exception as e:
  274. print(f"发生错误: {e}")
  275. if f:
  276. self.hide()
  277. del self