studia/jezyki-skryptowe/image-editor/editor/dialogs/RotationDialog.py
2024-06-18 04:19:20 +02:00

89 lines
3.1 KiB
Python

from PyQt6.QtWidgets import QLabel, QVBoxLayout, QHBoxLayout, QLineEdit, QCheckBox, QSlider
from PyQt6.QtGui import QIntValidator
from PyQt6.QtCore import Qt
import numpy as np
import cv2
from .ImageParameterDialog import ImageParameterDialog
from .. import ImageProcessingWorker
class RotationDialog(ImageParameterDialog):
def __init__(self, image):
super().__init__(image, ImageProcessingWorker.ImageProcessingWorker)
self.setWindowTitle("Rotation")
self.layout = QVBoxLayout()
self.angle_label = QLabel("Angle:")
self.angle_field = QLineEdit()
self.angle_field.setText("0")
self.angle_field.setPlaceholderText("Enter rotation angle")
self.angle_field.setValidator(QIntValidator(-360, 360))
self.angle_field.textEdited.connect(self.angle_text_changed)
self.angle_slider = QSlider(Qt.Orientation.Horizontal)
self.angle_slider.setRange(-360, 360)
self.angle_slider.setTickInterval(90)
self.angle_slider.setTickPosition(QSlider.TickPosition.TicksBelow)
self.angle_slider.valueChanged.connect(self.angle_slider_changed)
self.keep_size_checkbox = QCheckBox("Keep original size")
self.keep_size_checkbox.setChecked(True)
self.keep_size_checkbox.stateChanged.connect(self.update)
input_layout = QHBoxLayout()
input_layout.addWidget(self.angle_label)
input_layout.addWidget(self.angle_field)
self.layout.addLayout(input_layout)
self.layout.addWidget(self.angle_slider)
self.layout.addWidget(self.keep_size_checkbox)
self.layout.addWidget(self.button_box)
self.setLayout(self.layout)
def angle_text_changed(self, text):
if text:
angle = int(text)
self.angle_slider.setValue(angle)
self.update()
def angle_slider_changed(self, value):
self.angle_field.setText(str(value))
self.update()
def update(self):
angle = self.angle_field.text()
if not angle:
self.set_accept_enable(False)
return
self.send_to_process({
'angle': float(angle),
'keep_size': self.keep_size_checkbox.isChecked()
})
def process_image(self, image, values):
angle = values['angle']
keep_size = values['keep_size']
height, width = image.shape[:2]
center = (width // 2, height // 2)
matrix = cv2.getRotationMatrix2D(center, angle, 1.0)
if keep_size:
rotated_image = cv2.warpAffine(image, matrix, (width, height))
else:
cos = np.abs(matrix[0, 0])
sin = np.abs(matrix[0, 1])
new_width = int((height * sin) + (width * cos))
new_height = int((height * cos) + (width * sin))
matrix[0, 2] += (new_width / 2) - center[0]
matrix[1, 2] += (new_height / 2) - center[1]
rotated_image = cv2.warpAffine(image, matrix, (new_width, new_height))
self.set_accept_enable(True)
return rotated_image
@classmethod
def dialog_name(cls):
return "Rotate"