A rectangular highlighter app with python

PYTHON


import sys
from PyQt6.QtWidgets import (QApplication, QMainWindow, QFileDialog, QLabel,
QPushButton, QVBoxLayout, QWidget, QScrollArea,
QColorDialog, QInputDialog, QHBoxLayout)
from PyQt6.QtGui import QPixmap, QPainter, QPen, QColor, QIcon
from PyQt6.QtCore import Qt, QPoint, QSize
import os

class ColorIndicator(QWidget):
def __init__(self, color, parent=None):
super().__init__(parent)
self.color = color
self.setFixedSize(20, 20)

def paintEvent(self, event):
painter = QPainter(self)
painter.setBrush(self.color)
painter.drawRect(0, 0, self.width(), self.height())

def setColor(self, color):
self.color = color
self.update()

class ImageEditor(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Image Boundary Editor")
self.setGeometry(100, 100, 600, 400)

# 기본 변수 초기화
self.image_path = ""
self.drag_start = None
self.drag_end = None
self.original_pixmap = None
self.modified_pixmap = None
self.temp_pixmap = None
self.is_drag_mode = False
self.boundary_color = QColor(255, 0, 0)
self.boundary_thickness = 2

# UI 설정
self.central_widget = QWidget()
self.setCentralWidget(self.central_widget)
self.main_layout = QHBoxLayout(self.central_widget)

# 왼쪽: 이미지 영역
self.scroll_area = QScrollArea()
self.scroll_area.setWidgetResizable(True)
self.image_label = QLabel()
self.image_label.setAlignment(Qt.AlignmentFlag.AlignTop | Qt.AlignmentFlag.AlignLeft)
self.scroll_area.setWidget(self.image_label)
self.main_layout.addWidget(self.scroll_area, stretch=1)

# 오른쪽: 버튼 영역
self.button_layout = QVBoxLayout()
self.button_layout.addStretch(1)

self.load_button = QPushButton("이미지 불러오기")
self.load_button.clicked.connect(self.load_image)
self.button_layout.addWidget(self.load_button)

self.drag_button = QPushButton("드래그로 영역 강조")
self.drag_button.clicked.connect(self.toggle_drag_mode)
self.drag_button.setEnabled(False)
self.button_layout.addWidget(self.drag_button)

self.color_layout = QHBoxLayout()
self.color_button = QPushButton("경계 색상 선택")
self.color_button.clicked.connect(self.choose_color)
self.color_button.setEnabled(False)
self.color_indicator = ColorIndicator(self.boundary_color)
self.color_layout.addWidget(self.color_button)
self.color_layout.addWidget(self.color_indicator)
self.button_layout.addLayout(self.color_layout)

self.thickness_layout = QHBoxLayout()
self.thickness_button = QPushButton("경계 두께 선택")
self.thickness_button.clicked.connect(self.choose_thickness)
self.thickness_button.setEnabled(False)
self.thickness_label = QLabel(f"{self.boundary_thickness}px")
self.thickness_layout.addWidget(self.thickness_button)
self.thickness_layout.addWidget(self.thickness_label)
self.button_layout.addLayout(self.thickness_layout)

self.save_button = QPushButton("이미지 저장")
self.save_button.clicked.connect(self.save_image)
self.save_button.setEnabled(False)
self.button_layout.addWidget(self.save_button)

self.button_layout.addStretch(1)
self.main_layout.addLayout(self.button_layout)

# 마우스 이벤트 활성화
self.image_label.setMouseTracking(True)
self.image_label.installEventFilter(self)

def load_image(self):
file_name, _ = QFileDialog.getOpenFileName(
self, "이미지 선택", "", "Image Files (*.png *.jpg *.jpeg *.bmp)")
if file_name:
self.image_path = file_name
self.original_pixmap = QPixmap(file_name)
self.modified_pixmap = self.original_pixmap.copy()
self.temp_pixmap = self.original_pixmap.copy()
self.image_label.setPixmap(self.original_pixmap)
self.image_label.adjustSize()
self.drag_button.setEnabled(True)
self.color_button.setEnabled(True)
self.thickness_button.setEnabled(True)
self.save_button.setEnabled(False)
self.is_drag_mode = False
self.drag_button.setText("드래그로 영역 강조")

def toggle_drag_mode(self):
self.is_drag_mode = not self.is_drag_mode
self.drag_button.setText("드래그 모드 끄기" if self.is_drag_mode else "드래그로 영역 강조")
if not self.is_drag_mode:
self.image_label.setPixmap(self.modified_pixmap)
self.drag_start = None
self.drag_end = None

def choose_color(self):
color = QColorDialog.getColor(self.boundary_color, self, "경계 색상 선택")
if color.isValid():
self.boundary_color = color
self.color_indicator.setColor(color)
self.statusBar().showMessage(f"선택된 색상: {self.boundary_color.name()}", 5000)

def choose_thickness(self):
thickness, ok = QInputDialog.getInt(
self, "경계 두께 선택", "두께 (1-20px):",
self.boundary_thickness, 1, 20, 1)
if ok:
self.boundary_thickness = thickness
self.thickness_label.setText(f"{self.boundary_thickness}px")
self.statusBar().showMessage(f"선택된 두께: {self.boundary_thickness}px", 5000)

def eventFilter(self, source, event):
if source == self.image_label and self.original_pixmap and self.is_drag_mode:
if event.type() == event.Type.MouseButtonPress and event.button() == Qt.MouseButton.LeftButton:
self.drag_start = event.pos()
return True
elif event.type() == event.Type.MouseMove and self.drag_start:
self.drag_end = event.pos()
self.preview_boundary()
return True
elif event.type() == event.Type.MouseButtonRelease and event.button() == Qt.MouseButton.LeftButton:
self.drag_end = event.pos()
self.draw_boundary()
return True
return super().eventFilter(source, event)

def preview_boundary(self):
if not self.drag_start or not self.drag_end:
return

self.temp_pixmap = self.modified_pixmap.copy()
painter = QPainter(self.temp_pixmap)
preview_color = QColor(self.boundary_color)
preview_color.setAlpha(100)
pen = QPen(preview_color, self.boundary_thickness, Qt.PenStyle.DashLine)
painter.setPen(pen)

x1 = min(self.drag_start.x(), self.drag_end.x())
y1 = min(self.drag_start.y(), self.drag_end.y())
x2 = max(self.drag_start.x(), self.drag_end.x())
y2 = max(self.drag_start.y(), self.drag_end.y())

x1 = max(0, min(x1, self.original_pixmap.width()))
y1 = max(0, min(y1, self.original_pixmap.height()))
x2 = max(0, min(x2, self.original_pixmap.width()))
y2 = max(0, min(y2, self.original_pixmap.height()))

painter.drawRect(x1, y1, x2 - x1, y2 - y1)
painter.end()

self.image_label.setPixmap(self.temp_pixmap)

def draw_boundary(self):
if not self.drag_start or not self.drag_end:
return

self.modified_pixmap = self.modified_pixmap.copy()
painter = QPainter(self.modified_pixmap)
pen = QPen(self.boundary_color, self.boundary_thickness, Qt.PenStyle.SolidLine)
painter.setPen(pen)

x1 = min(self.drag_start.x(), self.drag_end.x())
y1 = min(self.drag_start.y(), self.drag_end.y())
x2 = max(self.drag_start.x(), self.drag_end.x())
y2 = max(self.drag_start.y(), self.drag_end.y())

x1 = max(0, min(x1, self.original_pixmap.width()))
y1 = max(0, min(y1, self.original_pixmap.height()))
x2 = max(0, min(x2, self.original_pixmap.width()))
y2 = max(0, min(y2, self.original_pixmap.height()))

painter.drawRect(x1, y1, x2 - x1, y2 - y1)
painter.end()

self.image_label.setPixmap(self.modified_pixmap)
self.save_button.setEnabled(True)
self.drag_start = None
self.drag_end = None

def save_image(self):
if not self.modified_pixmap:
return

save_dir = QFileDialog.getExistingDirectory(self, "저장 폴더 선택")
if save_dir:
file_name = os.path.splitext(os.path.basename(self.image_path))[0]
save_path = os.path.join(save_dir, f"{file_name}_modified.png")
self.modified_pixmap.save(save_path, "PNG")
self.statusBar().showMessage(f"이미지가 저장되었습니다: {save_path}", 5000)

def resizeEvent(self, event):
if self.original_pixmap:
self.image_label.adjustSize()
super().resizeEvent(event)

if __name__ == '__main__':
app = QApplication(sys.argv)
# 앱 아이콘 설정 (아이콘 파일이 필요하면 추가)
# app.setWindowIcon(QIcon('icon.png'))
window = ImageEditor()
window.show()
sys.exit(app.exec())


@ Terminal, Run below code
bin/zsh>   pyinstaller --onefile --windowed image_editor.py



#python #pythonApp #highliter #productivity #app #DIY 




댓글 쓰기

다음 이전