shinestacker 1.6.0__py3-none-any.whl → 1.7.0__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/algorithms/corrections.py +26 -0
- shinestacker/app/args_parser_opts.py +39 -0
- shinestacker/app/gui_utils.py +19 -2
- shinestacker/app/main.py +16 -25
- shinestacker/app/project.py +12 -21
- shinestacker/app/retouch.py +12 -20
- shinestacker/core/core_utils.py +2 -12
- shinestacker/core/logging.py +4 -3
- shinestacker/gui/ico/shinestacker.icns +0 -0
- shinestacker/gui/ico/shinestacker_bkg.png +0 -0
- shinestacker/gui/tab_widget.py +1 -5
- shinestacker/retouch/adjustments.py +93 -0
- shinestacker/retouch/base_filter.py +63 -8
- shinestacker/retouch/denoise_filter.py +1 -1
- shinestacker/retouch/display_manager.py +1 -2
- shinestacker/retouch/image_editor_ui.py +39 -39
- shinestacker/retouch/image_viewer.py +17 -9
- shinestacker/retouch/io_gui_handler.py +96 -44
- shinestacker/retouch/io_threads.py +78 -0
- shinestacker/retouch/layer_collection.py +12 -0
- shinestacker/retouch/overlaid_view.py +13 -5
- shinestacker/retouch/paint_area_manager.py +30 -0
- shinestacker/retouch/sidebyside_view.py +3 -3
- shinestacker/retouch/transformation_manager.py +1 -2
- shinestacker/retouch/undo_manager.py +15 -13
- shinestacker/retouch/unsharp_mask_filter.py +13 -28
- shinestacker/retouch/view_strategy.py +65 -22
- shinestacker/retouch/vignetting_filter.py +1 -1
- {shinestacker-1.6.0.dist-info → shinestacker-1.7.0.dist-info}/METADATA +2 -2
- {shinestacker-1.6.0.dist-info → shinestacker-1.7.0.dist-info}/RECORD +35 -32
- shinestacker/gui/ico/focus_stack_bkg.png +0 -0
- shinestacker/retouch/io_manager.py +0 -69
- {shinestacker-1.6.0.dist-info → shinestacker-1.7.0.dist-info}/WHEEL +0 -0
- {shinestacker-1.6.0.dist-info → shinestacker-1.7.0.dist-info}/entry_points.txt +0 -0
- {shinestacker-1.6.0.dist-info → shinestacker-1.7.0.dist-info}/licenses/LICENSE +0 -0
- {shinestacker-1.6.0.dist-info → shinestacker-1.7.0.dist-info}/top_level.txt +0 -0
|
@@ -16,8 +16,7 @@ class TransfromationManager(LayerCollectionHandler):
|
|
|
16
16
|
if undoable:
|
|
17
17
|
try:
|
|
18
18
|
undo = self.editor.undo_manager
|
|
19
|
-
undo.
|
|
20
|
-
undo.y_start, undo.y_stop = 0, 1
|
|
19
|
+
undo.set_paint_area(0, 1, 0, 1)
|
|
21
20
|
undo.save_undo_state(self.editor.master_layer(), label)
|
|
22
21
|
except Exception as e:
|
|
23
22
|
traceback.print_tb(e.__traceback__)
|
|
@@ -6,13 +6,10 @@ from .. config.gui_constants import gui_constants
|
|
|
6
6
|
class UndoManager(QObject):
|
|
7
7
|
stack_changed = Signal(bool, str, bool, str)
|
|
8
8
|
|
|
9
|
-
def __init__(self, transformation_manager):
|
|
9
|
+
def __init__(self, transformation_manager, paint_area_manager):
|
|
10
10
|
super().__init__()
|
|
11
11
|
self.transformation_manager = transformation_manager
|
|
12
|
-
self.
|
|
13
|
-
self.y_start = None
|
|
14
|
-
self.x_end = None
|
|
15
|
-
self.y_end = None
|
|
12
|
+
self.paint_area_manager = paint_area_manager
|
|
16
13
|
self.undo_stack = None
|
|
17
14
|
self.redo_stack = None
|
|
18
15
|
self.reset()
|
|
@@ -24,22 +21,25 @@ class UndoManager(QObject):
|
|
|
24
21
|
self.stack_changed.emit(False, "", False, "")
|
|
25
22
|
|
|
26
23
|
def reset_undo_area(self):
|
|
27
|
-
self.
|
|
28
|
-
self.x_start = self.y_start = gui_constants.MAX_UNDO_SIZE
|
|
24
|
+
self.paint_area_manager.reset()
|
|
29
25
|
|
|
30
26
|
def extend_undo_area(self, x_start, y_start, x_end, y_end):
|
|
31
|
-
self.x_start
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
self.
|
|
27
|
+
self.paint_area_manager.extend(x_start, y_start, x_end, y_end)
|
|
28
|
+
|
|
29
|
+
def paint_area(self):
|
|
30
|
+
return self.paint_area_manager.area()
|
|
31
|
+
|
|
32
|
+
def set_paint_area(self, x_start, y_start, x_end, y_end):
|
|
33
|
+
self.paint_area_manager.set_area(x_start, y_start, x_end, y_end)
|
|
35
34
|
|
|
36
35
|
def save_undo_state(self, layer, description):
|
|
37
36
|
if layer is None:
|
|
38
37
|
return
|
|
39
38
|
self.redo_stack = []
|
|
39
|
+
x_start, y_start, x_end, y_end = self.paint_area()
|
|
40
40
|
undo_state = {
|
|
41
|
-
'master': layer[
|
|
42
|
-
'area': (
|
|
41
|
+
'master': layer[y_start:y_end, x_start:x_end].copy(),
|
|
42
|
+
'area': (x_start, y_start, x_end, y_end),
|
|
43
43
|
'description': description
|
|
44
44
|
}
|
|
45
45
|
if len(self.undo_stack) >= gui_constants.MAX_UNDO_SIZE:
|
|
@@ -54,6 +54,7 @@ class UndoManager(QObject):
|
|
|
54
54
|
return False
|
|
55
55
|
undo_state = self.undo_stack.pop()
|
|
56
56
|
x_start, y_start, x_end, y_end = undo_state['area']
|
|
57
|
+
self.set_paint_area(x_start, y_start, x_end, y_end)
|
|
57
58
|
redo_state = {
|
|
58
59
|
'master': layer[y_start:y_end, x_start:x_end].copy(),
|
|
59
60
|
'area': (x_start, y_start, x_end, y_end),
|
|
@@ -80,6 +81,7 @@ class UndoManager(QObject):
|
|
|
80
81
|
return False
|
|
81
82
|
redo_state = self.redo_stack.pop()
|
|
82
83
|
x_start, y_start, x_end, y_end = redo_state['area']
|
|
84
|
+
self.set_paint_area(x_start, y_start, x_end, y_end)
|
|
83
85
|
undo_state = {
|
|
84
86
|
'master': layer[y_start:y_end, x_start:x_end].copy(),
|
|
85
87
|
'area': (x_start, y_start, x_end, y_end),
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
# pylint: disable=C0114, C0115, C0116, E0611, W0221, R0902, R0914, R0913, R0917
|
|
2
|
-
from PySide6.QtWidgets import QHBoxLayout, QLabel, QSlider, QDialogButtonBox
|
|
3
|
-
from PySide6.QtCore import Qt, QTimer
|
|
4
2
|
from .. algorithms.sharpen import unsharp_mask
|
|
5
3
|
from .base_filter import BaseFilter
|
|
6
4
|
|
|
@@ -9,9 +7,11 @@ class UnsharpMaskFilter(BaseFilter):
|
|
|
9
7
|
def __init__(self, name, parent, image_viewer, layer_collection, undo_manager):
|
|
10
8
|
super().__init__(name, parent, image_viewer, layer_collection, undo_manager,
|
|
11
9
|
preview_at_startup=True)
|
|
12
|
-
self.
|
|
10
|
+
self.min_radius = 0.0
|
|
13
11
|
self.max_radius = 4.0
|
|
12
|
+
self.min_amount = 0.0
|
|
14
13
|
self.max_amount = 3.0
|
|
14
|
+
self.min_threshold = 0.0
|
|
15
15
|
self.max_threshold = 64.0
|
|
16
16
|
self.initial_radius = 1.0
|
|
17
17
|
self.initial_amount = 0.5
|
|
@@ -24,31 +24,20 @@ class UnsharpMaskFilter(BaseFilter):
|
|
|
24
24
|
dlg.setWindowTitle("Unsharp Mask")
|
|
25
25
|
dlg.setMinimumWidth(600)
|
|
26
26
|
params = {
|
|
27
|
-
"Radius": (self.max_radius, self.initial_radius, "{:.2f}"),
|
|
28
|
-
"Amount": (self.max_amount, self.initial_amount, "{:.1%}"),
|
|
29
|
-
"Threshold": (self.max_threshold, self.initial_threshold, "{:.2f}")
|
|
27
|
+
"Radius": (self.min_radius, self.max_radius, self.initial_radius, "{:.2f}"),
|
|
28
|
+
"Amount": (self.min_amount, self.max_amount, self.initial_amount, "{:.1%}"),
|
|
29
|
+
"Threshold": (self.min_threshold, self.max_threshold, self.initial_threshold, "{:.2f}")
|
|
30
30
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
param_layout = QHBoxLayout()
|
|
34
|
-
name_label = QLabel(f"{name}:")
|
|
35
|
-
param_layout.addWidget(name_label)
|
|
36
|
-
slider = QSlider(Qt.Horizontal)
|
|
37
|
-
slider.setRange(0, self.max_range)
|
|
38
|
-
slider.setValue(int(init_val / max_val * self.max_range))
|
|
39
|
-
param_layout.addWidget(slider)
|
|
40
|
-
value_label = QLabel(fmt.format(init_val))
|
|
41
|
-
param_layout.addWidget(value_label)
|
|
42
|
-
layout.addLayout(param_layout)
|
|
31
|
+
|
|
32
|
+
def set_slider(name, slider):
|
|
43
33
|
if name == "Radius":
|
|
44
34
|
self.radius_slider = slider
|
|
45
35
|
elif name == "Amount":
|
|
46
36
|
self.amount_slider = slider
|
|
47
37
|
elif name == "Threshold":
|
|
48
38
|
self.threshold_slider = slider
|
|
49
|
-
|
|
50
|
-
self.
|
|
51
|
-
layout, QDialogButtonBox.Ok | QDialogButtonBox.Cancel, 200, dlg)
|
|
39
|
+
|
|
40
|
+
value_labels = self.create_sliders(params, dlg, layout, set_slider)
|
|
52
41
|
|
|
53
42
|
def update_value(name, value, max_val, fmt):
|
|
54
43
|
float_value = max_val * value / self.max_range
|
|
@@ -57,16 +46,12 @@ class UnsharpMaskFilter(BaseFilter):
|
|
|
57
46
|
self.preview_timer.start()
|
|
58
47
|
|
|
59
48
|
self.radius_slider.valueChanged.connect(
|
|
60
|
-
lambda v: update_value("Radius", v, self.max_radius, params["Radius"][
|
|
49
|
+
lambda v: update_value("Radius", v, self.max_radius, params["Radius"][3]))
|
|
61
50
|
self.amount_slider.valueChanged.connect(
|
|
62
|
-
lambda v: update_value("Amount", v, self.max_amount, params["Amount"][
|
|
51
|
+
lambda v: update_value("Amount", v, self.max_amount, params["Amount"][3]))
|
|
63
52
|
self.threshold_slider.valueChanged.connect(
|
|
64
53
|
lambda v: update_value("Threshold", v, self.max_threshold, params["Threshold"][2]))
|
|
65
|
-
self.
|
|
66
|
-
self.connect_preview_toggle(self.preview_check, do_preview, restore_original)
|
|
67
|
-
self.button_box.accepted.connect(dlg.accept)
|
|
68
|
-
self.button_box.rejected.connect(dlg.reject)
|
|
69
|
-
QTimer.singleShot(0, do_preview)
|
|
54
|
+
self.set_timer(do_preview, restore_original, dlg)
|
|
70
55
|
|
|
71
56
|
def get_params(self):
|
|
72
57
|
return (
|
|
@@ -79,10 +79,9 @@ class BrushCursor(QGraphicsItemGroup):
|
|
|
79
79
|
|
|
80
80
|
class ViewSignals:
|
|
81
81
|
temp_view_requested = Signal(bool)
|
|
82
|
-
|
|
83
|
-
brush_operation_continued = Signal(QPoint)
|
|
84
|
-
brush_operation_ended = Signal()
|
|
82
|
+
end_copy_brush_area_requested = Signal()
|
|
85
83
|
brush_size_change_requested = Signal(int) # +1 or -1
|
|
84
|
+
needs_update_requested = Signal()
|
|
86
85
|
|
|
87
86
|
|
|
88
87
|
class ImageGraphicsViewBase(QGraphicsView):
|
|
@@ -103,9 +102,12 @@ class ImageGraphicsViewBase(QGraphicsView):
|
|
|
103
102
|
|
|
104
103
|
|
|
105
104
|
class ViewStrategy(LayerCollectionHandler):
|
|
106
|
-
def __init__(self, layer_collection, status):
|
|
105
|
+
def __init__(self, layer_collection, status, brush_tool, paint_area_manager):
|
|
107
106
|
LayerCollectionHandler.__init__(self, layer_collection)
|
|
108
107
|
self.status = status
|
|
108
|
+
self.brush_tool = brush_tool
|
|
109
|
+
self.paint_area_manager = paint_area_manager
|
|
110
|
+
self.mask_layer = None
|
|
109
111
|
self.brush = None
|
|
110
112
|
self.brush_cursor = None
|
|
111
113
|
self.brush_preview = BrushPreviewItem(layer_collection)
|
|
@@ -123,6 +125,7 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
123
125
|
self.last_update_time = QTime.currentTime()
|
|
124
126
|
self.last_color_update_time = 0
|
|
125
127
|
self.last_cursor_update_time = 0
|
|
128
|
+
self.enable_paint = True
|
|
126
129
|
|
|
127
130
|
@abstractmethod
|
|
128
131
|
def create_pixmaps(self):
|
|
@@ -274,6 +277,25 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
274
277
|
view.verticalScrollBar().setValue(self.status.v_scroll)
|
|
275
278
|
self.arrange_images()
|
|
276
279
|
|
|
280
|
+
def update_master_display_area(self):
|
|
281
|
+
if self.empty():
|
|
282
|
+
return
|
|
283
|
+
x_start, y_start, x_end, y_end = self.paint_area_manager.area()
|
|
284
|
+
dirty_region = self.master_layer()[y_start:y_end, x_start:x_end]
|
|
285
|
+
qimage = self.numpy_to_qimage(dirty_region)
|
|
286
|
+
if not qimage:
|
|
287
|
+
return
|
|
288
|
+
pixmap = QPixmap.fromImage(qimage)
|
|
289
|
+
master_pixmap_item = self.get_master_pixmap()
|
|
290
|
+
current_pixmap = master_pixmap_item.pixmap()
|
|
291
|
+
if current_pixmap.isNull():
|
|
292
|
+
self.update_master_display()
|
|
293
|
+
return
|
|
294
|
+
painter = QPainter(current_pixmap)
|
|
295
|
+
painter.drawPixmap(x_start, y_start, pixmap)
|
|
296
|
+
painter.end()
|
|
297
|
+
master_pixmap_item.setPixmap(current_pixmap)
|
|
298
|
+
|
|
277
299
|
def update_master_display(self):
|
|
278
300
|
self.update_view_display(
|
|
279
301
|
self.master_layer(),
|
|
@@ -698,6 +720,42 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
698
720
|
self.status.set_scroll(view.horizontalScrollBar().value(),
|
|
699
721
|
view.verticalScrollBar().value())
|
|
700
722
|
|
|
723
|
+
def copy_brush_area_to_master(self, view_pos):
|
|
724
|
+
if self.layer_stack() is None or self.number_of_layers() == 0:
|
|
725
|
+
return
|
|
726
|
+
area = self.brush_tool.apply_brush_operation(
|
|
727
|
+
self.master_layer_copy(),
|
|
728
|
+
self.current_layer(),
|
|
729
|
+
self.master_layer(), self.mask_layer,
|
|
730
|
+
view_pos)
|
|
731
|
+
self.paint_area_manager.extend(*area)
|
|
732
|
+
|
|
733
|
+
def begin_copy_brush_area(self, pos):
|
|
734
|
+
self.mask_layer = self.blank_layer().copy()
|
|
735
|
+
self.copy_master_layer()
|
|
736
|
+
self.paint_area_manager.reset()
|
|
737
|
+
self.copy_brush_area_to_master(pos)
|
|
738
|
+
self.needs_update_requested.emit()
|
|
739
|
+
|
|
740
|
+
def continue_copy_brush_area(self, pos):
|
|
741
|
+
self.copy_brush_area_to_master(pos)
|
|
742
|
+
self.needs_update_requested.emit()
|
|
743
|
+
|
|
744
|
+
def mouse_press_event(self, event):
|
|
745
|
+
if self.empty():
|
|
746
|
+
return
|
|
747
|
+
if self.enable_paint and event.button() & Qt.LeftButton and self.has_master_layer():
|
|
748
|
+
if self.space_pressed:
|
|
749
|
+
self.scrolling = True
|
|
750
|
+
self.last_mouse_pos = event.position()
|
|
751
|
+
self.setCursor(Qt.ClosedHandCursor)
|
|
752
|
+
else:
|
|
753
|
+
self.last_brush_pos = event.position()
|
|
754
|
+
self.begin_copy_brush_area(event.position().toPoint())
|
|
755
|
+
self.dragging = True
|
|
756
|
+
if not self.scrolling:
|
|
757
|
+
self.show_brush_cursor()
|
|
758
|
+
|
|
701
759
|
def mouse_move_event(self, event):
|
|
702
760
|
if self.empty():
|
|
703
761
|
return
|
|
@@ -710,7 +768,7 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
710
768
|
brush_size = self.brush.size
|
|
711
769
|
if not self.space_pressed:
|
|
712
770
|
self.update_brush_cursor()
|
|
713
|
-
if self.dragging and event.buttons() & Qt.LeftButton:
|
|
771
|
+
if self.enable_paint and self.dragging and event.buttons() & Qt.LeftButton:
|
|
714
772
|
current_time = QTime.currentTime()
|
|
715
773
|
paint_refresh_time = AppConfig.get('paint_refresh_time')
|
|
716
774
|
if self.last_update_time.msecsTo(current_time) >= paint_refresh_time:
|
|
@@ -726,7 +784,7 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
726
784
|
for i in range(0, n_steps + 1):
|
|
727
785
|
pos = QPoint(self.last_brush_pos.x() + i * delta_x,
|
|
728
786
|
self.last_brush_pos.y() + i * delta_y)
|
|
729
|
-
self.
|
|
787
|
+
self.continue_copy_brush_area(pos)
|
|
730
788
|
self.last_brush_pos = position
|
|
731
789
|
self.last_update_time = current_time
|
|
732
790
|
if self.scrolling and event.buttons() & Qt.LeftButton:
|
|
@@ -738,21 +796,6 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
738
796
|
self.last_mouse_pos = position
|
|
739
797
|
self.scroll_view(master_view, delta.x(), delta.y())
|
|
740
798
|
|
|
741
|
-
def mouse_press_event(self, event):
|
|
742
|
-
if self.empty():
|
|
743
|
-
return
|
|
744
|
-
if event.button() == Qt.LeftButton and self.has_master_layer():
|
|
745
|
-
if self.space_pressed:
|
|
746
|
-
self.scrolling = True
|
|
747
|
-
self.last_mouse_pos = event.position()
|
|
748
|
-
self.setCursor(Qt.ClosedHandCursor)
|
|
749
|
-
else:
|
|
750
|
-
self.last_brush_pos = event.position()
|
|
751
|
-
self.brush_operation_started.emit(event.position().toPoint())
|
|
752
|
-
self.dragging = True
|
|
753
|
-
if not self.scrolling:
|
|
754
|
-
self.show_brush_cursor()
|
|
755
|
-
|
|
756
799
|
def mouse_release_event(self, event):
|
|
757
800
|
if self.empty():
|
|
758
801
|
return
|
|
@@ -769,4 +812,4 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
769
812
|
self.last_mouse_pos = None
|
|
770
813
|
elif self.dragging:
|
|
771
814
|
self.dragging = False
|
|
772
|
-
self.
|
|
815
|
+
self.end_copy_brush_area_requested.emit()
|
|
@@ -9,7 +9,7 @@ from .base_filter import OneSliderBaseFilter
|
|
|
9
9
|
class VignettingFilter(OneSliderBaseFilter):
|
|
10
10
|
def __init__(self, name, parent, image_viewer, layer_collection, undo_manager):
|
|
11
11
|
super().__init__(name, parent, image_viewer, layer_collection, undo_manager,
|
|
12
|
-
1.0, 0.90, "Vignetting correction",
|
|
12
|
+
0.0, 1.0, 0.90, "Vignetting correction",
|
|
13
13
|
allow_partial_preview=False, preview_at_startup=False)
|
|
14
14
|
self.subsample_box = None
|
|
15
15
|
self.fast_subsampling_check = None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: shinestacker
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.7.0
|
|
4
4
|
Summary: ShineStacker
|
|
5
5
|
Author-email: Luca Lista <luka.lista@gmail.com>
|
|
6
6
|
License-Expression: LGPL-3.0
|
|
@@ -85,7 +85,7 @@ In order to prevent this, follow the instructions below:
|
|
|
85
85
|
1. Download the compressed archive ```shinestacker-macos.tar.gz``` in your ```Download``` folder.
|
|
86
86
|
2. Double-click the archive to uncompress it. You will find a new folder ```shinestacker```.
|
|
87
87
|
3. Open a terminal (*Applications > Utilities > Terminal*)
|
|
88
|
-
4. Type the folliwng command on the terminal:
|
|
88
|
+
4. Type the folliwng command on the terminal (assuming you have expanded the ```tar.gz``` under ```Downloads```):
|
|
89
89
|
```bash
|
|
90
90
|
xattr -cr ~/Downloads/shinestacker/shinestacker.app
|
|
91
91
|
```
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
shinestacker/__init__.py,sha256=uq2fjAw2z_6TpH3mOcWFZ98GoEPRsNhTAK8N0MMm_e8,448
|
|
2
|
-
shinestacker/_version.py,sha256=
|
|
2
|
+
shinestacker/_version.py,sha256=ZUl2xcRi75lbPrlvl0NxpUt61vfrXEhe0YCcbPhhIX0,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
|
|
6
6
|
shinestacker/algorithms/align_parallel.py,sha256=5ru4HDcUObLNDP8bPUgsgwpLyflpcyVA16pPqHpYZfs,17671
|
|
7
7
|
shinestacker/algorithms/balance.py,sha256=aoqnc1u5A2C3R7fKaOoKnzudRiOT8GRIu4LEP-uzyZQ,24053
|
|
8
8
|
shinestacker/algorithms/base_stack_algo.py,sha256=RzxvLDHqxqhnAl83u2onjvfsRea1qGK_blbh2Vo0kxA,2670
|
|
9
|
+
shinestacker/algorithms/corrections.py,sha256=DrfLM33D20l4svuuBtoOiH-KGUH_BL1mAV7mHCA_nGA,1094
|
|
9
10
|
shinestacker/algorithms/denoise.py,sha256=GL3Z4_6MHxSa7Wo4ZzQECZS87tHBFqO0sIVF_jPuYQU,426
|
|
10
11
|
shinestacker/algorithms/depth_map.py,sha256=nRBrZQWbdUqFOtYMEQx9UNdnybrBTeAOr1eV91FlN8U,5611
|
|
11
12
|
shinestacker/algorithms/exif.py,sha256=SM4ZDDe8hCJ3xY6053FNndOiwzEStzdp0WrXurlcHVc,9429
|
|
@@ -22,13 +23,13 @@ shinestacker/algorithms/vignetting.py,sha256=gJOv-FN3GnTgaVn70W_6d-qbw3WmqinDiO9
|
|
|
22
23
|
shinestacker/algorithms/white_balance.py,sha256=PMKsBtxOSn5aRr_Gkx1StHS4eN6kBN2EhNnhg4UG24g,501
|
|
23
24
|
shinestacker/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
24
25
|
shinestacker/app/about_dialog.py,sha256=pkH7nnxUP8yc0D3vRGd1jRb5cwi1nDVbQRk_OC9yLk8,4144
|
|
25
|
-
shinestacker/app/args_parser_opts.py,sha256=
|
|
26
|
-
shinestacker/app/gui_utils.py,sha256=
|
|
26
|
+
shinestacker/app/args_parser_opts.py,sha256=G3jQjxBYk87ycmyf8Idk40c5H90O1l0owz0asTodm88,2183
|
|
27
|
+
shinestacker/app/gui_utils.py,sha256=rNDtC6vQ1hAJ5F3Vd-VKglCE06mhleu5eiw-oitgnxU,3656
|
|
27
28
|
shinestacker/app/help_menu.py,sha256=g8lKG_xZmXtNQaC3SIRzyROKVWva_PLEgZsQWh6zUcQ,499
|
|
28
|
-
shinestacker/app/main.py,sha256=
|
|
29
|
+
shinestacker/app/main.py,sha256=c9_rax1eemOfkJqWV7tT7-ZkEBkqz6n4kBST8iXsjD4,10662
|
|
29
30
|
shinestacker/app/open_frames.py,sha256=bsu32iJSYJQLe_tQQbvAU5DuMDVX6MRuNdE7B5lojZc,1488
|
|
30
|
-
shinestacker/app/project.py,sha256=
|
|
31
|
-
shinestacker/app/retouch.py,sha256=
|
|
31
|
+
shinestacker/app/project.py,sha256=nwvXllD2FBLQ4ChePQdIGVug46Wh2ubjrJ0sC7klops,2596
|
|
32
|
+
shinestacker/app/retouch.py,sha256=8XcYMv7-feG6yxNCpvlijZQRPlhmRK0OfZO5MuBju-0,2552
|
|
32
33
|
shinestacker/app/settings_dialog.py,sha256=0P3nqqZEiTIFgidW1_e3Q_zE7NbAouNsuj-yNsU41vk,8192
|
|
33
34
|
shinestacker/config/__init__.py,sha256=aXxi-LmAvXd0daIFrVnTHE5OCaYeK1uf1BKMr7oaXQs,197
|
|
34
35
|
shinestacker/config/app_config.py,sha256=rM1Rndk1GDa5c0AhcVNEN9zSAzxPZixzQYfjODbJUwE,771
|
|
@@ -38,10 +39,10 @@ shinestacker/config/gui_constants.py,sha256=PNxzwmVEppJ2mV_vwp68NhWzJOEitVy1Pk9S
|
|
|
38
39
|
shinestacker/config/settings.py,sha256=4p4r6wKOCbttzfH9tyHQSTd-iv-GfgCd1LxI3C7WIjU,3861
|
|
39
40
|
shinestacker/core/__init__.py,sha256=IUEIx6SQ3DygDEHN3_E6uKpHjHtUa4a_U_1dLd_8yEU,484
|
|
40
41
|
shinestacker/core/colors.py,sha256=kr_tJA1iRsdck2JaYDb2lS-codZ4Ty9gdu3kHfiWvuM,1340
|
|
41
|
-
shinestacker/core/core_utils.py,sha256=
|
|
42
|
+
shinestacker/core/core_utils.py,sha256=0x9iK9_iPQuj3BwF_QdWoxWTM-jyQytO57BvTQLdwmw,1378
|
|
42
43
|
shinestacker/core/exceptions.py,sha256=2-noG-ORAGdvDhL8jBQFs0xxZS4fI6UIkMqrWekgk2c,1618
|
|
43
44
|
shinestacker/core/framework.py,sha256=QaTfnzEUHwzlbyFG7KzeyteckTSWHWEEJE4d5Tc8H18,11015
|
|
44
|
-
shinestacker/core/logging.py,sha256=
|
|
45
|
+
shinestacker/core/logging.py,sha256=pN4FGcHwI5ouJKwCVoDWQx_Tg3t84mmPh0xhqszDDkw,3111
|
|
45
46
|
shinestacker/gui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
46
47
|
shinestacker/gui/action_config.py,sha256=Xv7SGbhPl1F_dUnU04VBt_E-wIItnN_q6QuhU_d9GfI,25929
|
|
47
48
|
shinestacker/gui/action_config_dialog.py,sha256=QN95FiVPYL6uin2sYO5F7tq6G5rBWh9yRkeTVvwKrwU,38341
|
|
@@ -63,47 +64,49 @@ shinestacker/gui/project_model.py,sha256=9dId8N-np4YHDpz_wO20Mvd06np3YKlej-0TMWa
|
|
|
63
64
|
shinestacker/gui/recent_file_manager.py,sha256=010bciuirKLiVCfOAKs0uFlB3iUjHNBlPX_9K2vH5j0,2916
|
|
64
65
|
shinestacker/gui/select_path_widget.py,sha256=HSwgSr702w5Et4c-6nkRXnIpm1KFqKJetAF5xQNa5zI,1017
|
|
65
66
|
shinestacker/gui/sys_mon.py,sha256=zU41YYVeqQ1-v6oGIh2_BFzQWq87keN-398Wdm59-Nk,3526
|
|
66
|
-
shinestacker/gui/tab_widget.py,sha256=
|
|
67
|
+
shinestacker/gui/tab_widget.py,sha256=Hu01_neCxTOG9TMGSI-Ha1w4brp1bEXyvxS24Gi_JS8,2786
|
|
67
68
|
shinestacker/gui/time_progress_bar.py,sha256=7_sllrQgayjRh__mwJ0-4lghXIakuRAx8wWucJ6olYs,3028
|
|
68
|
-
shinestacker/gui/ico/
|
|
69
|
-
shinestacker/gui/ico/shinestacker.icns,sha256=3IshIOv0uFexYsAEPkE9xiyuw8mB5X5gffekOUhFlt0,45278
|
|
69
|
+
shinestacker/gui/ico/shinestacker.icns,sha256=lKmyIUBTjpMQ6Cajcov6WA5neAbZS9-JN5ca02nCz5I,204834
|
|
70
70
|
shinestacker/gui/ico/shinestacker.ico,sha256=8IMRk-toObWUz8iDXA-zHBWQ8Ps3vXN5u5ZEyw7sP3c,109613
|
|
71
71
|
shinestacker/gui/ico/shinestacker.png,sha256=VybGY-nig_-wMW8g_uImGxRYvcnltWcAVEPSX6AZUHM,22448
|
|
72
72
|
shinestacker/gui/ico/shinestacker.svg,sha256=r8jx5aiIT9K70MRP0ANWniFE0ctRCqH7LMQ7vcGJ8ss,6571
|
|
73
|
+
shinestacker/gui/ico/shinestacker_bkg.png,sha256=C91Ek4bm8hPcit4JUac8FAjRTQsHfiKIKPTZMweHKqo,10462
|
|
73
74
|
shinestacker/gui/img/close-round-line-icon.png,sha256=9HZwCjgni1s_JGUPUb_MoOfoe4tRZgM5OWzk92XFZlE,8019
|
|
74
75
|
shinestacker/gui/img/forward-button-icon.png,sha256=lNw86T4TOEd_uokHYF8myGSGUXzdsHvmDAjlbE18Pgo,4788
|
|
75
76
|
shinestacker/gui/img/play-button-round-icon.png,sha256=9j6Ks9mOGa-2cXyRFpimepAAvSaHzqJKBfxShRb4_dE,4595
|
|
76
77
|
shinestacker/gui/img/plus-round-line-icon.png,sha256=LS068Hlu-CeBvJuB3dwwdJg1lZq6D5MUIv53lu1yKJA,7534
|
|
77
78
|
shinestacker/retouch/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
78
|
-
shinestacker/retouch/
|
|
79
|
+
shinestacker/retouch/adjustments.py,sha256=tNroGN7zjr4SsMJpB-ciSHUUOWgUWai8CChWgxZpr6Q,3826
|
|
80
|
+
shinestacker/retouch/base_filter.py,sha256=o_OkJbdD3jOGY--_sGL1_WqAMQI-QHGw-EEYxGhXOaQ,13976
|
|
79
81
|
shinestacker/retouch/brush.py,sha256=dzD2FzSpBIPdJRmTZobcrQ1FrVd3tF__ZPnUplNE72s,357
|
|
80
82
|
shinestacker/retouch/brush_gradient.py,sha256=F5SFhyzl8YTMqjJU3jK8BrIlLCYLUvITd5wz3cQE4xk,1453
|
|
81
83
|
shinestacker/retouch/brush_preview.py,sha256=cOFVMCbEsgR_alzmr_-LLghtGU_unrE-hAjLHcvrZAY,5484
|
|
82
84
|
shinestacker/retouch/brush_tool.py,sha256=8uVncTA375uC3Nhp2YM0eZjpOR-nN47i2eGjN8tJzOU,8714
|
|
83
|
-
shinestacker/retouch/denoise_filter.py,sha256=
|
|
84
|
-
shinestacker/retouch/display_manager.py,sha256=
|
|
85
|
+
shinestacker/retouch/denoise_filter.py,sha256=QVXFU54MDcylNWtiIcdQSZ3eClW_xNWZhCMIeoEQ8zk,576
|
|
86
|
+
shinestacker/retouch/display_manager.py,sha256=fTZTGbvmX5DXagexuvbNgOF5GiH2Vv-stLUQQwoglp8,10181
|
|
85
87
|
shinestacker/retouch/exif_data.py,sha256=LF-fRXW-reMq-xJ_QRE5j8DC2LVGKIlC6MR3QbC1cdg,1896
|
|
86
88
|
shinestacker/retouch/file_loader.py,sha256=z02-A8_uDZxayI1NFTxT2GVUvEBWStchX9hlN1o5-0U,4784
|
|
87
89
|
shinestacker/retouch/filter_manager.py,sha256=tOGIWj5HjViL1-iXHkd91X-sZ1c1G531pDmLO0x6zx0,866
|
|
88
90
|
shinestacker/retouch/icon_container.py,sha256=6gw1HO1bC2FrdB4dc_iH81DQuLjzuvRGksZ2hKLT9yA,585
|
|
89
|
-
shinestacker/retouch/image_editor_ui.py,sha256=
|
|
91
|
+
shinestacker/retouch/image_editor_ui.py,sha256=w6tyeYm1Arjyr-MxbLNKYvURV0qEZqigK0iUoqGy92o,34244
|
|
90
92
|
shinestacker/retouch/image_view_status.py,sha256=2rWi2ugdyjMhWCtRJkwOnb7-tCtVfnGfCY_54qpZhwM,1970
|
|
91
|
-
shinestacker/retouch/image_viewer.py,sha256=
|
|
92
|
-
shinestacker/retouch/io_gui_handler.py,sha256=
|
|
93
|
-
shinestacker/retouch/
|
|
94
|
-
shinestacker/retouch/layer_collection.py,sha256=
|
|
95
|
-
shinestacker/retouch/overlaid_view.py,sha256=
|
|
93
|
+
shinestacker/retouch/image_viewer.py,sha256=xf1vYZRPb9ClCQbqrqAFhPubdqIIpku7DgcY8O5bvYU,4694
|
|
94
|
+
shinestacker/retouch/io_gui_handler.py,sha256=tyHMmR6_uE_IEI-CIcJibVhupxarKYHzX2fuhnesHaI,14616
|
|
95
|
+
shinestacker/retouch/io_threads.py,sha256=r0X4it2PfwnmiAU7eStniIfcHhPvuaqdqf5VlnvjZ-4,2832
|
|
96
|
+
shinestacker/retouch/layer_collection.py,sha256=xx8INSLCXIeTQn_nxfCo4QljAmQK1qukSYO1Zk4rqqo,6183
|
|
97
|
+
shinestacker/retouch/overlaid_view.py,sha256=QTTdegUWs99YBZZPlIRdPI5O80U3t_c3HnyegbRqNbA,7029
|
|
98
|
+
shinestacker/retouch/paint_area_manager.py,sha256=ilK6uQT7lzNyvdc8uNv4xTHHHAbk5hGEClJRNmiA4P8,894
|
|
96
99
|
shinestacker/retouch/shortcuts_help.py,sha256=BFWTT5QvodqMhqa_9LI25hZqjICfckgyWG4fGrGzvnM,4283
|
|
97
|
-
shinestacker/retouch/sidebyside_view.py,sha256=
|
|
98
|
-
shinestacker/retouch/transformation_manager.py,sha256=
|
|
99
|
-
shinestacker/retouch/undo_manager.py,sha256=
|
|
100
|
-
shinestacker/retouch/unsharp_mask_filter.py,sha256=
|
|
101
|
-
shinestacker/retouch/view_strategy.py,sha256=
|
|
102
|
-
shinestacker/retouch/vignetting_filter.py,sha256=
|
|
100
|
+
shinestacker/retouch/sidebyside_view.py,sha256=4sNa_IUMbNH18iECO7eDO9S_ls3v2ENwP1AWrBFhofI,18907
|
|
101
|
+
shinestacker/retouch/transformation_manager.py,sha256=QFYCL-l9V6qlhw3y7tcs0saWWClNPsh7F9pTBkfPbRU,1711
|
|
102
|
+
shinestacker/retouch/undo_manager.py,sha256=J4hEAnv9bKLQ0N1wllWswjJBhgRgasCnBoMT5LEw-dM,4453
|
|
103
|
+
shinestacker/retouch/unsharp_mask_filter.py,sha256=SO-6ZgPPDAO9em_MMefVvvSvt01-2gm1HF6OBsShmL4,2795
|
|
104
|
+
shinestacker/retouch/view_strategy.py,sha256=jZxB_vX3_0notH0ClxKkLzbdtx4is3vQiYoIP-sDv3M,30216
|
|
105
|
+
shinestacker/retouch/vignetting_filter.py,sha256=M7PZGPdVSq4bqo6wkEznrILMIG3-mTT7iwpgK4Hieyg,3794
|
|
103
106
|
shinestacker/retouch/white_balance_filter.py,sha256=UaH4yxG3fU4vPutBAkV5oTXIQyUTN09x0uTywAzv3sY,8286
|
|
104
|
-
shinestacker-1.
|
|
105
|
-
shinestacker-1.
|
|
106
|
-
shinestacker-1.
|
|
107
|
-
shinestacker-1.
|
|
108
|
-
shinestacker-1.
|
|
109
|
-
shinestacker-1.
|
|
107
|
+
shinestacker-1.7.0.dist-info/licenses/LICENSE,sha256=pWgb-bBdsU2Gd2kwAXxketnm5W_2u8_fIeWEgojfrxs,7651
|
|
108
|
+
shinestacker-1.7.0.dist-info/METADATA,sha256=mAPgYAr3pS4P6hdAXRB-WBoYKXJZLRvADmX1CE0tDjA,7046
|
|
109
|
+
shinestacker-1.7.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
110
|
+
shinestacker-1.7.0.dist-info/entry_points.txt,sha256=SY6g1LqtMmp23q1DGwLUDT_dhLX9iss8DvWkiWLyo_4,166
|
|
111
|
+
shinestacker-1.7.0.dist-info/top_level.txt,sha256=MhijwnBVX5psfsyX8JZjqp3SYiWPsKe69f3Gnyze4Fw,13
|
|
112
|
+
shinestacker-1.7.0.dist-info/RECORD,,
|
|
Binary file
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
# pylint: disable=E1101, C0114, C0115, C0116, E0611, W0718, R0903
|
|
2
|
-
import traceback
|
|
3
|
-
import cv2
|
|
4
|
-
from PySide6.QtCore import QThread, Signal
|
|
5
|
-
from .. algorithms.utils import read_img, validate_image, get_img_metadata
|
|
6
|
-
from .. algorithms.exif import get_exif, write_image_with_exif_data
|
|
7
|
-
from .. algorithms.multilayer import write_multilayer_tiff_from_images
|
|
8
|
-
from .layer_collection import LayerCollectionHandler
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class FileMultilayerSaver(QThread):
|
|
12
|
-
finished = Signal()
|
|
13
|
-
error = Signal(str)
|
|
14
|
-
|
|
15
|
-
def __init__(self, images_dict, path, exif_path=None):
|
|
16
|
-
super().__init__()
|
|
17
|
-
self.images_dict = images_dict
|
|
18
|
-
self.path = path
|
|
19
|
-
self.exif_path = exif_path
|
|
20
|
-
|
|
21
|
-
def run(self):
|
|
22
|
-
try:
|
|
23
|
-
write_multilayer_tiff_from_images(
|
|
24
|
-
self.images_dict, self.path, exif_path=self.exif_path)
|
|
25
|
-
self.finished.emit()
|
|
26
|
-
except Exception as e:
|
|
27
|
-
traceback.print_tb(e.__traceback__)
|
|
28
|
-
self.error.emit(str(e))
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
class IOManager(LayerCollectionHandler):
|
|
32
|
-
def __init__(self, layer_collection):
|
|
33
|
-
super().__init__(layer_collection)
|
|
34
|
-
self.exif_path = ''
|
|
35
|
-
self.exif_data = None
|
|
36
|
-
|
|
37
|
-
def import_frames(self, file_paths):
|
|
38
|
-
stack = []
|
|
39
|
-
labels = []
|
|
40
|
-
master = None
|
|
41
|
-
shape, dtype = get_img_metadata(self.master_layer())
|
|
42
|
-
for path in file_paths:
|
|
43
|
-
try:
|
|
44
|
-
label = path.split("/")[-1].split(".")[0]
|
|
45
|
-
img = cv2.cvtColor(read_img(path), cv2.COLOR_BGR2RGB)
|
|
46
|
-
if shape is not None and dtype is not None:
|
|
47
|
-
validate_image(img, shape, dtype)
|
|
48
|
-
else:
|
|
49
|
-
shape, dtype = get_img_metadata(img)
|
|
50
|
-
label_x = label
|
|
51
|
-
i = 0
|
|
52
|
-
while label_x in labels:
|
|
53
|
-
i += 1
|
|
54
|
-
label_x = f"{label} ({i})"
|
|
55
|
-
labels.append(label_x)
|
|
56
|
-
stack.append(img)
|
|
57
|
-
if master is None:
|
|
58
|
-
master = img.copy()
|
|
59
|
-
except Exception as e:
|
|
60
|
-
raise RuntimeError(f"Error loading file: {path}.\n{str(e)}") from e
|
|
61
|
-
return stack, labels, master
|
|
62
|
-
|
|
63
|
-
def save_master(self, path):
|
|
64
|
-
img = cv2.cvtColor(self.master_layer(), cv2.COLOR_RGB2BGR)
|
|
65
|
-
write_image_with_exif_data(self.exif_data, img, path)
|
|
66
|
-
|
|
67
|
-
def set_exif_data(self, path):
|
|
68
|
-
self.exif_path = path
|
|
69
|
-
self.exif_data = get_exif(path)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|