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.

@@ -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.brush_preview.show()
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.brush_preview.hide()
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
- return True
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 * (1.0 / self.get_current_scale())
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.brush_cursor.hide()
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.brush_cursor.hide()
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.brush_preview.show()
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.brush_preview.hide()
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, editor):
10
- super().__init__(name, editor, preview_at_startup=True)
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.editor.connect_preview_toggle(self.preview_check, do_preview, restore_original)
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
- def update_master_display(self):
184
- if not self.empty():
185
- master_qimage = self.numpy_to_qimage(self.master_layer())
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
- def update_current_display(self):
195
- if not self.empty() and self.number_of_layers() > 0:
196
- current_qimage = self.numpy_to_qimage(self.current_layer())
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 update_cursor_pen_width(self):
206
- width = gui_constants.BRUSH_LINE_WIDTH / self.zoom_factor()
207
- if self.brush_cursor is not None:
208
- pen = self.brush_cursor.pen()
209
- pen.setWidthF(width)
210
- self.brush_cursor.setPen(pen)
211
- return width
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 set_allow_cursor_preview(self, state):
214
- self.allow_cursor_preview = state
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
- if self.brush_cursor:
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
- if self.brush_cursor:
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
- gui_constants.BRUSH_LINE_WIDTH / self.zoom_factor()))
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
- pen_width = gui_constants.BRUSH_LINE_WIDTH / self.zoom_factor()
398
- pen = QPen(QColor(*gui_constants.BRUSH_COLORS['pen']), pen_width, line_style)
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
- pen_width = gui_constants.BRUSH_LINE_WIDTH / self.zoom_factor()
413
- pen = QPen(QColor(*gui_constants.BRUSH_COLORS['pen']), pen_width, line_style)
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.brush_cursor.hide()
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 allow_cursor_preview:
446
- self.brush_cursor.hide()
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.brush_preview.hide()
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
- if not self.brush_cursor.isVisible():
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
- if self.brush_cursor:
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
- if self.brush_cursor:
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
- if self.brush_cursor:
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
- if self.brush_cursor:
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
- if self.brush_cursor:
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
- if self.brush_cursor:
600
- self.brush_cursor.hide()
609
+ self.hide_brush_cursor()
601
610
  else:
602
611
  master_view.setCursor(Qt.BlankCursor)
603
- if self.brush_cursor:
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, editor):
11
- super().__init__(name, editor, 1.0, 0.90, "Vignetting correction",
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, editor):
12
- super().__init__(name, editor, preview_at_startup=True)
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.editor.connect_preview_toggle(self.preview_check, do_preview, restore_original)
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.editor.image_viewer.set_cursor_style('outline')
111
- if self.editor.image_viewer.brush_cursor:
112
- self.editor.image_viewer.brush_cursor.hide()
113
- self.editor.brush_preview.hide()
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.editor.image_viewer.setCursor(Qt.CrossCursor)
116
- self.original_mouse_press = self.editor.image_viewer.mousePressEvent
117
- self.editor.image_viewer.mousePressEvent = self.pick_color_from_click
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.editor.get_pixel_color_at(pos, radius=int(self.editor.brush.size))
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
- QApplication.restoreOverrideCursor()
125
- self.editor.image_viewer.unsetCursor()
126
- self.editor.image_viewer.mousePressEvent = self.original_mouse_press
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,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shinestacker
3
- Version: 1.5.1
3
+ Version: 1.5.2
4
4
  Summary: ShineStacker
5
5
  Author-email: Luca Lista <luka.lista@gmail.com>
6
6
  License-Expression: LGPL-3.0
@@ -1,5 +1,5 @@
1
1
  shinestacker/__init__.py,sha256=uq2fjAw2z_6TpH3mOcWFZ98GoEPRsNhTAK8N0MMm_e8,448
2
- shinestacker/_version.py,sha256=oU1lLCdhmPP8CUfgzMFfhCPjCfk4eDfd8WSwOfXNBOk,21
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=gvRGvhOhhWS05jKOXyNdMnia3b7rscQqR8-xnySIWFc,10260
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=TDUHzhRKlKvCa3D5SCYCZKTpjcl81kGwmONsgSDtO1k,440
80
- shinestacker/retouch/display_manager.py,sha256=wwbX4n7ulg53fM3E5QL5YEb5IFV0jN8za6yfYc74anA,8624
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=SdYIZkZBUvuB6wDG0moGWav5sfEvIcB9ioUJR5wJFts,388
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=ifrlHafXdELwCXoVfUiSM7jcz3O6qH7z2WjNpNPEmUs,33505
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=D7feFlaZkR2nzJ9VcKcVg8lYPS7AMjA_uxJs9L099kQ,4412
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=0V6Y0wVmf7vPzhB4O9BSF8UwBnw0RdBdYCt_tHD4vls,8478
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=We4hY_ZGwINPVPHACPGYFPaiU3Khpax7Sf9Xur317FA,17358
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=uFnth8fpZFGhdIgJCnS8x5v6lBQgJ3hX0CBke9pFXeM,3510
97
- shinestacker/retouch/view_strategy.py,sha256=5AiSYH_FkeIhaUMtQwZ3v1_8r6KckvOYPFoufEtw12Y,23877
98
- shinestacker/retouch/vignetting_filter.py,sha256=MA97rQkSL0D-Nh-n2L4AiPR064RoTROkvza4tw84g9U,3658
99
- shinestacker/retouch/white_balance_filter.py,sha256=glMBYlmrF-i_OrB3sGUpjZE6X4FQdyLC4GBy2bWtaFc,6056
100
- shinestacker-1.5.1.dist-info/licenses/LICENSE,sha256=pWgb-bBdsU2Gd2kwAXxketnm5W_2u8_fIeWEgojfrxs,7651
101
- shinestacker-1.5.1.dist-info/METADATA,sha256=FrhfVRsmH4sx7-cQxDajn-zZinLt-UIhhHf2xYZNzvM,6978
102
- shinestacker-1.5.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
103
- shinestacker-1.5.1.dist-info/entry_points.txt,sha256=SY6g1LqtMmp23q1DGwLUDT_dhLX9iss8DvWkiWLyo_4,166
104
- shinestacker-1.5.1.dist-info/top_level.txt,sha256=MhijwnBVX5psfsyX8JZjqp3SYiWPsKe69f3Gnyze4Fw,13
105
- shinestacker-1.5.1.dist-info/RECORD,,
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,,