import json import os.path from import_qt_mode import * from UI.manual_image_matching.image_items import Ui_Form as Ui_Image_Items from PIL import Image import rawpy, io class ImageLabel(QLabel, Ui_Image_Items): drop_sign = Signal(dict) # 粘贴的位置 drop_from_sign = Signal(dict) # 粘贴来源的位置 select_clearn_all_sign = Signal() selected_sign = Signal() # 有选中 delete_image_sign = Signal(list) # 删除通知 def __init__(self, text, image_index, image_path, image_name, root_path, is_goods_list, parent=None, windows=None, top_windows=None): super().__init__(parent) self.setupUi(self) # self.setFixedSize(150, 160) # self.ui_image.setFixedSize(150, 150) self.windows = windows self.top_windows = top_windows self.parent = parent self.text = image_name self.image_index = image_index self.image_path = image_path self.image_name = image_name self.root_path = root_path self.ui_text.setText(self.text) # 是图片列表还是普通列表 self.is_goods_list = is_goods_list self.icon = None self.set_label_image() self.setMouseTracking(True) self.drag_start_position = None self.selected = False self.setAcceptDrops(True) def set_image_label_windows(self,windows): self.windows = windows def show_text(self): self.ui_text.setText(self.text) def crop_to_square(self, img): # 打开图片 width, height = img.size # 获取原始图片的宽度和高度 if width == height: return img if width > height: _x = int((width - height) / 2) img = img.crop((_x, 0, width - _x, height)) else: _y = int((height - width) / 2) img = img.crop((0, _y, width, height - _y)) return img def set_new_parent(self, parent): self.parent = parent self.setParent(parent) def show_big_image(self): if self.top_windows is not None: if self.icon: self.top_windows.show_big_image(self.icon) def set_label_image2(self): try: w, h = self.ui_image.width() * 2, self.ui_image.height() * 2 if "CR2" == self.image_path[-3:]: _img_raw = Image.open(self.image_path) else: if "jpg" == self.image_path[-3:] or "png" == self.image_path[-3:]: _img_raw = Image.open(self.image_path) else: with rawpy.imread(self.image_path) as raw: raw_image = raw.postprocess() _img_raw = Image.fromarray(raw_image) size = (w, int(_img_raw.height * w / _img_raw.width)) _img_raw = _img_raw.resize(size) _img_raw = _img_raw.convert("RGB") bytes_io = io.BytesIO() _img_raw.save(bytes_io, "JPEG") icon = QPixmap() icon.loadFromData(bytes_io.getvalue()) self.icon = icon icon = icon.scaled( self.ui_image.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation ) self.ui_image.setPixmap(icon) except: pass def set_label_image(self): try: w, h = self.ui_image.width() * 2, self.ui_image.height() * 2 if "CR2" == self.image_path[-3:]: _img_raw = Image.open(self.image_path) else: if "jpg" == self.image_path[-3:] or "png" == self.image_path[-3:]: _img_raw = Image.open(self.image_path) else: with rawpy.imread(self.image_path) as raw: raw_image = raw.postprocess() _img_raw = Image.fromarray(raw_image) # 取缩略图 _img_raw.thumbnail((w, int(_img_raw.height * w / _img_raw.width))) size = (w, int(_img_raw.height * w / _img_raw.width)) _img_raw = _img_raw.resize(size) _img_raw = _img_raw.convert("RGB") bytes_io = io.BytesIO() _img_raw.save(bytes_io, "JPEG") icon = QPixmap() icon.loadFromData(bytes_io.getvalue()) self.icon = icon icon = icon.scaled( self.ui_image.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation ) self.ui_image.setPixmap(icon) except: pass def get_image_orientation(self, img): # 获取EXIF数据 exif = img._getexif() if exif is not None: # EXIF标签274对应的是Orientation orientation = exif.get(0x0112) if orientation == 2: # 水平翻转 img = img.transpose(Image.FLIP_LEFT_RIGHT) elif orientation == 3: # 旋转180度 img = img.rotate(180, expand=True) elif orientation == 4: # 垂直翻转 img = img.transpose(Image.FLIP_TOP_BOTTOM) elif orientation == 5: # 水平翻转后顺时针旋转90度 img = img.transpose(Image.FLIP_LEFT_RIGHT).transpose(Image.ROTATE_270) elif orientation == 6: # 顺时针旋转90度 img = img.transpose(Image.ROTATE_270) elif orientation == 7: # 水平翻转后逆时针旋转90度 img = img.transpose(Image.FLIP_LEFT_RIGHT).transpose(Image.ROTATE_90) elif orientation == 8: # 逆时针旋转90度 img = img.transpose(Image.ROTATE_90) else: pass return img def set_selected(self, selected): self.selected = selected self.setStyleSheet("background-color: yellow;" if selected else "background-color: white;") def mouseMoveEvent(self, event): if not (event.buttons() & Qt.LeftButton) or self.drag_start_position is None: return if (event.pos() - self.drag_start_position).manhattanLength() < QApplication.startDragDistance(): return print("Starting drag...{}".format(self.image_name)) # 调试信息 # 创建拖拽任务 drag = QDrag(self) mime_data = QMimeData() # 收集所有选中的控件的数据 data = QByteArray() stream = QDataStream(data, QIODevice.WriteOnly) # 写入图片索引 for widget in self.parent.findChildren(ImageLabel): if widget.selected: if widget != self: stream.writeInt32(widget.image_index) # 设置当前为选中 self.set_selected(True) stream.writeInt32(self.image_index) mime_data.setData('application/x-draggable-labels', data) drag.setMimeData(mime_data) # 可选:设置一个图标或快照来表示正在拖拽的对象 pixmap = QPixmap(self.size()) self.render(pixmap) drag.setPixmap(pixmap) # 设置热点为鼠标点击位置相对窗口的位置 hot_spot = event.position().toPoint() drag.setHotSpot(hot_spot) # 开始拖拽操作 result = drag.exec(Qt.MoveAction) if result == Qt.MoveAction: self.setParent(None) # 如果成功移动,则从原位置移除 self.hide() self.drag_start_position = None print("end drag...{}".format(self.image_name)) # 调试信息 def mouseReleaseEvent(self, event): super().mouseReleaseEvent(event) # print("Mouse released.") # 调试信息 self.drag_start_position = None # 清除所有已选 def clear_all(self): self.select_clearn_all_sign.emit() def mousePressEvent(self, event): if event.button() == Qt.LeftButton: self.show_big_image() self.drag_start_position = event.pos() self.selected_sign.emit() # 发送单击事件给父窗口 if event.modifiers() & Qt.ControlModifier: # 如果按下了 Ctrl 键,则进行复选 self.set_selected(not self.selected) else: self.clear_all() self.set_selected(not self.selected) def dragEnterEvent(self, event): event.acceptProposedAction() def dragMoveEvent(self, event): event.acceptProposedAction() # 粘贴来源的位置,发送信号 def drop_from_event(self, return_data): self.drop_from_sign.emit(return_data) def dropEvent(self, event): mime = event.mimeData() if mime.hasFormat('application/x-draggable-labels'): return_data = {"is_same_folder": True, "from_image_index_list": [], "from_source": "", "to_image_index": 0, "to_source": "", } byte_array = mime.data('application/x-draggable-labels') stream = QDataStream(byte_array, QIODevice.ReadOnly) while not stream.atEnd(): image_index = stream.readInt32() return_data["from_image_index_list"].append(image_index) from_source = event.source() return_data["from_source"] = from_source.windows return_data["to_source"] = self.windows return_data["to_image_index"] = self.image_index if from_source.windows == self.windows: return_data["is_same_folder"] = True print("同文件夹") else: return_data["is_same_folder"] = False print("不同文件夹") if return_data["is_same_folder"] is False: # 不同文件夹处理,处理发送到来源文件夹的操作 from_source.drop_from_event(return_data) else: # 同文件夹处理,发送粘贴的信号 self.drop_sign.emit(return_data) def contextMenuEvent(self, event): # 创建一个QMenu对象 menu = QMenu(self) # 添加菜单项 delete_action = menu.addAction("删除图片") # 连接菜单项到槽函数 action = menu.exec(self.mapToGlobal(event.pos())) if action == delete_action: self.delete_selected_item() def delete_selected_item(self): # 获取当前选中的项并删除它 print("delete_selected_item") image_index_list = [self.image_index] # 写入图片索引 for widget in self.parent.findChildren(ImageLabel): if widget.selected: if widget != self: image_index_list.append(widget.image_index) if image_index_list: self.delete_image_sign.emit(image_index_list) def del_image(self): """ 删除图片 """ parentPath, _ = os.path.split(self.root_path) cutImagePath = "{}/原始图_已抠图/{}.png".format(parentPath, self.image_name) f = False try: if os.path.exists(self.image_path): os.remove(self.image_path) f = True if os.path.exists(cutImagePath): os.remove(cutImagePath) f = True except FileNotFoundError: print(f"删除文件失败.") except Exception as e: print(f"发生错误: {e}") if f: self.hide() del self