shinestacker 1.5.4__tar.gz → 1.6.1__tar.gz
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-1.5.4 → shinestacker-1.6.1}/.github/workflows/release.yml +11 -1
- {shinestacker-1.5.4 → shinestacker-1.6.1}/CHANGELOG.md +34 -0
- {shinestacker-1.5.4/src/shinestacker.egg-info → shinestacker-1.6.1}/PKG-INFO +1 -1
- shinestacker-1.6.1/scripts/build_release.py +112 -0
- shinestacker-1.6.1/scripts/hooks/hook-IPython.py +10 -0
- shinestacker-1.6.1/scripts/hooks/hook-PySide6.py +53 -0
- shinestacker-1.6.1/scripts/hooks/hook-opencv.py +24 -0
- shinestacker-1.6.1/scripts/hooks/hook-tests.py +7 -0
- shinestacker-1.6.1/scripts/scan_imports.py +47 -0
- shinestacker-1.6.1/scripts/shinestacker-inno-setup.iss +68 -0
- shinestacker-1.6.1/shinestacker-inno-setup.iss +68 -0
- shinestacker-1.6.1/src/shinestacker/_version.py +1 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/algorithms/multilayer.py +1 -1
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/algorithms/stack.py +17 -9
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/app/args_parser_opts.py +4 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/app/gui_utils.py +10 -2
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/app/main.py +8 -3
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/app/project.py +7 -3
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/app/retouch.py +8 -1
- shinestacker-1.6.1/src/shinestacker/app/settings_dialog.py +171 -0
- shinestacker-1.6.1/src/shinestacker/config/app_config.py +30 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/config/constants.py +3 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/config/gui_constants.py +4 -2
- shinestacker-1.6.1/src/shinestacker/config/settings.py +110 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/core/core_utils.py +3 -12
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/core/logging.py +3 -2
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/action_config.py +6 -5
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/action_config_dialog.py +17 -74
- shinestacker-1.6.1/src/shinestacker/gui/config_dialog.py +78 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/main_window.py +6 -6
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/menu_manager.py +2 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/new_project.py +2 -1
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/project_controller.py +8 -6
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/project_model.py +16 -1
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/recent_file_manager.py +3 -21
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/retouch/base_filter.py +1 -1
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/retouch/display_manager.py +48 -7
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/retouch/image_editor_ui.py +27 -36
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/retouch/image_view_status.py +4 -1
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/retouch/image_viewer.py +17 -9
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/retouch/io_gui_handler.py +96 -44
- shinestacker-1.6.1/src/shinestacker/retouch/io_threads.py +78 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/retouch/layer_collection.py +12 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/retouch/overlaid_view.py +13 -5
- shinestacker-1.6.1/src/shinestacker/retouch/paint_area_manager.py +30 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/retouch/sidebyside_view.py +32 -16
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/retouch/transformation_manager.py +1 -3
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/retouch/undo_manager.py +15 -13
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/retouch/view_strategy.py +79 -26
- {shinestacker-1.5.4 → shinestacker-1.6.1/src/shinestacker.egg-info}/PKG-INFO +1 -1
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker.egg-info/SOURCES.txt +13 -1
- shinestacker-1.5.4/scripts/build_release.py +0 -54
- shinestacker-1.5.4/src/shinestacker/_version.py +0 -1
- shinestacker-1.5.4/src/shinestacker/retouch/io_manager.py +0 -69
- {shinestacker-1.5.4 → shinestacker-1.6.1}/.coveragerc +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/.flake8 +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/.github/workflows/ci-multiplatform.yml +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/.github/workflows/pylint.yml +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/.github/workflows/pypi-publish.yml +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/.gitignore +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/.pylintrc +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/.readthedocs.yaml +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/LICENSE +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/MANIFEST.in +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/README.md +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/THIRD_PARTY_LICENSES.txt +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/docs/alignment.md +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/docs/api.md +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/docs/balancing.md +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/docs/conf.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/docs/focus_stacking.md +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/docs/gui.md +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/docs/index.md +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/docs/job.md +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/docs/main.md +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/docs/multilayer.md +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/docs/noise.md +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/docs/requirements.txt +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/docs/vignetting.md +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/img/coffee.gif +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/img/coffee_stack.jpg +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/img/extreme-vignetting.jpg +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/img/flies.gif +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/img/flies_stack.jpg +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/img/flow-diagram.png +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/img/gui-finder.png +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/img/gui-project-new.png +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/img/gui-project-run.png +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/img/gui-retouch.png +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/index.html +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/pyproject.toml +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/requirements.txt +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/scripts/git-rev-list.sh +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/scripts/validate-tomli.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/setup.cfg +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/__init__.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/algorithms/__init__.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/algorithms/align.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/algorithms/align_auto.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/algorithms/align_parallel.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/algorithms/balance.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/algorithms/base_stack_algo.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/algorithms/denoise.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/algorithms/depth_map.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/algorithms/exif.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/algorithms/noise_detection.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/algorithms/pyramid.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/algorithms/pyramid_auto.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/algorithms/pyramid_tiles.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/algorithms/sharpen.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/algorithms/stack_framework.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/algorithms/utils.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/algorithms/vignetting.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/algorithms/white_balance.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/app/__init__.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/app/about_dialog.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/app/help_menu.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/app/open_frames.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/config/__init__.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/config/config.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/core/__init__.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/core/colors.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/core/exceptions.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/core/framework.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/__init__.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/base_form_dialog.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/colors.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/flow_layout.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/folder_file_selection.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/gui_images.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/gui_logging.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/gui_run.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/ico/focus_stack_bkg.png +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/ico/shinestacker.icns +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/ico/shinestacker.ico +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/ico/shinestacker.png +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/ico/shinestacker.svg +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/img/close-round-line-icon.png +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/img/forward-button-icon.png +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/img/play-button-round-icon.png +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/img/plus-round-line-icon.png +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/project_converter.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/project_editor.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/select_path_widget.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/sys_mon.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/tab_widget.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/gui/time_progress_bar.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/retouch/__init__.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/retouch/brush.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/retouch/brush_gradient.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/retouch/brush_preview.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/retouch/brush_tool.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/retouch/denoise_filter.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/retouch/exif_data.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/retouch/file_loader.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/retouch/filter_manager.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/retouch/icon_container.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/retouch/shortcuts_help.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/retouch/unsharp_mask_filter.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/retouch/vignetting_filter.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker/retouch/white_balance_filter.py +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker.egg-info/dependency_links.txt +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker.egg-info/entry_points.txt +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker.egg-info/requires.txt +0 -0
- {shinestacker-1.5.4 → shinestacker-1.6.1}/src/shinestacker.egg-info/top_level.txt +0 -0
|
@@ -29,6 +29,10 @@ jobs:
|
|
|
29
29
|
with:
|
|
30
30
|
python-version: "3.12"
|
|
31
31
|
|
|
32
|
+
- name: Install Inno Setup
|
|
33
|
+
if: runner.os == 'Windows'
|
|
34
|
+
run: choco install innosetup -y --no-progress --accept-license
|
|
35
|
+
|
|
32
36
|
- name: Install dependencies
|
|
33
37
|
run: |
|
|
34
38
|
python -m pip install --upgrade pip
|
|
@@ -40,12 +44,14 @@ jobs:
|
|
|
40
44
|
run: |
|
|
41
45
|
python build_release.py
|
|
42
46
|
|
|
43
|
-
- name: Upload
|
|
47
|
+
- name: Upload artifacts
|
|
44
48
|
uses: actions/upload-artifact@v4
|
|
45
49
|
with:
|
|
46
50
|
name: shinestacker-${{ matrix.os }}
|
|
47
51
|
path: |
|
|
48
52
|
${{ matrix.os == 'windows-latest' && 'dist/shinestacker-release.zip' || 'dist/shinestacker-release.tar.gz' }}
|
|
53
|
+
${{ matrix.os == 'windows-latest' && 'dist/*.exe' || '' }}
|
|
54
|
+
if-no-files-found: ignore
|
|
49
55
|
create-release:
|
|
50
56
|
needs: publish-release
|
|
51
57
|
runs-on: ubuntu-latest
|
|
@@ -61,6 +67,9 @@ jobs:
|
|
|
61
67
|
cp artifacts/shinestacker-ubuntu-latest/shinestacker-release.tar.gz release_assets/shinestacker-ubuntu.tar.gz
|
|
62
68
|
cp artifacts/shinestacker-macos-latest/shinestacker-release.tar.gz release_assets/shinestacker-macos.tar.gz
|
|
63
69
|
cp artifacts/shinestacker-windows-latest/shinestacker-release.zip release_assets/shinestacker-windows.zip
|
|
70
|
+
if ls artifacts/shinestacker-windows-latest/shinestacker-setup.exe 1> /dev/null 2>&1; then
|
|
71
|
+
cp artifacts/shinestacker-windows-latest/shinestacker-setup.exe release_assets/
|
|
72
|
+
fi
|
|
64
73
|
ls -la release_assets/
|
|
65
74
|
|
|
66
75
|
- name: Create release
|
|
@@ -71,3 +80,4 @@ jobs:
|
|
|
71
80
|
release_assets/shinestacker-ubuntu.tar.gz
|
|
72
81
|
release_assets/shinestacker-macos.tar.gz
|
|
73
82
|
release_assets/shinestacker-windows.zip
|
|
83
|
+
release_assets/shinestacker-setup.exe
|
|
@@ -2,6 +2,40 @@
|
|
|
2
2
|
|
|
3
3
|
This page reports the main releases only and the main changes therein.
|
|
4
4
|
|
|
5
|
+
## [v1.6.1] - 2025-10-01
|
|
6
|
+
** Unreleased updates **
|
|
7
|
+
|
|
8
|
+
### Changed
|
|
9
|
+
- improved display update performance by refreshing only the painted area
|
|
10
|
+
- multiple frame import now runs in a separate thread, avoiding UI freezes
|
|
11
|
+
- reduced dependencies and code refactored for more robust architecture
|
|
12
|
+
- added windows installer
|
|
13
|
+
- dropped examples and test images reduces distribution file size
|
|
14
|
+
|
|
15
|
+
-----
|
|
16
|
+
|
|
17
|
+
## [v1.6.0] - 2025-09-27
|
|
18
|
+
**Few more features and several fixes**
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
- persistent settings dialog to configure app startup options
|
|
22
|
+
- command-line option ```-n``` to prevent opening the "new project" dialog
|
|
23
|
+
- zoom factor display in the status bar
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
- ghost brush gradient no longer appears at cursor transitions
|
|
27
|
+
- action and job names are now correctly set in the input dialog
|
|
28
|
+
- image centering fixed in viewport for double-view modes
|
|
29
|
+
- frame highlight works correctly when clicking on a thumbnail
|
|
30
|
+
- exif data is now correctly inserted into stacked output files
|
|
31
|
+
- bug in the retouch undo has been fixed
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
- cursor updates are now throttled (~60 fps) to improve responsiveness
|
|
35
|
+
- new projects created via dialog save exif data by default
|
|
36
|
+
|
|
37
|
+
----
|
|
38
|
+
|
|
5
39
|
## [v1.5.4] - 2025-09-23
|
|
6
40
|
**Bug fixes**
|
|
7
41
|
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import shutil
|
|
3
|
+
import tarfile
|
|
4
|
+
import subprocess
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
import platform
|
|
7
|
+
|
|
8
|
+
#
|
|
9
|
+
# assume the scripts runs under its directory, "scripts", as defined in release.yml
|
|
10
|
+
#
|
|
11
|
+
os.chdir("../")
|
|
12
|
+
project_root = Path(__file__).resolve().parent.parent
|
|
13
|
+
dist_dir = project_root / "dist"
|
|
14
|
+
project_name = "shinestacker"
|
|
15
|
+
app_name = "shinestacker"
|
|
16
|
+
package_dir = "shinestacker"
|
|
17
|
+
|
|
18
|
+
sys_name = platform.system().lower()
|
|
19
|
+
|
|
20
|
+
hooks_dir = "scripts/hooks"
|
|
21
|
+
|
|
22
|
+
print("=== USING HOOKS ===")
|
|
23
|
+
hook_files = list(Path(hooks_dir).glob("hook-*.py"))
|
|
24
|
+
for hook in hook_files:
|
|
25
|
+
print(f" - {hook.name}")
|
|
26
|
+
|
|
27
|
+
pyinstaller_cmd = [
|
|
28
|
+
"pyinstaller", "--onedir", f"--name={app_name}", "--paths=src",
|
|
29
|
+
f"--distpath=dist/{package_dir}", f"--collect-all={project_name}",
|
|
30
|
+
"--collect-data=imagecodecs", "--collect-submodules=imagecodecs",
|
|
31
|
+
"--copy-metadata=imagecodecs", f"--additional-hooks-dir={hooks_dir}"
|
|
32
|
+
]
|
|
33
|
+
if sys_name == 'darwin':
|
|
34
|
+
pyinstaller_cmd += ["--windowed", "--icon=src/shinestacker/gui/ico/shinestacker.icns"]
|
|
35
|
+
elif sys_name == 'windows':
|
|
36
|
+
pyinstaller_cmd += ["--windowed", "--icon=src/shinestacker/gui/ico/shinestacker.ico"]
|
|
37
|
+
pyinstaller_cmd += ["src/shinestacker/app/main.py"]
|
|
38
|
+
|
|
39
|
+
print(" ".join(pyinstaller_cmd))
|
|
40
|
+
subprocess.run(pyinstaller_cmd, check=True)
|
|
41
|
+
|
|
42
|
+
# examples_dir = project_root / "examples"
|
|
43
|
+
# target_examples = dist_dir / package_dir / "examples"
|
|
44
|
+
# target_examples.mkdir(exist_ok=True)
|
|
45
|
+
# for project_file in ["complete-project.fsp", "stack-from-frames.fsp"]:
|
|
46
|
+
# shutil.copy(examples_dir / project_file, target_examples)
|
|
47
|
+
# shutil.copytree(examples_dir / 'input', target_examples / 'input', dirs_exist_ok=True)
|
|
48
|
+
|
|
49
|
+
if sys_name == 'windows':
|
|
50
|
+
shutil.make_archive(
|
|
51
|
+
base_name=str(dist_dir / "shinestacker-release"),
|
|
52
|
+
format="zip",
|
|
53
|
+
root_dir=dist_dir,
|
|
54
|
+
base_dir=package_dir
|
|
55
|
+
)
|
|
56
|
+
else:
|
|
57
|
+
archive_path = dist_dir / "shinestacker-release.tar.gz"
|
|
58
|
+
with tarfile.open(archive_path, "w:gz") as tar:
|
|
59
|
+
tar.add(
|
|
60
|
+
dist_dir / package_dir,
|
|
61
|
+
arcname=package_dir,
|
|
62
|
+
recursive=True,
|
|
63
|
+
filter=lambda info: info
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
if sys_name == 'windows':
|
|
67
|
+
print("=== CREATING WINDOWS INSTALLER ===")
|
|
68
|
+
inno_paths = [
|
|
69
|
+
r"C:\Program Files (x86)\Inno Setup 6\ISCC.exe",
|
|
70
|
+
r"C:\Program Files (x86)\Inno Setup 5\ISCC.exe",
|
|
71
|
+
r"C:\Program Files\Inno Setup 6\ISCC.exe",
|
|
72
|
+
r"C:\Program Files\Inno Setup 5\ISCC.exe"
|
|
73
|
+
]
|
|
74
|
+
iscc_exe = None
|
|
75
|
+
for path in inno_paths:
|
|
76
|
+
if os.path.exists(path):
|
|
77
|
+
iscc_exe = path
|
|
78
|
+
print(f"Found Inno Setup at: {path}")
|
|
79
|
+
break
|
|
80
|
+
if not iscc_exe:
|
|
81
|
+
print("Inno Setup not found in standard locations. Checking for Chocolatey...")
|
|
82
|
+
try:
|
|
83
|
+
subprocess.run(["choco", "--version"], check=True, capture_output=True)
|
|
84
|
+
print("Installing Inno Setup via Chocolatey...")
|
|
85
|
+
subprocess.run(["choco", "install", "innosetup", "-y", "--no-progress", "--accept-license"], check=True)
|
|
86
|
+
for path in inno_paths:
|
|
87
|
+
if os.path.exists(path):
|
|
88
|
+
iscc_exe = path
|
|
89
|
+
print(f"Found Inno Setup at: {path}")
|
|
90
|
+
break
|
|
91
|
+
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
92
|
+
print("Chocolatey not available or installation failed.")
|
|
93
|
+
if iscc_exe:
|
|
94
|
+
iss_script_source = project_root / "scripts" / "shinestacker-inno-setup.iss"
|
|
95
|
+
iss_script_temp = project_root / "shinestacker-inno-setup.iss"
|
|
96
|
+
if iss_script_source.exists():
|
|
97
|
+
print(f"Copying ISS script to project root: {iss_script_temp}")
|
|
98
|
+
shutil.copy2(iss_script_source, iss_script_temp)
|
|
99
|
+
print(f"Compiling installer with: {iscc_exe}")
|
|
100
|
+
subprocess.run([iscc_exe, str(iss_script_temp)], check=True)
|
|
101
|
+
print("Removing temporary ISS script")
|
|
102
|
+
iss_script_temp.unlink()
|
|
103
|
+
if dist_dir.exists():
|
|
104
|
+
installer_files = list(dist_dir.glob("*.exe"))
|
|
105
|
+
if installer_files:
|
|
106
|
+
print(f"Installer created: {installer_files[0].name}")
|
|
107
|
+
else:
|
|
108
|
+
print(f"ISS script not found at: {iss_script_source}")
|
|
109
|
+
else:
|
|
110
|
+
print("WARNING: Could not find or install Inno Setup. Skipping installer creation.")
|
|
111
|
+
print("You can manually install Inno Setup from: https://jrsoftware.org/isdl.php")
|
|
112
|
+
print("Or install Chocolatey and run: choco install innosetup -y")
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
excludedimports = [
|
|
2
|
+
# Keep only these 5 modules actually used:
|
|
3
|
+
# PySide6.QtCore
|
|
4
|
+
# PySide6.QtGui
|
|
5
|
+
# PySide6.QtPdf
|
|
6
|
+
# PySide6.QtPdfWidgets
|
|
7
|
+
# PySide6.QtWidgets
|
|
8
|
+
|
|
9
|
+
# Exclude everything else:
|
|
10
|
+
'PySide6.Qt3DAnimation',
|
|
11
|
+
'PySide6.Qt3DCore',
|
|
12
|
+
'PySide6.Qt3DExtras',
|
|
13
|
+
'PySide6.Qt3DInput',
|
|
14
|
+
'PySide6.Qt3DLogic',
|
|
15
|
+
'PySide6.Qt3DRender',
|
|
16
|
+
'PySide6.QtBluetooth',
|
|
17
|
+
'PySide6.QtCharts',
|
|
18
|
+
'PySide6.QtConcurrent',
|
|
19
|
+
'PySide6.QtDataVisualization',
|
|
20
|
+
'PySide6.QtDBus',
|
|
21
|
+
'PySide6.QtDesigner',
|
|
22
|
+
'PySide6.QtGamepad',
|
|
23
|
+
'PySide6.QtHelp',
|
|
24
|
+
'PySide6.QtLocation',
|
|
25
|
+
'PySide6.QtMultimedia',
|
|
26
|
+
'PySide6.QtMultimediaWidgets',
|
|
27
|
+
'PySide6.QtNetwork',
|
|
28
|
+
'PySide6.QtNfc',
|
|
29
|
+
'PySide6.QtOpenGL',
|
|
30
|
+
'PySide6.QtOpenGLWidgets',
|
|
31
|
+
'PySide6.QtPositioning',
|
|
32
|
+
'PySide6.QtPrintSupport',
|
|
33
|
+
'PySide6.QtQml',
|
|
34
|
+
'PySide6.QtQuick',
|
|
35
|
+
'PySide6.QtQuick3D',
|
|
36
|
+
'PySide6.QtQuickWidgets',
|
|
37
|
+
'PySide6.QtRemoteObjects',
|
|
38
|
+
'PySide6.QtScxml',
|
|
39
|
+
'PySide6.QtSensors',
|
|
40
|
+
'PySide6.QtSerialPort',
|
|
41
|
+
'PySide6.QtSql',
|
|
42
|
+
'PySide6.QtSvg',
|
|
43
|
+
'PySide6.QtTest',
|
|
44
|
+
'PySide6.QtTextToSpeech',
|
|
45
|
+
'PySide6.QtUiTools',
|
|
46
|
+
'PySide6.QtWebChannel',
|
|
47
|
+
'PySide6.QtWebEngine',
|
|
48
|
+
'PySide6.QtWebEngineCore',
|
|
49
|
+
'PySide6.QtWebEngineWidgets',
|
|
50
|
+
'PySide6.QtWebSockets',
|
|
51
|
+
'PySide6.QtXml',
|
|
52
|
+
'PySide6.QtXmlPatterns',
|
|
53
|
+
]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
excludedimports = [
|
|
2
|
+
'cv2.videoio',
|
|
3
|
+
'cv2.videostab',
|
|
4
|
+
'cv2.face',
|
|
5
|
+
'cv2.bgsegm',
|
|
6
|
+
'cv2.optflow',
|
|
7
|
+
'cv2.saliency',
|
|
8
|
+
'cv2.text',
|
|
9
|
+
'cv2.tracking',
|
|
10
|
+
'cv2.mcc',
|
|
11
|
+
'cv2.rapid',
|
|
12
|
+
'cv2.stereo',
|
|
13
|
+
'cv2.dnn',
|
|
14
|
+
'cv2.freetype',
|
|
15
|
+
'cv2.hdf',
|
|
16
|
+
'cv2.img_hash',
|
|
17
|
+
'cv2.line_descriptor',
|
|
18
|
+
'cv2.reg',
|
|
19
|
+
'cv2.rgbd',
|
|
20
|
+
'cv2.surface_matching',
|
|
21
|
+
'cv2.xfeatures2d',
|
|
22
|
+
'cv2.ximgproc',
|
|
23
|
+
'cv2.xphoto',
|
|
24
|
+
]
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import ast
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
def scan_imports():
|
|
5
|
+
project_root = Path("../src/shinestacker")
|
|
6
|
+
imports = {
|
|
7
|
+
'PySide6': set(),
|
|
8
|
+
'scipy': set(),
|
|
9
|
+
'matplotlib': set(),
|
|
10
|
+
'cv2': set(),
|
|
11
|
+
'numpy': set(),
|
|
12
|
+
'PIL': set()
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
for py_file in project_root.rglob("*.py"):
|
|
16
|
+
with open(py_file, 'r', encoding='utf-8') as f:
|
|
17
|
+
try:
|
|
18
|
+
tree = ast.parse(f.read())
|
|
19
|
+
except:
|
|
20
|
+
continue
|
|
21
|
+
|
|
22
|
+
for node in ast.walk(tree):
|
|
23
|
+
if isinstance(node, ast.Import):
|
|
24
|
+
for alias in node.names:
|
|
25
|
+
for lib in imports.keys():
|
|
26
|
+
if lib in alias.name:
|
|
27
|
+
imports[lib].add(alias.name)
|
|
28
|
+
elif isinstance(node, ast.ImportFrom):
|
|
29
|
+
if node.module:
|
|
30
|
+
for lib in imports.keys():
|
|
31
|
+
if lib in node.module:
|
|
32
|
+
imports[lib].add(node.module)
|
|
33
|
+
if node.names:
|
|
34
|
+
for alias in node.names:
|
|
35
|
+
imports[lib].add(f"{node.module}.{alias.name}")
|
|
36
|
+
return imports
|
|
37
|
+
|
|
38
|
+
def print_imports(imports):
|
|
39
|
+
for lib, modules in imports.items():
|
|
40
|
+
if modules:
|
|
41
|
+
print(f"\n=== {lib.upper()} IMPORTS ===")
|
|
42
|
+
for imp in sorted(modules):
|
|
43
|
+
print(f" {imp}")
|
|
44
|
+
|
|
45
|
+
if __name__ == "__main__":
|
|
46
|
+
found_imports = scan_imports()
|
|
47
|
+
print_imports(found_imports)
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#define MyAppName "ShineStacker"
|
|
2
|
+
#define MyAppVersion "1.6.1"
|
|
3
|
+
#define MyAppPublisher "Luca Lista"
|
|
4
|
+
#define MyAppURL "https://shinestacker.wordpress.com/"
|
|
5
|
+
#define MyAppExeName "shinestacker.exe"
|
|
6
|
+
#define MyAppAssocName MyAppName + " focus stacking project"
|
|
7
|
+
#define MyAppAssocExt ".fsp"
|
|
8
|
+
#define MyAppAssocKey StringChange(MyAppAssocName, " ", "") + MyAppAssocExt
|
|
9
|
+
|
|
10
|
+
[Setup]
|
|
11
|
+
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
|
|
12
|
+
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
|
|
13
|
+
AppId={{A2B55EAF-932F-4D5A-8D80-B7DF79D5AE7B}
|
|
14
|
+
AppName={#MyAppName}
|
|
15
|
+
AppVersion={#MyAppVersion}
|
|
16
|
+
;AppVerName={#MyAppName} {#MyAppVersion}
|
|
17
|
+
AppPublisher={#MyAppPublisher}
|
|
18
|
+
AppPublisherURL={#MyAppURL}
|
|
19
|
+
AppSupportURL={#MyAppURL}
|
|
20
|
+
AppUpdatesURL={#MyAppURL}
|
|
21
|
+
DefaultDirName={autopf}\{#MyAppName}
|
|
22
|
+
UninstallDisplayIcon={app}\{#MyAppExeName}
|
|
23
|
+
; "ArchitecturesAllowed=x64compatible" specifies that Setup cannot run
|
|
24
|
+
; on anything but x64 and Windows 11 on Arm.
|
|
25
|
+
ArchitecturesAllowed=x64compatible
|
|
26
|
+
; "ArchitecturesInstallIn64BitMode=x64compatible" requests that the
|
|
27
|
+
; install be done in "64-bit mode" on x64 or Windows 11 on Arm,
|
|
28
|
+
; meaning it should use the native 64-bit Program Files directory and
|
|
29
|
+
; the 64-bit view of the registry.
|
|
30
|
+
ArchitecturesInstallIn64BitMode=x64compatible
|
|
31
|
+
ChangesAssociations=yes
|
|
32
|
+
DisableProgramGroupPage=yes
|
|
33
|
+
LicenseFile=.\LICENSE
|
|
34
|
+
; Uncomment the following line to run in non administrative install mode (install for current user only).
|
|
35
|
+
;PrivilegesRequired=lowest
|
|
36
|
+
OutputBaseFilename=shinestacker-setup
|
|
37
|
+
OutputDir=.\dist
|
|
38
|
+
VersionInfoVersion={#MyAppVersion}
|
|
39
|
+
VersionInfoCompany={#MyAppPublisher}
|
|
40
|
+
SetupIconFile=.\src\shinestacker\gui\ico\shinestacker.ico
|
|
41
|
+
SolidCompression=yes
|
|
42
|
+
WizardStyle=modern
|
|
43
|
+
|
|
44
|
+
[Languages]
|
|
45
|
+
Name: "english"; MessagesFile: "compiler:Default.isl"
|
|
46
|
+
|
|
47
|
+
[Tasks]
|
|
48
|
+
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
|
|
49
|
+
|
|
50
|
+
[Files]
|
|
51
|
+
; Copy the entire shinestacker folder structure that contains both the exe and _internal
|
|
52
|
+
Source: ".\dist\shinestacker\shinestacker\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
|
53
|
+
Source: ".\examples\*"; DestDir: "{app}\examples"; Flags: ignoreversion recursesubdirs
|
|
54
|
+
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
|
|
55
|
+
|
|
56
|
+
[Registry]
|
|
57
|
+
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocExt}\OpenWithProgids"; ValueType: string; ValueName: "{#MyAppAssocKey}"; ValueData: ""; Flags: uninsdeletevalue
|
|
58
|
+
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}"; ValueType: string; ValueName: ""; ValueData: "{#MyAppAssocName}"; Flags: uninsdeletekey
|
|
59
|
+
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName},0"
|
|
60
|
+
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1"""
|
|
61
|
+
|
|
62
|
+
[Icons]
|
|
63
|
+
Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
|
|
64
|
+
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
|
|
65
|
+
|
|
66
|
+
[Run]
|
|
67
|
+
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
|
|
68
|
+
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#define MyAppName "ShineStacker"
|
|
2
|
+
#define MyAppVersion "1.6.1"
|
|
3
|
+
#define MyAppPublisher "Luca Lista"
|
|
4
|
+
#define MyAppURL "https://shinestacker.wordpress.com/"
|
|
5
|
+
#define MyAppExeName "shinestacker.exe"
|
|
6
|
+
#define MyAppAssocName MyAppName + " focus stacking project"
|
|
7
|
+
#define MyAppAssocExt ".fsp"
|
|
8
|
+
#define MyAppAssocKey StringChange(MyAppAssocName, " ", "") + MyAppAssocExt
|
|
9
|
+
|
|
10
|
+
[Setup]
|
|
11
|
+
; NOTE: The value of AppId uniquely identifies this application. Do not use the same AppId value in installers for other applications.
|
|
12
|
+
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
|
|
13
|
+
AppId={{A2B55EAF-932F-4D5A-8D80-B7DF79D5AE7B}
|
|
14
|
+
AppName={#MyAppName}
|
|
15
|
+
AppVersion={#MyAppVersion}
|
|
16
|
+
;AppVerName={#MyAppName} {#MyAppVersion}
|
|
17
|
+
AppPublisher={#MyAppPublisher}
|
|
18
|
+
AppPublisherURL={#MyAppURL}
|
|
19
|
+
AppSupportURL={#MyAppURL}
|
|
20
|
+
AppUpdatesURL={#MyAppURL}
|
|
21
|
+
DefaultDirName={autopf}\{#MyAppName}
|
|
22
|
+
UninstallDisplayIcon={app}\{#MyAppExeName}
|
|
23
|
+
; "ArchitecturesAllowed=x64compatible" specifies that Setup cannot run
|
|
24
|
+
; on anything but x64 and Windows 11 on Arm.
|
|
25
|
+
ArchitecturesAllowed=x64compatible
|
|
26
|
+
; "ArchitecturesInstallIn64BitMode=x64compatible" requests that the
|
|
27
|
+
; install be done in "64-bit mode" on x64 or Windows 11 on Arm,
|
|
28
|
+
; meaning it should use the native 64-bit Program Files directory and
|
|
29
|
+
; the 64-bit view of the registry.
|
|
30
|
+
ArchitecturesInstallIn64BitMode=x64compatible
|
|
31
|
+
ChangesAssociations=yes
|
|
32
|
+
DisableProgramGroupPage=yes
|
|
33
|
+
LicenseFile=.\LICENSE
|
|
34
|
+
; Uncomment the following line to run in non administrative install mode (install for current user only).
|
|
35
|
+
;PrivilegesRequired=lowest
|
|
36
|
+
OutputBaseFilename=shinestacker-setup
|
|
37
|
+
OutputDir=.\dist
|
|
38
|
+
VersionInfoVersion={#MyAppVersion}
|
|
39
|
+
VersionInfoCompany={#MyAppPublisher}
|
|
40
|
+
SetupIconFile=.\src\shinestacker\gui\ico\shinestacker.ico
|
|
41
|
+
SolidCompression=yes
|
|
42
|
+
WizardStyle=modern
|
|
43
|
+
|
|
44
|
+
[Languages]
|
|
45
|
+
Name: "english"; MessagesFile: "compiler:Default.isl"
|
|
46
|
+
|
|
47
|
+
[Tasks]
|
|
48
|
+
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
|
|
49
|
+
|
|
50
|
+
[Files]
|
|
51
|
+
; Copy the entire shinestacker folder structure that contains both the exe and _internal
|
|
52
|
+
Source: ".\dist\shinestacker\shinestacker\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
|
|
53
|
+
Source: ".\examples\*"; DestDir: "{app}\examples"; Flags: ignoreversion recursesubdirs
|
|
54
|
+
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
|
|
55
|
+
|
|
56
|
+
[Registry]
|
|
57
|
+
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocExt}\OpenWithProgids"; ValueType: string; ValueName: "{#MyAppAssocKey}"; ValueData: ""; Flags: uninsdeletevalue
|
|
58
|
+
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}"; ValueType: string; ValueName: ""; ValueData: "{#MyAppAssocName}"; Flags: uninsdeletekey
|
|
59
|
+
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\{#MyAppExeName},0"
|
|
60
|
+
Root: HKA; Subkey: "Software\Classes\{#MyAppAssocKey}\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#MyAppExeName}"" ""%1"""
|
|
61
|
+
|
|
62
|
+
[Icons]
|
|
63
|
+
Name: "{autoprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
|
|
64
|
+
Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
|
|
65
|
+
|
|
66
|
+
[Run]
|
|
67
|
+
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent
|
|
68
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '1.6.1'
|
|
@@ -174,7 +174,7 @@ class MultiLayer(TaskBase, ImageSequenceManager):
|
|
|
174
174
|
if self.exif_path == '':
|
|
175
175
|
self.exif_path = job.action_path(0)
|
|
176
176
|
if self.exif_path != '':
|
|
177
|
-
self.exif_path = self.working_path
|
|
177
|
+
self.exif_path = os.path.join(self.working_path, self.exif_path)
|
|
178
178
|
|
|
179
179
|
def run_core(self):
|
|
180
180
|
if isinstance(self.input_full_path(), str):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# pylint: disable=C0114, C0115, C0116, R0913, R0917
|
|
2
2
|
import os
|
|
3
|
-
import
|
|
3
|
+
import traceback
|
|
4
4
|
from .. config.constants import constants
|
|
5
5
|
from .. core.framework import TaskBase
|
|
6
6
|
from .. core.colors import color_str
|
|
@@ -34,13 +34,19 @@ class FocusStackBase(TaskBase, ImageSequenceManager):
|
|
|
34
34
|
self.sub_message_r(': denoise image')
|
|
35
35
|
stacked_img = denoise(stacked_img, self.denoise_amount, self.denoise_amount)
|
|
36
36
|
write_img(out_filename, stacked_img)
|
|
37
|
-
if self.exif_path != ''
|
|
38
|
-
self.sub_message_r(': copy exif data')
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
37
|
+
if self.exif_path != '':
|
|
38
|
+
self.sub_message_r(color_str(': copy exif data', constants.LOG_COLOR_LEVEL_3))
|
|
39
|
+
if not os.path.exists(self.exif_path):
|
|
40
|
+
raise RuntimeError(f"Path {self.exif_path} does not exist.")
|
|
41
|
+
try:
|
|
42
|
+
_dirpath, _, fnames = next(os.walk(self.exif_path))
|
|
43
|
+
fnames = [name for name in fnames if extension_tif_jpg(name)]
|
|
44
|
+
exif_filename = os.path.join(self.exif_path, fnames[0])
|
|
45
|
+
copy_exif_from_file_to_file(exif_filename, out_filename)
|
|
46
|
+
self.sub_message_r(' ' * 60)
|
|
47
|
+
except Exception as e:
|
|
48
|
+
traceback.print_tb(e.__traceback__)
|
|
49
|
+
raise RuntimeError("Can't copy EXIF data") from e
|
|
44
50
|
if self.plot_stack:
|
|
45
51
|
idx_str = f"{self.frame_count + 1:04d}" if self.frame_count >= 0 else ''
|
|
46
52
|
name = f"{self.name}: {self.stack_algo.name()}"
|
|
@@ -51,11 +57,13 @@ class FocusStackBase(TaskBase, ImageSequenceManager):
|
|
|
51
57
|
self.frame_count += 1
|
|
52
58
|
|
|
53
59
|
def init(self, job, working_path=''):
|
|
60
|
+
if working_path == '':
|
|
61
|
+
working_path = job.working_path
|
|
54
62
|
ImageSequenceManager.init(self, job)
|
|
55
63
|
if self.exif_path is None:
|
|
56
64
|
self.exif_path = job.action_path(0)
|
|
57
65
|
if self.exif_path != '':
|
|
58
|
-
self.exif_path = working_path
|
|
66
|
+
self.exif_path = os.path.join(working_path, self.exif_path)
|
|
59
67
|
|
|
60
68
|
|
|
61
69
|
def get_bunches(collection, n_frames, n_overlap):
|
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
def add_project_arguments(parser):
|
|
4
4
|
parser.add_argument('-x', '--expert', action='store_true', help='''
|
|
5
5
|
expert options are visible by default.
|
|
6
|
+
''')
|
|
7
|
+
parser.add_argument('-n', '--no-new-project', dest='new-project',
|
|
8
|
+
action='store_false', default=True, help='''
|
|
9
|
+
Do not open new project dialog at startup (default: open).
|
|
6
10
|
''')
|
|
7
11
|
|
|
8
12
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# pylint: disable=C0114, C0116, E0611
|
|
1
|
+
# pylint: disable=C0114, C0116, E0611, R0913, R0917
|
|
2
2
|
import os
|
|
3
3
|
import sys
|
|
4
4
|
from PySide6.QtCore import QCoreApplication, QProcess
|
|
@@ -6,6 +6,7 @@ from PySide6.QtGui import QAction
|
|
|
6
6
|
from shinestacker.config.constants import constants
|
|
7
7
|
from shinestacker.config.config import config
|
|
8
8
|
from shinestacker.app.about_dialog import show_about_dialog
|
|
9
|
+
from shinestacker.app.settings_dialog import show_settings_dialog
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
def disable_macos_special_menu_items():
|
|
@@ -40,11 +41,18 @@ def disable_macos_special_menu_items():
|
|
|
40
41
|
QProcess.startDetached("pkill", ["-u", user, "-f", "SystemUIServer"])
|
|
41
42
|
|
|
42
43
|
|
|
43
|
-
def fill_app_menu(app, app_menu
|
|
44
|
+
def fill_app_menu(app, app_menu, project_settings, retouch_settings,
|
|
45
|
+
handle_project_config, handle_retouch_config):
|
|
44
46
|
about_action = QAction(f"About {constants.APP_STRING}", app)
|
|
45
47
|
about_action.triggered.connect(lambda: show_about_dialog(app))
|
|
46
48
|
app_menu.addAction(about_action)
|
|
47
49
|
app_menu.addSeparator()
|
|
50
|
+
settings_action = QAction("Settings", app)
|
|
51
|
+
settings_action.triggered.connect(lambda: show_settings_dialog(
|
|
52
|
+
app, project_settings, retouch_settings,
|
|
53
|
+
handle_project_config, handle_retouch_config))
|
|
54
|
+
app_menu.addAction(settings_action)
|
|
55
|
+
app_menu.addSeparator()
|
|
48
56
|
if config.DONT_USE_NATIVE_MENU:
|
|
49
57
|
quit_txt, quit_short = "&Quit", "Ctrl+Q"
|
|
50
58
|
else:
|
|
@@ -13,6 +13,7 @@ from PySide6.QtCore import Qt, QEvent, QTimer, Signal
|
|
|
13
13
|
from shinestacker.config.config import config
|
|
14
14
|
config.init(DISABLE_TQDM=True, COMBINED_APP=True, DONT_USE_NATIVE_MENU=True)
|
|
15
15
|
from shinestacker.config.constants import constants
|
|
16
|
+
from shinestacker.config.settings import StdPathFile
|
|
16
17
|
from shinestacker.core.logging import setup_logging
|
|
17
18
|
from shinestacker.gui.main_window import MainWindow
|
|
18
19
|
from shinestacker.retouch.image_editor_ui import ImageEditorUI
|
|
@@ -140,7 +141,9 @@ class MainApp(QMainWindow):
|
|
|
140
141
|
app_menu.addAction(self.switch_to_project_action)
|
|
141
142
|
app_menu.addAction(self.switch_to_retouch_action)
|
|
142
143
|
app_menu.addSeparator()
|
|
143
|
-
fill_app_menu(self, app_menu
|
|
144
|
+
fill_app_menu(self, app_menu, True, True,
|
|
145
|
+
self.project_window.handle_config,
|
|
146
|
+
self.retouch_window.handle_config)
|
|
144
147
|
return app_menu
|
|
145
148
|
|
|
146
149
|
def quit(self):
|
|
@@ -227,7 +230,8 @@ open retouch window at startup instead of project windows.
|
|
|
227
230
|
if filename and path:
|
|
228
231
|
print("can't specify both arguments --filename and --path", file=sys.stderr)
|
|
229
232
|
sys.exit(1)
|
|
230
|
-
setup_logging(console_level=logging.DEBUG, file_level=logging.DEBUG, disable_console=True
|
|
233
|
+
setup_logging(console_level=logging.DEBUG, file_level=logging.DEBUG, disable_console=True,
|
|
234
|
+
log_file=StdPathFile('shinestacker.log').get_file_path())
|
|
231
235
|
app = Application(sys.argv)
|
|
232
236
|
if config.DONT_USE_NATIVE_MENU:
|
|
233
237
|
app.setAttribute(Qt.AA_DontUseNativeMenuBar)
|
|
@@ -264,7 +268,8 @@ open retouch window at startup instead of project windows.
|
|
|
264
268
|
main_app.switch_to_retouch()
|
|
265
269
|
else:
|
|
266
270
|
main_app.switch_to_project()
|
|
267
|
-
|
|
271
|
+
if args['new-project']:
|
|
272
|
+
QTimer.singleShot(100, main_app.project_window.project_controller.new_project)
|
|
268
273
|
QTimer.singleShot(100, main_app.setFocus)
|
|
269
274
|
sys.exit(app.exec())
|
|
270
275
|
|