shinestacker 1.9.1__py3-none-any.whl → 1.9.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.

@@ -82,6 +82,10 @@ class FocusStackBase(TaskBase, ImageSequenceManager):
82
82
 
83
83
 
84
84
  def get_bunches(collection, n_frames, n_overlap):
85
+ if n_frames == n_overlap:
86
+ raise RuntimeError(
87
+ f"Can't get bunch collection, total number of frames ({n_frames}) "
88
+ "is equal to the number of overlapping grames")
85
89
  bunches = [collection[x:x + n_frames]
86
90
  for x in range(0, len(collection) - n_overlap, n_frames - n_overlap)]
87
91
  return bunches
@@ -109,7 +113,7 @@ class FocusStackBunch(SequentialTask, FocusStackBase):
109
113
 
110
114
  def begin(self):
111
115
  SequentialTask.begin(self)
112
- self._chunks = get_bunches(self.input_filepaths(), self.frames, self.overlap)
116
+ self._chunks = get_bunches(sorted(self.input_filepaths()), self.frames, self.overlap)
113
117
  self.set_counts(len(self._chunks))
114
118
 
115
119
  def end(self):
@@ -122,9 +126,9 @@ class FocusStackBunch(SequentialTask, FocusStackBase):
122
126
  self.print_message(
123
127
  color_str(f"fusing bunch: {action_count + 1}/{self.total_action_counts}",
124
128
  constants.LOG_COLOR_LEVEL_2))
125
- img_files = self._chunks[action_count - 1]
129
+ img_files = self._chunks[action_count]
126
130
  self.stack_algo.init(img_files)
127
- self.focus_stack(self._chunks[action_count - 1])
131
+ self.focus_stack(self._chunks[action_count])
128
132
  return True
129
133
 
130
134
 
@@ -318,6 +318,12 @@ class MainWindow(QMainWindow, LogManager):
318
318
  edit_config_action.triggered.connect(self.edit_current_action)
319
319
  menu.addAction(edit_config_action)
320
320
  menu.addSeparator()
321
+ menu.addAction(self.menu_manager.cut_action)
322
+ menu.addAction(self.menu_manager.copy_action)
323
+ menu.addAction(self.menu_manager.paste_action)
324
+ menu.addAction(self.menu_manager.duplicate_action)
325
+ menu.addAction(self.menu_manager.delete_element_action)
326
+ menu.addSeparator()
321
327
  menu.addAction(self.menu_manager.run_job_action)
322
328
  menu.addAction(self.menu_manager.run_all_jobs_action)
323
329
  menu.addSeparator()
@@ -123,8 +123,14 @@ class MenuManager(QObject):
123
123
  self.undo_action = self.action("&Undo")
124
124
  self.undo_action.setEnabled(False)
125
125
  menu.addAction(self.undo_action)
126
- for name in ["&Cut", "Cop&y", "&Paste", "Duplicate"]:
127
- menu.addAction(self.action(name, requires_file=True))
126
+ self.cut_action = self.action("&Cut", requires_file=True)
127
+ menu.addAction(self.cut_action)
128
+ self.copy_action = self.action("Cop&y", requires_file=True)
129
+ menu.addAction(self.copy_action)
130
+ self.paste_action = self.action("&Paste", requires_file=True)
131
+ menu.addAction(self.paste_action)
132
+ self.duplicate_action = self.action("Duplicate", requires_file=True)
133
+ menu.addAction(self.duplicate_action)
128
134
  self.delete_element_action = self.action("Delete", requires_file=True)
129
135
  self.delete_element_action.setEnabled(False)
130
136
  menu.addAction(self.delete_element_action)
@@ -245,6 +245,7 @@ class ProjectController(QObject):
245
245
  self.add_job_to_project(job)
246
246
  self.project_editor.set_modified(True)
247
247
  self.refresh_ui(0, -1)
248
+ self.set_enabled_file_open_close_actions_requested.emit(True)
248
249
 
249
250
  def open_project(self, file_path=False):
250
251
  if not self.check_unsaved_changes():
@@ -75,6 +75,26 @@ class BrushTool:
75
75
  self.hardness_slider.setValue(val)
76
76
  self.update_brush_hardness(val)
77
77
 
78
+ def increase_brush_opacity(self, amount=2):
79
+ val = min(self.opacity_slider.value() + amount, self.opacity_slider.maximum())
80
+ self.opacity_slider.setValue(val)
81
+ self.update_brush_opacity(val)
82
+
83
+ def decrease_brush_opacity(self, amount=2):
84
+ val = max(self.opacity_slider.value() - amount, self.opacity_slider.minimum())
85
+ self.opacity_slider.setValue(val)
86
+ self.update_brush_opacity(val)
87
+
88
+ def increase_brush_flow(self, amount=2):
89
+ val = min(self.flow_slider.value() + amount, self.flow_slider.maximum())
90
+ self.flow_slider.setValue(val)
91
+ self.update_brush_flow(val)
92
+
93
+ def decrease_brush_flow(self, amount=2):
94
+ val = max(self.flow_slider.value() - amount, self.flow_slider.minimum())
95
+ self.flow_slider.setValue(val)
96
+ self.update_brush_flow(val)
97
+
78
98
  def update_brush_hardness(self, hardness):
79
99
  self.brush.hardness = hardness
80
100
  self.update_brush_thumb()
@@ -1,4 +1,5 @@
1
- # pylint: disable=C0114, C0115, C0116, E0611, W0718
1
+ # pylint: disable=C0114, C0115, C0116, E0611, W0718, R0912
2
+ from fractions import Fraction
2
3
  from xml.dom import minidom
3
4
  from PIL.TiffImagePlugin import IFDRational
4
5
  from PySide6.QtWidgets import QLabel, QTextEdit
@@ -18,6 +19,42 @@ class ExifData(ConfigDialog):
18
19
  self.ok_button.setFixedWidth(100)
19
20
  self.button_box.setAlignment(Qt.AlignCenter)
20
21
 
22
+ def format_aperture(self, value):
23
+ if isinstance(value, IFDRational):
24
+ if value.denominator == 0:
25
+ return "f/>1024"
26
+ aperture_value = value.numerator / value.denominator
27
+ return f"f/{aperture_value:.1f}"
28
+ if isinstance(value, (int, float)):
29
+ return f"f/{float(value):.1f}"
30
+ return str(value)
31
+
32
+ def format_exposure_time(self, value):
33
+ if isinstance(value, IFDRational):
34
+ exposure_time = value.numerator / value.denominator
35
+ elif isinstance(value, (int, float)):
36
+ exposure_time = float(value)
37
+ else:
38
+ return str(value)
39
+ if exposure_time >= 0.5:
40
+ return f"{exposure_time:.1f} s"
41
+ if isinstance(value, IFDRational):
42
+ return f"{value.numerator}/{value.denominator} s"
43
+ frac = Fraction(exposure_time).limit_denominator(1000)
44
+ return f"{frac.numerator}/{frac.denominator} s"
45
+
46
+ def format_date_time(self, value):
47
+ if not isinstance(value, str):
48
+ return str(value)
49
+ try:
50
+ if ':' in value and ' ' in value:
51
+ date_part, time_part = value.split(' ', 1)
52
+ year, month, day = date_part.split(':', 2)
53
+ return f"{day}/{month}/{year} {time_part}"
54
+ return value
55
+ except (ValueError, IndexError):
56
+ return value
57
+
21
58
  def is_likely_xml(self, text):
22
59
  if not isinstance(text, str):
23
60
  return False
@@ -47,9 +84,17 @@ class ExifData(ConfigDialog):
47
84
  data = exif_dict(self.exif)
48
85
  if len(data) > 0:
49
86
  for k, (_, d) in data.items():
50
- if isinstance(d, IFDRational):
51
- d = f"{d.numerator}/{d.denominator}"
52
- d_str = str(d)
87
+ if k in ['FNumber', 'ApertureValue']:
88
+ display_value = self.format_aperture(d)
89
+ elif k in ['ExposureTime', 'ShutterSpeedValue']:
90
+ display_value = self.format_exposure_time(d)
91
+ elif k in ['DateTime', 'DateTimeOriginal', 'DateTimeDigitized']:
92
+ display_value = self.format_date_time(d)
93
+ elif isinstance(d, IFDRational):
94
+ display_value = f"{d.numerator}/{d.denominator}"
95
+ else:
96
+ display_value = str(d)
97
+ d_str = display_value
53
98
  if "<<<" not in d_str and k != 'IPTCNAA':
54
99
  if len(d_str) <= 40:
55
100
  self.container_layout.addRow(f"<b>{k}:</b>", QLabel(d_str))
@@ -1,4 +1,4 @@
1
- # pylint: disable=C0114, C0115, C0116, E0611, R0902, R0914, R0915, R0904, W0108
1
+ # pylint: disable=C0114, C0115, C0116, E0611, R0902, R0914, R0915, R0904, W0108, R0911
2
2
  from functools import partial
3
3
  from PySide6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QFrame, QLabel, QMenu,
4
4
  QFileDialog, QListWidget, QSlider, QMainWindow, QMessageBox,
@@ -60,6 +60,9 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
60
60
  self.handle_temp_view,
61
61
  self.end_copy_brush_area,
62
62
  self.handle_brush_size_change,
63
+ self.handle_brush_hardness_change,
64
+ self.handle_brush_opacity_change,
65
+ self.handle_brush_flow_change,
63
66
  self.handle_needs_update)
64
67
  side_panel = QWidget()
65
68
  side_layout = QVBoxLayout(side_panel)
@@ -608,6 +611,18 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
608
611
  if event.text() == '}':
609
612
  self.brush_tool.increase_brush_hardness()
610
613
  return
614
+ if event.text() == ',':
615
+ self.brush_tool.decrease_brush_opacity()
616
+ return
617
+ if event.text() == '.':
618
+ self.brush_tool.increase_brush_opacity()
619
+ return
620
+ if event.text() == ';':
621
+ self.brush_tool.decrease_brush_flow()
622
+ return
623
+ if event.text() == ':':
624
+ self.brush_tool.increase_brush_flow()
625
+ return
611
626
  super().keyPressEvent(event)
612
627
  # pylint: enable=C0103
613
628
 
@@ -806,5 +821,23 @@ class ImageEditorUI(QMainWindow, LayerCollectionHandler):
806
821
  else:
807
822
  self.brush_tool.decrease_brush_size()
808
823
 
824
+ def handle_brush_hardness_change(self, delta):
825
+ if delta > 0:
826
+ self.brush_tool.increase_brush_hardness()
827
+ else:
828
+ self.brush_tool.decrease_brush_hardness()
829
+
830
+ def handle_brush_opacity_change(self, delta):
831
+ if delta > 0:
832
+ self.brush_tool.increase_brush_opacity()
833
+ else:
834
+ self.brush_tool.decrease_brush_opacity()
835
+
836
+ def handle_brush_flow_change(self, delta):
837
+ if delta > 0:
838
+ self.brush_tool.increase_brush_flow()
839
+ else:
840
+ self.brush_tool.decrease_brush_flow()
841
+
809
842
  def handle_set_zoom_factor(self, zoom_factor):
810
843
  self.zoom_factor_label.setText(f"zoom: {zoom_factor:.1%}")
@@ -132,10 +132,15 @@ class ImageViewer(QWidget):
132
132
 
133
133
  def connect_signals(
134
134
  self, handle_temp_view, end_copy_brush_area,
135
- handle_brush_size_change, handle_needs_update):
135
+ handle_brush_size_change, handle_brush_hardness_change,
136
+ handle_brush_opacity_change, handle_brush_flow_change,
137
+ handle_needs_update):
136
138
  for st in self._strategies.values():
137
139
  st.temp_view_requested.connect(handle_temp_view)
138
140
  st.end_copy_brush_area_requested.connect(end_copy_brush_area)
139
141
  st.brush_size_change_requested.connect(handle_brush_size_change)
142
+ st.brush_hardness_change_requested.connect(handle_brush_hardness_change)
143
+ st.brush_opacity_change_requested.connect(handle_brush_opacity_change)
144
+ st.brush_flow_change_requested.connect(handle_brush_flow_change)
140
145
  st.needs_update_requested.connect(handle_needs_update)
141
146
  st.setFocusPolicy(Qt.StrongFocus)
@@ -303,7 +303,6 @@ class IOGuiHandler(QObject, LayerCollectionHandler):
303
303
  img = cv2.cvtColor(self.master_layer(), cv2.COLOR_RGB2BGR)
304
304
  write_image_with_exif_data(self.exif_data, img, path)
305
305
  self.current_file_path_master = os.path.abspath(path)
306
- # self.mark_as_modified_requested.emit(False)
307
306
  self.update_title_requested.emit()
308
307
  self.add_recent_file_requested.emit(self.current_file_path_master)
309
308
  self.status_message_requested.emit(f"Saved master layer to: {path}")
@@ -61,7 +61,10 @@ class ShortcutsHelp(QDialog):
61
61
  "Ctrl + +": "Zoom in",
62
62
  "Ctrl + -": "Zoom out",
63
63
  "Ctrl + 0": "Fit to screen",
64
- "Ctrl + R": "Actual size"
64
+ "Ctrl + R": "Actual size",
65
+ "Ctrl + 1": "View: overlaid",
66
+ "Ctrl + 2": "View: side by side",
67
+ "Ctrl + 3": "View: top-bottom",
65
68
  }
66
69
 
67
70
  self.add_bold_label(left_layout, "Keyboard Shortcuts")
@@ -69,13 +72,14 @@ class ShortcutsHelp(QDialog):
69
72
  left_layout.addRow(f"<b>{k}</b>", QLabel(v))
70
73
 
71
74
  shortcuts = {
72
- "Ctrl + 1": "View: overlaid",
73
- "Ctrl + 2": "View: side by side",
74
- "Ctrl + 3": "View: top-bottom",
75
- "[": "Increase brush size",
76
- "]": "Decrease brush size",
77
- "{": "Increase brush hardness",
78
- "}": "Decrease brush hardness"
75
+ "[": "Decrease brush size",
76
+ "]": "Increase brush size",
77
+ "{": "Decrease brush hardness",
78
+ "}": "Increase brush hardness",
79
+ ",": "Decrease brush opacity",
80
+ ".": "Increase brush opacity",
81
+ ";": "Decrease brush flow",
82
+ ":": "Increase brush flow"
79
83
  }
80
84
 
81
85
  self.add_bold_label(right_layout, "Keyboard Shortcuts")
@@ -86,6 +90,9 @@ class ShortcutsHelp(QDialog):
86
90
  "Space + Drag": "Move",
87
91
  "Wheel": "Zoom in/out",
88
92
  "Ctrl + Wheel": "Adjust brush size",
93
+ "Shift + Wheel": "Adjust brush hardness",
94
+ "Alt + Wheel": "Adjust brush opacity",
95
+ "Ctrl + Shift + Wheel": "Adjust brush flow",
89
96
  "Left Click": "Use brush to copy from selected layer to master",
90
97
  }
91
98
 
@@ -6,7 +6,7 @@ import numpy as np
6
6
  from PySide6.QtCore import Qt, QPointF, QTime, QPoint, Signal, QRectF
7
7
  from PySide6.QtGui import QImage, QPainter, QColor, QBrush, QPen, QCursor, QPixmap, QPainterPath
8
8
  from PySide6.QtWidgets import (
9
- QGraphicsEllipseItem, QGraphicsView, QGraphicsScene, QGraphicsPixmapItem,
9
+ QGraphicsEllipseItem, QGraphicsView, QGraphicsScene, QGraphicsPixmapItem, QApplication,
10
10
  QGraphicsItemGroup, QGraphicsPathItem)
11
11
  from .. config.gui_constants import gui_constants
12
12
  from .. config.app_config import AppConfig
@@ -81,6 +81,9 @@ class ViewSignals:
81
81
  temp_view_requested = Signal(bool)
82
82
  end_copy_brush_area_requested = Signal()
83
83
  brush_size_change_requested = Signal(int) # +1 or -1
84
+ brush_hardness_change_requested = Signal(int)
85
+ brush_opacity_change_requested = Signal(int)
86
+ brush_flow_change_requested = Signal(int)
84
87
  needs_update_requested = Signal()
85
88
 
86
89
 
@@ -444,8 +447,15 @@ class ViewStrategy(LayerCollectionHandler):
444
447
  if self.empty() or self.gesture_active:
445
448
  return
446
449
  if event.source() == Qt.MouseEventNotSynthesized: # Physical mouse
447
- if self.control_pressed:
450
+ modifiers = QApplication.keyboardModifiers()
451
+ if modifiers & Qt.ControlModifier and modifiers & Qt.ShiftModifier:
452
+ self.brush_flow_change_requested.emit(1 if event.angleDelta().y() > 0 else -1)
453
+ elif modifiers & Qt.ControlModifier:
448
454
  self.brush_size_change_requested.emit(1 if event.angleDelta().y() > 0 else -1)
455
+ elif modifiers & Qt.ShiftModifier:
456
+ self.brush_hardness_change_requested.emit(1 if event.angleDelta().y() > 0 else -1)
457
+ elif modifiers & Qt.AltModifier:
458
+ self.brush_opacity_change_requested.emit(1 if event.angleDelta().y() > 0 else -1)
449
459
  else:
450
460
  self.handle_zoom_wheel(self.get_view_with_mouse(event), event)
451
461
  self.update_brush_cursor()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shinestacker
3
- Version: 1.9.1
3
+ Version: 1.9.3
4
4
  Summary: ShineStacker
5
5
  Author-email: Luca Lista <luka.lista@gmail.com>
6
6
  License-Expression: LGPL-3.0
@@ -1,22 +1,22 @@
1
1
  shinestacker/__init__.py,sha256=uq2fjAw2z_6TpH3mOcWFZ98GoEPRsNhTAK8N0MMm_e8,448
2
- shinestacker/_version.py,sha256=zzuY_qaJa652YnCSIsHTbX-QYu0qr0lMpakTuIQMbtg,21
2
+ shinestacker/_version.py,sha256=4DpAu5D3128MDKPMWUy6pytWYJewAWMYY3nQrnHx_9k,21
3
3
  shinestacker/algorithms/__init__.py,sha256=1FwVJ3w9GGbFFkjYJRUedTvcdE4j0ieSgaH9RC9iCY4,877
4
- shinestacker/algorithms/align.py,sha256=840SLh38JePGQv9vgG2H6jHkgHSAYzSpbNDDTxV5ghg,37915
4
+ shinestacker/algorithms/align.py,sha256=_eBU7TZ_xitZI0HwyWw4cgeVW48AEiYRR1Fyg8K7-iw,38424
5
5
  shinestacker/algorithms/align_auto.py,sha256=DsHuAkFXSHbtFwp6XRaV3Sy1LGcUZWYAFijJXWrd1Bo,3833
6
- shinestacker/algorithms/align_parallel.py,sha256=TcoIRBqrEbxDwOPOo1SinSGwW3M3cq3Agx6o8Sf9ILg,19215
7
- shinestacker/algorithms/balance.py,sha256=aoqnc1u5A2C3R7fKaOoKnzudRiOT8GRIu4LEP-uzyZQ,24053
6
+ shinestacker/algorithms/align_parallel.py,sha256=X1mawwK3I-NUoKJ2evMH0DJag3_ObegQ9MJ78fxkGAU,19496
7
+ shinestacker/algorithms/balance.py,sha256=HZ0TPfzqvUV3SydDsjgLJMHn6jC1MAYVTY2nLEj6vLg,24051
8
8
  shinestacker/algorithms/base_stack_algo.py,sha256=mqCCRufLc9k5fZV5Su41AsN1ecHrZJzp1xtpmbJ7wb0,2669
9
9
  shinestacker/algorithms/corrections.py,sha256=DrfLM33D20l4svuuBtoOiH-KGUH_BL1mAV7mHCA_nGA,1094
10
10
  shinestacker/algorithms/denoise.py,sha256=GL3Z4_6MHxSa7Wo4ZzQECZS87tHBFqO0sIVF_jPuYQU,426
11
11
  shinestacker/algorithms/depth_map.py,sha256=nRBrZQWbdUqFOtYMEQx9UNdnybrBTeAOr1eV91FlN8U,5611
12
- shinestacker/algorithms/exif.py,sha256=jdUl3qMUif3wdQr7z8TnDFUo8iR84Zjmg57nmAmskxc,21729
12
+ shinestacker/algorithms/exif.py,sha256=QG6d2Xhw2S24UHXtfaWSHZhFY279kYw5ms0DQcg7qYg,37058
13
13
  shinestacker/algorithms/multilayer.py,sha256=SX4digCMvPxvm9KRrwroUwoAc83ScbmjIjN8s5au3wg,10053
14
14
  shinestacker/algorithms/noise_detection.py,sha256=SbWcxSPZIxnThXITAe7koPLKhQZ_gciQby50u3QfkGs,9464
15
15
  shinestacker/algorithms/pyramid.py,sha256=Z7tlp8Hh3ploAXJCr0VNe33d8H9GNrlqHXq_LapgRwo,8205
16
16
  shinestacker/algorithms/pyramid_auto.py,sha256=fl_jXNYLWsBiX0M0UghzCLqai0SGXlmKYHU7Z9SUYSo,6173
17
17
  shinestacker/algorithms/pyramid_tiles.py,sha256=t04_06oYF6QkSSyFQEivHh-GDTska2dQEmfCYoscy-c,12216
18
18
  shinestacker/algorithms/sharpen.py,sha256=h7PMJBYxucg194Usp_6pvItPUMFYbT-ebAc_-7XBFUw,949
19
- shinestacker/algorithms/stack.py,sha256=dRaxNF3Uap18Q6uXWgPMKHSd18Ci0QooEJZciH68_VE,6495
19
+ shinestacker/algorithms/stack.py,sha256=mIynzHv9iqvF-VomBiwjQ0RSLLqwhBndGKqRxYJ5SjE,6693
20
20
  shinestacker/algorithms/stack_framework.py,sha256=HwB0gDncjJEKHdaR9fFcc2XoRrgxFNrrFDfVyeO4NRM,14616
21
21
  shinestacker/algorithms/utils.py,sha256=1RCsOSQ5TSM8y10Wg5JBDWCAEf-vEQReN_5VMtrLW7o,13127
22
22
  shinestacker/algorithms/vignetting.py,sha256=Y-K_CTjtNpl0YX86PaM0te-HFxuEcWozhWoB7-g_S7Y,10849
@@ -54,10 +54,10 @@ shinestacker/gui/folder_file_selection.py,sha256=CwussPYMguMk8WuyuUKk28VneafwGR-
54
54
  shinestacker/gui/gui_images.py,sha256=KxGBFLL2ztfNmvL4pconi3z5HJCoD2HXxpYZP70aUfM,6803
55
55
  shinestacker/gui/gui_logging.py,sha256=kiZcrC2AFYCWgPZo0O5SKw-E5cFrezwf4anS3HjPuNw,8168
56
56
  shinestacker/gui/gui_run.py,sha256=Tp3BQTbASdfyELQonJPM10dX9mWb7TdecsIjzCnVQsA,15680
57
- shinestacker/gui/main_window.py,sha256=VYGX-w-A8sy1zsQAJEfLpImax8oB-inx_nZ2XofDEBQ,25777
58
- shinestacker/gui/menu_manager.py,sha256=mS-pRMymd1yYimbr6Z5YXjMA5AsNuaNcezs8MYWF2DU,12364
57
+ shinestacker/gui/main_window.py,sha256=5DiSho2SALtRNlF_ZnWQIORzKJFK1rcXdTHx4YlPMpg,26114
58
+ shinestacker/gui/menu_manager.py,sha256=_qIxDgydb9BXeKA-bBEdYRTaBZR7cPGHii_whBP-a_U,12686
59
59
  shinestacker/gui/new_project.py,sha256=fnTWxT0YS390T4CTu6Cdl7pWrjsCiphnKZJvDLzXGlE,16728
60
- shinestacker/gui/project_controller.py,sha256=h2x7Z1MFKXQGB4dGmdLcXQgcDTtId9RMi3m-4pSli2Y,16963
60
+ shinestacker/gui/project_controller.py,sha256=vIGPZOJQAKzypXlSxqm_hBRh7ECNDfoMmE0xSAReu8g,17033
61
61
  shinestacker/gui/project_converter.py,sha256=Gmna0HwbvACcXiX74TaQYumif8ZV8sZ2APLTMM-L1mU,7436
62
62
  shinestacker/gui/project_editor.py,sha256=9KEH-CkIbK_yLKRo184C08uYXQ9_aqepEGQrKRqhfUg,25991
63
63
  shinestacker/gui/project_model.py,sha256=9Mr3Y87Pj8J-mSkgn9NexaxzZkB39zkIGG5zzeUojB0,4869
@@ -86,32 +86,32 @@ shinestacker/retouch/base_filter.py,sha256=o_OkJbdD3jOGY--_sGL1_WqAMQI-QHGw-EEYx
86
86
  shinestacker/retouch/brush.py,sha256=dzD2FzSpBIPdJRmTZobcrQ1FrVd3tF__ZPnUplNE72s,357
87
87
  shinestacker/retouch/brush_gradient.py,sha256=F5SFhyzl8YTMqjJU3jK8BrIlLCYLUvITd5wz3cQE4xk,1453
88
88
  shinestacker/retouch/brush_preview.py,sha256=cOFVMCbEsgR_alzmr_-LLghtGU_unrE-hAjLHcvrZAY,5484
89
- shinestacker/retouch/brush_tool.py,sha256=8uVncTA375uC3Nhp2YM0eZjpOR-nN47i2eGjN8tJzOU,8714
89
+ shinestacker/retouch/brush_tool.py,sha256=OoAs_9TYbgDhBiixspwSND3c41LpSwcWylQsSK7Cprk,9552
90
90
  shinestacker/retouch/denoise_filter.py,sha256=QVXFU54MDcylNWtiIcdQSZ3eClW_xNWZhCMIeoEQ8zk,576
91
91
  shinestacker/retouch/display_manager.py,sha256=fTZTGbvmX5DXagexuvbNgOF5GiH2Vv-stLUQQwoglp8,10181
92
- shinestacker/retouch/exif_data.py,sha256=9m2_XwSZk58u3EJQnySLFB-IVdMdyrVWkiLPhcKEfPk,3298
92
+ shinestacker/retouch/exif_data.py,sha256=Xffb0QMwRZJegizsx0npj7kEhAR84bi4J82qh885Dlc,5204
93
93
  shinestacker/retouch/file_loader.py,sha256=FTOGOuQRHekofESFDsCvnUU5XnZH_GbLfxXwKnoxZ4s,4832
94
94
  shinestacker/retouch/filter_manager.py,sha256=tOGIWj5HjViL1-iXHkd91X-sZ1c1G531pDmLO0x6zx0,866
95
95
  shinestacker/retouch/icon_container.py,sha256=6gw1HO1bC2FrdB4dc_iH81DQuLjzuvRGksZ2hKLT9yA,585
96
- shinestacker/retouch/image_editor_ui.py,sha256=a48GiU-Pm6viNe54KEwq6y_Re-YqsB6juxLLj4-C53Y,36189
96
+ shinestacker/retouch/image_editor_ui.py,sha256=5S31vG6kdQow127QYHprBWu-LgdWQ8-AWM_wIxyx0WU,37315
97
97
  shinestacker/retouch/image_view_status.py,sha256=2rWi2ugdyjMhWCtRJkwOnb7-tCtVfnGfCY_54qpZhwM,1970
98
- shinestacker/retouch/image_viewer.py,sha256=xf1vYZRPb9ClCQbqrqAFhPubdqIIpku7DgcY8O5bvYU,4694
99
- shinestacker/retouch/io_gui_handler.py,sha256=iXVCNIWxLwF28g5H-BePYYzAZgCuksUreITmOO8MI9E,14508
98
+ shinestacker/retouch/image_viewer.py,sha256=jj6xHEfIJ9x-bf38DxOdeTtwWW2hdXoa3lCJHdzZJmU,5048
99
+ shinestacker/retouch/io_gui_handler.py,sha256=DPS01f3eBhh3iPNzINShghHH0vdWCf8K4hQPxJi6wJU,14450
100
100
  shinestacker/retouch/io_threads.py,sha256=r0X4it2PfwnmiAU7eStniIfcHhPvuaqdqf5VlnvjZ-4,2832
101
101
  shinestacker/retouch/layer_collection.py,sha256=xx8INSLCXIeTQn_nxfCo4QljAmQK1qukSYO1Zk4rqqo,6183
102
102
  shinestacker/retouch/overlaid_view.py,sha256=QTTdegUWs99YBZZPlIRdPI5O80U3t_c3HnyegbRqNbA,7029
103
103
  shinestacker/retouch/paint_area_manager.py,sha256=ilK6uQT7lzNyvdc8uNv4xTHHHAbk5hGEClJRNmiA4P8,894
104
- shinestacker/retouch/shortcuts_help.py,sha256=BFWTT5QvodqMhqa_9LI25hZqjICfckgyWG4fGrGzvnM,4283
104
+ shinestacker/retouch/shortcuts_help.py,sha256=sjhLYows2OmUsI_ldQwqkzwviP8oQ65upOeWKdZO1wo,4612
105
105
  shinestacker/retouch/sidebyside_view.py,sha256=4sNa_IUMbNH18iECO7eDO9S_ls3v2ENwP1AWrBFhofI,18907
106
106
  shinestacker/retouch/transformation_manager.py,sha256=QFYCL-l9V6qlhw3y7tcs0saWWClNPsh7F9pTBkfPbRU,1711
107
107
  shinestacker/retouch/undo_manager.py,sha256=J4hEAnv9bKLQ0N1wllWswjJBhgRgasCnBoMT5LEw-dM,4453
108
108
  shinestacker/retouch/unsharp_mask_filter.py,sha256=SO-6ZgPPDAO9em_MMefVvvSvt01-2gm1HF6OBsShmL4,2795
109
- shinestacker/retouch/view_strategy.py,sha256=jZxB_vX3_0notH0ClxKkLzbdtx4is3vQiYoIP-sDv3M,30216
109
+ shinestacker/retouch/view_strategy.py,sha256=pgLQZdxrQQpr6TM4RRP3dxLU6bvt2V1LzNuLz7aHZfE,30908
110
110
  shinestacker/retouch/vignetting_filter.py,sha256=M7PZGPdVSq4bqo6wkEznrILMIG3-mTT7iwpgK4Hieyg,3794
111
111
  shinestacker/retouch/white_balance_filter.py,sha256=UaH4yxG3fU4vPutBAkV5oTXIQyUTN09x0uTywAzv3sY,8286
112
- shinestacker-1.9.1.dist-info/licenses/LICENSE,sha256=pWgb-bBdsU2Gd2kwAXxketnm5W_2u8_fIeWEgojfrxs,7651
113
- shinestacker-1.9.1.dist-info/METADATA,sha256=Udu0wqbX3XEcA_H38Rc9ZIjFMruYS3vEOTS4kYpKfOY,6883
114
- shinestacker-1.9.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
115
- shinestacker-1.9.1.dist-info/entry_points.txt,sha256=SY6g1LqtMmp23q1DGwLUDT_dhLX9iss8DvWkiWLyo_4,166
116
- shinestacker-1.9.1.dist-info/top_level.txt,sha256=MhijwnBVX5psfsyX8JZjqp3SYiWPsKe69f3Gnyze4Fw,13
117
- shinestacker-1.9.1.dist-info/RECORD,,
112
+ shinestacker-1.9.3.dist-info/licenses/LICENSE,sha256=pWgb-bBdsU2Gd2kwAXxketnm5W_2u8_fIeWEgojfrxs,7651
113
+ shinestacker-1.9.3.dist-info/METADATA,sha256=ulZ3X2yOUd2Qa5ZCHZb90GeFgIHiaIkQ5y7SgiA9zPg,6883
114
+ shinestacker-1.9.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
115
+ shinestacker-1.9.3.dist-info/entry_points.txt,sha256=SY6g1LqtMmp23q1DGwLUDT_dhLX9iss8DvWkiWLyo_4,166
116
+ shinestacker-1.9.3.dist-info/top_level.txt,sha256=MhijwnBVX5psfsyX8JZjqp3SYiWPsKe69f3Gnyze4Fw,13
117
+ shinestacker-1.9.3.dist-info/RECORD,,