shinestacker 1.5.2__py3-none-any.whl → 1.5.3__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/app/main.py +1 -1
- shinestacker/app/project.py +1 -1
- shinestacker/app/retouch.py +1 -1
- shinestacker/config/gui_constants.py +1 -1
- shinestacker/retouch/sidebyside_view.py +18 -0
- shinestacker/retouch/view_strategy.py +70 -6
- {shinestacker-1.5.2.dist-info → shinestacker-1.5.3.dist-info}/METADATA +1 -1
- {shinestacker-1.5.2.dist-info → shinestacker-1.5.3.dist-info}/RECORD +14 -14
- /shinestacker/app/{args.py → args_parser_opts.py} +0 -0
- {shinestacker-1.5.2.dist-info → shinestacker-1.5.3.dist-info}/WHEEL +0 -0
- {shinestacker-1.5.2.dist-info → shinestacker-1.5.3.dist-info}/entry_points.txt +0 -0
- {shinestacker-1.5.2.dist-info → shinestacker-1.5.3.dist-info}/licenses/LICENSE +0 -0
- {shinestacker-1.5.2.dist-info → shinestacker-1.5.3.dist-info}/top_level.txt +0 -0
shinestacker/_version.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = '1.5.
|
|
1
|
+
__version__ = '1.5.3'
|
shinestacker/app/main.py
CHANGED
|
@@ -20,7 +20,7 @@ from shinestacker.app.gui_utils import (
|
|
|
20
20
|
disable_macos_special_menu_items, fill_app_menu, set_css_style)
|
|
21
21
|
from shinestacker.app.help_menu import add_help_action
|
|
22
22
|
from shinestacker.app.open_frames import open_frames
|
|
23
|
-
from .
|
|
23
|
+
from shinestacker.app.args_parser_opts import add_project_arguments, add_retouch_arguments
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
class SelectionDialog(QDialog):
|
shinestacker/app/project.py
CHANGED
|
@@ -17,7 +17,7 @@ from shinestacker.gui.main_window import MainWindow
|
|
|
17
17
|
from shinestacker.app.gui_utils import (
|
|
18
18
|
disable_macos_special_menu_items, fill_app_menu, set_css_style)
|
|
19
19
|
from shinestacker.app.help_menu import add_help_action
|
|
20
|
-
from .
|
|
20
|
+
from shinestacker.app.args_parser_opts import add_project_arguments
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
class ProjectApp(MainWindow):
|
shinestacker/app/retouch.py
CHANGED
|
@@ -13,7 +13,7 @@ from shinestacker.app.gui_utils import (
|
|
|
13
13
|
disable_macos_special_menu_items, fill_app_menu, set_css_style)
|
|
14
14
|
from shinestacker.app.help_menu import add_help_action
|
|
15
15
|
from shinestacker.app.open_frames import open_frames
|
|
16
|
-
from .
|
|
16
|
+
from shinestacker.app.args_parser_opts import add_retouch_arguments
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
class RetouchApp(ImageEditorUI):
|
|
@@ -26,7 +26,7 @@ class _GuiConstants:
|
|
|
26
26
|
'outer': (255, 0, 0, 200),
|
|
27
27
|
'inner': (255, 0, 0, 150),
|
|
28
28
|
'gradient_end': (255, 0, 0, 0),
|
|
29
|
-
'pen': (255,
|
|
29
|
+
'pen': (255, 255, 255, 200),
|
|
30
30
|
'preview': (255, 180, 180),
|
|
31
31
|
'cursor_inner': (255, 0, 0, 120),
|
|
32
32
|
'preview_inner': (255, 255, 255, 150)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# pylint: disable=C0114, C0115, C0116, R0904, R0915, E0611, R0902, R0911, R0914, E1003
|
|
2
|
+
import time
|
|
2
3
|
from PySide6.QtCore import Qt, Signal, QEvent, QRectF
|
|
3
4
|
from PySide6.QtGui import QCursor
|
|
4
5
|
from PySide6.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QFrame
|
|
@@ -58,6 +59,7 @@ class DoubleViewBase(ViewStrategy, QWidget, ViewSignals):
|
|
|
58
59
|
self.current_view.setFocusPolicy(Qt.NoFocus)
|
|
59
60
|
self.master_view.setFocusPolicy(Qt.NoFocus)
|
|
60
61
|
self.current_brush_cursor = None
|
|
62
|
+
self.last_color_update_time_current = 0
|
|
61
63
|
|
|
62
64
|
def setup_layout(self):
|
|
63
65
|
raise NotImplementedError("Subclasses must implement setup_layout")
|
|
@@ -311,9 +313,11 @@ class DoubleViewBase(ViewStrategy, QWidget, ViewSignals):
|
|
|
311
313
|
radius = size / 2
|
|
312
314
|
self.current_brush_cursor.setRect(
|
|
313
315
|
scene_pos.x() - radius, scene_pos.y() - radius, size, size)
|
|
316
|
+
self.update_current_cursor_color()
|
|
314
317
|
self.current_brush_cursor.show()
|
|
315
318
|
self.brush_cursor.setRect(
|
|
316
319
|
scene_pos.x() - radius, scene_pos.y() - radius, size, size)
|
|
320
|
+
self.update_master_cursor_color()
|
|
317
321
|
self.brush_cursor.show()
|
|
318
322
|
else:
|
|
319
323
|
self.brush_cursor.hide()
|
|
@@ -321,6 +325,19 @@ class DoubleViewBase(ViewStrategy, QWidget, ViewSignals):
|
|
|
321
325
|
self.master_view.setCursor(Qt.ArrowCursor)
|
|
322
326
|
self.current_view.setCursor(Qt.ArrowCursor)
|
|
323
327
|
|
|
328
|
+
def update_current_cursor_color(self):
|
|
329
|
+
self.update_cursor_color_based_on_background(
|
|
330
|
+
self.current_brush_cursor, self.current_layer(),
|
|
331
|
+
self.get_visible_current_image_region, self.get_current_pixmap,
|
|
332
|
+
self.update_color_time_current)
|
|
333
|
+
|
|
334
|
+
def update_color_time_current(self):
|
|
335
|
+
current_time = time.time()
|
|
336
|
+
if current_time - self.last_color_update_time_current < 0.2:
|
|
337
|
+
return False
|
|
338
|
+
self.last_color_update_time_current = current_time
|
|
339
|
+
return True
|
|
340
|
+
|
|
324
341
|
def handle_master_mouse_press(self, event):
|
|
325
342
|
self.setFocus()
|
|
326
343
|
self.mouse_press_event(event)
|
|
@@ -425,6 +442,7 @@ class DoubleViewBase(ViewStrategy, QWidget, ViewSignals):
|
|
|
425
442
|
scene_pos.x() - radius, scene_pos.y() - radius,
|
|
426
443
|
size, size)
|
|
427
444
|
if self.brush_cursor.isVisible():
|
|
445
|
+
self.update_current_cursor_color()
|
|
428
446
|
self.current_brush_cursor.show()
|
|
429
447
|
else:
|
|
430
448
|
self.current_brush_cursor.hide()
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# pylint: disable=C0114, C0115, C0116, E0611, R0904, R0903, R0902, E1101, R0914, R0913, R0917
|
|
2
2
|
import math
|
|
3
|
+
import time
|
|
3
4
|
from abc import abstractmethod
|
|
4
5
|
import numpy as np
|
|
5
6
|
from PySide6.QtCore import Qt, QPointF, QTime, QPoint, Signal, QRectF
|
|
@@ -116,6 +117,7 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
116
117
|
self.last_brush_pos = None
|
|
117
118
|
self.last_mouse_pos = None
|
|
118
119
|
self.last_update_time = QTime.currentTime()
|
|
120
|
+
self.last_color_update_time = 0
|
|
119
121
|
|
|
120
122
|
@abstractmethod
|
|
121
123
|
def create_pixmaps(self):
|
|
@@ -236,6 +238,8 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
236
238
|
|
|
237
239
|
def set_cursor_style(self, style):
|
|
238
240
|
self.cursor_style = style
|
|
241
|
+
if style == 'preview':
|
|
242
|
+
self.show_brush_preview()
|
|
239
243
|
self.update_brush_cursor()
|
|
240
244
|
|
|
241
245
|
def get_cursor_style(self):
|
|
@@ -402,9 +406,12 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
402
406
|
self.update_cursor_pen_width()
|
|
403
407
|
|
|
404
408
|
def setup_simple_brush_style(self, center_x, center_y, radius):
|
|
409
|
+
if self.brush_cursor:
|
|
410
|
+
pen = self.brush_cursor.pen()
|
|
411
|
+
else:
|
|
412
|
+
pen = QPen(QColor(*gui_constants.BRUSH_COLORS['pen']), self.current_line_width())
|
|
405
413
|
gradient = create_default_brush_gradient(center_x, center_y, radius, self.brush)
|
|
406
|
-
self.brush_cursor.setPen(
|
|
407
|
-
self.current_line_width()))
|
|
414
|
+
self.brush_cursor.setPen(pen)
|
|
408
415
|
self.brush_cursor.setBrush(QBrush(gradient))
|
|
409
416
|
|
|
410
417
|
def create_circle(self, scene, line_style=Qt.SolidLine):
|
|
@@ -469,10 +476,58 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
469
476
|
self.brush_preview.update(scene_pos, int(size))
|
|
470
477
|
else:
|
|
471
478
|
self.hide_brush_preview()
|
|
472
|
-
|
|
473
|
-
|
|
479
|
+
self.update_master_cursor_color()
|
|
480
|
+
if self.cursor_style == 'brush':
|
|
481
|
+
self.setup_simple_brush_style(scene_pos.x(), scene_pos.y(), radius)
|
|
474
482
|
self.show_brush_cursor()
|
|
475
483
|
|
|
484
|
+
def update_color_time(self):
|
|
485
|
+
current_time = time.time()
|
|
486
|
+
if current_time - self.last_color_update_time < 0.2:
|
|
487
|
+
return False
|
|
488
|
+
self.last_color_update_time = current_time
|
|
489
|
+
return True
|
|
490
|
+
|
|
491
|
+
def update_master_cursor_color(self):
|
|
492
|
+
self.update_cursor_color_based_on_background(
|
|
493
|
+
self.brush_cursor, self.master_layer(),
|
|
494
|
+
self.get_visible_image_region, self.get_master_pixmap,
|
|
495
|
+
self.update_color_time)
|
|
496
|
+
|
|
497
|
+
def update_cursor_color_based_on_background(
|
|
498
|
+
self, cursor, layer,
|
|
499
|
+
visible_region, get_pixmap, update_timer):
|
|
500
|
+
if not update_timer():
|
|
501
|
+
return
|
|
502
|
+
cursor_rect = cursor.rect()
|
|
503
|
+
image_region = visible_region()
|
|
504
|
+
if image_region and cursor_rect.intersects(image_region):
|
|
505
|
+
intersect_rect = cursor_rect.intersected(image_region)
|
|
506
|
+
top_left = get_pixmap().mapFromScene(intersect_rect.topLeft())
|
|
507
|
+
bottom_right = get_pixmap().mapFromScene(intersect_rect.bottomRight())
|
|
508
|
+
x1, y1 = max(0, int(top_left.x())), max(0, int(top_left.y()))
|
|
509
|
+
x2, y2 = min(layer.shape[1], int(bottom_right.x())), \
|
|
510
|
+
min(layer.shape[0], int(bottom_right.y()))
|
|
511
|
+
if x2 > x1 and y2 > y1:
|
|
512
|
+
region = layer[y1:y2, x1:x2]
|
|
513
|
+
if region.size > 10000:
|
|
514
|
+
step = int(math.sqrt(region.size / 100))
|
|
515
|
+
region = region[::step, ::step]
|
|
516
|
+
if region.ndim == 3:
|
|
517
|
+
luminosity = np.dot(region[..., :3], [0.299, 0.587, 0.114])
|
|
518
|
+
avg_luminosity = np.mean(luminosity)
|
|
519
|
+
else:
|
|
520
|
+
avg_luminosity = np.mean(region)
|
|
521
|
+
if region.dtype == np.uint16:
|
|
522
|
+
avg_luminosity /= 256.0
|
|
523
|
+
if avg_luminosity < 128:
|
|
524
|
+
new_color = QColor(255, 255, 255)
|
|
525
|
+
else:
|
|
526
|
+
new_color = QColor(0, 0, 0)
|
|
527
|
+
current_pen = cursor.pen()
|
|
528
|
+
current_pen.setColor(new_color)
|
|
529
|
+
cursor.setPen(current_pen)
|
|
530
|
+
|
|
476
531
|
def position_on_image(self, pos):
|
|
477
532
|
master_view = self.get_master_view()
|
|
478
533
|
pixmap = self.get_master_pixmap()
|
|
@@ -485,11 +540,20 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
485
540
|
return None
|
|
486
541
|
master_view = self.get_master_view()
|
|
487
542
|
master_pixmap = self.get_master_pixmap()
|
|
488
|
-
pixmap = self.get_master_pixmap()
|
|
489
543
|
view_rect = master_view.viewport().rect()
|
|
490
544
|
scene_rect = master_view.mapToScene(view_rect).boundingRect()
|
|
491
545
|
image_rect = master_pixmap.mapFromScene(scene_rect).boundingRect().toRect()
|
|
492
|
-
return image_rect.intersected(
|
|
546
|
+
return image_rect.intersected(master_pixmap.boundingRect().toRect())
|
|
547
|
+
|
|
548
|
+
def get_visible_current_image_region(self):
|
|
549
|
+
if self.empty():
|
|
550
|
+
return None
|
|
551
|
+
current_view = self.get_current_view()
|
|
552
|
+
current_pixmap = self.get_current_pixmap()
|
|
553
|
+
view_rect = current_view.viewport().rect()
|
|
554
|
+
scene_rect = current_view.mapToScene(view_rect).boundingRect()
|
|
555
|
+
image_rect = current_pixmap.mapFromScene(scene_rect).boundingRect().toRect()
|
|
556
|
+
return image_rect.intersected(current_pixmap.boundingRect().toRect())
|
|
493
557
|
|
|
494
558
|
def get_visible_image_portion(self):
|
|
495
559
|
if self.has_no_master_layer():
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
shinestacker/__init__.py,sha256=uq2fjAw2z_6TpH3mOcWFZ98GoEPRsNhTAK8N0MMm_e8,448
|
|
2
|
-
shinestacker/_version.py,sha256=
|
|
2
|
+
shinestacker/_version.py,sha256=zG2cd7WLo5fIizFwE9xNzjpfZPff6uzTZIgsxS6ri_g,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
|
|
@@ -22,17 +22,17 @@ shinestacker/algorithms/vignetting.py,sha256=gJOv-FN3GnTgaVn70W_6d-qbw3WmqinDiO9
|
|
|
22
22
|
shinestacker/algorithms/white_balance.py,sha256=PMKsBtxOSn5aRr_Gkx1StHS4eN6kBN2EhNnhg4UG24g,501
|
|
23
23
|
shinestacker/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
24
|
shinestacker/app/about_dialog.py,sha256=pkH7nnxUP8yc0D3vRGd1jRb5cwi1nDVbQRk_OC9yLk8,4144
|
|
25
|
-
shinestacker/app/
|
|
25
|
+
shinestacker/app/args_parser_opts.py,sha256=TlfMR5GBd6Zz9wZNrN7CGJ1_hm1FnLZn5EoP5mkRHrk,776
|
|
26
26
|
shinestacker/app/gui_utils.py,sha256=fSpkwPXTON_l676UHdAnJNrGq7BPbSlPOiHpOF_LZaI,2519
|
|
27
27
|
shinestacker/app/help_menu.py,sha256=g8lKG_xZmXtNQaC3SIRzyROKVWva_PLEgZsQWh6zUcQ,499
|
|
28
|
-
shinestacker/app/main.py,sha256=
|
|
28
|
+
shinestacker/app/main.py,sha256=UkWz4jvaBPH4Fs-arHe8H0NqKVTA4B_1e9BRn9S5oFo,10963
|
|
29
29
|
shinestacker/app/open_frames.py,sha256=bsu32iJSYJQLe_tQQbvAU5DuMDVX6MRuNdE7B5lojZc,1488
|
|
30
|
-
shinestacker/app/project.py,sha256=
|
|
31
|
-
shinestacker/app/retouch.py,sha256=
|
|
30
|
+
shinestacker/app/project.py,sha256=_kopeyb8e5JAA3XjNXoCshlYBfT5Avw-kTqiJN4GVlo,2805
|
|
31
|
+
shinestacker/app/retouch.py,sha256=On2oV2QonfMziQAvRkO6qw-h6E6wWQE0svKzZQKHeyg,2687
|
|
32
32
|
shinestacker/config/__init__.py,sha256=aXxi-LmAvXd0daIFrVnTHE5OCaYeK1uf1BKMr7oaXQs,197
|
|
33
33
|
shinestacker/config/config.py,sha256=eBko2D3ADhLTIm9X6hB_a_WsIjwgfE-qmBVkhP1XSvc,1636
|
|
34
34
|
shinestacker/config/constants.py,sha256=EEdr7pZg4JpbIjUWaP7kJQfTuBB85FN739myDNAfn8A,8301
|
|
35
|
-
shinestacker/config/gui_constants.py,sha256=
|
|
35
|
+
shinestacker/config/gui_constants.py,sha256=55Qr0KzrTx8eQHCkT-EVabSiD59VvLZIh5o2cA9028s,2791
|
|
36
36
|
shinestacker/core/__init__.py,sha256=IUEIx6SQ3DygDEHN3_E6uKpHjHtUa4a_U_1dLd_8yEU,484
|
|
37
37
|
shinestacker/core/colors.py,sha256=kr_tJA1iRsdck2JaYDb2lS-codZ4Ty9gdu3kHfiWvuM,1340
|
|
38
38
|
shinestacker/core/core_utils.py,sha256=1LYj19Dfc9jZN9-4dlf1paximDH5WZYa7DXvKr7R7QY,1719
|
|
@@ -90,16 +90,16 @@ shinestacker/retouch/io_manager.py,sha256=JUAA--AK0mVa1PTErJTnBFjaXIle5Qs7Ow0Wkd
|
|
|
90
90
|
shinestacker/retouch/layer_collection.py,sha256=fZlGrkm9-Ycc7AOzFSpImhafiTieBeCZRk-UlvlFHbo,5819
|
|
91
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=2BrIrr38FxYJ522GLpHomScwbJgAczO9LiPwTAIlPUE,18647
|
|
94
94
|
shinestacker/retouch/transformation_manager.py,sha256=NSHGUF-JFv4Y81gSvizjQCTp49TLo1so7c0WoUElO08,1812
|
|
95
95
|
shinestacker/retouch/undo_manager.py,sha256=cKUkqnJtnJ-Hq-LQs5Bv49FC6qkG6XSw9oCVySJ8jS0,4312
|
|
96
96
|
shinestacker/retouch/unsharp_mask_filter.py,sha256=Iapc8UmSVpj3V0LcJq_38P5qerRqTevMynbbk5Rk6iE,3634
|
|
97
|
-
shinestacker/retouch/view_strategy.py,sha256=
|
|
97
|
+
shinestacker/retouch/view_strategy.py,sha256=Di0iaYwTMI58pheF51d9MBJ0eLDvJog1DnmBLNMMMRs,26100
|
|
98
98
|
shinestacker/retouch/vignetting_filter.py,sha256=JhFr6OVIripQzSJrZEG4lxq7wBsmpofLqJQ-aP2bKw8,3789
|
|
99
99
|
shinestacker/retouch/white_balance_filter.py,sha256=QlMnzWmBYqUQqckY8XTH3dWPdqo7mz4gTwTZafxldPw,8237
|
|
100
|
-
shinestacker-1.5.
|
|
101
|
-
shinestacker-1.5.
|
|
102
|
-
shinestacker-1.5.
|
|
103
|
-
shinestacker-1.5.
|
|
104
|
-
shinestacker-1.5.
|
|
105
|
-
shinestacker-1.5.
|
|
100
|
+
shinestacker-1.5.3.dist-info/licenses/LICENSE,sha256=pWgb-bBdsU2Gd2kwAXxketnm5W_2u8_fIeWEgojfrxs,7651
|
|
101
|
+
shinestacker-1.5.3.dist-info/METADATA,sha256=8-9HAKfGrk6TEYj1rr_O6habe-0YlUGpHrrlhmQvRwY,6978
|
|
102
|
+
shinestacker-1.5.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
103
|
+
shinestacker-1.5.3.dist-info/entry_points.txt,sha256=SY6g1LqtMmp23q1DGwLUDT_dhLX9iss8DvWkiWLyo_4,166
|
|
104
|
+
shinestacker-1.5.3.dist-info/top_level.txt,sha256=MhijwnBVX5psfsyX8JZjqp3SYiWPsKe69f3Gnyze4Fw,13
|
|
105
|
+
shinestacker-1.5.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|