shinestacker 1.5.1__py3-none-any.whl → 1.5.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of shinestacker might be problematic. Click here for more details.
- shinestacker/_version.py +1 -1
- shinestacker/retouch/base_filter.py +59 -35
- shinestacker/retouch/denoise_filter.py +4 -3
- shinestacker/retouch/display_manager.py +14 -19
- shinestacker/retouch/filter_manager.py +11 -3
- shinestacker/retouch/image_editor_ui.py +32 -73
- shinestacker/retouch/image_viewer.py +31 -25
- shinestacker/retouch/overlaid_view.py +15 -6
- shinestacker/retouch/sidebyside_view.py +22 -6
- shinestacker/retouch/unsharp_mask_filter.py +5 -4
- shinestacker/retouch/view_strategy.py +78 -70
- shinestacker/retouch/vignetting_filter.py +4 -3
- shinestacker/retouch/white_balance_filter.py +62 -17
- {shinestacker-1.5.1.dist-info → shinestacker-1.5.2.dist-info}/METADATA +1 -1
- {shinestacker-1.5.1.dist-info → shinestacker-1.5.2.dist-info}/RECORD +19 -19
- {shinestacker-1.5.1.dist-info → shinestacker-1.5.2.dist-info}/WHEEL +0 -0
- {shinestacker-1.5.1.dist-info → shinestacker-1.5.2.dist-info}/entry_points.txt +0 -0
- {shinestacker-1.5.1.dist-info → shinestacker-1.5.2.dist-info}/licenses/LICENSE +0 -0
- {shinestacker-1.5.1.dist-info → shinestacker-1.5.2.dist-info}/top_level.txt +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# pylint: disable=C0114, C0115, C0116, E0611, E1101, R0904, R0912, R0914, R0902
|
|
1
|
+
# pylint: disable=C0114, C0115, C0116, E0611, E1101, R0904, R0912, R0914, R0902, E0202
|
|
2
2
|
from PySide6.QtCore import Qt, QPointF, QEvent, QRectF
|
|
3
3
|
from .. config.gui_constants import gui_constants
|
|
4
4
|
from .view_strategy import ViewStrategy, ImageGraphicsViewBase, ViewSignals
|
|
@@ -107,6 +107,16 @@ class OverlaidView(ViewStrategy, ImageGraphicsViewBase, ViewSignals):
|
|
|
107
107
|
if self.brush_cursor:
|
|
108
108
|
self.brush_cursor.show()
|
|
109
109
|
super().enterEvent(event)
|
|
110
|
+
|
|
111
|
+
def get_mouse_callbacks(self):
|
|
112
|
+
return self.mousePressEvent
|
|
113
|
+
|
|
114
|
+
def set_mouse_callbacks(self, callbacks):
|
|
115
|
+
self.mousePressEvent = callbacks
|
|
116
|
+
|
|
117
|
+
def show(self):
|
|
118
|
+
self.show_master()
|
|
119
|
+
super().show()
|
|
110
120
|
# pylint: enable=C0103
|
|
111
121
|
|
|
112
122
|
def event(self, event):
|
|
@@ -147,7 +157,7 @@ class OverlaidView(ViewStrategy, ImageGraphicsViewBase, ViewSignals):
|
|
|
147
157
|
def show_master(self):
|
|
148
158
|
self.pixmap_item_master.setVisible(True)
|
|
149
159
|
self.pixmap_item_current.setVisible(False)
|
|
150
|
-
self.
|
|
160
|
+
self.show_brush_preview()
|
|
151
161
|
if self.brush_cursor:
|
|
152
162
|
self.scene.removeItem(self.brush_cursor)
|
|
153
163
|
self.brush_cursor = self.create_circle(self.scene)
|
|
@@ -156,7 +166,7 @@ class OverlaidView(ViewStrategy, ImageGraphicsViewBase, ViewSignals):
|
|
|
156
166
|
def show_current(self):
|
|
157
167
|
self.pixmap_item_master.setVisible(False)
|
|
158
168
|
self.pixmap_item_current.setVisible(True)
|
|
159
|
-
self.
|
|
169
|
+
self.hide_brush_preview()
|
|
160
170
|
if self.brush_cursor:
|
|
161
171
|
self.scene.removeItem(self.brush_cursor)
|
|
162
172
|
self.brush_cursor = self.create_alt_circle(self.scene)
|
|
@@ -211,8 +221,7 @@ class OverlaidView(ViewStrategy, ImageGraphicsViewBase, ViewSignals):
|
|
|
211
221
|
handled = True
|
|
212
222
|
if handled:
|
|
213
223
|
event.accept()
|
|
214
|
-
|
|
215
|
-
return False
|
|
224
|
+
return handled
|
|
216
225
|
|
|
217
226
|
def handle_pan_gesture(self, pan_gesture):
|
|
218
227
|
if pan_gesture.state() == Qt.GestureStarted:
|
|
@@ -221,7 +230,7 @@ class OverlaidView(ViewStrategy, ImageGraphicsViewBase, ViewSignals):
|
|
|
221
230
|
elif pan_gesture.state() == Qt.GestureUpdated:
|
|
222
231
|
delta = pan_gesture.delta() - self.last_scroll_pos
|
|
223
232
|
self.last_scroll_pos = pan_gesture.delta()
|
|
224
|
-
scaled_delta = delta
|
|
233
|
+
scaled_delta = delta / self.get_current_scale()
|
|
225
234
|
self.scroll_view(self, int(scaled_delta.x()), int(scaled_delta.y()))
|
|
226
235
|
elif pan_gesture.state() == Qt.GestureFinished:
|
|
227
236
|
self.gesture_active = False
|
|
@@ -146,6 +146,14 @@ class DoubleViewBase(ViewStrategy, QWidget, ViewSignals):
|
|
|
146
146
|
self.pixmap_item_current: self.current_view
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
+
def hide_brush_cursor(self):
|
|
150
|
+
super().hide_brush_cursor()
|
|
151
|
+
self.current_brush_cursor.hide()
|
|
152
|
+
|
|
153
|
+
def show_brush_cursor(self):
|
|
154
|
+
super().show_brush_cursor()
|
|
155
|
+
self.current_brush_cursor.show()
|
|
156
|
+
|
|
149
157
|
# pylint: disable=C0103
|
|
150
158
|
def focusInEvent(self, event):
|
|
151
159
|
super().focusInEvent(event)
|
|
@@ -193,8 +201,7 @@ class DoubleViewBase(ViewStrategy, QWidget, ViewSignals):
|
|
|
193
201
|
else:
|
|
194
202
|
if self.brush_cursor is None or self.current_brush_cursor is None:
|
|
195
203
|
self.setup_brush_cursor()
|
|
196
|
-
self.
|
|
197
|
-
self.current_brush_cursor.hide()
|
|
204
|
+
self.hide_brush_cursor()
|
|
198
205
|
self.master_view.setCursor(Qt.ArrowCursor)
|
|
199
206
|
self.current_view.setCursor(Qt.ArrowCursor)
|
|
200
207
|
super().leaveEvent(event)
|
|
@@ -208,6 +215,16 @@ class DoubleViewBase(ViewStrategy, QWidget, ViewSignals):
|
|
|
208
215
|
super().keyReleaseEvent(event)
|
|
209
216
|
if event.key() == Qt.Key_Space:
|
|
210
217
|
self.update_brush_cursor()
|
|
218
|
+
|
|
219
|
+
def get_mouse_callbacks(self):
|
|
220
|
+
return self.master_view.mousePressEvent, self.current_view.mousePressEvent
|
|
221
|
+
|
|
222
|
+
def set_mouse_callbacks(self, callbacks):
|
|
223
|
+
if isinstance(callbacks, tuple):
|
|
224
|
+
self.master_view.mousePressEvent, self.current_view.mousePressEvent = callbacks
|
|
225
|
+
else:
|
|
226
|
+
self.master_view.mousePressEvent = callbacks
|
|
227
|
+
self.current_view.mousePressEvent = callbacks
|
|
211
228
|
# pylint: enable=C0103
|
|
212
229
|
|
|
213
230
|
# pylint: enable=R0801
|
|
@@ -272,8 +289,7 @@ class DoubleViewBase(ViewStrategy, QWidget, ViewSignals):
|
|
|
272
289
|
cursor_style = Qt.OpenHandCursor if not self.scrolling else Qt.ClosedHandCursor
|
|
273
290
|
self.master_view.setCursor(cursor_style)
|
|
274
291
|
self.current_view.setCursor(cursor_style)
|
|
275
|
-
self.
|
|
276
|
-
self.current_brush_cursor.hide()
|
|
292
|
+
self.hide_brush_cursor()
|
|
277
293
|
return
|
|
278
294
|
self.master_view.setCursor(Qt.BlankCursor)
|
|
279
295
|
self.current_view.setCursor(Qt.BlankCursor)
|
|
@@ -285,11 +301,11 @@ class DoubleViewBase(ViewStrategy, QWidget, ViewSignals):
|
|
|
285
301
|
self.current_brush_cursor.hide()
|
|
286
302
|
if master_has_mouse:
|
|
287
303
|
if self.cursor_style == 'preview':
|
|
288
|
-
self.
|
|
304
|
+
self.show_brush_preview()
|
|
289
305
|
super().update_brush_cursor()
|
|
290
306
|
self.sync_current_cursor_with_master()
|
|
291
307
|
elif current_has_mouse:
|
|
292
|
-
self.
|
|
308
|
+
self.hide_brush_preview()
|
|
293
309
|
scene_pos = self.current_view.mapToScene(mouse_pos_current)
|
|
294
310
|
size = self.brush.size
|
|
295
311
|
radius = size / 2
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# pylint: disable=C0114, C0115, C0116, E0611, W0221, R0902, R0914
|
|
1
|
+
# pylint: disable=C0114, C0115, C0116, E0611, W0221, R0902, R0914, R0913, R0917
|
|
2
2
|
from PySide6.QtWidgets import QHBoxLayout, QLabel, QSlider, QDialogButtonBox
|
|
3
3
|
from PySide6.QtCore import Qt, QTimer
|
|
4
4
|
from .. algorithms.sharpen import unsharp_mask
|
|
@@ -6,8 +6,9 @@ from .base_filter import BaseFilter
|
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
class UnsharpMaskFilter(BaseFilter):
|
|
9
|
-
def __init__(self, name,
|
|
10
|
-
super().__init__(name,
|
|
9
|
+
def __init__(self, name, parent, image_viewer, layer_collection, undo_manager):
|
|
10
|
+
super().__init__(name, parent, image_viewer, layer_collection, undo_manager,
|
|
11
|
+
preview_at_startup=True)
|
|
11
12
|
self.max_range = 500.0
|
|
12
13
|
self.max_radius = 4.0
|
|
13
14
|
self.max_amount = 3.0
|
|
@@ -62,7 +63,7 @@ class UnsharpMaskFilter(BaseFilter):
|
|
|
62
63
|
self.threshold_slider.valueChanged.connect(
|
|
63
64
|
lambda v: update_value("Threshold", v, self.max_threshold, params["Threshold"][2]))
|
|
64
65
|
self.preview_timer.timeout.connect(do_preview)
|
|
65
|
-
self.
|
|
66
|
+
self.connect_preview_toggle(self.preview_check, do_preview, restore_original)
|
|
66
67
|
self.button_box.accepted.connect(dlg.accept)
|
|
67
68
|
self.button_box.rejected.connect(dlg.reject)
|
|
68
69
|
QTimer.singleShot(0, do_preview)
|
|
@@ -100,14 +100,11 @@ class ImageGraphicsViewBase(QGraphicsView):
|
|
|
100
100
|
class ViewStrategy(LayerCollectionHandler):
|
|
101
101
|
def __init__(self, layer_collection, status):
|
|
102
102
|
LayerCollectionHandler.__init__(self, layer_collection)
|
|
103
|
-
self.display_manager = None
|
|
104
103
|
self.status = status
|
|
105
104
|
self.brush = None
|
|
106
105
|
self.brush_cursor = None
|
|
107
|
-
self.display_manager = None
|
|
108
106
|
self.brush_preview = BrushPreviewItem(layer_collection)
|
|
109
107
|
self.cursor_style = gui_constants.DEFAULT_CURSOR_STYLE
|
|
110
|
-
self.allow_cursor_preview = True
|
|
111
108
|
self.control_pressed = False
|
|
112
109
|
self.space_pressed = False
|
|
113
110
|
self.gesture_active = False
|
|
@@ -180,38 +177,32 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
180
177
|
def arrange_images(self):
|
|
181
178
|
pass
|
|
182
179
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
if master_qimage:
|
|
187
|
-
pixmap = QPixmap.fromImage(master_qimage)
|
|
188
|
-
self.get_master_pixmap().setPixmap(pixmap)
|
|
189
|
-
self.get_master_scene().setSceneRect(QRectF(pixmap.rect()))
|
|
190
|
-
self.get_master_view().horizontalScrollBar().setValue(self.status.h_scroll)
|
|
191
|
-
self.get_master_view().verticalScrollBar().setValue(self.status.v_scroll)
|
|
192
|
-
self.arrange_images()
|
|
180
|
+
@abstractmethod
|
|
181
|
+
def get_mouse_callbacks(self):
|
|
182
|
+
pass
|
|
193
183
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
if current_qimage:
|
|
198
|
-
pixmap = QPixmap.fromImage(current_qimage)
|
|
199
|
-
self.get_current_pixmap().setPixmap(pixmap)
|
|
200
|
-
self.get_current_scene().setSceneRect(QRectF(pixmap.rect()))
|
|
201
|
-
self.get_current_view().horizontalScrollBar().setValue(self.status.h_scroll)
|
|
202
|
-
self.get_current_view().verticalScrollBar().setValue(self.status.v_scroll)
|
|
203
|
-
self.arrange_images()
|
|
184
|
+
@abstractmethod
|
|
185
|
+
def set_mouse_callbacks(self, callbacks):
|
|
186
|
+
pass
|
|
204
187
|
|
|
205
|
-
def
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
188
|
+
def hide_brush_cursor(self):
|
|
189
|
+
if self.brush_cursor:
|
|
190
|
+
self.brush_cursor.hide()
|
|
191
|
+
|
|
192
|
+
def show_brush_cursor(self):
|
|
193
|
+
if self.brush_cursor:
|
|
194
|
+
self.brush_cursor.show()
|
|
195
|
+
|
|
196
|
+
def hide_brush_preview(self):
|
|
197
|
+
if self.brush_preview:
|
|
198
|
+
self.brush_preview.hide()
|
|
199
|
+
|
|
200
|
+
def show_brush_preview(self):
|
|
201
|
+
if self.brush_preview:
|
|
202
|
+
self.brush_preview.show()
|
|
212
203
|
|
|
213
|
-
def
|
|
214
|
-
|
|
204
|
+
def current_line_width(self):
|
|
205
|
+
return gui_constants.BRUSH_LINE_WIDTH / self.zoom_factor()
|
|
215
206
|
|
|
216
207
|
def zoom_factor(self):
|
|
217
208
|
return self.status.zoom_factor
|
|
@@ -243,13 +234,9 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
243
234
|
def set_preview_brush(self, brush):
|
|
244
235
|
self.brush_preview.brush = brush
|
|
245
236
|
|
|
246
|
-
def set_display_manager(self, dm):
|
|
247
|
-
self.display_manager = dm
|
|
248
|
-
|
|
249
237
|
def set_cursor_style(self, style):
|
|
250
238
|
self.cursor_style = style
|
|
251
|
-
|
|
252
|
-
self.update_brush_cursor()
|
|
239
|
+
self.update_brush_cursor()
|
|
253
240
|
|
|
254
241
|
def get_cursor_style(self):
|
|
255
242
|
return self.cursor_style
|
|
@@ -260,6 +247,42 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
260
247
|
def handle_key_release_event(self, _event):
|
|
261
248
|
return True
|
|
262
249
|
|
|
250
|
+
def update_view_display(self, layer, pixmap_item, scene, view):
|
|
251
|
+
if self.empty():
|
|
252
|
+
return
|
|
253
|
+
qimage = self.numpy_to_qimage(layer)
|
|
254
|
+
if qimage:
|
|
255
|
+
pixmap = QPixmap.fromImage(qimage)
|
|
256
|
+
pixmap_item.setPixmap(pixmap)
|
|
257
|
+
scene.setSceneRect(QRectF(pixmap.rect()))
|
|
258
|
+
view.horizontalScrollBar().setValue(self.status.h_scroll)
|
|
259
|
+
view.verticalScrollBar().setValue(self.status.v_scroll)
|
|
260
|
+
self.arrange_images()
|
|
261
|
+
|
|
262
|
+
def update_master_display(self):
|
|
263
|
+
self.update_view_display(
|
|
264
|
+
self.master_layer(),
|
|
265
|
+
self.get_master_pixmap(),
|
|
266
|
+
self.get_master_scene(),
|
|
267
|
+
self.get_master_view())
|
|
268
|
+
|
|
269
|
+
def update_current_display(self):
|
|
270
|
+
if self.number_of_layers() <= 0:
|
|
271
|
+
return
|
|
272
|
+
self.update_view_display(
|
|
273
|
+
self.current_layer(),
|
|
274
|
+
self.get_current_pixmap(),
|
|
275
|
+
self.get_current_view(),
|
|
276
|
+
self.get_current_view())
|
|
277
|
+
|
|
278
|
+
def update_cursor_pen_width(self):
|
|
279
|
+
width = self.current_line_width()
|
|
280
|
+
if self.brush_cursor is not None:
|
|
281
|
+
pen = self.brush_cursor.pen()
|
|
282
|
+
pen.setWidthF(width)
|
|
283
|
+
self.brush_cursor.setPen(pen)
|
|
284
|
+
return width
|
|
285
|
+
|
|
263
286
|
def clear_image(self):
|
|
264
287
|
for scene in self.get_scenes():
|
|
265
288
|
scene.clear()
|
|
@@ -269,13 +292,7 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
269
292
|
self.brush_preview = BrushPreviewItem(self.layer_collection)
|
|
270
293
|
self.get_master_scene().addItem(self.brush_preview)
|
|
271
294
|
self.setCursor(Qt.ArrowCursor)
|
|
272
|
-
|
|
273
|
-
self.brush_cursor.hide()
|
|
274
|
-
|
|
275
|
-
def cleanup_brush_preview(self):
|
|
276
|
-
if self.brush_cursor:
|
|
277
|
-
self.brush_cursor.hide()
|
|
278
|
-
self.brush_preview.hide()
|
|
295
|
+
self.hide_brush_cursor()
|
|
279
296
|
|
|
280
297
|
def set_master_image_np(self, img):
|
|
281
298
|
self.set_master_image(self.numpy_to_qimage(img))
|
|
@@ -387,15 +404,15 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
387
404
|
def setup_simple_brush_style(self, center_x, center_y, radius):
|
|
388
405
|
gradient = create_default_brush_gradient(center_x, center_y, radius, self.brush)
|
|
389
406
|
self.brush_cursor.setPen(QPen(QColor(*gui_constants.BRUSH_COLORS['pen']),
|
|
390
|
-
|
|
407
|
+
self.current_line_width()))
|
|
391
408
|
self.brush_cursor.setBrush(QBrush(gradient))
|
|
392
409
|
|
|
393
410
|
def create_circle(self, scene, line_style=Qt.SolidLine):
|
|
394
411
|
for item in scene.items():
|
|
395
412
|
if isinstance(item, QGraphicsEllipseItem) and item != self.brush_preview:
|
|
396
413
|
scene.removeItem(item)
|
|
397
|
-
|
|
398
|
-
|
|
414
|
+
pen = QPen(QColor(*gui_constants.BRUSH_COLORS['pen']),
|
|
415
|
+
self.current_line_width(), line_style)
|
|
399
416
|
brush = Qt.NoBrush
|
|
400
417
|
scene_center = scene.sceneRect().center()
|
|
401
418
|
brush_cursor = scene.addEllipse(
|
|
@@ -409,8 +426,8 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
409
426
|
for item in scene.items():
|
|
410
427
|
if isinstance(item, BrushCursor) and item != self.brush_preview:
|
|
411
428
|
scene.removeItem(item)
|
|
412
|
-
|
|
413
|
-
|
|
429
|
+
pen = QPen(QColor(*gui_constants.BRUSH_COLORS['pen']),
|
|
430
|
+
self.current_line_width(), line_style)
|
|
414
431
|
brush = Qt.NoBrush
|
|
415
432
|
scene_center = scene.sceneRect().center()
|
|
416
433
|
brush_cursor = BrushCursor(
|
|
@@ -434,16 +451,15 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
434
451
|
master_view = self.get_master_view()
|
|
435
452
|
mouse_pos = master_view.mapFromGlobal(QCursor.pos())
|
|
436
453
|
if not master_view.rect().contains(mouse_pos):
|
|
437
|
-
self.
|
|
454
|
+
self.hide_brush_cursor()
|
|
438
455
|
return
|
|
439
456
|
scene_pos = master_view.mapToScene(mouse_pos)
|
|
440
457
|
size = self.brush.size
|
|
441
458
|
radius = size / 2
|
|
442
459
|
self.brush_cursor.setRect(scene_pos.x() - radius, scene_pos.y() - radius, size, size)
|
|
443
|
-
allow_cursor_preview = self.display_manager.allow_cursor_preview()
|
|
444
460
|
if self.cursor_style == 'preview':
|
|
445
|
-
if
|
|
446
|
-
self.
|
|
461
|
+
if self.brush_preview.isVisible():
|
|
462
|
+
self.hide_brush_cursor()
|
|
447
463
|
pos = QCursor.pos()
|
|
448
464
|
if isinstance(pos, QPointF):
|
|
449
465
|
scene_pos = pos
|
|
@@ -452,11 +468,10 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
452
468
|
scene_pos = master_view.mapToScene(cursor_pos)
|
|
453
469
|
self.brush_preview.update(scene_pos, int(size))
|
|
454
470
|
else:
|
|
455
|
-
self.
|
|
471
|
+
self.hide_brush_preview()
|
|
456
472
|
if self.cursor_style != 'outline':
|
|
457
473
|
self.setup_simple_brush_style(scene_pos.x(), scene_pos.y(), radius)
|
|
458
|
-
|
|
459
|
-
self.brush_cursor.show()
|
|
474
|
+
self.show_brush_cursor()
|
|
460
475
|
|
|
461
476
|
def position_on_image(self, pos):
|
|
462
477
|
master_view = self.get_master_view()
|
|
@@ -497,8 +512,7 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
497
512
|
if event.key() == Qt.Key_Space and not self.scrolling:
|
|
498
513
|
self.space_pressed = True
|
|
499
514
|
self.get_master_view().setCursor(Qt.OpenHandCursor)
|
|
500
|
-
|
|
501
|
-
self.brush_cursor.hide()
|
|
515
|
+
self.hide_brush_cursor()
|
|
502
516
|
if self.handle_key_press_event(event):
|
|
503
517
|
if event.key() == Qt.Key_Control and not self.scrolling:
|
|
504
518
|
self.control_pressed = True
|
|
@@ -511,8 +525,7 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
511
525
|
self.space_pressed = False
|
|
512
526
|
if not self.scrolling:
|
|
513
527
|
self.get_master_view().setCursor(Qt.BlankCursor)
|
|
514
|
-
|
|
515
|
-
self.brush_cursor.show()
|
|
528
|
+
self.show_brush_cursor()
|
|
516
529
|
if self.handle_key_release_event(event):
|
|
517
530
|
if event.key() == Qt.Key_Control:
|
|
518
531
|
self.control_pressed = False
|
|
@@ -523,8 +536,7 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
523
536
|
self.setCursor(Qt.ArrowCursor)
|
|
524
537
|
else:
|
|
525
538
|
self.get_master_view().setCursor(Qt.ArrowCursor)
|
|
526
|
-
|
|
527
|
-
self.brush_cursor.hide()
|
|
539
|
+
self.hide_brush_cursor()
|
|
528
540
|
super().leaveEvent(event)
|
|
529
541
|
# pylint: enable=C0103
|
|
530
542
|
|
|
@@ -569,8 +581,7 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
569
581
|
master_view = self.get_master_view()
|
|
570
582
|
if self.space_pressed:
|
|
571
583
|
master_view.setCursor(Qt.ClosedHandCursor)
|
|
572
|
-
|
|
573
|
-
self.brush_cursor.hide()
|
|
584
|
+
self.hide_brush_cursor()
|
|
574
585
|
delta = position - self.last_mouse_pos
|
|
575
586
|
self.last_mouse_pos = position
|
|
576
587
|
self.scroll_view(master_view, delta.x(), delta.y())
|
|
@@ -587,8 +598,7 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
587
598
|
self.last_brush_pos = event.position()
|
|
588
599
|
self.brush_operation_started.emit(event.position().toPoint())
|
|
589
600
|
self.dragging = True
|
|
590
|
-
|
|
591
|
-
self.brush_cursor.show()
|
|
601
|
+
self.show_brush_cursor()
|
|
592
602
|
|
|
593
603
|
def mouse_release_event(self, event):
|
|
594
604
|
if self.empty():
|
|
@@ -596,12 +606,10 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
596
606
|
master_view = self.get_master_view()
|
|
597
607
|
if self.space_pressed:
|
|
598
608
|
master_view.setCursor(Qt.OpenHandCursor)
|
|
599
|
-
|
|
600
|
-
self.brush_cursor.hide()
|
|
609
|
+
self.hide_brush_cursor()
|
|
601
610
|
else:
|
|
602
611
|
master_view.setCursor(Qt.BlankCursor)
|
|
603
|
-
|
|
604
|
-
self.brush_cursor.show()
|
|
612
|
+
self.show_brush_cursor()
|
|
605
613
|
if event.button() == Qt.LeftButton:
|
|
606
614
|
if self.scrolling:
|
|
607
615
|
self.scrolling = False
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# pylint: disable=C0114, C0115, C0116, E0611, W0221, R0902
|
|
1
|
+
# pylint: disable=C0114, C0115, C0116, E0611, W0221, R0902, R0913, R0917
|
|
2
2
|
from PySide6.QtCore import Qt
|
|
3
3
|
from PySide6.QtWidgets import QSpinBox, QCheckBox, QLabel, QHBoxLayout, QSlider, QComboBox
|
|
4
4
|
from .. config.constants import constants
|
|
@@ -7,8 +7,9 @@ from .base_filter import OneSliderBaseFilter
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
class VignettingFilter(OneSliderBaseFilter):
|
|
10
|
-
def __init__(self, name,
|
|
11
|
-
super().__init__(name,
|
|
10
|
+
def __init__(self, name, parent, image_viewer, layer_collection, undo_manager):
|
|
11
|
+
super().__init__(name, parent, image_viewer, layer_collection, undo_manager,
|
|
12
|
+
1.0, 0.90, "Vignetting correction",
|
|
12
13
|
allow_partial_preview=False, preview_at_startup=False)
|
|
13
14
|
self.subsample_box = None
|
|
14
15
|
self.fast_subsampling_check = None
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# pylint: disable=C0114, C0115, C0116, E0611, W0221, R0913, R0914, R0917, R0902
|
|
2
|
+
import numpy as np
|
|
2
3
|
from PySide6.QtWidgets import (QHBoxLayout, QPushButton, QFrame, QVBoxLayout, QLabel, QDialog,
|
|
3
4
|
QApplication, QSlider, QDialogButtonBox, QLineEdit)
|
|
4
5
|
from PySide6.QtCore import Qt, QTimer
|
|
@@ -8,8 +9,9 @@ from .base_filter import BaseFilter
|
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
class WhiteBalanceFilter(BaseFilter):
|
|
11
|
-
def __init__(self, name,
|
|
12
|
-
super().__init__(name,
|
|
12
|
+
def __init__(self, name, parent, image_viewer, layer_collection, undo_manager):
|
|
13
|
+
super().__init__(name, parent, image_viewer, layer_collection, undo_manager,
|
|
14
|
+
preview_at_startup=True)
|
|
13
15
|
self.max_range = 255
|
|
14
16
|
self.initial_val = (128, 128, 128)
|
|
15
17
|
self.sliders = {}
|
|
@@ -18,6 +20,7 @@ class WhiteBalanceFilter(BaseFilter):
|
|
|
18
20
|
self.color_preview = None
|
|
19
21
|
self.preview_timer = None
|
|
20
22
|
self.original_mouse_press = None
|
|
23
|
+
self.original_cursor_style = None
|
|
21
24
|
|
|
22
25
|
def setup_ui(self, dlg, layout, do_preview, restore_original, init_val=None):
|
|
23
26
|
if init_val:
|
|
@@ -65,7 +68,7 @@ class WhiteBalanceFilter(BaseFilter):
|
|
|
65
68
|
for slider in self.sliders.values():
|
|
66
69
|
slider.valueChanged.connect(self.on_slider_change)
|
|
67
70
|
self.preview_timer.timeout.connect(do_preview)
|
|
68
|
-
self.
|
|
71
|
+
self.connect_preview_toggle(self.preview_check, do_preview, restore_original)
|
|
69
72
|
pick_button.clicked.connect(self.start_color_pick)
|
|
70
73
|
self.button_box.accepted.connect(dlg.accept)
|
|
71
74
|
self.button_box.rejected.connect(dlg.reject)
|
|
@@ -107,27 +110,33 @@ class WhiteBalanceFilter(BaseFilter):
|
|
|
107
110
|
widget.hide()
|
|
108
111
|
widget.reject()
|
|
109
112
|
break
|
|
110
|
-
self.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
self.
|
|
113
|
+
self.original_cursor_style = self.image_viewer.get_cursor_style()
|
|
114
|
+
self.image_viewer.set_cursor_style('outline')
|
|
115
|
+
self.image_viewer.hide_brush_cursor()
|
|
116
|
+
self.image_viewer.hide_brush_preview()
|
|
114
117
|
QApplication.setOverrideCursor(QCursor(Qt.CrossCursor))
|
|
115
|
-
self.
|
|
116
|
-
self.original_mouse_press = self.
|
|
117
|
-
self.
|
|
118
|
+
self.image_viewer.strategy.setCursor(Qt.CrossCursor)
|
|
119
|
+
self.original_mouse_press = self.image_viewer.strategy.get_mouse_callbacks()
|
|
120
|
+
self.image_viewer.strategy.set_mouse_callbacks(self.pick_color_from_click)
|
|
121
|
+
self.filter_gui_set_enabled_requested.emit(False)
|
|
118
122
|
|
|
119
123
|
def pick_color_from_click(self, event):
|
|
120
124
|
if event.button() == Qt.LeftButton:
|
|
121
125
|
pos = event.pos()
|
|
122
|
-
bgr = self.
|
|
126
|
+
bgr = self.get_pixel_color_at(
|
|
127
|
+
pos, radius=int(self.image_viewer.get_brush().size))
|
|
123
128
|
rgb = (bgr[2], bgr[1], bgr[0])
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
self.editor.image_viewer.brush_cursor.show()
|
|
128
|
-
self.editor.brush_preview.show()
|
|
129
|
-
new_filter = WhiteBalanceFilter(self.name, self.editor)
|
|
129
|
+
new_filter = WhiteBalanceFilter(
|
|
130
|
+
self.name, self.parent(), self.image_viewer, self.layer_collection,
|
|
131
|
+
self.undo_manager)
|
|
130
132
|
new_filter.run_with_preview(init_val=rgb)
|
|
133
|
+
QApplication.restoreOverrideCursor()
|
|
134
|
+
self.image_viewer.unsetCursor()
|
|
135
|
+
self.image_viewer.strategy.set_mouse_callbacks(self.original_mouse_press)
|
|
136
|
+
self.image_viewer.set_cursor_style(self.original_cursor_style)
|
|
137
|
+
self.image_viewer.show_brush_cursor()
|
|
138
|
+
self.image_viewer.show_brush_preview()
|
|
139
|
+
self.filter_gui_set_enabled_requested.emit(True)
|
|
131
140
|
|
|
132
141
|
def reset_rgb(self):
|
|
133
142
|
for name, slider in self.sliders.items():
|
|
@@ -138,3 +147,39 @@ class WhiteBalanceFilter(BaseFilter):
|
|
|
138
147
|
|
|
139
148
|
def apply(self, image, r, g, b):
|
|
140
149
|
return white_balance_from_rgb(image, (r, g, b))
|
|
150
|
+
|
|
151
|
+
def get_pixel_color_at(self, pos, radius=None):
|
|
152
|
+
item_pos = self.image_viewer.strategy.position_on_image(pos)
|
|
153
|
+
x = int(item_pos.x())
|
|
154
|
+
y = int(item_pos.y())
|
|
155
|
+
master_layer = self.master_layer()
|
|
156
|
+
if (0 <= x < self.master_layer().shape[1]) and \
|
|
157
|
+
(0 <= y < self.master_layer().shape[0]):
|
|
158
|
+
if radius is None:
|
|
159
|
+
radius = int(self.brush.size)
|
|
160
|
+
if radius > 0:
|
|
161
|
+
y_indices, x_indices = np.ogrid[-radius:radius + 1, -radius:radius + 1]
|
|
162
|
+
mask = x_indices**2 + y_indices**2 <= radius**2
|
|
163
|
+
x0 = max(0, x - radius)
|
|
164
|
+
x1 = min(master_layer.shape[1], x + radius + 1)
|
|
165
|
+
y0 = max(0, y - radius)
|
|
166
|
+
y1 = min(master_layer.shape[0], y + radius + 1)
|
|
167
|
+
mask = mask[radius - (y - y0): radius + (y1 - y),
|
|
168
|
+
radius - (x - x0): radius + (x1 - x)]
|
|
169
|
+
region = master_layer[y0:y1, x0:x1]
|
|
170
|
+
if region.size == 0:
|
|
171
|
+
pixel = master_layer[y, x]
|
|
172
|
+
else:
|
|
173
|
+
if region.ndim == 3:
|
|
174
|
+
pixel = [region[:, :, c][mask].mean() for c in range(region.shape[2])]
|
|
175
|
+
else:
|
|
176
|
+
pixel = region[mask].mean()
|
|
177
|
+
else:
|
|
178
|
+
pixel = self.master_layer()[y, x]
|
|
179
|
+
if np.isscalar(pixel):
|
|
180
|
+
pixel = [pixel, pixel, pixel]
|
|
181
|
+
pixel = [np.float32(x) for x in pixel]
|
|
182
|
+
if master_layer.dtype == np.uint16:
|
|
183
|
+
pixel = [x / 256.0 for x in pixel]
|
|
184
|
+
return tuple(int(v) for v in pixel)
|
|
185
|
+
return (0, 0, 0)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
shinestacker/__init__.py,sha256=uq2fjAw2z_6TpH3mOcWFZ98GoEPRsNhTAK8N0MMm_e8,448
|
|
2
|
-
shinestacker/_version.py,sha256=
|
|
2
|
+
shinestacker/_version.py,sha256=7jrl0OaiREGeLqi1Vco5z6ma0w6Mxq8kDBXuswywlc8,21
|
|
3
3
|
shinestacker/algorithms/__init__.py,sha256=1FwVJ3w9GGbFFkjYJRUedTvcdE4j0ieSgaH9RC9iCY4,877
|
|
4
4
|
shinestacker/algorithms/align.py,sha256=mb44u-YxZI1TTSHz81nRpX_2c8awlOhnGrK0LyfTQeQ,33543
|
|
5
5
|
shinestacker/algorithms/align_auto.py,sha256=pJetw6zZEWQLouzcelkI8gD4cPiOp887ePXzVbm0E6Q,3800
|
|
@@ -71,35 +71,35 @@ shinestacker/gui/img/forward-button-icon.png,sha256=lNw86T4TOEd_uokHYF8myGSGUXzd
|
|
|
71
71
|
shinestacker/gui/img/play-button-round-icon.png,sha256=9j6Ks9mOGa-2cXyRFpimepAAvSaHzqJKBfxShRb4_dE,4595
|
|
72
72
|
shinestacker/gui/img/plus-round-line-icon.png,sha256=LS068Hlu-CeBvJuB3dwwdJg1lZq6D5MUIv53lu1yKJA,7534
|
|
73
73
|
shinestacker/retouch/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
74
|
-
shinestacker/retouch/base_filter.py,sha256=
|
|
74
|
+
shinestacker/retouch/base_filter.py,sha256=zpedVvTpof8BsENWdDeu9PDul7Uw0UAXUSsyLZjbcpg,11265
|
|
75
75
|
shinestacker/retouch/brush.py,sha256=dzD2FzSpBIPdJRmTZobcrQ1FrVd3tF__ZPnUplNE72s,357
|
|
76
76
|
shinestacker/retouch/brush_gradient.py,sha256=F5SFhyzl8YTMqjJU3jK8BrIlLCYLUvITd5wz3cQE4xk,1453
|
|
77
77
|
shinestacker/retouch/brush_preview.py,sha256=cOFVMCbEsgR_alzmr_-LLghtGU_unrE-hAjLHcvrZAY,5484
|
|
78
78
|
shinestacker/retouch/brush_tool.py,sha256=8uVncTA375uC3Nhp2YM0eZjpOR-nN47i2eGjN8tJzOU,8714
|
|
79
|
-
shinestacker/retouch/denoise_filter.py,sha256=
|
|
80
|
-
shinestacker/retouch/display_manager.py,sha256=
|
|
79
|
+
shinestacker/retouch/denoise_filter.py,sha256=UpNKbFs7uArdglEej8AUHan7oCVYV5E7HNzkovj7XMQ,571
|
|
80
|
+
shinestacker/retouch/display_manager.py,sha256=vRmaSfHP47rYQrqvJ3flx_GgMJnMZDfQO4PXTfKcpqE,8505
|
|
81
81
|
shinestacker/retouch/exif_data.py,sha256=LF-fRXW-reMq-xJ_QRE5j8DC2LVGKIlC6MR3QbC1cdg,1896
|
|
82
82
|
shinestacker/retouch/file_loader.py,sha256=z02-A8_uDZxayI1NFTxT2GVUvEBWStchX9hlN1o5-0U,4784
|
|
83
|
-
shinestacker/retouch/filter_manager.py,sha256=
|
|
83
|
+
shinestacker/retouch/filter_manager.py,sha256=tOGIWj5HjViL1-iXHkd91X-sZ1c1G531pDmLO0x6zx0,866
|
|
84
84
|
shinestacker/retouch/icon_container.py,sha256=6gw1HO1bC2FrdB4dc_iH81DQuLjzuvRGksZ2hKLT9yA,585
|
|
85
|
-
shinestacker/retouch/image_editor_ui.py,sha256=
|
|
85
|
+
shinestacker/retouch/image_editor_ui.py,sha256=wvsYmS7cXt61KJlv7b3X9EbymMLgdUfeEOzi8jEuR3g,31662
|
|
86
86
|
shinestacker/retouch/image_view_status.py,sha256=bdIhsXiYXm7eyjkTGWkw5PRShzaF_by-g7daqgmhwjM,1858
|
|
87
|
-
shinestacker/retouch/image_viewer.py,sha256=
|
|
87
|
+
shinestacker/retouch/image_viewer.py,sha256=H8w-ORug1aKf7X3FeSX4lQV-a0IewZ9OVG1-50BK4cE,4452
|
|
88
88
|
shinestacker/retouch/io_gui_handler.py,sha256=BRQ5eSt1tCMDYtOqxfdYGhx2BLCrncfNrNLGuWIy5Rk,11873
|
|
89
89
|
shinestacker/retouch/io_manager.py,sha256=JUAA--AK0mVa1PTErJTnBFjaXIle5Qs7Ow0Wkd8at0o,2437
|
|
90
90
|
shinestacker/retouch/layer_collection.py,sha256=fZlGrkm9-Ycc7AOzFSpImhafiTieBeCZRk-UlvlFHbo,5819
|
|
91
|
-
shinestacker/retouch/overlaid_view.py,sha256=
|
|
91
|
+
shinestacker/retouch/overlaid_view.py,sha256=uIMolD1984uQPWXpd27tMvGBTcSrYT-4vxO0pWVlEO4,8686
|
|
92
92
|
shinestacker/retouch/shortcuts_help.py,sha256=BFWTT5QvodqMhqa_9LI25hZqjICfckgyWG4fGrGzvnM,4283
|
|
93
|
-
shinestacker/retouch/sidebyside_view.py,sha256=
|
|
93
|
+
shinestacker/retouch/sidebyside_view.py,sha256=dN5uDG0ioFvYcbmZbx97slh4cOLmJ2T14jtTshg5F9w,17918
|
|
94
94
|
shinestacker/retouch/transformation_manager.py,sha256=NSHGUF-JFv4Y81gSvizjQCTp49TLo1so7c0WoUElO08,1812
|
|
95
95
|
shinestacker/retouch/undo_manager.py,sha256=cKUkqnJtnJ-Hq-LQs5Bv49FC6qkG6XSw9oCVySJ8jS0,4312
|
|
96
|
-
shinestacker/retouch/unsharp_mask_filter.py,sha256=
|
|
97
|
-
shinestacker/retouch/view_strategy.py,sha256=
|
|
98
|
-
shinestacker/retouch/vignetting_filter.py,sha256=
|
|
99
|
-
shinestacker/retouch/white_balance_filter.py,sha256=
|
|
100
|
-
shinestacker-1.5.
|
|
101
|
-
shinestacker-1.5.
|
|
102
|
-
shinestacker-1.5.
|
|
103
|
-
shinestacker-1.5.
|
|
104
|
-
shinestacker-1.5.
|
|
105
|
-
shinestacker-1.5.
|
|
96
|
+
shinestacker/retouch/unsharp_mask_filter.py,sha256=Iapc8UmSVpj3V0LcJq_38P5qerRqTevMynbbk5Rk6iE,3634
|
|
97
|
+
shinestacker/retouch/view_strategy.py,sha256=_Zo-SU2hlVVSv1g5eWgp72njcmfMpAlkkPggd89XJFo,23326
|
|
98
|
+
shinestacker/retouch/vignetting_filter.py,sha256=JhFr6OVIripQzSJrZEG4lxq7wBsmpofLqJQ-aP2bKw8,3789
|
|
99
|
+
shinestacker/retouch/white_balance_filter.py,sha256=QlMnzWmBYqUQqckY8XTH3dWPdqo7mz4gTwTZafxldPw,8237
|
|
100
|
+
shinestacker-1.5.2.dist-info/licenses/LICENSE,sha256=pWgb-bBdsU2Gd2kwAXxketnm5W_2u8_fIeWEgojfrxs,7651
|
|
101
|
+
shinestacker-1.5.2.dist-info/METADATA,sha256=AuETmZdF7h5LSior9SUBcdWaiSmCxenl_9bECasvSLk,6978
|
|
102
|
+
shinestacker-1.5.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
103
|
+
shinestacker-1.5.2.dist-info/entry_points.txt,sha256=SY6g1LqtMmp23q1DGwLUDT_dhLX9iss8DvWkiWLyo_4,166
|
|
104
|
+
shinestacker-1.5.2.dist-info/top_level.txt,sha256=MhijwnBVX5psfsyX8JZjqp3SYiWPsKe69f3Gnyze4Fw,13
|
|
105
|
+
shinestacker-1.5.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|