shinestacker 1.4.0__py3-none-any.whl → 1.5.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/app/main.py +1 -1
- shinestacker/config/gui_constants.py +5 -0
- shinestacker/retouch/base_filter.py +8 -10
- shinestacker/retouch/brush_preview.py +0 -1
- shinestacker/retouch/display_manager.py +42 -42
- shinestacker/retouch/image_editor_ui.py +52 -31
- shinestacker/retouch/image_view_status.py +4 -0
- shinestacker/retouch/image_viewer.py +6 -0
- shinestacker/retouch/layer_collection.py +3 -0
- shinestacker/retouch/overlaid_view.py +87 -84
- shinestacker/retouch/sidebyside_view.py +113 -115
- shinestacker/retouch/transformation_manager.py +43 -0
- shinestacker/retouch/undo_manager.py +22 -3
- shinestacker/retouch/view_strategy.py +135 -44
- {shinestacker-1.4.0.dist-info → shinestacker-1.5.0.dist-info}/METADATA +7 -7
- {shinestacker-1.4.0.dist-info → shinestacker-1.5.0.dist-info}/RECORD +21 -20
- {shinestacker-1.4.0.dist-info → shinestacker-1.5.0.dist-info}/WHEEL +0 -0
- {shinestacker-1.4.0.dist-info → shinestacker-1.5.0.dist-info}/entry_points.txt +0 -0
- {shinestacker-1.4.0.dist-info → shinestacker-1.5.0.dist-info}/licenses/LICENSE +0 -0
- {shinestacker-1.4.0.dist-info → shinestacker-1.5.0.dist-info}/top_level.txt +0 -0
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import math
|
|
3
3
|
from abc import abstractmethod
|
|
4
4
|
import numpy as np
|
|
5
|
-
from PySide6.QtCore import Qt, QPointF, QTime, QPoint, Signal
|
|
6
|
-
from PySide6.QtGui import QImage, QPainter, QColor, QBrush, QPen, QCursor
|
|
5
|
+
from PySide6.QtCore import Qt, QPointF, QTime, QPoint, Signal, QRectF
|
|
6
|
+
from PySide6.QtGui import QImage, QPainter, QColor, QBrush, QPen, QCursor, QPixmap
|
|
7
7
|
from PySide6.QtWidgets import (
|
|
8
8
|
QGraphicsEllipseItem, QGraphicsView, QGraphicsScene, QGraphicsPixmapItem)
|
|
9
9
|
from .. config.gui_constants import gui_constants
|
|
@@ -52,7 +52,6 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
52
52
|
self.pinch_center_view = None
|
|
53
53
|
self.pinch_center_scene = None
|
|
54
54
|
self.pinch_start_scale = None
|
|
55
|
-
self.last_scroll_pos = None
|
|
56
55
|
self.scrolling = False
|
|
57
56
|
self.dragging = False
|
|
58
57
|
self.last_brush_pos = None
|
|
@@ -72,19 +71,19 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
72
71
|
pass
|
|
73
72
|
|
|
74
73
|
@abstractmethod
|
|
75
|
-
def
|
|
74
|
+
def get_master_view(self):
|
|
76
75
|
pass
|
|
77
76
|
|
|
78
77
|
@abstractmethod
|
|
79
|
-
def
|
|
78
|
+
def get_current_view(self):
|
|
80
79
|
pass
|
|
81
80
|
|
|
82
81
|
@abstractmethod
|
|
83
|
-
def
|
|
82
|
+
def get_master_scene(self):
|
|
84
83
|
pass
|
|
85
84
|
|
|
86
85
|
@abstractmethod
|
|
87
|
-
def
|
|
86
|
+
def get_current_scene(self):
|
|
88
87
|
pass
|
|
89
88
|
|
|
90
89
|
@abstractmethod
|
|
@@ -103,12 +102,52 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
103
102
|
def get_master_pixmap(self):
|
|
104
103
|
pass
|
|
105
104
|
|
|
105
|
+
@abstractmethod
|
|
106
|
+
def get_current_pixmap(self):
|
|
107
|
+
pass
|
|
108
|
+
|
|
109
|
+
@abstractmethod
|
|
106
110
|
def show_master(self):
|
|
107
111
|
pass
|
|
108
112
|
|
|
113
|
+
@abstractmethod
|
|
109
114
|
def show_current(self):
|
|
110
115
|
pass
|
|
111
116
|
|
|
117
|
+
@abstractmethod
|
|
118
|
+
def arrange_images(self):
|
|
119
|
+
pass
|
|
120
|
+
|
|
121
|
+
def update_master_display(self):
|
|
122
|
+
if not self.empty():
|
|
123
|
+
master_qimage = self.numpy_to_qimage(self.master_layer())
|
|
124
|
+
if master_qimage:
|
|
125
|
+
pixmap = QPixmap.fromImage(master_qimage)
|
|
126
|
+
self.get_master_pixmap().setPixmap(pixmap)
|
|
127
|
+
self.get_master_scene().setSceneRect(QRectF(pixmap.rect()))
|
|
128
|
+
self.get_master_view().horizontalScrollBar().setValue(self.status.h_scroll)
|
|
129
|
+
self.get_master_view().verticalScrollBar().setValue(self.status.v_scroll)
|
|
130
|
+
self.arrange_images()
|
|
131
|
+
|
|
132
|
+
def update_current_display(self):
|
|
133
|
+
if not self.empty() and self.number_of_layers() > 0:
|
|
134
|
+
current_qimage = self.numpy_to_qimage(self.current_layer())
|
|
135
|
+
if current_qimage:
|
|
136
|
+
pixmap = QPixmap.fromImage(current_qimage)
|
|
137
|
+
self.get_current_pixmap().setPixmap(pixmap)
|
|
138
|
+
self.get_current_scene().setSceneRect(QRectF(pixmap.rect()))
|
|
139
|
+
self.get_current_view().horizontalScrollBar().setValue(self.status.h_scroll)
|
|
140
|
+
self.get_current_view().verticalScrollBar().setValue(self.status.v_scroll)
|
|
141
|
+
self.arrange_images()
|
|
142
|
+
|
|
143
|
+
def update_cursor_pen_width(self):
|
|
144
|
+
pen_width = gui_constants.BRUSH_LINE_WIDTH / self.zoom_factor()
|
|
145
|
+
if self.brush_cursor is not None:
|
|
146
|
+
master_pen = self.brush_cursor.pen()
|
|
147
|
+
master_pen.setWidthF(pen_width)
|
|
148
|
+
self.brush_cursor.setPen(master_pen)
|
|
149
|
+
return pen_width
|
|
150
|
+
|
|
112
151
|
def set_allow_cursor_preview(self, state):
|
|
113
152
|
self.allow_cursor_preview = state
|
|
114
153
|
|
|
@@ -154,10 +193,10 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
154
193
|
return self.cursor_style
|
|
155
194
|
|
|
156
195
|
def handle_key_press_event(self, _event):
|
|
157
|
-
return
|
|
196
|
+
return True
|
|
158
197
|
|
|
159
198
|
def handle_key_release_event(self, _event):
|
|
160
|
-
return
|
|
199
|
+
return True
|
|
161
200
|
|
|
162
201
|
def clear_image(self):
|
|
163
202
|
for scene in self.get_scenes():
|
|
@@ -171,6 +210,11 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
171
210
|
if self.brush_cursor:
|
|
172
211
|
self.brush_cursor.hide()
|
|
173
212
|
|
|
213
|
+
def cleanup_brush_preview(self):
|
|
214
|
+
if self.brush_cursor:
|
|
215
|
+
self.brush_cursor.hide()
|
|
216
|
+
self.brush_preview.hide()
|
|
217
|
+
|
|
174
218
|
def set_master_image_np(self, img):
|
|
175
219
|
self.set_master_image(self.numpy_to_qimage(img))
|
|
176
220
|
|
|
@@ -201,9 +245,14 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
201
245
|
return pixmap_item
|
|
202
246
|
|
|
203
247
|
def refresh_display(self):
|
|
204
|
-
self.update_brush_cursor()
|
|
205
248
|
for scene in self.get_scenes():
|
|
206
249
|
scene.update()
|
|
250
|
+
self.update_brush_cursor()
|
|
251
|
+
|
|
252
|
+
def set_max_min_scales(self, img_width, img_height):
|
|
253
|
+
self.set_min_scale(min(gui_constants.MIN_ZOOMED_IMG_WIDTH / img_width,
|
|
254
|
+
gui_constants.MIN_ZOOMED_IMG_HEIGHT / img_height))
|
|
255
|
+
self.set_max_scale(gui_constants.MAX_ZOOMED_IMG_PX_SIZE)
|
|
207
256
|
|
|
208
257
|
def zoom_in(self):
|
|
209
258
|
if self.empty():
|
|
@@ -218,6 +267,15 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
218
267
|
self.set_zoom_factor(new_scale)
|
|
219
268
|
master_view.centerOn(old_center)
|
|
220
269
|
self.update_brush_cursor()
|
|
270
|
+
self.update_cursor_pen_width()
|
|
271
|
+
|
|
272
|
+
def apply_zoom(self):
|
|
273
|
+
if self.empty():
|
|
274
|
+
return
|
|
275
|
+
for view in self.get_views():
|
|
276
|
+
current_scale = view.transform().m11()
|
|
277
|
+
scale_factor = self.zoom_factor() / current_scale
|
|
278
|
+
view.scale(scale_factor, scale_factor)
|
|
221
279
|
|
|
222
280
|
def zoom_out(self):
|
|
223
281
|
if self.empty():
|
|
@@ -232,12 +290,12 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
232
290
|
self.set_zoom_factor(new_scale)
|
|
233
291
|
master_view.centerOn(old_center)
|
|
234
292
|
self.update_brush_cursor()
|
|
293
|
+
self.update_cursor_pen_width()
|
|
235
294
|
|
|
236
295
|
def reset_zoom(self):
|
|
237
296
|
if self.empty():
|
|
238
297
|
return
|
|
239
298
|
self.pinch_start_scale = 1.0
|
|
240
|
-
self.last_scroll_pos = QPointF()
|
|
241
299
|
self.gesture_active = False
|
|
242
300
|
self.pinch_center_view = None
|
|
243
301
|
self.pinch_center_scene = None
|
|
@@ -249,6 +307,7 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
249
307
|
view.resetTransform()
|
|
250
308
|
view.scale(self.zoom_factor(), self.zoom_factor())
|
|
251
309
|
self.update_brush_cursor()
|
|
310
|
+
self.update_cursor_pen_width()
|
|
252
311
|
|
|
253
312
|
def actual_size(self):
|
|
254
313
|
if self.empty():
|
|
@@ -258,6 +317,7 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
258
317
|
view.resetTransform()
|
|
259
318
|
view.scale(self.zoom_factor(), self.zoom_factor())
|
|
260
319
|
self.update_brush_cursor()
|
|
320
|
+
self.update_cursor_pen_width()
|
|
261
321
|
|
|
262
322
|
def setup_outline_style(self):
|
|
263
323
|
self.brush_cursor.setPen(QPen(QColor(*gui_constants.BRUSH_COLORS['pen']),
|
|
@@ -278,17 +338,16 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
278
338
|
if isinstance(item, QGraphicsEllipseItem) and item != self.brush_preview:
|
|
279
339
|
scene.removeItem(item)
|
|
280
340
|
pen = QPen(QColor(*gui_constants.BRUSH_COLORS['pen']), 1)
|
|
281
|
-
brush =
|
|
341
|
+
brush = Qt.NoBrush
|
|
282
342
|
self.brush_cursor = scene.addEllipse(
|
|
283
343
|
0, 0, self.brush.size, self.brush.size, pen, brush)
|
|
284
344
|
self.brush_cursor.setZValue(1000)
|
|
285
345
|
self.brush_cursor.hide()
|
|
286
346
|
|
|
287
347
|
def update_brush_cursor(self):
|
|
288
|
-
if self.empty():
|
|
289
|
-
return
|
|
290
|
-
if not self.brush_cursor or not self.isVisible():
|
|
348
|
+
if self.empty() or not self.brush_cursor or not self.isVisible():
|
|
291
349
|
return
|
|
350
|
+
self.update_cursor_pen_width()
|
|
292
351
|
master_view = self.get_master_view()
|
|
293
352
|
mouse_pos = master_view.mapFromGlobal(QCursor.pos())
|
|
294
353
|
if not master_view.rect().contains(mouse_pos):
|
|
@@ -299,19 +358,20 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
299
358
|
radius = size / 2
|
|
300
359
|
self.brush_cursor.setRect(scene_pos.x() - radius, scene_pos.y() - radius, size, size)
|
|
301
360
|
allow_cursor_preview = self.display_manager.allow_cursor_preview()
|
|
302
|
-
if self.cursor_style == 'preview'
|
|
361
|
+
if self.cursor_style == 'preview':
|
|
303
362
|
self.setup_outline_style()
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
363
|
+
if allow_cursor_preview:
|
|
364
|
+
self.brush_cursor.hide()
|
|
365
|
+
pos = QCursor.pos()
|
|
366
|
+
if isinstance(pos, QPointF):
|
|
367
|
+
scene_pos = pos
|
|
368
|
+
else:
|
|
369
|
+
cursor_pos = master_view.mapFromGlobal(pos)
|
|
370
|
+
scene_pos = master_view.mapToScene(cursor_pos)
|
|
371
|
+
self.brush_preview.update(scene_pos, int(size))
|
|
312
372
|
else:
|
|
313
373
|
self.brush_preview.hide()
|
|
314
|
-
if self.cursor_style == 'outline'
|
|
374
|
+
if self.cursor_style == 'outline':
|
|
315
375
|
self.setup_outline_style()
|
|
316
376
|
else:
|
|
317
377
|
self.setup_simple_brush_style(scene_pos.x(), scene_pos.y(), radius)
|
|
@@ -354,41 +414,53 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
354
414
|
def keyPressEvent(self, event):
|
|
355
415
|
if self.empty():
|
|
356
416
|
return
|
|
357
|
-
master_view = self.get_master_view()
|
|
358
417
|
if event.key() == Qt.Key_Space and not self.scrolling:
|
|
359
418
|
self.space_pressed = True
|
|
360
|
-
|
|
419
|
+
self.get_master_view().setCursor(Qt.OpenHandCursor)
|
|
361
420
|
if self.brush_cursor:
|
|
362
421
|
self.brush_cursor.hide()
|
|
363
|
-
self.handle_key_press_event(event)
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
422
|
+
if self.handle_key_press_event(event):
|
|
423
|
+
if event.key() == Qt.Key_Control and not self.scrolling:
|
|
424
|
+
self.control_pressed = True
|
|
425
|
+
super().keyPressEvent(event)
|
|
367
426
|
|
|
368
427
|
def keyReleaseEvent(self, event):
|
|
369
428
|
if self.empty():
|
|
370
429
|
return
|
|
371
|
-
master_view = self.get_master_view()
|
|
372
430
|
self.update_brush_cursor()
|
|
373
431
|
if event.key() == Qt.Key_Space:
|
|
374
432
|
self.space_pressed = False
|
|
375
433
|
if not self.scrolling:
|
|
376
|
-
|
|
434
|
+
self.get_master_view().setCursor(Qt.BlankCursor)
|
|
377
435
|
if self.brush_cursor:
|
|
378
436
|
self.brush_cursor.show()
|
|
379
|
-
self.handle_key_release_event(event)
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
437
|
+
if self.handle_key_release_event(event):
|
|
438
|
+
if event.key() == Qt.Key_Control:
|
|
439
|
+
self.control_pressed = False
|
|
440
|
+
super().keyReleaseEvent(event)
|
|
383
441
|
|
|
384
442
|
def leaveEvent(self, event):
|
|
385
|
-
if
|
|
443
|
+
if self.empty():
|
|
444
|
+
self.setCursor(Qt.ArrowCursor)
|
|
445
|
+
else:
|
|
386
446
|
self.get_master_view().setCursor(Qt.ArrowCursor)
|
|
387
447
|
if self.brush_cursor:
|
|
388
448
|
self.brush_cursor.hide()
|
|
389
449
|
super().leaveEvent(event)
|
|
390
450
|
# pylint: enable=C0103
|
|
391
451
|
|
|
452
|
+
def scroll_view(self, view, delta_x, delta_y):
|
|
453
|
+
view.horizontalScrollBar().setValue(
|
|
454
|
+
view.horizontalScrollBar().value() - delta_x)
|
|
455
|
+
view.verticalScrollBar().setValue(
|
|
456
|
+
view.verticalScrollBar().value() - delta_y)
|
|
457
|
+
self.status.set_scroll(view.horizontalScrollBar().value(),
|
|
458
|
+
view.verticalScrollBar().value())
|
|
459
|
+
|
|
460
|
+
def center_image(self, view):
|
|
461
|
+
view.horizontalScrollBar().setValue(self.status.h_scroll)
|
|
462
|
+
view.verticalScrollBar().setValue(self.status.v_scroll)
|
|
463
|
+
|
|
392
464
|
def mouse_move_event(self, event):
|
|
393
465
|
if self.empty():
|
|
394
466
|
return
|
|
@@ -424,12 +496,6 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
424
496
|
self.last_mouse_pos = position
|
|
425
497
|
self.scroll_view(master_view, delta.x(), delta.y())
|
|
426
498
|
|
|
427
|
-
def scroll_view(self, view, delta_x, delta_y):
|
|
428
|
-
view.horizontalScrollBar().setValue(
|
|
429
|
-
view.horizontalScrollBar().value() - delta_x)
|
|
430
|
-
view.verticalScrollBar().setValue(
|
|
431
|
-
view.verticalScrollBar().value() - delta_y)
|
|
432
|
-
|
|
433
499
|
def mouse_press_event(self, event):
|
|
434
500
|
if self.empty():
|
|
435
501
|
return
|
|
@@ -464,3 +530,28 @@ class ViewStrategy(LayerCollectionHandler):
|
|
|
464
530
|
elif self.dragging:
|
|
465
531
|
self.dragging = False
|
|
466
532
|
self.brush_operation_ended.emit()
|
|
533
|
+
|
|
534
|
+
def handle_pinch_gesture(self, pinch):
|
|
535
|
+
master_view = self.get_master_view()
|
|
536
|
+
if pinch.state() == Qt.GestureStarted:
|
|
537
|
+
self.pinch_start_scale = self.zoom_factor()
|
|
538
|
+
self.pinch_center_view = pinch.centerPoint()
|
|
539
|
+
self.pinch_center_scene = master_view.mapToScene(self.pinch_center_view.toPoint())
|
|
540
|
+
self.gesture_active = True
|
|
541
|
+
elif pinch.state() == Qt.GestureUpdated:
|
|
542
|
+
new_scale = self.pinch_start_scale * pinch.totalScaleFactor()
|
|
543
|
+
new_scale = max(self.min_scale(), min(new_scale, self.max_scale()))
|
|
544
|
+
if abs(new_scale - self.zoom_factor()) > 0.01:
|
|
545
|
+
self.set_zoom_factor(new_scale)
|
|
546
|
+
self.apply_zoom()
|
|
547
|
+
new_center = master_view.mapToScene(self.pinch_center_view.toPoint())
|
|
548
|
+
delta = self.pinch_center_scene - new_center
|
|
549
|
+
h_scroll = master_view.horizontalScrollBar().value() + \
|
|
550
|
+
int(delta.x() * self.zoom_factor())
|
|
551
|
+
v_scroll = master_view.verticalScrollBar().value() + \
|
|
552
|
+
int(delta.y() * self.zoom_factor())
|
|
553
|
+
self.status.set_scroll(h_scroll, v_scroll)
|
|
554
|
+
self.center_image(master_view)
|
|
555
|
+
elif pinch.state() in (Qt.GestureFinished, Qt.GestureCanceled):
|
|
556
|
+
self.gesture_active = False
|
|
557
|
+
self.update_cursor_pen_width()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: shinestacker
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.5.0
|
|
4
4
|
Summary: ShineStacker
|
|
5
5
|
Author-email: Luca Lista <luka.lista@gmail.com>
|
|
6
6
|
License-Expression: LGPL-3.0
|
|
@@ -70,11 +70,11 @@ The GUI has two main working areas:
|
|
|
70
70
|
|
|
71
71
|
<img src='https://raw.githubusercontent.com/lucalista/shinestacker/main/img/gui-retouch.png' width="600" referrerpolicy="no-referrer">
|
|
72
72
|
|
|
73
|
-
|
|
73
|
+
## Resources
|
|
74
74
|
|
|
75
75
|
🌍 [Website on WordPress](https://shinestacker.wordpress.com) • 📖 [Main documentation](https://shinestacker.readthedocs.io) • 📝 [Changelog](https://github.com/lucalista/shinestacker/blob/main/CHANGELOG.md)
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
## Note for macOS users
|
|
78
78
|
|
|
79
79
|
**The following note is only relevant if you download the application as compressed archive from the [release page](https://github.com/lucalista/shinestacker/releases).**
|
|
80
80
|
|
|
@@ -93,17 +93,17 @@ xattr -cr ~/Downloads/shinestacker/shinestacker.app
|
|
|
93
93
|
|
|
94
94
|
macOS adds a quarantine flag to all files downloaded from the internet. The above command removes that flag while preserving all other application functionality.
|
|
95
95
|
|
|
96
|
-
|
|
96
|
+
## Credits
|
|
97
97
|
|
|
98
98
|
The first version of the core focus stack algorithm was initially inspired by the [Laplacian pyramids method](https://github.com/sjawhar/focus-stacking) implementation by Sami Jawhar that was used under permission of the author. The implementation in the latest releases was rewritten from the original code.
|
|
99
99
|
|
|
100
|
-
|
|
100
|
+
## Resources
|
|
101
101
|
|
|
102
102
|
* [Pyramid Methods in Image Processing](https://www.researchgate.net/publication/246727904_Pyramid_Methods_in_Image_Processing), E. H. Adelson, C. H. Anderson, J. R. Bergen, P. J. Burt, J. M. Ogden, RCA Engineer, 29-6, Nov/Dec 1984
|
|
103
103
|
Pyramid methods in image processing
|
|
104
104
|
* [A Multi-focus Image Fusion Method Based on Laplacian Pyramid](http://www.jcomputers.us/vol6/jcp0612-07.pdf), Wencheng Wang, Faliang Chang, Journal of Computers 6 (12), 2559, December 2011
|
|
105
105
|
|
|
106
|
-
|
|
106
|
+
## License
|
|
107
107
|
|
|
108
108
|
<img src="https://www.gnu.org/graphics/lgplv3-147x51.png" alt="LGPL 3 logo">
|
|
109
109
|
|
|
@@ -112,7 +112,7 @@ Pyramid methods in image processing
|
|
|
112
112
|
|
|
113
113
|
- **Logo**: The Shine Stacker logo was designed by [Alessandro Lista](https://linktr.ee/alelista). Copyright © Alessandro Lista. All rights reserved. The logo is not covered by the LGPL-3.0 license of this project.
|
|
114
114
|
|
|
115
|
-
|
|
115
|
+
## Attribution request
|
|
116
116
|
📸 If you publish images created with Shine Stacker, please consider adding a note such as:
|
|
117
117
|
|
|
118
118
|
*Created with Shine Stacker – https://github.com/lucalista/shinestacker*
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
shinestacker/__init__.py,sha256=uq2fjAw2z_6TpH3mOcWFZ98GoEPRsNhTAK8N0MMm_e8,448
|
|
2
|
-
shinestacker/_version.py,sha256=
|
|
2
|
+
shinestacker/_version.py,sha256=XyInpe-Rlf1hgwkiRXtR0uPYm4ZwRFpgchjcpZZ9Pms,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
|
|
@@ -24,14 +24,14 @@ shinestacker/app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,
|
|
|
24
24
|
shinestacker/app/about_dialog.py,sha256=pkH7nnxUP8yc0D3vRGd1jRb5cwi1nDVbQRk_OC9yLk8,4144
|
|
25
25
|
shinestacker/app/gui_utils.py,sha256=fSpkwPXTON_l676UHdAnJNrGq7BPbSlPOiHpOF_LZaI,2519
|
|
26
26
|
shinestacker/app/help_menu.py,sha256=g8lKG_xZmXtNQaC3SIRzyROKVWva_PLEgZsQWh6zUcQ,499
|
|
27
|
-
shinestacker/app/main.py,sha256=
|
|
27
|
+
shinestacker/app/main.py,sha256=JRfobAg_stqk7FZbGWNQChfdQHRzMXqFzVXe1gOci_I,10459
|
|
28
28
|
shinestacker/app/open_frames.py,sha256=bsu32iJSYJQLe_tQQbvAU5DuMDVX6MRuNdE7B5lojZc,1488
|
|
29
29
|
shinestacker/app/project.py,sha256=oopOiqU6bOK1cQdpot88z49KbKrlB-LAz_q4-8Iui0U,2819
|
|
30
30
|
shinestacker/app/retouch.py,sha256=dpSozNWSxL6wIO0SMjoviDbXZbbfRN_rVLjeL324c54,2527
|
|
31
31
|
shinestacker/config/__init__.py,sha256=aXxi-LmAvXd0daIFrVnTHE5OCaYeK1uf1BKMr7oaXQs,197
|
|
32
32
|
shinestacker/config/config.py,sha256=eBko2D3ADhLTIm9X6hB_a_WsIjwgfE-qmBVkhP1XSvc,1636
|
|
33
33
|
shinestacker/config/constants.py,sha256=EEdr7pZg4JpbIjUWaP7kJQfTuBB85FN739myDNAfn8A,8301
|
|
34
|
-
shinestacker/config/gui_constants.py,sha256=
|
|
34
|
+
shinestacker/config/gui_constants.py,sha256=YigJ5pRKjzjQKAN-ulosS6zLfnTj2BQESvVIvqXNzjA,2786
|
|
35
35
|
shinestacker/core/__init__.py,sha256=IUEIx6SQ3DygDEHN3_E6uKpHjHtUa4a_U_1dLd_8yEU,484
|
|
36
36
|
shinestacker/core/colors.py,sha256=kr_tJA1iRsdck2JaYDb2lS-codZ4Ty9gdu3kHfiWvuM,1340
|
|
37
37
|
shinestacker/core/core_utils.py,sha256=1LYj19Dfc9jZN9-4dlf1paximDH5WZYa7DXvKr7R7QY,1719
|
|
@@ -70,34 +70,35 @@ shinestacker/gui/img/forward-button-icon.png,sha256=lNw86T4TOEd_uokHYF8myGSGUXzd
|
|
|
70
70
|
shinestacker/gui/img/play-button-round-icon.png,sha256=9j6Ks9mOGa-2cXyRFpimepAAvSaHzqJKBfxShRb4_dE,4595
|
|
71
71
|
shinestacker/gui/img/plus-round-line-icon.png,sha256=LS068Hlu-CeBvJuB3dwwdJg1lZq6D5MUIv53lu1yKJA,7534
|
|
72
72
|
shinestacker/retouch/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
73
|
-
shinestacker/retouch/base_filter.py,sha256=
|
|
73
|
+
shinestacker/retouch/base_filter.py,sha256=gvRGvhOhhWS05jKOXyNdMnia3b7rscQqR8-xnySIWFc,10260
|
|
74
74
|
shinestacker/retouch/brush.py,sha256=dzD2FzSpBIPdJRmTZobcrQ1FrVd3tF__ZPnUplNE72s,357
|
|
75
75
|
shinestacker/retouch/brush_gradient.py,sha256=F5SFhyzl8YTMqjJU3jK8BrIlLCYLUvITd5wz3cQE4xk,1453
|
|
76
|
-
shinestacker/retouch/brush_preview.py,sha256=
|
|
76
|
+
shinestacker/retouch/brush_preview.py,sha256=03x7Hh-5g4JEQgBCK5mGUtVDtiOnJPOdU1JgeUJhGaA,4945
|
|
77
77
|
shinestacker/retouch/brush_tool.py,sha256=8uVncTA375uC3Nhp2YM0eZjpOR-nN47i2eGjN8tJzOU,8714
|
|
78
78
|
shinestacker/retouch/denoise_filter.py,sha256=TDUHzhRKlKvCa3D5SCYCZKTpjcl81kGwmONsgSDtO1k,440
|
|
79
|
-
shinestacker/retouch/display_manager.py,sha256=
|
|
79
|
+
shinestacker/retouch/display_manager.py,sha256=wwbX4n7ulg53fM3E5QL5YEb5IFV0jN8za6yfYc74anA,8624
|
|
80
80
|
shinestacker/retouch/exif_data.py,sha256=LF-fRXW-reMq-xJ_QRE5j8DC2LVGKIlC6MR3QbC1cdg,1896
|
|
81
81
|
shinestacker/retouch/file_loader.py,sha256=z02-A8_uDZxayI1NFTxT2GVUvEBWStchX9hlN1o5-0U,4784
|
|
82
82
|
shinestacker/retouch/filter_manager.py,sha256=SdYIZkZBUvuB6wDG0moGWav5sfEvIcB9ioUJR5wJFts,388
|
|
83
83
|
shinestacker/retouch/icon_container.py,sha256=6gw1HO1bC2FrdB4dc_iH81DQuLjzuvRGksZ2hKLT9yA,585
|
|
84
|
-
shinestacker/retouch/image_editor_ui.py,sha256=
|
|
85
|
-
shinestacker/retouch/image_view_status.py,sha256=
|
|
86
|
-
shinestacker/retouch/image_viewer.py,sha256=
|
|
84
|
+
shinestacker/retouch/image_editor_ui.py,sha256=0EW-jnKrQz9Z_xLS51AltWul7lHst4fAvubiWNH-g2o,33456
|
|
85
|
+
shinestacker/retouch/image_view_status.py,sha256=bdIhsXiYXm7eyjkTGWkw5PRShzaF_by-g7daqgmhwjM,1858
|
|
86
|
+
shinestacker/retouch/image_viewer.py,sha256=jkFVuBxWxoZqtaOS8N1R8iZ9WnyGfKGdczEdET2KTWU,4452
|
|
87
87
|
shinestacker/retouch/io_gui_handler.py,sha256=Upt8VWwDUrB-UnqCI54SQQwfR4w9kfznCdRL2UwupWQ,12010
|
|
88
88
|
shinestacker/retouch/io_manager.py,sha256=JUAA--AK0mVa1PTErJTnBFjaXIle5Qs7Ow0Wkd8at0o,2437
|
|
89
|
-
shinestacker/retouch/layer_collection.py,sha256=
|
|
90
|
-
shinestacker/retouch/overlaid_view.py,sha256=
|
|
89
|
+
shinestacker/retouch/layer_collection.py,sha256=fZlGrkm9-Ycc7AOzFSpImhafiTieBeCZRk-UlvlFHbo,5819
|
|
90
|
+
shinestacker/retouch/overlaid_view.py,sha256=NoFEwokTqbx41xnzYEHS0xhprHEAd2pRlH5NRAHxc2Y,7960
|
|
91
91
|
shinestacker/retouch/shortcuts_help.py,sha256=EDxwR7MZwUC9NHLjvqAlh5iEHT9g3g8Tzl18VUGErI4,4130
|
|
92
|
-
shinestacker/retouch/sidebyside_view.py,sha256=
|
|
93
|
-
shinestacker/retouch/
|
|
92
|
+
shinestacker/retouch/sidebyside_view.py,sha256=d9Pc2P_apTd0krsERIuEVc8RYBxiXs5tC7X9__t8TBc,18883
|
|
93
|
+
shinestacker/retouch/transformation_manager.py,sha256=NSHGUF-JFv4Y81gSvizjQCTp49TLo1so7c0WoUElO08,1812
|
|
94
|
+
shinestacker/retouch/undo_manager.py,sha256=cKUkqnJtnJ-Hq-LQs5Bv49FC6qkG6XSw9oCVySJ8jS0,4312
|
|
94
95
|
shinestacker/retouch/unsharp_mask_filter.py,sha256=uFnth8fpZFGhdIgJCnS8x5v6lBQgJ3hX0CBke9pFXeM,3510
|
|
95
|
-
shinestacker/retouch/view_strategy.py,sha256=
|
|
96
|
+
shinestacker/retouch/view_strategy.py,sha256=ex_bNym9pBXk9GDcpZr1vh4sJXx4ytrzavLRkHzeEXc,21234
|
|
96
97
|
shinestacker/retouch/vignetting_filter.py,sha256=MA97rQkSL0D-Nh-n2L4AiPR064RoTROkvza4tw84g9U,3658
|
|
97
98
|
shinestacker/retouch/white_balance_filter.py,sha256=glMBYlmrF-i_OrB3sGUpjZE6X4FQdyLC4GBy2bWtaFc,6056
|
|
98
|
-
shinestacker-1.
|
|
99
|
-
shinestacker-1.
|
|
100
|
-
shinestacker-1.
|
|
101
|
-
shinestacker-1.
|
|
102
|
-
shinestacker-1.
|
|
103
|
-
shinestacker-1.
|
|
99
|
+
shinestacker-1.5.0.dist-info/licenses/LICENSE,sha256=pWgb-bBdsU2Gd2kwAXxketnm5W_2u8_fIeWEgojfrxs,7651
|
|
100
|
+
shinestacker-1.5.0.dist-info/METADATA,sha256=FXzUo0Sa94vwqOVxvbUHFIeRrjRvGgNMqnmUgooYcIY,6978
|
|
101
|
+
shinestacker-1.5.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
102
|
+
shinestacker-1.5.0.dist-info/entry_points.txt,sha256=SY6g1LqtMmp23q1DGwLUDT_dhLX9iss8DvWkiWLyo_4,166
|
|
103
|
+
shinestacker-1.5.0.dist-info/top_level.txt,sha256=MhijwnBVX5psfsyX8JZjqp3SYiWPsKe69f3Gnyze4Fw,13
|
|
104
|
+
shinestacker-1.5.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|