-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathimageView.py
185 lines (143 loc) · 6.54 KB
/
imageView.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
from PyQt5.QtCore import Qt, QRectF, QPointF, pyqtSignal
from PyQt5.QtGui import QPixmap, QPen
from PyQt5.QtWidgets import QGraphicsScene, QGraphicsView, QGraphicsItem, QGraphicsLineItem, QGraphicsEllipseItem, \
QMessageBox
class HandleItem(QGraphicsEllipseItem):
def __init__(self, parent=None):
super().__init__(-10, -10, 20, 20, parent)
self.setBrush(Qt.red)
def mousePressEvent(self, event):
self.setSelected(True)
super().mousePressEvent(event)
class DraggableLineItem(QGraphicsLineItem):
def __init__(self, x, y, width, height):
super().__init__(x, y, width, height)
self.handle = HandleItem(self)
self.__initUi()
self.updateHandlePosition()
def updateHandlePosition(self):
line = self.line()
center_x = (line.x1() + line.x2()) / 2
center_y = (line.y1() + line.y2()) / 2
self.handle.setPos(center_x, center_y)
def __initUi(self):
self.setFlags(QGraphicsItem.ItemIsMovable)
self.setPen(QPen(Qt.black, 10, Qt.DashDotLine))
def updateHeight(self, new_height):
self.setLine(self.line().x1(), 0, self.line().x2(), new_height)
self.updateHandlePosition()
def mouseMoveEvent(self, event):
super().mouseMoveEvent(event)
self.updateHandlePosition()
cur_x = self.scene().itemsBoundingRect().x()
new_x = self.x()
if new_x > self.scene().sceneRect().width():
new_x = self.scene().sceneRect().width()
self.setPos(new_x, 0)
elif cur_x < 0:
new_x = 0
self.setPos(new_x, 0)
else:
self.setPos(new_x, 0)
from PyQt5.QtWidgets import QGraphicsPixmapItem
from PyQt5.QtGui import QPainterPath
class ClippablePixmapItem(QGraphicsPixmapItem):
def __init__(self, pixmap, line_item, side, parent=None):
super().__init__(pixmap, parent)
self.line_item = line_item
self.side = side # 'left' or 'right'
def updateLine(self, line_item):
self.line_item = line_item
def paint(self, painter, option, widget):
# Create a path that represents the visible area of this pixmap
clip_path = QPainterPath()
line_x = self.line_item.x()
scene_rect = self.scene().sceneRect()
if self.side == 'left':
clip_rect = QRectF(scene_rect.topLeft(), QPointF(line_x, scene_rect.bottom()))
clip_path.addRect(clip_rect)
elif self.side == 'right':
clip_rect = QRectF(QPointF(line_x, scene_rect.top()), scene_rect.bottomRight())
clip_path.addRect(clip_rect)
painter.setClipPath(clip_path)
super().paint(painter, option, widget)
class SplittedImageView(QGraphicsView):
def __init__(self, parent=None):
super().__init__(parent)
self.__aspectRatioMode = Qt.KeepAspectRatio
self.__initVal()
self.__initUi()
def __initVal(self):
self.__scene = QGraphicsScene(self)
self.__p_left = QPixmap()
self.__p_right = QPixmap()
self.__item_left = ''
self.__item_right = ''
self.__line = None
self.__min_width = 300
self.__min_height = 300
def __initUi(self):
self.setMinimumSize(self.__min_width, self.__min_height)
self.__scene.setSceneRect(0, 0, self.__min_width, self.__min_height)
self.__line = DraggableLineItem(0, 0, 0, self.height())
self.__line.setZValue(1)
self.__scene.addItem(self.__line)
self.setScene(self.__scene)
self.setViewportUpdateMode(QGraphicsView.FullViewportUpdate)
self.__line.setX(self.sceneRect().width() // 2)
def __refresh_scene_size(self):
new_scene_width = min(self.__p_left.width(), self.__p_right.width()) if self.__p_right.width() != 0 else self.__p_left.width()
new_scene_height = min(self.__p_left.height(), self.__p_right.height()) if self.__p_right.height() != 0 else self.__p_left.height()
self.__scene.setSceneRect(0, 0, new_scene_width, new_scene_height)
def __refresh_line(self):
if self.__line:
if self.__line.x() > self.__scene.width():
self.__line.setX(0)
self.__line.setLine(self.__line.line().x1(), 0, self.__line.line().x2(), self.__scene.height())
self.__line.updateHandlePosition()
def setFilenameToLeft(self, filename):
pixmap = QPixmap(filename)
if pixmap.width() < self.__min_width or pixmap.height() < self.__min_height:
QMessageBox.information(self, 'Notification', f'Image is too small. Must be at least {self.__min_width}x{self.__min_height}.')
return
if self.__item_left:
self.__scene.removeItem(self.__item_left)
self.__p_left = pixmap
self.__item_left = ClippablePixmapItem(self.__p_left, self.__line, 'left')
self.__scene.addItem(self.__item_left)
self.__item_left.setTransformationMode(Qt.SmoothTransformation)
self.__item_left.setPos(0, 0)
self.__refresh_scene_size()
self.__refresh_line()
self.setScene(self.__scene)
self.fitInView(self.__scene.sceneRect(), self.__aspectRatioMode)
def setFilenameToRight(self, filename):
pixmap = QPixmap(filename)
if pixmap.width() < self.__min_width or pixmap.height() < self.__min_height:
QMessageBox.information(self, 'Notification', f'Image is too small. Must be at least {self.__min_width}x{self.__min_height}.')
return
if self.__item_right:
self.__scene.removeItem(self.__item_right)
self.__p_right = pixmap
self.__item_right = ClippablePixmapItem(self.__p_right, self.__line, 'right')
self.__scene.addItem(self.__item_right)
self.__item_right.setTransformationMode(Qt.SmoothTransformation)
self.__item_right.setPos(0, 0)
self.__refresh_scene_size()
self.__refresh_line()
self.setScene(self.__scene)
self.fitInView(self.__scene.sceneRect(), self.__aspectRatioMode)
def removeItemOnTheLeft(self):
if self.__item_left:
self.__scene.removeItem(self.__item_left)
self.__item_left = ''
def removeItemOnTheRight(self):
if self.__item_right:
self.__scene.removeItem(self.__item_right)
self.__item_right = ''
def setAspectRatioMode(self, mode):
self.__aspectRatioMode = mode
def resizeEvent(self, e):
super().resizeEvent(e)
if self.__line or self.__item_left or self.__item_right:
self.fitInView(self.sceneRect(), self.__aspectRatioMode)