diff --git a/jezyki-skryptowe/image-editor/ImageCanvas.py b/jezyki-skryptowe/image-editor/ImageCanvas.py index e321e1c..7a6cc51 100644 --- a/jezyki-skryptowe/image-editor/ImageCanvas.py +++ b/jezyki-skryptowe/image-editor/ImageCanvas.py @@ -4,7 +4,7 @@ from PyQt6.QtCore import Qt class ImageCanvas(QGraphicsView): _pixmapItem: QGraphicsPixmapItem - + empty = True def __init__(self): super().__init__() @@ -30,6 +30,16 @@ class ImageCanvas(QGraphicsView): def updatePixmap(self, image: QImage): pixmap = QPixmap.fromImage(image) self._pixmapItem.setPixmap(pixmap) + if self.empty: + self.reset() + self.empty = False + + def clear(self): + self.scene.removeItem(self._pixmapItem) + self._pixmapItem = QGraphicsPixmapItem() + self.scene.addItem(self._pixmapItem) + + self.empty = True def reset(self): self.resetTransform() # Reset the zoom level to default diff --git a/jezyki-skryptowe/image-editor/ImageManagePanel.py b/jezyki-skryptowe/image-editor/ImageManagePanel.py new file mode 100644 index 0000000..eaa3fb0 --- /dev/null +++ b/jezyki-skryptowe/image-editor/ImageManagePanel.py @@ -0,0 +1,73 @@ +from PyQt6.QtWidgets import QFileDialog, QWidget, QToolBar, QHBoxLayout, QPushButton +from PyQt6.QtGui import QIcon +from PyQt6.QtCore import pyqtSignal +import numpy as np + +from ImageManager import ImageManager + +class ImageManagePanel(QWidget): + on_update = pyqtSignal(np.ndarray) + on_close = pyqtSignal() + + def __init__(self): + super().__init__() + + self.mgr = ImageManager(self._on_update) + + layout = QHBoxLayout() + self.setLayout(layout) + + self.open_button = QPushButton(QIcon.fromTheme("document-open"), "Open", self) + layout.addWidget(self.open_button) + self.open_button.clicked.connect(self._open_image) + + self.save_button = QPushButton(QIcon("save.png"), "Save", self) + layout.addWidget(self.save_button) + self.save_button.clicked.connect(self._save_image) + + self.close_button = QPushButton(QIcon("close.png"), "Close", self) + layout.addWidget(self.close_button) + self.close_button.clicked.connect(self._close_image) + + self.undo_button = QPushButton(QIcon("undo.png"), "Undo", self) + layout.addWidget(self.undo_button) + self.undo_button.clicked.connect(self._undo) + + self.redo_button = QPushButton(QIcon("redo.png"), "Redo", self) + layout.addWidget(self.redo_button) + self.redo_button.clicked.connect(self._redo) + + self._enable_buttons() + + def _redo(self): + self.mgr.redo() + self._enable_buttons() + + def _undo(self): + self.mgr.undo() + self._enable_buttons() + + def _on_update(self, image): + self.on_update.emit(image) + self._enable_buttons() + + def _enable_buttons(self): + self.undo_button.setEnabled(self.mgr.can_undo()) + self.redo_button.setEnabled(self.mgr.can_redo()) + + + def _close_image(self): + self.mgr.close() + self.on_close.emit() + + def _open_image(self): + file_name, _ = QFileDialog.getOpenFileName(self, "Open Image File", "", "Image Files (*.jpg *.jpeg *.png)") + if file_name: + self.mgr.open(file_name) + + def _save_image(self): + file_name, _ = QFileDialog.getSaveFileName(self, "Save Image File", "", "Image Files (*.jpg *.png)") + if file_name: + self.mgr.save(file_name) + + diff --git a/jezyki-skryptowe/image-editor/ImageManager.py b/jezyki-skryptowe/image-editor/ImageManager.py new file mode 100644 index 0000000..bb8c36b --- /dev/null +++ b/jezyki-skryptowe/image-editor/ImageManager.py @@ -0,0 +1,61 @@ +from collections import deque + +import numpy as np +import cv2 + +class ImageManager(): + + def __init__(self, update_fn): + super().__init__() + self.update_fn = update_fn + self.close() + + def undo(self): + if len(self._undo_deque) == 0: + return + prev = self._undo_deque.pop() + self._redo_deque.append(self._curr_image) + self._curr_image = prev + self.update_fn(self._curr_image) + + def redo(self): + if len(self._redo_deque) == 0: + return + latter = self._redo_deque.pop() + self._undo_deque.append(self._curr_image) + self._curr_image = latter + self.update_fn(self._curr_image) + + def update(self, new_image): + self._undo_deque.append(self._curr_image) + self._redo_deque = deque() + self._curr_image = new_image.copy() + self.update_fn(self._curr_image) + + def open(self, file_name): + self.close() + self._curr_image = cv2.imread(file_name) + self._curr_image = cv2.cvtColor(self._curr_image, cv2.COLOR_BGR2RGB) + self.update_fn(self._curr_image) + + + def close(self): + self._undo_deque = deque() + self._redo_deque = deque() + self._curr_image = None + + def save(self, file_name): + if self._curr_image is not None: + cv2.imwrite(file_name, cv2.cvtColor(self._curr_image, cv2.COLOR_RGB2BGR)) + + def refresh(self): + self.update_fn(self._curr_image) + + def image(self): + return self._curr_image + + def can_redo(self): + return len(self._redo_deque) > 0 + + def can_undo(self): + return len(self._undo_deque) > 0 \ No newline at end of file