Add splash screen and PyInstaller build script

This commit is contained in:
2026-07-02 20:05:02 +02:00
parent a9604023b3
commit ca934fe4b9
5 changed files with 116 additions and 2 deletions

1
.gitignore vendored
View File

@@ -17,3 +17,4 @@ _office_convertiti_pdf/
build/ build/
dist/ dist/
*.spec *.spec
*.exe

View File

@@ -141,9 +141,30 @@ Per Office COM serve anche `pywin32`, installato nell'ambiente in cui viene eseg
Il progetto e pensato per essere trasformato in un eseguibile Windows con PyInstaller. Il progetto e pensato per essere trasformato in un eseguibile Windows con PyInstaller.
Da valutare: Script disponibile:
```powershell
.\build_exe.ps1 -Clean
```
Lo script:
- installa le dipendenze Python;
- installa/aggiorna PyInstaller;
- include lo splash screen `assets/splash.png`;
- crea un eseguibile Windows `dist\ZipBundler.exe`;
- prova a includere Ghostscript se trova `gswin64c`, `gswin32c` o `gs` nel PATH.
Lo splash screen riporta `ZipBundler`, `versione 1.0` e `ai.teamstudio.it`.
Componenti inclusi o gestiti:
- CustomTkinter, Pillow e PyMuPDF vengono inclusi da PyInstaller come dipendenze Python;
- Ghostscript viene incluso se rilevato in fase di build;
- Microsoft Office non viene incluso: la conversione Office -> PDF usa Office COM e richiede Office installato sul PC di destinazione.
Da valutare in futuro:
- inclusione o rilevamento esterno di Ghostscript;
- gestione piu esplicita di `pywin32`; - gestione piu esplicita di `pywin32`;
- eventuale icona applicativa; - eventuale icona applicativa;
- firma dell'eseguibile, se necessaria in ambiente aziendale. - firma dell'eseguibile, se necessaria in ambiente aziendale.

BIN
assets/splash.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

77
build_exe.ps1 Normal file
View File

@@ -0,0 +1,77 @@
param(
[switch]$Clean,
[switch]$SkipGhostscriptBundle
)
$ErrorActionPreference = "Stop"
$ProjectRoot = Split-Path -Parent $MyInvocation.MyCommand.Path
Set-Location $ProjectRoot
$AppName = "ZipBundler"
$EntryPoint = Join-Path $ProjectRoot "zipbundler.py"
$SplashImage = Join-Path $ProjectRoot "assets\splash.png"
if (-not (Test-Path -LiteralPath $EntryPoint)) {
throw "File principale non trovato: $EntryPoint"
}
if (-not (Test-Path -LiteralPath $SplashImage)) {
throw "Immagine splash non trovata: $SplashImage"
}
if ($Clean) {
Remove-Item -LiteralPath (Join-Path $ProjectRoot "build") -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item -LiteralPath (Join-Path $ProjectRoot "dist") -Recurse -Force -ErrorAction SilentlyContinue
Remove-Item -LiteralPath (Join-Path $ProjectRoot "$AppName.spec") -Force -ErrorAction SilentlyContinue
}
python -m pip install --upgrade pip
python -m pip install -r requirements.txt
python -m pip install --upgrade pyinstaller
$argsList = @(
"--noconfirm",
"--clean",
"--windowed",
"--onefile",
"--name", $AppName,
"--splash", $SplashImage,
"--add-data", "$SplashImage;assets",
"--hidden-import", "customtkinter",
"--hidden-import", "PIL._tkinter_finder",
"--hidden-import", "fitz",
"--hidden-import", "win32com",
"--hidden-import", "win32com.client",
"--hidden-import", "pythoncom"
)
if (-not $SkipGhostscriptBundle) {
$ghostscriptCommand = Get-Command gswin64c.exe, gswin32c.exe, gs.exe -ErrorAction SilentlyContinue | Select-Object -First 1
if ($ghostscriptCommand) {
$ghostscriptBin = Split-Path -Parent $ghostscriptCommand.Source
$ghostscriptRoot = Split-Path -Parent $ghostscriptBin
Write-Host "Includo Ghostscript da: $ghostscriptRoot"
$argsList += @("--add-data", "$ghostscriptRoot;ghostscript")
}
else {
Write-Warning "Ghostscript non trovato nel PATH. Il programma usera Ghostscript solo se installato sul PC di destinazione."
}
}
else {
Write-Warning "Bundle Ghostscript saltato per richiesta esplicita."
}
$argsList += $EntryPoint
python -m PyInstaller @argsList
$exePath = Join-Path $ProjectRoot "dist\$AppName.exe"
if (Test-Path -LiteralPath $exePath) {
Write-Host ""
Write-Host "Build completata:"
Write-Host $exePath
}
else {
throw "Build completata senza trovare l'eseguibile atteso: $exePath"
}

View File

@@ -141,6 +141,14 @@ def shortened_stem(stem, max_length=80):
def find_ghostscript(): def find_ghostscript():
bundled_root = getattr(sys, "_MEIPASS", None)
if bundled_root:
bundled_ghostscript = Path(bundled_root) / "ghostscript"
for executable in ("gswin64c.exe", "gswin32c.exe", "gs.exe"):
matches = list(bundled_ghostscript.rglob(executable))
if matches:
return str(matches[0])
for executable in ("gswin64c", "gswin32c", "gs"): for executable in ("gswin64c", "gswin32c", "gs"):
path = shutil.which(executable) path = shutil.which(executable)
if path: if path:
@@ -1432,6 +1440,13 @@ class ZipBundlerApp(ctk.CTk):
def run_gui(): def run_gui():
app = ZipBundlerApp() app = ZipBundlerApp()
try:
import pyi_splash
pyi_splash.close()
except Exception:
pass
app.mainloop() app.mainloop()