Skip to content

Commit 8ed155b

Browse files
Merge pull request #23 from gregzaal/openCVless
Merging the refactored code, running on uv, with expanded ui features, and working setup for builds using nuitka. OpenCV implementations have been excluded due to failing to build.
2 parents 0f6d03a + 342c14d commit 8ed155b

39 files changed

Lines changed: 3599 additions & 1700 deletions

.github/workflows/release.yml

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
name: Build and Release EXE
2+
3+
on:
4+
push:
5+
tags:
6+
- 'v*' # Triggers only when you push a tag like v0.1.3
7+
8+
jobs:
9+
build:
10+
runs-on: windows-latest
11+
12+
steps:
13+
- name: Checkout Code
14+
uses: actions/checkout@v4
15+
16+
- name: Install uv
17+
uses: astral-sh/setup-uv@v5
18+
with:
19+
enable-cache: true
20+
21+
- name: Set up Python
22+
run: uv python install
23+
24+
- name: Extract Version from pyproject.toml
25+
id: get_version
26+
shell: pwsh
27+
run: |
28+
$version = (Get-Content pyproject.toml | Select-String '^version\s*=\s*\"(.*)\"').Matches.Groups[1].Value
29+
echo "VERSION=$version" >> $env:GITHUB_OUTPUT
30+
31+
- name: Build with Nuitka
32+
run: uv run python -m nuitka hdr_brackets.py
33+
# Note: Nuitka uses your # nuitka-project: comments automatically.
34+
35+
36+
- name: Rename Dist Folder
37+
shell: pwsh
38+
run: |
39+
Rename-Item -Path "build/hdr_brackets.dist" -NewName "hdr_merge_master.dist"
40+
41+
- name: Create Zip Archive
42+
shell: pwsh
43+
run: |
44+
Compress-Archive -Path "build/hdr_merge_master.dist/*" -DestinationPath "build/hdr_merge_master_v${{ steps.get_version.outputs.VERSION }}.zip"
45+
46+
- name: Create GitHub Release
47+
uses: softprops/action-gh-release@v2
48+
with:
49+
files: build/hdr_merge_master_v${{ steps.get_version.outputs.VERSION }}.zip
50+
name: Release v${{ steps.get_version.outputs.VERSION }}
51+
tag_name: ${{ github.ref_name }}
52+
draft: false
53+
prerelease: false
54+
env:
55+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,24 @@
1+
# --- UV & Python Essentials ---
2+
.venv/
3+
__pycache__/
4+
*.py[cod]
5+
*$py.class
6+
*.egg-info/
7+
*.egg
8+
9+
# --- Nuitka Build Artifacts ---
10+
# This ignores the temp C++ files but keeps your final 'build' folder
11+
# (unless you want to ignore the final EXE too)
12+
build/
13+
*.build/
14+
*.dist/
15+
*.onefile-build/
16+
17+
# --- Project Specific ---
118
exe_paths.json
219
pushover.json
320
config.json
421
*.blend?
5-
/build
622
/tmp
723
*.pts
8-
__pycache__
924
*.pp3
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": null,
6+
"id": "be6198d0-a4b5-482f-96fa-3ab5b9504092",
7+
"metadata": {},
8+
"outputs": [],
9+
"source": []
10+
}
11+
],
12+
"metadata": {
13+
"kernelspec": {
14+
"display_name": "Python 3 (ipykernel)",
15+
"language": "python",
16+
"name": "python3"
17+
},
18+
"language_info": {
19+
"codemirror_mode": {
20+
"name": "ipython",
21+
"version": 3
22+
},
23+
"file_extension": ".py",
24+
"mimetype": "text/x-python",
25+
"name": "python",
26+
"nbconvert_exporter": "python",
27+
"pygments_lexer": "ipython3",
28+
"version": "3.14.3"
29+
}
30+
},
31+
"nbformat": 4,
32+
"nbformat_minor": 5
33+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
from tkinter import (
2+
PhotoImage,
3+
Tk,
4+
)
5+
6+
from src.config import SCRIPT_DIR, CONFIG
7+
from src.center import center
8+
from src.gui.HDRMergeMaster import HDRMergeMaster
9+
from src.gui.SetupDialog import SetupDialog
10+
from utils.save_config import save_config
11+
12+
EXE_PATHS = CONFIG.get("exe_paths", {})
13+
14+
def main():
15+
16+
print("This window will report detailed progress of the blender renders.")
17+
print("Use the other window to start the merging process.")
18+
19+
global root
20+
root = Tk()
21+
root.geometry("450x86")
22+
center(root)
23+
png_icon = SCRIPT_DIR / "icons" / "icon.png"
24+
if png_icon.exists():
25+
root.iconphoto(True, PhotoImage(file=png_icon.as_posix()))
26+
else:
27+
root.iconbitmap(str(SCRIPT_DIR / "icons/icon.ico"))
28+
29+
# Check if setup is needed (config missing or required paths not configured)
30+
needs_setup = CONFIG.get("_needs_setup", False)
31+
if not needs_setup:
32+
required_keys = ["blender_exe", "luminance_cli_exe"]
33+
needs_setup = not all(EXE_PATHS.get(key) for key in required_keys)
34+
35+
if needs_setup:
36+
# Show setup dialog first
37+
def on_setup_save(config):
38+
save_config(config)
39+
setup_dialog = SetupDialog(root, CONFIG, on_setup_save)
40+
setup_dialog.wait_window()
41+
# Reload config after setup
42+
from src.config import reload_config
43+
CONFIG.update(reload_config())
44+
45+
HDRMergeMaster(root)
46+
root.mainloop()
47+
48+
if __name__ == "__main__":
49+
main()

.python-version

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
3.14

.vscode/launch.json

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"version": "0.2.0",
3+
"configurations": [
4+
5+
{
6+
"name": "Python: Current File (uv)",
7+
"type": "debugpy",
8+
"request": "launch",
9+
"program": "C:\\Users\\Savva\\HDR-Merge-Master\\hdr_brackets.py",
10+
"console": "integratedTerminal",
11+
"justMyCode": "True"
12+
}
13+
]
14+
}

.vscode/settings.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
{
22
"[python]": {
3-
"editor.defaultFormatter": "ms-python.black-formatter"
3+
"editor.formatOnSave": true,
4+
"editor.defaultFormatter": "charliermarsh.ruff",
5+
"editor.codeActionsOnSave": {
6+
"source.fixAll": "explicit",
7+
"source.organizeImports": "explicit"
8+
}
49
},
5-
"python.formatting.provider": "none",
610
"workbench.editor.highlightModifiedTabs": true
711
}

TODO.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
## Small changes:
22

3-
- [ ] Dialog to select exe files for required programs
3+
- [x] Dialog to select exe files for required programs
44
- added default file paths for both windows and linux
5-
- [ ] Ask to download required programs (Blender, etc.) on first use
5+
- added a setup dialog, complete with download links. This will open on first run, or can be accessed later throught the setup button
6+
- [x] Ask to download required programs (Blender, etc.) on first use
7+
- links and message included in the setup dialog
8+
- do we need to automate downloading the programs?
69
- [x] Remember last used threads and other values in config.json
710
- [x] Store exe_paths in config.json
811
- [x] Queue/batch processing
@@ -16,7 +19,7 @@
1619
- [ ] Better error handling in general, too many bug reports of people saying "it doesn't work" even when the issue is simple
1720
- [x] Added raw file processing with rawtherapee-cli
1821
- [ ] Allow for inconsistant exposure brackets - currently the first exposure set determines how many images there are per set, but it should be possible to support exposure sets with varying numbers of images.
19-
- [ ] Refactor the code and split it into multiple files, the hdr_brackets.py file is getting too long
22+
- [x] Refactor the code and split it into multiple files, the hdr_brackets.py file is getting too long
2023

2124
## Big changes:
2225
- [ ] Replace Blender merging with custom solution that includes deghosting & weighted merging to reduce noise. Possibly built with [OpenCV](https://learnopencv.com/high-dynamic-range-hdr-imaging-using-opencv-cpp-python)

Untitled.ipynb

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "code",
5+
"execution_count": null,
6+
"id": "be6198d0-a4b5-482f-96fa-3ab5b9504092",
7+
"metadata": {},
8+
"outputs": [],
9+
"source": []
10+
}
11+
],
12+
"metadata": {
13+
"kernelspec": {
14+
"display_name": "Python 3 (ipykernel)",
15+
"language": "python",
16+
"name": "python3"
17+
},
18+
"language_info": {
19+
"codemirror_mode": {
20+
"name": "ipython",
21+
"version": 3
22+
},
23+
"file_extension": ".py",
24+
"mimetype": "text/x-python",
25+
"name": "python",
26+
"nbconvert_exporter": "python",
27+
"pygments_lexer": "ipython3",
28+
"version": "3.14.3"
29+
}
30+
},
31+
"nbformat": 4,
32+
"nbformat_minor": 5
33+
}

build.bat

Lines changed: 38 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,50 @@
11
@echo off
2-
setlocal
2+
setlocal enabledelayedexpansion
33

4-
set "PY=py -3"
4+
:: --- Configuration ---
55
set "MAIN_SCRIPT=hdr_brackets.py"
66
set "DIST_ROOT=build"
7-
set "GENERATED_OUT_DIR=%DIST_ROOT%\hdr_brackets.dist"
8-
set "OUT_DIR=%DIST_ROOT%\hdr_merge_master.dist"
9-
set "VERSION=dev"
10-
set "ZIP_PATH=%DIST_ROOT%\hdr_merge_master_v%VERSION%.zip"
11-
12-
for /f "tokens=2 delims==" %%v in ('findstr /b "__version__" "%MAIN_SCRIPT%"') do set "VERSION=%%v"
13-
set "VERSION=%VERSION: =%"
14-
set "VERSION=%VERSION:"=%"
15-
set "VERSION=%VERSION:'=%"
7+
set "OUT_NAME=hdr_merge_master"
8+
set "OUT_DIR=%DIST_ROOT%\%OUT_NAME%.dist"
9+
10+
echo [1/4] Syncing environment and extracting version...
11+
uv sync >nul 2>&1
12+
13+
:: Extract version from pyproject.toml using PowerShell
14+
for /f "usebackq tokens=*" %%v in (`powershell -NoProfile -Command "(Get-Content pyproject.toml | Select-String '^version\s*=\s*\"(.*)\"').Matches.Groups[1].Value"`) do (
15+
set "VERSION=%%v"
16+
)
17+
1618
if "%VERSION%"=="" set "VERSION=dev"
17-
set "ZIP_PATH=%DIST_ROOT%\hdr_merge_master_v%VERSION%.zip"
19+
set "ZIP_PATH=%DIST_ROOT%\%OUT_NAME%_v%VERSION%.zip"
1820

19-
echo [1/5] Installing build dependencies...
20-
%PY% -m pip install -q nuitka ordered-set zstandard
21-
if errorlevel 1 exit /b 1
21+
echo [2/4] Cleaning previous outputs...
22+
if exist "%DIST_ROOT%" rmdir /s /q "%DIST_ROOT%"
2223

23-
echo [2/5] Cleaning previous outputs...
24-
if exist "%OUT_DIR%" rmdir /s /q "%OUT_DIR%"
25-
if exist "%GENERATED_OUT_DIR%" rmdir /s /q "%GENERATED_OUT_DIR%"
26-
if exist "%DIST_ROOT%\hdr_brackets.build" rmdir /s /q "%DIST_ROOT%\hdr_brackets.build"
27-
if exist "%ZIP_PATH%" del /q "%ZIP_PATH%"
28-
29-
echo [3/5] Building standalone executable with Nuitka...
30-
%PY% -m nuitka ^
31-
--standalone ^
32-
--assume-yes-for-downloads ^
33-
--enable-plugin=tk-inter ^
34-
--windows-icon-from-ico=icons/icon.ico ^
35-
--include-data-dir=blender=blender ^
36-
--include-data-files=blender/blender_merge.py=blender/blender_merge.py ^
37-
--include-data-dir=icons=icons ^
38-
--output-dir=%DIST_ROOT% ^
39-
--output-filename=hdr_merge_master.exe ^
40-
%MAIN_SCRIPT%
41-
if errorlevel 1 exit /b 1
24+
echo [3/4] Building with Nuitka via uv...
25+
:: Nuitka will automatically read the # nuitka-project: flags from %MAIN_SCRIPT%
26+
uv run python -m nuitka %MAIN_SCRIPT%
27+
28+
if errorlevel 1 (
29+
echo.
30+
echo [ERROR] Build failed.
31+
exit /b 1
32+
)
4233

43-
if exist "%GENERATED_OUT_DIR%" (
44-
pushd "%DIST_ROOT%"
45-
ren "hdr_brackets.dist" "hdr_merge_master.dist"
46-
popd
34+
:: Rename the output directory to our desired name
35+
:: Nuitka defaults to [filename].dist
36+
if exist "%DIST_ROOT%\hdr_brackets.dist" (
37+
ren "%DIST_ROOT%\hdr_brackets.dist" "%OUT_NAME%.dist"
4738
)
4839

49-
echo [4/5] Packaging distribution...
50-
powershell -NoProfile -Command "Compress-Archive -Path '%OUT_DIR%\*' -DestinationPath '%ZIP_PATH%' -CompressionLevel Optimal"
40+
echo [4/4] Packaging distribution to ZIP...
41+
powershell -NoProfile -Command "Compress-Archive -Path '%OUT_DIR%\*' -DestinationPath '%ZIP_PATH%' -Force"
5142
if errorlevel 1 exit /b 1
5243

53-
echo [5/5] Done.
54-
echo Version: v%VERSION%
55-
echo Output : %OUT_DIR%
56-
echo Zip : %ZIP_PATH%
44+
echo.
45+
echo ========================================
46+
echo DONE: v%VERSION%
47+
echo Path: %OUT_DIR%
48+
echo Zip : %ZIP_PATH%
49+
echo ========================================
50+
pause

0 commit comments

Comments
 (0)