shinestacker 0.3.0__tar.gz → 0.3.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.

Files changed (188) hide show
  1. {shinestacker-0.3.0 → shinestacker-0.3.1}/CHANGELOG.md +21 -0
  2. {shinestacker-0.3.0 → shinestacker-0.3.1}/PKG-INFO +1 -1
  3. {shinestacker-0.3.0 → shinestacker-0.3.1}/docs/gui.md +3 -6
  4. {shinestacker-0.3.0 → shinestacker-0.3.1}/docs/main.md +2 -2
  5. shinestacker-0.3.1/src/shinestacker/_version.py +1 -0
  6. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/algorithms/utils.py +4 -0
  7. shinestacker-0.3.1/src/shinestacker/algorithms/white_balance.py +13 -0
  8. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/gui/new_project.py +1 -0
  9. shinestacker-0.3.1/src/shinestacker/retouch/brush_gradient.py +20 -0
  10. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/retouch/brush_preview.py +11 -14
  11. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/retouch/image_editor.py +93 -202
  12. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/retouch/image_editor_ui.py +15 -8
  13. shinestacker-0.3.1/src/shinestacker/retouch/image_filters.py +391 -0
  14. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/retouch/image_viewer.py +13 -21
  15. shinestacker-0.3.1/src/shinestacker/retouch/io_manager.py +57 -0
  16. shinestacker-0.3.1/src/shinestacker/retouch/layer_collection.py +54 -0
  17. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker.egg-info/PKG-INFO +1 -1
  18. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker.egg-info/SOURCES.txt +6 -0
  19. shinestacker-0.3.1/tests/test_0053_white_balance.py +37 -0
  20. shinestacker-0.3.1/tests/test_0100_layer_collection.py +66 -0
  21. shinestacker-0.3.0/src/shinestacker/_version.py +0 -1
  22. shinestacker-0.3.0/src/shinestacker/retouch/image_filters.py +0 -463
  23. {shinestacker-0.3.0 → shinestacker-0.3.1}/.coverage +0 -0
  24. {shinestacker-0.3.0 → shinestacker-0.3.1}/.coveragerc +0 -0
  25. {shinestacker-0.3.0 → shinestacker-0.3.1}/.flake8 +0 -0
  26. {shinestacker-0.3.0 → shinestacker-0.3.1}/.github/workflows/ci-multiplatform.yml +0 -0
  27. {shinestacker-0.3.0 → shinestacker-0.3.1}/.github/workflows/pypi-publish.yml +0 -0
  28. {shinestacker-0.3.0 → shinestacker-0.3.1}/.github/workflows/release.yml +0 -0
  29. {shinestacker-0.3.0 → shinestacker-0.3.1}/.gitignore +0 -0
  30. {shinestacker-0.3.0 → shinestacker-0.3.1}/.readthedocs.yaml +0 -0
  31. {shinestacker-0.3.0 → shinestacker-0.3.1}/LICENSE +0 -0
  32. {shinestacker-0.3.0 → shinestacker-0.3.1}/README.md +0 -0
  33. {shinestacker-0.3.0 → shinestacker-0.3.1}/docs/alignment.md +0 -0
  34. {shinestacker-0.3.0 → shinestacker-0.3.1}/docs/api.md +0 -0
  35. {shinestacker-0.3.0 → shinestacker-0.3.1}/docs/balancing.md +0 -0
  36. {shinestacker-0.3.0 → shinestacker-0.3.1}/docs/conf.py +0 -0
  37. {shinestacker-0.3.0 → shinestacker-0.3.1}/docs/focus_stacking.md +0 -0
  38. {shinestacker-0.3.0 → shinestacker-0.3.1}/docs/index.md +0 -0
  39. {shinestacker-0.3.0 → shinestacker-0.3.1}/docs/job.md +0 -0
  40. {shinestacker-0.3.0 → shinestacker-0.3.1}/docs/multilayer.md +0 -0
  41. {shinestacker-0.3.0 → shinestacker-0.3.1}/docs/noise.md +0 -0
  42. {shinestacker-0.3.0 → shinestacker-0.3.1}/docs/requirements.txt +0 -0
  43. {shinestacker-0.3.0 → shinestacker-0.3.1}/docs/vignetting.md +0 -0
  44. {shinestacker-0.3.0 → shinestacker-0.3.1}/examples/balance-only.fsp +0 -0
  45. {shinestacker-0.3.0 → shinestacker-0.3.1}/examples/complete-project.fsp +0 -0
  46. {shinestacker-0.3.0 → shinestacker-0.3.1}/examples/focus-stack-1.ipynb +0 -0
  47. {shinestacker-0.3.0 → shinestacker-0.3.1}/examples/focus-stack-2.ipynb +0 -0
  48. {shinestacker-0.3.0 → shinestacker-0.3.1}/examples/input/img-jpg/0000.jpg +0 -0
  49. {shinestacker-0.3.0 → shinestacker-0.3.1}/examples/input/img-jpg/0001.jpg +0 -0
  50. {shinestacker-0.3.0 → shinestacker-0.3.1}/examples/input/img-jpg/0002.jpg +0 -0
  51. {shinestacker-0.3.0 → shinestacker-0.3.1}/examples/input/img-jpg/0003.jpg +0 -0
  52. {shinestacker-0.3.0 → shinestacker-0.3.1}/examples/input/img-jpg/0004.jpg +0 -0
  53. {shinestacker-0.3.0 → shinestacker-0.3.1}/examples/input/img-jpg/0005.jpg +0 -0
  54. {shinestacker-0.3.0 → shinestacker-0.3.1}/examples/input/img-noise/0001.jpg +0 -0
  55. {shinestacker-0.3.0 → shinestacker-0.3.1}/examples/input/img-noise/0002.jpg +0 -0
  56. {shinestacker-0.3.0 → shinestacker-0.3.1}/examples/input/img-noise/0003.jpg +0 -0
  57. {shinestacker-0.3.0 → shinestacker-0.3.1}/examples/input/img-noise/0004.jpg +0 -0
  58. {shinestacker-0.3.0 → shinestacker-0.3.1}/examples/input/img-noise/0005.jpg +0 -0
  59. {shinestacker-0.3.0 → shinestacker-0.3.1}/examples/input/img-noise/0006.jpg +0 -0
  60. {shinestacker-0.3.0 → shinestacker-0.3.1}/examples/input/img-tif/0000.tif +0 -0
  61. {shinestacker-0.3.0 → shinestacker-0.3.1}/examples/input/img-tif/0001.tif +0 -0
  62. {shinestacker-0.3.0 → shinestacker-0.3.1}/examples/input/img-tif/0002.tif +0 -0
  63. {shinestacker-0.3.0 → shinestacker-0.3.1}/examples/input/img-tif/0003.tif +0 -0
  64. {shinestacker-0.3.0 → shinestacker-0.3.1}/examples/input/img-tif/0004.tif +0 -0
  65. {shinestacker-0.3.0 → shinestacker-0.3.1}/examples/input/img-tif/0005.tif +0 -0
  66. {shinestacker-0.3.0 → shinestacker-0.3.1}/examples/input/img-vignetted/vig-0000.jpg +0 -0
  67. {shinestacker-0.3.0 → shinestacker-0.3.1}/examples/input/img-vignetted/vig-0001.jpg +0 -0
  68. {shinestacker-0.3.0 → shinestacker-0.3.1}/examples/input/img-vignetted/vig-0002.jpg +0 -0
  69. {shinestacker-0.3.0 → shinestacker-0.3.1}/examples/input/img-vignetted/vig-0003.jpg +0 -0
  70. {shinestacker-0.3.0 → shinestacker-0.3.1}/examples/stack-comparison.fsp +0 -0
  71. {shinestacker-0.3.0 → shinestacker-0.3.1}/examples/stack-from-frames.fsp +0 -0
  72. {shinestacker-0.3.0 → shinestacker-0.3.1}/examples/vignetting.fsp +0 -0
  73. {shinestacker-0.3.0 → shinestacker-0.3.1}/img/extreme-vignetting.jpg +0 -0
  74. {shinestacker-0.3.0 → shinestacker-0.3.1}/img/flies.gif +0 -0
  75. {shinestacker-0.3.0 → shinestacker-0.3.1}/img/flies_stack.jpg +0 -0
  76. {shinestacker-0.3.0 → shinestacker-0.3.1}/img/flow-diagram.png +0 -0
  77. {shinestacker-0.3.0 → shinestacker-0.3.1}/img/gui-finder.png +0 -0
  78. {shinestacker-0.3.0 → shinestacker-0.3.1}/img/gui-project-new.png +0 -0
  79. {shinestacker-0.3.0 → shinestacker-0.3.1}/img/gui-project-run.png +0 -0
  80. {shinestacker-0.3.0 → shinestacker-0.3.1}/img/gui-retouch.png +0 -0
  81. {shinestacker-0.3.0 → shinestacker-0.3.1}/pyproject.toml +0 -0
  82. {shinestacker-0.3.0 → shinestacker-0.3.1}/scripts/build_release.py +0 -0
  83. {shinestacker-0.3.0 → shinestacker-0.3.1}/scripts/validate-tomli.py +0 -0
  84. {shinestacker-0.3.0 → shinestacker-0.3.1}/setup.cfg +0 -0
  85. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/__init__.py +0 -0
  86. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/algorithms/__init__.py +0 -0
  87. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/algorithms/align.py +0 -0
  88. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/algorithms/balance.py +0 -0
  89. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/algorithms/core_utils.py +0 -0
  90. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/algorithms/denoise.py +0 -0
  91. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/algorithms/depth_map.py +0 -0
  92. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/algorithms/exif.py +0 -0
  93. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/algorithms/multilayer.py +0 -0
  94. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/algorithms/noise_detection.py +0 -0
  95. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/algorithms/pyramid.py +0 -0
  96. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/algorithms/sharpen.py +0 -0
  97. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/algorithms/stack.py +0 -0
  98. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/algorithms/stack_framework.py +0 -0
  99. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/algorithms/vignetting.py +0 -0
  100. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/app/__init__.py +0 -0
  101. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/app/about_dialog.py +0 -0
  102. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/app/app_config.py +0 -0
  103. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/app/gui_utils.py +0 -0
  104. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/app/help_menu.py +0 -0
  105. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/app/main.py +0 -0
  106. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/app/open_frames.py +0 -0
  107. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/app/project.py +0 -0
  108. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/app/retouch.py +0 -0
  109. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/config/__init__.py +0 -0
  110. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/config/config.py +0 -0
  111. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/config/constants.py +0 -0
  112. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/config/gui_constants.py +0 -0
  113. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/core/__init__.py +0 -0
  114. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/core/colors.py +0 -0
  115. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/core/core_utils.py +0 -0
  116. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/core/exceptions.py +0 -0
  117. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/core/framework.py +0 -0
  118. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/core/logging.py +0 -0
  119. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/gui/__init__.py +0 -0
  120. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/gui/action_config.py +0 -0
  121. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/gui/actions_window.py +0 -0
  122. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/gui/colors.py +0 -0
  123. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/gui/gui_images.py +0 -0
  124. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/gui/gui_logging.py +0 -0
  125. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/gui/gui_run.py +0 -0
  126. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/gui/ico/focus_stack_bkg.png +0 -0
  127. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/gui/ico/shinestacker.icns +0 -0
  128. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/gui/ico/shinestacker.ico +0 -0
  129. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/gui/ico/shinestacker.png +0 -0
  130. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/gui/img/close-round-line-icon.png +0 -0
  131. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/gui/img/forward-button-icon.png +0 -0
  132. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/gui/img/play-button-round-icon.png +0 -0
  133. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/gui/img/plus-round-line-icon.png +0 -0
  134. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/gui/main_window.py +0 -0
  135. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/gui/project_converter.py +0 -0
  136. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/gui/project_editor.py +0 -0
  137. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/gui/project_model.py +0 -0
  138. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/retouch/__init__.py +0 -0
  139. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/retouch/brush.py +0 -0
  140. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/retouch/brush_controller.py +0 -0
  141. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/retouch/exif_data.py +0 -0
  142. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/retouch/file_loader.py +0 -0
  143. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/retouch/shortcuts_help.py +0 -0
  144. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker/retouch/undo_manager.py +0 -0
  145. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker.egg-info/dependency_links.txt +0 -0
  146. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker.egg-info/entry_points.txt +0 -0
  147. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker.egg-info/requires.txt +0 -0
  148. {shinestacker-0.3.0 → shinestacker-0.3.1}/src/shinestacker.egg-info/top_level.txt +0 -0
  149. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test-align-balance.ipynb +0 -0
  150. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test-align.ipynb +0 -0
  151. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test-balance.ipynb +0 -0
  152. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test-exif.ipynb +0 -0
  153. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test-job.ipynb +0 -0
  154. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test-logging.ipynb +0 -0
  155. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test-multilayer.ipynb +0 -0
  156. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test-noise-detection.ipynb +0 -0
  157. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test-stack.ipynb +0 -0
  158. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test-vignetting.ipynb +0 -0
  159. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_0000_logging.py +0 -0
  160. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_0001_colors.py +0 -0
  161. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_0002_config.py +0 -0
  162. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_0005_make_test_img.py +0 -0
  163. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_0006_exceptions.py +0 -0
  164. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_0010_job.py +0 -0
  165. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_0011_core_utils.py +0 -0
  166. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_0020_noise_detection.py +0 -0
  167. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_0030_align.py +0 -0
  168. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_0031_align_precision.py +0 -0
  169. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_0032_align_methods.py +0 -0
  170. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_0040_balance.py +0 -0
  171. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_0050_align_balance.py +0 -0
  172. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_0051_denoise.py +0 -0
  173. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_0052_sharpen.py +0 -0
  174. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_0060_stack.py +0 -0
  175. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_0061_depth_map.py +0 -0
  176. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_0070_multilayer.py +0 -0
  177. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_0080_exif.py +0 -0
  178. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_0090_vignetting.py +0 -0
  179. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_0091_vignetting_algo.py +0 -0
  180. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_1000_brush_mask.py +0 -0
  181. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_1010_gui.py +0 -0
  182. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_1020_gui_images.py +0 -0
  183. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_1030_gui_logging.py +0 -0
  184. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_1040_action_config.py +0 -0
  185. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_1050_project_converter.py +0 -0
  186. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_1060_gui_run.py +0 -0
  187. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_1070_project_editor.py +0 -0
  188. {shinestacker-0.3.0 → shinestacker-0.3.1}/tests/test_1080_actions_window.py +0 -0
@@ -4,6 +4,27 @@ This page reports the main releases only and the main changes therein.
4
4
 
5
5
  ---
6
6
 
7
+ ## [v0.3.1] - 2025-08-12
8
+ **Fixes and code refactoring**
9
+
10
+ ### Changes
11
+
12
+ * some GUI fixes
13
+ * some code refactoring and cleanup
14
+
15
+ ---
16
+
17
+ ## [v0.3.0] - 2025-08-11
18
+ **Filters added to retouch GUI**
19
+
20
+ ### Changes
21
+
22
+ * added filters for sharpening, denoise and white balance
23
+ * updated documentation
24
+ * some bug fixes
25
+
26
+ ---
27
+
7
28
  ## [v0.2.2] - 2025-07-28
8
29
  **More stability and improved tests**
9
30
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: shinestacker
3
- Version: 0.3.0
3
+ Version: 0.3.1
4
4
  Summary: ShineStacker
5
5
  Author-email: Luca Lista <luka.lista@gmail.com>
6
6
  License-Expression: LGPL-3.0
@@ -99,7 +99,9 @@ Adjust in the top toolbar:
99
99
  3. **Verify**:
100
100
  - Toggle master view (`M`) to check results
101
101
  - Compare before/after with `L`/`M` toggle
102
- 3. **Export**:
102
+ 4. **Filters**:
103
+ - Improve the final image with sharpening, denoise and color balance
104
+ 5. **Export**:
103
105
  - ✅ Final image: Single TIFF/JPEG
104
106
  - 🗂️ Editable: Multilayer TIFF (large)
105
107
 
@@ -123,9 +125,4 @@ See help menu for complete list of shortcuts.
123
125
  **EXIF metadata**:
124
126
  * EXIF data can be imported from source images and saved with final file.
125
127
 
126
- ## Final retouch
127
-
128
- The final retouch, including color and luminosity balance, sharpness enhancement and
129
- so on can be applied with your favorite image processing application, like [GIMP](https://www.gimp.org/)
130
- or other.
131
128
 
@@ -94,7 +94,7 @@ job.run()
94
94
  ## Requirements
95
95
 
96
96
  * Python: 3.12 (3.13 may not work due to garbage collection issues)
97
- * RAM: 16GB+ recommended for >15 images of 20Mpx respolution
97
+ * RAM: 16GB+ recommended for >15 images at 20Mpx resolution
98
98
 
99
99
  ## Dependencies
100
100
 
@@ -116,6 +116,6 @@ pip install ipywidgets
116
116
 
117
117
  | Issue | Workaround |
118
118
  |----------|----------------|
119
- | Balance modes ```HSV```/```HLS``` fail with 16-bit images | convert to 8-bit or use ```RGB``` or luminosity |
119
+ | Balance modes ```HSV```/```HLS``` don't support 16-bit images | convert to 8-bit or use ```RGB``` or luminosity |
120
120
  | PNG support untested | Convert to TIFF/JPEG first |
121
121
  | GUI tests limited | Report bugs as GitHub issuse |
@@ -0,0 +1 @@
1
+ __version__ = '0.3.1'
@@ -47,10 +47,14 @@ def img_bw(img):
47
47
 
48
48
 
49
49
  def get_img_metadata(img):
50
+ if img is None:
51
+ return None, None
50
52
  return img.shape[:2], img.dtype
51
53
 
52
54
 
53
55
  def validate_image(img, expected_shape=None, expected_dtype=None):
56
+ if img is None:
57
+ raise RuntimeError("Image is None")
54
58
  shape, dtype = get_img_metadata(img)
55
59
  if expected_shape and shape[:2] != expected_shape[:2]:
56
60
  raise ShapeError(expected_shape, shape)
@@ -0,0 +1,13 @@
1
+ import numpy as np
2
+
3
+
4
+ def white_balance_from_rgb(img, target_rgb):
5
+ img_float = img.astype(np.float64)
6
+ target_bgr = (target_rgb[2], target_rgb[1], target_rgb[0])
7
+ target_gray = sum(target_bgr) / 3.0
8
+ scales = [target_gray / val if val != 0 else 1.0 for val in target_bgr]
9
+ for c in range(3):
10
+ img_float[..., c] *= scales[c]
11
+ max_val = np.iinfo(img.dtype).max
12
+ img_float = np.clip(img_float, 0, max_val)
13
+ return img_float.astype(img.dtype)
@@ -85,6 +85,7 @@ class NewProjectDialog(QDialog):
85
85
  bunch_overlap_range = gui_constants.NEW_PROJECT_BUNCH_OVERLAP
86
86
  self.bunch_overlap.setRange(bunch_overlap_range['min'], bunch_overlap_range['max'])
87
87
  self.bunch_overlap.setValue(constants.DEFAULT_OVERLAP)
88
+ self.update_bunch_options(gui_constants.NEW_PROJECT_BUNCH_STACK)
88
89
  self.focus_stack_pyramid = QCheckBox()
89
90
  self.focus_stack_pyramid.setChecked(gui_constants.NEW_PROJECT_FOCUS_STACK_PYRAMID)
90
91
  self.focus_stack_depth_map = QCheckBox()
@@ -0,0 +1,20 @@
1
+ from PySide6.QtGui import QRadialGradient
2
+ from PySide6.QtGui import QColor
3
+ from .. config.gui_constants import gui_constants
4
+
5
+
6
+ def create_brush_gradient(center_x, center_y, radius, hardness, inner_color=None, outer_color=None, opacity=100):
7
+ gradient = QRadialGradient(center_x, center_y, float(radius))
8
+ inner = inner_color if inner_color is not None else QColor(*gui_constants.BRUSH_COLORS['inner'])
9
+ outer = outer_color if outer_color is not None else QColor(*gui_constants.BRUSH_COLORS['gradient_end'])
10
+ inner_with_opacity = QColor(inner)
11
+ inner_with_opacity.setAlpha(int(float(inner.alpha()) * float(opacity) / 100.0))
12
+ if hardness < 100:
13
+ hardness_normalized = float(hardness) / 100.0
14
+ gradient.setColorAt(0.0, inner_with_opacity)
15
+ gradient.setColorAt(hardness_normalized, inner_with_opacity)
16
+ gradient.setColorAt(1.0, outer)
17
+ else:
18
+ gradient.setColorAt(0.0, inner_with_opacity)
19
+ gradient.setColorAt(1.0, inner_with_opacity)
20
+ return gradient
@@ -1,6 +1,6 @@
1
1
  import numpy as np
2
2
  from PySide6.QtWidgets import QGraphicsPixmapItem
3
- from PySide6.QtCore import Qt, QPointF
3
+ from PySide6.QtCore import Qt
4
4
  from PySide6.QtGui import QPixmap, QPainter, QImage
5
5
 
6
6
 
@@ -42,6 +42,8 @@ def create_brush_mask(size, hardness_percent, opacity_percent):
42
42
  class BrushPreviewItem(QGraphicsPixmapItem):
43
43
  def __init__(self):
44
44
  super().__init__()
45
+ self.layer_collection = None
46
+ self.brush = None
45
47
  self.setVisible(False)
46
48
  self.setZValue(500)
47
49
  self.setTransformationMode(Qt.SmoothTransformation)
@@ -68,31 +70,26 @@ class BrushPreviewItem(QGraphicsPixmapItem):
68
70
  else:
69
71
  raise Exception("Bitmas is neither 8 bit nor 16, but of type " + area.dtype)
70
72
 
71
- def update(self, editor, pos, size):
73
+ def update(self, scene_pos, size):
72
74
  try:
73
- if editor.current_stack is None or not hasattr(editor, 'image_viewer') or size <= 0:
75
+ if self.layer_collection.layer_stack is None or size <= 0:
74
76
  self.hide()
75
77
  return
76
78
  radius = size // 2
77
- if isinstance(pos, QPointF):
78
- scene_pos = pos
79
- else:
80
- cursor_pos = editor.image_viewer.mapFromGlobal(pos)
81
- scene_pos = editor.image_viewer.mapToScene(cursor_pos)
82
79
  x = int(scene_pos.x() - radius + 0.5)
83
80
  y = int(scene_pos.y() - radius)
84
81
  w = h = size
85
- if editor.current_layer < 0 or editor.current_layer >= len(editor.current_stack):
82
+ if not self.layer_collection.valid_current_layer_idx():
86
83
  self.hide()
87
84
  return
88
- layer_area = self.get_layer_area(editor.current_stack[editor.current_layer], x, y, w, h)
89
- master_area = self.get_layer_area(editor.master_layer, x, y, w, h)
85
+ layer_area = self.get_layer_area(self.layer_collection.current_layer(), x, y, w, h)
86
+ master_area = self.get_layer_area(self.layer_collection.master_layer, x, y, w, h)
90
87
  if layer_area is None or master_area is None:
91
88
  self.hide()
92
89
  return
93
- height, width = editor.current_stack[editor.current_layer].shape[:2]
94
- full_mask = create_brush_mask(size=size, hardness_percent=editor.brush.hardness,
95
- opacity_percent=editor.brush.opacity)[:, :, np.newaxis]
90
+ height, width = self.layer_collection.current_layer().shape[:2]
91
+ full_mask = create_brush_mask(size=size, hardness_percent=self.brush.hardness,
92
+ opacity_percent=self.brush.opacity)[:, :, np.newaxis]
96
93
  mask_x_start = max(0, -x) if x < 0 else 0
97
94
  mask_y_start = max(0, -y) if y < 0 else 0
98
95
  mask_x_end = size - (max(0, (x + w) - width)) if (x + w) > width else size