diff --git a/.gitignore b/.gitignore index 505a3b1..6da1502 100644 --- a/.gitignore +++ b/.gitignore @@ -6,5 +6,14 @@ dist/ wheels/ *.egg-info +# PyInstaller +*.spec.bak +*.manifest +*.log +version_info.txt + +# Generierte Icons (optional - entfernen falls Icons versioniert werden sollen) +# resources/icon.ico + # Virtual environments .venv diff --git a/BUILD.md b/BUILD.md new file mode 100644 index 0000000..3178776 --- /dev/null +++ b/BUILD.md @@ -0,0 +1,305 @@ +# DocuMentor Build-Anleitung + +## Schnellstart: Windows-Distribution erstellen + +### Voraussetzungen + +```bash +# Dependencies installieren (inkl. Pillow für Icon-Generierung) +uv sync --all-groups +``` + +### Build ausführen + +```bash +# Automatischer Build (empfohlen) +uv run python build_windows.py +``` + +Dies erstellt automatisch: +1. **Icon** (falls nicht vorhanden): `resources/icon.ico` +2. **Versionsinformationen**: `version_info.txt` +3. **Executable**: `dist/DocuMentor/DocuMentor.exe` (mit Icon und Versionsinformationen) +4. **ZIP-Archiv**: `dist/DocuMentor-YYYYMMDD-Windows.zip` + +### Icon anpassen (optional) + +```bash +# Standard-Icon generieren +uv run python create_icon.py + +# Oder eigenes PNG-Icon konvertieren +uv run python create_icon.py mein-logo.png +``` + +### Manuelle Build-Schritte + +```bash +# 1. Cleanup +rm -rf build/ dist/ + +# 2. PyInstaller ausführen +uv run pyinstaller --clean DocuMentor.spec + +# 3. Testen +# Auf Windows: dist/DocuMentor/DocuMentor.exe +# Mit Wine: wine dist/DocuMentor/DocuMentor.exe +``` + +## Setup.exe erstellen (optional) + +### Mit Inno Setup + +1. **Inno Setup installieren**: https://jrsoftware.org/isdl.php + +2. **GUID generieren** für `installer.iss` (nur beim ersten Mal!): + ```bash + uv run python generate_guid.py + ``` + + Kopiere die generierte GUID und füge sie in `installer.iss` bei `AppId` ein (Zeile ~22). + + **WICHTIG**: Die GUID nur EINMAL generieren! Bei Updates dieselbe GUID verwenden. + +3. **Windows-Build erstellen**: + ```bash + uv run python build_windows.py + ``` + + Dies erstellt automatisch das Icon und kopiert es nach `dist/DocuMentor/`. + +4. **Installer kompilieren**: + ```bash + iscc installer.iss + ``` + +5. **Ergebnis**: + - `dist/installer/DocuMentor-Setup-0.1.0.exe` (mit Icon und Versionsinformationen) + +## MSI erstellen (optional) + +Mit WiX Toolset - noch zu implementieren. + +## Konfiguration anpassen + +### Icon anpassen + +**Option 1: Standard-Icon generieren** +```bash +uv run python create_icon.py +``` + +**Option 2: Eigenes Icon aus PNG erstellen** +```bash +uv run python create_icon.py ihr-logo.png +``` + +**Option 3: Manuell ICO-Datei platzieren** +1. Icon erstellen oder downloaden (`.ico` Format mit mehreren Größen) +2. Als `resources/icon.ico` speichern +3. Beim nächsten Build wird es automatisch verwendet + +Das Icon wird automatisch verwendet für: +- Windows-Executable (DocuMentor.exe) +- Inno Setup Installer +- Desktop-Verknüpfungen + +**Anforderungen:** +- Multi-Size ICO (16x16 bis 256x256 Pixel) +- Das `create_icon.py` Skript erstellt alle Größen automatisch + +### Versionsinformationen + +**Automatische Generierung:** + +Versionsinformationen werden automatisch aus `pyproject.toml` generiert: + +```bash +uv run python create_version_info.py +``` + +Dies liest die Version aus `pyproject.toml` und erstellt `version_info.txt`. + +**Version ändern:** + +In `pyproject.toml`: +```toml +version = "0.2.0" +``` + +Auch aktualisieren in: +- `installer.iss` (Zeile 13: `#define MyAppVersion`) + +Dann Versionsinformationen neu generieren: +```bash +uv run python create_version_info.py +``` + +**Was enthalten die Versionsinformationen:** +- Dateiversion und Produktversion +- Beschreibung und Copyright +- Anwendungsname +- Wird in Windows Explorer angezeigt (Rechtsklick → Eigenschaften → Details) + +### Build-Größe reduzieren + +In `DocuMentor.spec` Module ausschließen: +```python +excludes=[ + 'tkinter', + 'matplotlib', + 'test', + 'unittest', +], +``` + +### One-File Build (alles in einer .exe) + +In `DocuMentor.spec` ändern: +```python +exe = EXE( + pyz, + a.scripts, + a.binaries, # Uncomment + a.zipfiles, # Uncomment + a.datas, # Uncomment + [], # Comment out + exclude_binaries=False, # Ändern + # ... + name='DocuMentor', + onefile=True, # Hinzufügen +) + +# COLLECT auskommentieren oder entfernen +``` + +**Achtung**: One-File ist langsamer beim Start (3-5 Sekunden). + +## Testing + +### Lokales Testing + +```bash +# Build erstellen +uv run python build_windows.py + +# Mit Wine testen (Linux/WSL) +wine dist/DocuMentor/DocuMentor.exe +``` + +### Testing auf Windows + +1. ZIP-Datei auf Windows-System kopieren +2. Entpacken +3. `DocuMentor.exe` starten +4. Features testen: + - [ ] Programmstart + - [ ] Einstellungsdialog öffnet beim ersten Start + - [ ] Projekt öffnen/erstellen + - [ ] Tree-Navigation + - [ ] XSL/XML-Dateien hinzufügen + - [ ] PDF-Generierung (mit konfigurierten Tools) + - [ ] PDF-Vergleich + +## Troubleshooting + +### "Module not found" beim Start + +**Lösung**: Hidden imports in `DocuMentor.spec` ergänzen: +```python +hiddenimports=[ + 'missing.module', +] +``` + +### Antivirus blockiert die .exe + +**Ursache**: Unsigned executables werden oft als verdächtig eingestuft. + +**Lösungen**: +1. Code-Signing-Zertifikat kaufen und verwenden +2. Bei Microsoft SmartScreen einreichen +3. Exception in Antivirus eintragen (für Tests) + +### Executable ist zu groß (>200 MB) + +**Lösungen**: +1. UPX-Kompression ist bereits aktiv +2. Ungenutzte Module excluden (siehe oben) +3. Virtual Environment aufräumen: `uv sync --no-dev` + +### UI-Dateien nicht gefunden + +**Problem**: `.ui` Dateien werden nicht gefunden. + +**Lösung**: In `DocuMentor.spec` prüfen: +```python +datas=ui_files, # Muss gesetzt sein +``` + +## Automatisierung + +### GitHub Actions (CI/CD) + +Siehe `docs/windows_distribution.md` für vollständiges Beispiel. + +### Lokales Release-Skript + +```bash +#!/bin/bash +# release.sh - Erstellt vollständiges Release + +VERSION="0.1.0" + +echo "Building DocuMentor v$VERSION..." + +# 1. Build +uv run python build_windows.py + +# 2. Installer (falls Inno Setup installiert) +if command -v iscc &> /dev/null; then + iscc installer.iss + echo "✓ Installer erstellt" +fi + +echo "" +echo "Release v$VERSION fertig!" +echo " • ZIP: dist/DocuMentor-*-Windows.zip" +echo " • Setup: dist/installer/DocuMentor-Setup-$VERSION.exe" +``` + +## Distribution + +### ZIP-Archiv + +**Vorteile:** +- Einfach, portable +- Keine Installation nötig +- USB-Stick-fähig + +**Verwendung:** +- Auf GitHub Releases hochladen +- Per E-Mail versenden +- Auf Webserver bereitstellen + +### Setup.exe + +**Vorteile:** +- Professionell +- Start-Menü-Integration +- Deinstallation + +**Verwendung:** +- Primäre Distributions-Methode +- Auf Website zum Download anbieten + +## Dokumentation für Endbenutzer + +Die `dist/DocuMentor/README.txt` wird automatisch erstellt und enthält: +- Installationsanweisungen +- Liste der externen Abhängigkeiten +- Konfigurationshinweise + +## Weitere Informationen + +Siehe `docs/windows_distribution.md` für detaillierte Dokumentation. diff --git a/DocuMentor.spec b/DocuMentor.spec new file mode 100644 index 0000000..0ad33ea --- /dev/null +++ b/DocuMentor.spec @@ -0,0 +1,79 @@ +# -*- mode: python ; coding: utf-8 -*- +""" +PyInstaller Konfiguration für DocuMentor +Erstellt eine eigenständige Windows-Executable ohne Python-Installation +""" + +import sys +from pathlib import Path + +block_cipher = None + +# Projektpfad +project_root = Path(SPECPATH) +src_path = project_root / 'src' + +# Alle UI-Dateien sammeln +ui_files = [] +for ui_file in (src_path / 'ui').glob('*.ui'): + ui_files.append((str(ui_file), 'ui')) + +a = Analysis( + [str(src_path / 'main.py')], + pathex=[str(src_path)], + binaries=[], + datas=ui_files, # UI-Dateien einbinden + hiddenimports=[ + 'PySide6.QtCore', + 'PySide6.QtGui', + 'PySide6.QtWidgets', + 'pydantic', + 'pydantic_settings', + 'pydantic_yaml', + 'polars', + 'pyarrow', + 'connectorx', + 'pyqtdarktheme', + ], + hookspath=[], + hooksconfig={}, + runtime_hooks=[], + excludes=[], + win_no_prefer_redirects=False, + win_private_assemblies=False, + cipher=block_cipher, + noarchive=False, +) + +pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) + +exe = EXE( + pyz, + a.scripts, + [], + exclude_binaries=True, + name='DocuMentor', + debug=False, + bootloader_ignore_signals=False, + strip=False, + upx=True, + console=False, # Keine Konsole anzeigen (GUI-Anwendung) + disable_windowed_traceback=False, + argv_emulation=False, + target_arch=None, + codesign_identity=None, + entitlements_file=None, + icon=str(project_root / 'resources' / 'icon.ico') if (project_root / 'resources' / 'icon.ico').exists() else None, + version=str(project_root / 'version_info.txt') if (project_root / 'version_info.txt').exists() else None, +) + +coll = COLLECT( + exe, + a.binaries, + a.zipfiles, + a.datas, + strip=False, + upx=True, + upx_exclude=[], + name='DocuMentor', +) diff --git a/build_windows.py b/build_windows.py new file mode 100644 index 0000000..dd642ec --- /dev/null +++ b/build_windows.py @@ -0,0 +1,141 @@ +#!/usr/bin/env python3 +""" +Build-Skript für Windows-Distribution von DocuMentor + +Erstellt: +1. Eigenständige Executable mit PyInstaller +2. Optional: ZIP-Archiv für portable Distribution +""" + +import shutil +import subprocess +import sys +from pathlib import Path +from datetime import datetime + +def main(): + project_root = Path(__file__).parent + dist_dir = project_root / "dist" + build_dir = project_root / "build" + resources_dir = project_root / "resources" + icon_path = resources_dir / "icon.ico" + version_info_path = project_root / "version_info.txt" + + print("=" * 60) + print("DocuMentor Windows Build") + print("=" * 60) + + # 1. Icon und Versionsinformationen generieren + print("\n[1/6] Icon und Versionsinformationen generieren...") + + # Icon erstellen falls nicht vorhanden + if not icon_path.exists(): + print(" Erstelle Standard-Icon...") + try: + subprocess.run([sys.executable, "create_icon.py"], check=True, cwd=project_root) + print(" ✓ Icon erstellt") + except subprocess.CalledProcessError as e: + print(f" ✗ Icon-Erstellung fehlgeschlagen: {e}") + print(" ⚠ Fahre ohne Icon fort...") + else: + print(f" ✓ Icon vorhanden: {icon_path.name}") + + # Versionsinformationen erstellen + print(" Erstelle Versionsinformationen...") + try: + subprocess.run([sys.executable, "create_version_info.py"], check=True, cwd=project_root) + print(" ✓ Versionsinformationen erstellt") + except subprocess.CalledProcessError as e: + print(f" ✗ Versionsinformationen-Erstellung fehlgeschlagen: {e}") + print(" ⚠ Fahre ohne Versionsinformationen fort...") + + # 2. Cleanup alter Builds + print("\n[2/6] Cleanup alter Builds...") + if dist_dir.exists(): + shutil.rmtree(dist_dir) + print(" ✓ dist/ gelöscht") + if build_dir.exists(): + shutil.rmtree(build_dir) + print(" ✓ build/ gelöscht") + + # 3. PyInstaller ausführen + print("\n[3/6] PyInstaller Build starten...") + try: + subprocess.run( + ["pyinstaller", "--clean", "DocuMentor.spec"], + check=True, + cwd=project_root + ) + print(" ✓ Build erfolgreich") + except subprocess.CalledProcessError as e: + print(f" ✗ Build fehlgeschlagen: {e}") + return 1 + + # 4. README für Distribution erstellen + print("\n[4/6] README erstellen...") + readme_content = """DocuMentor - XSL-Transformations-Verwaltung +============================================ + +Installation: +1. Entpacken Sie dieses Archiv in ein Verzeichnis Ihrer Wahl +2. Führen Sie DocuMentor.exe aus + +Externe Abhängigkeiten (separat zu installieren): +- Java Runtime Environment (JRE) oder JDK +- Apache FOP (für PDF-Generierung) +- Saxon XSLT-Prozessor (JAR-Datei) +- diff-pdf (für PDF-Vergleiche) + +Beim ersten Start werden Sie aufgefordert, die Pfade zu diesen +Tools in den Programmeinstellungen zu konfigurieren. + +Konfiguration und Logs: +- Windows: %APPDATA%\\DocuMentor\\ +- Konfiguration: config.json +- Logs: logs\\ + +Support: +Bei Fragen oder Problemen erstellen Sie bitte ein Issue auf GitHub. +""" + + readme_path = dist_dir / "DocuMentor" / "README.txt" + readme_path.write_text(readme_content, encoding='utf-8') + print(" ✓ README.txt erstellt") + + # 5. Icon ins dist-Verzeichnis kopieren (für Installer) + print("\n[5/6] Icon für Installer vorbereiten...") + if icon_path.exists(): + dist_icon = dist_dir / "DocuMentor" / "icon.ico" + shutil.copy2(icon_path, dist_icon) + print(" ✓ Icon kopiert") + else: + print(" ⚠ Kein Icon vorhanden") + + # 6. ZIP-Archiv erstellen + print("\n[6/6] ZIP-Archiv erstellen...") + timestamp = datetime.now().strftime("%Y%m%d") + zip_name = f"DocuMentor-{timestamp}-Windows" + zip_path = dist_dir / zip_name + + shutil.make_archive( + str(zip_path), + 'zip', + dist_dir, + 'DocuMentor' + ) + print(f" ✓ {zip_name}.zip erstellt") + + print("\n" + "=" * 60) + print("Build abgeschlossen!") + print("=" * 60) + print(f"\nErgebnisse:") + print(f" • Executable: dist/DocuMentor/DocuMentor.exe") + print(f" • ZIP-Archiv: dist/{zip_name}.zip") + print("\nNächste Schritte:") + print(" 1. Testen Sie DocuMentor.exe auf einem Windows-System") + print(" 2. Optional: Erstellen Sie einen Installer mit Inno Setup") + + return 0 + +if __name__ == "__main__": + sys.exit(main()) diff --git a/create_icon.py b/create_icon.py new file mode 100644 index 0000000..29fc611 --- /dev/null +++ b/create_icon.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python3 +""" +Icon-Generator für DocuMentor + +Erstellt ein Icon aus einem PNG oder generiert ein Standard-Icon. +Unterstützt Windows (.ico) und verschiedene Größen. + +Verwendung: + python create_icon.py # Generiert Standard-Icon + python create_icon.py source.png # Konvertiert PNG zu ICO +""" + +import sys +from pathlib import Path + +try: + from PIL import Image, ImageDraw, ImageFont +except ImportError: + print("Fehler: Pillow ist nicht installiert.") + print("Installation: uv pip install pillow") + sys.exit(1) + + +def create_default_icon(output_path: Path): + """Erstellt ein Standard-Icon mit DocuMentor-Branding.""" + sizes = [256, 128, 64, 48, 32, 16] + images = [] + + for size in sizes: + # Neues Bild erstellen mit Farbverlauf + img = Image.new('RGB', (size, size), color='white') + draw = ImageDraw.Draw(img) + + # Hintergrund: Blau-Verlauf (vereinfacht als solides Blau) + bg_color = (41, 128, 185) # Professionelles Blau + draw.rectangle([0, 0, size, size], fill=bg_color) + + # Dokument-Symbol (vereinfachte Darstellung) + margin = size // 8 + doc_left = margin + doc_top = margin + doc_right = size - margin + doc_bottom = size - margin + + # Weißes Dokument + draw.rectangle( + [doc_left, doc_top, doc_right, doc_bottom], + fill='white', + outline=(52, 73, 94), + width=max(1, size // 64) + ) + + # Ecke umgeknickt (rechts oben) + fold_size = size // 6 + points = [ + (doc_right - fold_size, doc_top), + (doc_right, doc_top + fold_size), + (doc_right - fold_size, doc_top + fold_size), + ] + draw.polygon(points, fill=(220, 220, 220), outline=(52, 73, 94)) + + # Text-Linien im Dokument (nur bei größeren Icons) + if size >= 32: + line_margin = doc_left + size // 12 + line_width = doc_right - doc_left - size // 6 + line_count = min(3, size // 32) + line_spacing = (doc_bottom - doc_top - fold_size) // (line_count + 2) + + for i in range(line_count): + y = doc_top + fold_size + line_spacing * (i + 1) + draw.rectangle( + [line_margin, y, line_margin + line_width, y + max(1, size // 128)], + fill=(52, 73, 94) + ) + + # "M" für Mentor (nur bei großen Icons) + if size >= 64: + try: + # Versuche System-Font zu verwenden + font_size = size // 4 + font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", font_size) + except: + # Fallback auf Default-Font + font = ImageFont.load_default() + + text = "M" + # Zentrieren (grobe Schätzung) + bbox = draw.textbbox((0, 0), text, font=font) + text_width = bbox[2] - bbox[0] + text_height = bbox[3] - bbox[1] + text_x = (size - text_width) // 2 + text_y = doc_bottom - text_height - margin // 2 + + draw.text((text_x, text_y), text, fill=bg_color, font=font) + + images.append(img) + + # Als ICO speichern + images[0].save( + output_path, + format='ICO', + sizes=[(img.width, img.height) for img in images], + append_images=images[1:] + ) + print(f"✓ Standard-Icon erstellt: {output_path}") + + +def convert_png_to_ico(source_path: Path, output_path: Path): + """Konvertiert ein PNG-Bild zu einem Multi-Size ICO.""" + try: + img = Image.open(source_path) + + # Zu RGBA konvertieren falls nötig + if img.mode != 'RGBA': + img = img.convert('RGBA') + + # Verschiedene Größen erstellen + sizes = [256, 128, 64, 48, 32, 16] + images = [] + + for size in sizes: + resized = img.resize((size, size), Image.Resampling.LANCZOS) + images.append(resized) + + # Als ICO speichern + images[0].save( + output_path, + format='ICO', + sizes=[(img.width, img.height) for img in images], + append_images=images[1:] + ) + print(f"✓ Icon erstellt aus {source_path.name}: {output_path}") + + except Exception as e: + print(f"✗ Fehler beim Konvertieren: {e}") + sys.exit(1) + + +def main(): + project_root = Path(__file__).parent + resources_dir = project_root / "resources" + resources_dir.mkdir(exist_ok=True) + + output_ico = resources_dir / "icon.ico" + + if len(sys.argv) > 1: + # PNG zu ICO konvertieren + source_path = Path(sys.argv[1]) + if not source_path.exists(): + print(f"Fehler: Datei nicht gefunden: {source_path}") + sys.exit(1) + + convert_png_to_ico(source_path, output_ico) + else: + # Standard-Icon generieren + print("Erstelle Standard-Icon...") + create_default_icon(output_ico) + + print(f"\nIcon gespeichert: {output_ico}") + print("Das Icon wird automatisch von PyInstaller und Inno Setup verwendet.") + + +if __name__ == "__main__": + main() diff --git a/create_version_info.py b/create_version_info.py new file mode 100644 index 0000000..75402e9 --- /dev/null +++ b/create_version_info.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python3 +""" +Generiert Windows-Versionsinformationen für PyInstaller + +Liest Version aus pyproject.toml und erstellt version_info.txt +""" + +import tomllib +from pathlib import Path +from datetime import datetime + + +def parse_version(version_str: str) -> tuple[int, int, int, int]: + """Parst Version-String (z.B. '0.1.0') zu Tuple (0, 1, 0, 0).""" + parts = version_str.split('.') + major = int(parts[0]) if len(parts) > 0 else 0 + minor = int(parts[1]) if len(parts) > 1 else 0 + patch = int(parts[2]) if len(parts) > 2 else 0 + build = 0 # Könnte aus Git-Commit-Count generiert werden + return (major, minor, patch, build) + + +def create_version_info(project_root: Path): + """Erstellt version_info.txt für PyInstaller.""" + + # pyproject.toml lesen + pyproject_path = project_root / "pyproject.toml" + with open(pyproject_path, 'rb') as f: + pyproject = tomllib.load(f) + + project = pyproject['project'] + version = project['version'] + name = project['name'] + description = project['description'] + + # Version parsen + file_version = parse_version(version) + product_version = file_version + + # Jahr für Copyright + year = datetime.now().year + + # version_info.txt Content + version_info_content = f"""# UTF-8 +# +# Generiert automatisch von create_version_info.py +# NICHT manuell bearbeiten! +# + +VSVersionInfo( + ffi=FixedFileInfo( + # filevers und prodvers als Tuple: (1, 0, 0, 0) + filevers={file_version}, + prodvers={product_version}, + # Maske für gültige Bits in filevers und prodvers + mask=0x3f, + # Flags - kann VS_FF_DEBUG, VS_FF_PRERELEASE, etc. enthalten + flags=0x0, + # Betriebssystem - VOS_NT_WINDOWS32 + OS=0x40004, + # Dateityp - VFT_APP (Anwendung) + fileType=0x1, + # Subtyp (nicht verwendet für VFT_APP) + subtype=0x0, + # Datumsstempel + date=(0, 0) + ), + kids=[ + StringFileInfo( + [ + StringTable( + '040904B0', # Deutsch (0x0409 = Englisch, 0x0407 = Deutsch), Unicode + [StringStruct('CompanyName', 'Ihr Name/Organisation'), + StringStruct('FileDescription', '{description}'), + StringStruct('FileVersion', '{version}'), + StringStruct('InternalName', '{name}'), + StringStruct('LegalCopyright', '© {year} Ihr Name. Alle Rechte vorbehalten.'), + StringStruct('OriginalFilename', '{name}.exe'), + StringStruct('ProductName', '{name}'), + StringStruct('ProductVersion', '{version}')]) + ]), + VarFileInfo([VarStruct('Translation', [1033, 1200])]) # Englisch, Unicode + ] +) +""" + + # version_info.txt schreiben + version_info_path = project_root / "version_info.txt" + version_info_path.write_text(version_info_content, encoding='utf-8') + + print(f"✓ version_info.txt erstellt") + print(f" Version: {version}") + print(f" Datei: {version_info_path}") + + +def main(): + project_root = Path(__file__).parent + create_version_info(project_root) + + +if __name__ == "__main__": + main() diff --git a/docs/icon_and_version_info.md b/docs/icon_and_version_info.md new file mode 100644 index 0000000..2a01d89 --- /dev/null +++ b/docs/icon_and_version_info.md @@ -0,0 +1,274 @@ +# Icon und Versionsinformationen für Windows-Build + +## Übersicht + +DocuMentor unterstützt professionelle Windows-Builds mit: +- **Anwendungs-Icon** in allen benötigten Größen +- **Windows-Versionsinformationen** (Datei-Eigenschaften) +- Automatische Integration in Build-Prozess + +## Icon-System + +### Automatische Icon-Generierung + +Das Build-Skript generiert automatisch ein Standard-Icon, falls keins vorhanden ist: + +```bash +uv run python build_windows.py +``` + +Falls `resources/icon.ico` nicht existiert, wird automatisch ein Standard-Icon mit DocuMentor-Branding erstellt. + +### Manuelles Icon erstellen + +#### Option 1: Standard-Icon + +```bash +uv run python create_icon.py +``` + +Erstellt ein einfaches Icon mit: +- Blauem Hintergrund (professionelles Blau: #2980B9) +- Weißem Dokument-Symbol +- "M" für Mentor (bei großen Icons) +- Umgeknickter Ecke +- Mehreren Größen (16×16 bis 256×256) + +#### Option 2: Aus eigenem PNG + +```bash +uv run python create_icon.py mein-logo.png +``` + +Konvertiert ein PNG-Bild zu einem Multi-Size Windows-Icon: +- Unterstützt Transparenz +- Erstellt alle benötigten Größen +- Optimiert für verschiedene Bildschirmauflösungen + +**PNG-Anforderungen:** +- Idealerweise 256×256 Pixel oder größer +- Quadratisches Format +- PNG oder JPEG Format +- Transparenter Hintergrund empfohlen + +### Icon-Größen + +Das ICO-Format enthält folgende Auflösungen: + +| Größe | Verwendung | +|---------|--------------------------------------| +| 256×256 | Windows 7+, Taskleiste, große Icons | +| 128×128 | Windows 7+, große Icons | +| 64×64 | Hohe DPI-Displays | +| 48×48 | Standard Desktop-Icon | +| 32×32 | Explorer Details-Ansicht | +| 16×16 | Kleinstes Icon, Titelleiste | + +### Wo wird das Icon verwendet? + +- **DocuMentor.exe** - Anwendungs-Icon +- **Setup.exe** - Installer-Icon (Inno Setup) +- **Desktop-Verknüpfung** - Erstellt beim Installieren +- **Start-Menü** - Windows-Programmgruppe +- **Taskleiste** - Beim Ausführen +- **Deinstallations-Programm** - System-Einstellungen + +## Versionsinformationen + +### Automatische Generierung + +Versionsinformationen werden automatisch vom Build-Skript generiert: + +```bash +uv run python build_windows.py +``` + +### Manuelle Generierung + +```bash +uv run python create_version_info.py +``` + +### Inhalt der Versionsinformationen + +Die `version_info.txt` enthält: + +``` +FileVersion: 0.1.0.0 +ProductVersion: 0.1.0.0 +CompanyName: Ihr Name/Organisation +FileDescription: Professionelle XSL-Transformations-Verwaltung und PDF-Generierung +InternalName: DocuMentor +LegalCopyright: © 2026 Ihr Name. Alle Rechte vorbehalten. +OriginalFilename: DocuMentor.exe +ProductName: DocuMentor +``` + +### Version aus pyproject.toml + +Die Version wird automatisch aus `pyproject.toml` gelesen: + +```toml +[project] +name = "DocuMentor" +version = "0.1.0" +description = "Professionelle XSL-Transformations-Verwaltung und PDF-Generierung" +``` + +### Version ändern + +**Schritt 1:** Version in `pyproject.toml` ändern: + +```toml +version = "0.2.0" +``` + +**Schritt 2:** Version in `installer.iss` ändern (Zeile 13): + +```iss +#define MyAppVersion "0.2.0" +``` + +**Schritt 3:** Build neu ausführen: + +```bash +uv run python build_windows.py +``` + +Die Versionsinformationen werden automatisch neu generiert. + +### Versionsnummern-Schema + +DocuMentor verwendet [Semantic Versioning](https://semver.org/lang/de/): + +``` +MAJOR.MINOR.PATCH + +0.1.0 → Erste Beta-Version +1.0.0 → Erste stabile Version +1.1.0 → Neue Features +1.1.1 → Bugfixes +2.0.0 → Breaking Changes +``` + +### Windows-Eigenschaften anzeigen + +Nach dem Build können Sie die Versionsinformationen in Windows anzeigen: + +1. Rechtsklick auf `DocuMentor.exe` +2. **Eigenschaften** auswählen +3. Tab **Details** öffnen + +Dort sehen Sie: +- Dateiversion +- Produktversion +- Beschreibung +- Copyright +- Produktname +- Original-Dateiname + +## Integration in Build-Prozess + +### DocuMentor.spec + +```python +exe = EXE( + # ... + icon=str(project_root / 'resources' / 'icon.ico') if (project_root / 'resources' / 'icon.ico').exists() else None, + version=str(project_root / 'version_info.txt') if (project_root / 'version_info.txt').exists() else None, +) +``` + +**Automatische Erkennung:** +- Icon wird verwendet, falls vorhanden +- Versionsinformationen werden verwendet, falls vorhanden +- Build funktioniert auch ohne Icon/Version (mit Warnung) + +### installer.iss + +```iss +SetupIconFile=dist\DocuMentor\icon.ico +UninstallDisplayIcon={app}\DocuMentor.exe +``` + +Das Icon wird automatisch vom `build_windows.py` nach `dist/DocuMentor/` kopiert. + +## Anpassungen + +### Company Name / Copyright + +In `create_version_info.py` (Zeile ~65): + +```python +StringStruct('CompanyName', 'Ihr Name/Organisation'), +StringStruct('LegalCopyright', '© {year} Ihr Name. Alle Rechte vorbehalten.'), +``` + +Ändern Sie "Ihr Name/Organisation" auf Ihren tatsächlichen Namen oder Firmennamen. + +### Icon-Design + +Falls Sie das Standard-Icon anpassen möchten, bearbeiten Sie `create_icon.py`: + +**Farben ändern** (Zeile ~31): +```python +bg_color = (41, 128, 185) # Blau - ändern Sie RGB-Werte +``` + +**Symbol ändern:** +- Bearbeiten Sie die `create_default_icon()` Funktion +- Oder erstellen Sie Ihr eigenes Icon in einem Grafikprogramm + +## Best Practices + +### Icon-Design + +1. **Einfach und klar**: Funktioniert auch bei 16×16 Pixel +2. **Hoher Kontrast**: Gut lesbar auf hellem und dunklem Hintergrund +3. **Professionell**: Passend zum Business-Kontext +4. **Wiedererkennbar**: Symbolisiert die Anwendung + +### Versionierung + +1. **Semantische Versionierung**: MAJOR.MINOR.PATCH +2. **Vor jedem Release aktualisieren** +3. **Git-Tags verwenden**: `git tag v0.1.0` +4. **GUID beibehalten**: Nie die Inno Setup GUID ändern bei Updates! + +## Troubleshooting + +### Icon wird nicht angezeigt + +**Problem**: DocuMentor.exe zeigt kein Icon + +**Lösungen:** +1. Prüfen ob `resources/icon.ico` existiert +2. Build neu ausführen: `uv run python build_windows.py` +3. Windows Icon-Cache löschen und neu starten + +### Versionsinformationen fehlen + +**Problem**: Eigenschaften → Details zeigt keine Informationen + +**Lösungen:** +1. Prüfen ob `version_info.txt` existiert +2. `uv run python create_version_info.py` ausführen +3. Build neu ausführen + +### Pillow-Fehler beim Icon-Erstellen + +**Problem**: `ImportError: No module named 'PIL'` + +**Lösung:** +```bash +uv sync --all-groups +``` + +Dies installiert Pillow automatisch. + +## Weiterführende Informationen + +- **PyInstaller Icon-Dokumentation**: https://pyinstaller.org/en/stable/usage.html#icons +- **Windows ICO Format**: https://en.wikipedia.org/wiki/ICO_(file_format) +- **Semantic Versioning**: https://semver.org/lang/de/ +- **Pillow Dokumentation**: https://pillow.readthedocs.io/ diff --git a/docs/windows_distribution.md b/docs/windows_distribution.md new file mode 100644 index 0000000..e1630f0 --- /dev/null +++ b/docs/windows_distribution.md @@ -0,0 +1,291 @@ +# Windows Distribution Guide für DocuMentor + +## Überblick + +Dieses Dokument beschreibt, wie DocuMentor für Windows-Benutzer ohne Python-Installation verpackt wird. + +## Voraussetzungen + +### Auf dem Entwicklungssystem + +```bash +# Dependencies installieren (inkl. PyInstaller) +uv sync --all-groups +``` + +### Für Setup.exe (optional) + +- **Inno Setup**: Download von https://jrsoftware.org/isdl.php +- Oder **WiX Toolset** für MSI: https://wixtoolset.org/ + +## Build-Prozess + +### Option 1: Einfacher Build (ZIP-Distribution) + +```bash +# 1. PyInstaller installieren +uv sync --all-groups + +# 2. Build ausführen +uv run python build_windows.py +``` + +Dies erstellt: +- `dist/DocuMentor/DocuMentor.exe` - Eigenständige Executable +- `dist/DocuMentor-YYYYMMDD-Windows.zip` - Portable ZIP-Archiv + +### Option 2: Professionelle Setup.exe mit Inno Setup + +```bash +# 1. PyInstaller Build +uv run python build_windows.py + +# 2. Inno Setup Compiler ausführen +iscc installer.iss +``` + +Dies erstellt: +- `dist/installer/DocuMentor-Setup-0.1.0.exe` - Professioneller Installer + +### Option 3: MSI-Installer mit WiX + +```bash +# TODO: WiX-Konfiguration noch zu erstellen +``` + +## Manuelle Schritte + +### 1. PyInstaller direkt verwenden + +```bash +# Cleanup +rm -rf build/ dist/ + +# Build +uv run pyinstaller --clean DocuMentor.spec + +# Testen +dist/DocuMentor/DocuMentor.exe +``` + +### 2. Anpassungen vornehmen + +**Icon hinzufügen:** +1. Icon-Datei (`.ico`) im Projekt speichern, z.B. `resources/icon.ico` +2. In `DocuMentor.spec` anpassen: + ```python + icon='resources/icon.ico' + ``` + +**Versionsinformationen:** +In `DocuMentor.spec` erweitern: +```python +exe = EXE( + # ... + version='version_info.txt', # Windows-Versionsinformationen +) +``` + +## PyInstaller .spec Konfiguration + +Die Datei `DocuMentor.spec` enthält: + +- **datas**: UI-Dateien (.ui) werden mitgepackt +- **hiddenimports**: Alle notwendigen PySide6/Polars-Module +- **console=False**: GUI-Anwendung ohne Konsole +- **upx=True**: Kompression der Binaries + +### Wichtige Einstellungen + +```python +# Ein-Datei-Build (alles in einer .exe) +exe = EXE( + pyz, + a.scripts, + a.binaries, # Diese Zeilen + a.zipfiles, # auskommentieren + a.datas, # für One-File + # ... + onefile=True, # Hinzufügen +) +``` + +**Achtung**: One-File-Build ist langsamer beim Start, da alles temporär entpackt werden muss. + +## Distribution + +### ZIP-Archive + +```bash +# Automatisch durch build_windows.py erstellt +dist/DocuMentor-YYYYMMDD-Windows.zip +``` + +**Vorteile:** +- Einfach, portable +- Keine Installation nötig +- Kann auf USB-Stick verwendet werden + +**Nachteile:** +- Keine Deinstallationsroutine +- Keine Verknüpfungen +- Keine Registry-Einträge + +### Setup.exe mit Inno Setup + +**Vorteile:** +- Professionell +- Deinstallation integriert +- Start-Menü und Desktop-Icons +- Update-Mechanismus möglich + +**Nachteile:** +- Benötigt Administrator-Rechte (optional) +- Komplexere Konfiguration + +### MSI-Installer + +**Vorteile:** +- Windows-Standard +- Gruppen-Richtlinien-fähig +- Silent Installation möglich + +**Nachteile:** +- Komplexe Erstellung +- Benötigt WiX Toolset + +## Externe Abhängigkeiten + +DocuMentor benötigt diese Tools (NICHT im Installer enthalten): + +1. **Java Runtime Environment (JRE) 11+** + - Für Saxon und Apache FOP + - Download: https://adoptium.net/ + +2. **Apache FOP** + - XSL-FO zu PDF Konvertierung + - Download: https://xmlgraphics.apache.org/fop/ + +3. **Saxon XSLT Prozessor** + - XSLT 2.0/3.0 Transformationen + - Download: https://www.saxonica.com/ + +4. **diff-pdf** + - PDF-Vergleich + - Download: https://vslavik.github.io/diff-pdf/ + +### Benutzer-Anleitung + +Nach der Installation: + +1. DocuMentor starten +2. Beim ersten Start öffnet sich automatisch die Einstellungen +3. Pfade zu Java, Saxon, FOP und diff-pdf konfigurieren +4. Projekt-Verzeichnis wählen oder neues Projekt erstellen + +## Testing + +### Lokales Testing (Linux/WSL) + +```bash +# Build für Windows erstellen +uv run python build_windows.py + +# Executable mit Wine testen (falls verfügbar) +wine dist/DocuMentor/DocuMentor.exe +``` + +### Testing auf Windows + +1. ZIP auf Windows-System kopieren +2. Entpacken +3. `DocuMentor.exe` ausführen +4. Alle Features testen: + - Projekt öffnen/erstellen + - Tree-Navigation + - PDF-Generierung + - Einstellungen + +## Troubleshooting + +### Problem: "Module not found" Fehler + +**Lösung**: Hidden imports in `DocuMentor.spec` ergänzen: +```python +hiddenimports=[ + # ... existing + 'missing_module', +] +``` + +### Problem: UI-Dateien nicht gefunden + +**Lösung**: Prüfen ob datas korrekt konfiguriert: +```python +datas=[ + ('src/ui/*.ui', 'ui'), +] +``` + +### Problem: Executable zu groß + +**Lösungen**: +1. UPX-Kompression aktivieren (bereits aktiv) +2. Excludes hinzufügen für ungenutzte Module: + ```python + excludes=['tkinter', 'matplotlib', 'test', 'unittest'] + ``` +3. One-File-Build verwenden (langsamer Start) + +### Problem: Antivirus blockiert + +**Lösung**: +- Code-Signing-Zertifikat verwenden +- Bei Microsoft einreichen für SmartScreen +- README mit Hinweis erweitern + +## Automatisierung mit CI/CD + +### GitHub Actions Beispiel + +```yaml +name: Build Windows Release + +on: + push: + tags: + - 'v*' + +jobs: + build: + runs-on: windows-latest + steps: + - uses: actions/checkout@v3 + + - name: Install uv + uses: astral-sh/setup-uv@v1 + + - name: Build + run: uv run python build_windows.py + + - name: Create Release + uses: softprops/action-gh-release@v1 + with: + files: dist/*.zip +``` + +## Versionierung + +Version in folgenden Dateien aktualisieren: +1. `pyproject.toml` - `version = "X.Y.Z"` +2. `installer.iss` - `#define MyAppVersion "X.Y.Z"` +3. Optional: `src/version.py` erstellen + +## Lizenz und Rechtliches + +- Alle Python-Dependencies sind in der Distribution enthalten +- PySide6 (LGPL): Dynamische Verlinkung ist OK +- Polars (MIT): Unproblematisch +- Pydantic (MIT): Unproblematisch + +Externe Tools (Saxon, FOP) haben eigene Lizenzen und müssen separat installiert werden. diff --git a/generate_guid.py b/generate_guid.py new file mode 100644 index 0000000..ecdb2d3 --- /dev/null +++ b/generate_guid.py @@ -0,0 +1,41 @@ +#!/usr/bin/env python3 +""" +GUID-Generator für Inno Setup + +Generiert eine eindeutige GUID für die AppId in installer.iss +""" + +import uuid +import sys + + +def main(): + # GUID generieren + guid = uuid.uuid4() + guid_str = f"{{{{{str(guid).upper()}}}}}" + + print("=" * 60) + print("GUID für Inno Setup AppId") + print("=" * 60) + print() + print("Generierte GUID:") + print(f" {guid_str}") + print() + print("Anleitung:") + print("1. Kopieren Sie die GUID oben") + print("2. Öffnen Sie installer.iss") + print("3. Suchen Sie nach 'AppId={{' (Zeile ~22)") + print("4. Ersetzen Sie die Beispiel-GUID mit Ihrer neuen GUID") + print() + print("Beispiel:") + print(f" AppId={guid_str}") + print() + print("WICHTIG:") + print("- Die GUID sollte nur EINMAL beim ersten Setup generiert werden") + print("- Ändern Sie die GUID NICHT bei Updates, sonst wird die App") + print(" als separate Anwendung installiert!") + print("=" * 60) + + +if __name__ == "__main__": + main() diff --git a/installer.iss b/installer.iss new file mode 100644 index 0000000..e393320 --- /dev/null +++ b/installer.iss @@ -0,0 +1,73 @@ +; Inno Setup Konfiguration für DocuMentor +; Erstellt eine professionelle Setup.exe für Windows +; +; Installation von Inno Setup: https://jrsoftware.org/isdl.php +; +; WICHTIG: Vor dem ersten Build GUID generieren! +; python -c "import uuid; print(f'{{{{' + str(uuid.uuid4()).upper() + '}}}}')" +; Ergebnis in AppId unten einfügen +; +; Build-Befehl: iscc installer.iss + +#define MyAppName "DocuMentor" +#define MyAppVersion "0.1.0" +#define MyAppPublisher "Ihr Name/Organisation" +#define MyAppURL "https://github.com/yourusername/xsl-validator" +#define MyAppExeName "DocuMentor.exe" + +[Setup] +; Basis-Informationen +; WICHTIG: Ersetzen Sie die GUID mit einer eigenen generierten GUID! +; AppId={{BEISPIEL-GUID-HIER-EINFÜGEN}} +AppId={{A1B2C3D4-E5F6-4789-ABCD-EF0123456789}} +AppName={#MyAppName} +AppVersion={#MyAppVersion} +AppPublisher={#MyAppPublisher} +AppPublisherURL={#MyAppURL} +AppSupportURL={#MyAppURL} +AppUpdatesURL={#MyAppURL} + +; Installation +DefaultDirName={autopf}\{#MyAppName} +DefaultGroupName={#MyAppName} +AllowNoIcons=yes + +; Output +OutputDir=dist\installer +OutputBaseFilename=DocuMentor-Setup-{#MyAppVersion} +SetupIconFile=dist\DocuMentor\icon.ico +UninstallDisplayIcon={app}\{#MyAppExeName} + +; Kompression +Compression=lzma +SolidCompression=yes + +; Moderne UI +WizardStyle=modern + +; Rechte (normal für User-Installation, admin für System-weite Installation) +PrivilegesRequired=lowest +PrivilegesRequiredOverridesAllowed=dialog + +[Languages] +Name: "german"; MessagesFile: "compiler:Languages\German.isl" +Name: "english"; MessagesFile: "compiler:Default.isl" + +[Tasks] +Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked + +[Files] +; Alle Dateien aus dem PyInstaller-Build +Source: "dist\DocuMentor\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs + +[Icons] +Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}" +Name: "{group}\{cm:UninstallProgram,{#MyAppName}}"; Filename: "{uninstallexe}" +Name: "{autodesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon + +[Run] +Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#StringChange(MyAppName, '&', '&&')}}"; Flags: nowait postinstall skipifsilent + +[Messages] +; Deutsche Anpassungen +german.WelcomeLabel2=Dies wird [name/ver] auf Ihrem Computer installieren.%n%nBitte stellen Sie sicher, dass folgende externe Tools installiert sind:%n• Java Runtime Environment (JRE)%n• Apache FOP%n• Saxon XSLT-Prozessor%n• diff-pdf diff --git a/pyproject.toml b/pyproject.toml index 9c7769c..aeb8b47 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,4 +26,6 @@ extend-exclude = ["*_ui.py"] [dependency-groups] dev = [ "ruff>=0.14.8", + "pyinstaller>=6.0.0", + "pillow>=10.0.0", ] diff --git a/resources/Gemini_Generated_Image_awup6aawup6aawup.png b/resources/Gemini_Generated_Image_awup6aawup6aawup.png new file mode 100644 index 0000000..efbc8b5 Binary files /dev/null and b/resources/Gemini_Generated_Image_awup6aawup6aawup.png differ diff --git a/resources/Gemini_Generated_Image_gszflagszflagszf.png b/resources/Gemini_Generated_Image_gszflagszflagszf.png new file mode 100644 index 0000000..765807f Binary files /dev/null and b/resources/Gemini_Generated_Image_gszflagszflagszf.png differ diff --git a/resources/README.md b/resources/README.md new file mode 100644 index 0000000..63ae21d --- /dev/null +++ b/resources/README.md @@ -0,0 +1,64 @@ +# Resources für DocuMentor + +Dieses Verzeichnis enthält Ressourcen für den Windows-Build. + +## Icon (icon.ico) + +Das Icon wird verwendet für: +- Windows-Executable (DocuMentor.exe) +- Inno Setup Installer +- Desktop-Verknüpfungen +- Start-Menü-Einträge + +### Icon erstellen + +#### Automatisch (Standard-Icon): +```bash +python create_icon.py +``` + +Dies erstellt ein einfaches Standard-Icon mit DocuMentor-Branding. + +#### Aus eigenem PNG-Bild: +```bash +python create_icon.py mein-icon.png +``` + +Ihr PNG sollte idealerweise: +- Mindestens 256x256 Pixel groß sein +- Quadratisch sein +- Transparenten Hintergrund haben (optional) + +### Icon-Anforderungen + +Das `.ico`-Dateiformat enthält mehrere Auflösungen: +- 256x256 (Windows 7+, Taskleiste) +- 128x128 +- 64x64 +- 48x48 (Standard Desktop-Icon) +- 32x32 (Explorer Details) +- 16x16 (kleines Icon) + +Das `create_icon.py` Skript erstellt automatisch alle diese Größen. + +## Icon manuell ersetzen + +1. Eigenes Icon als `resources/icon.ico` speichern +2. Oder mit einem Online-Tool PNG→ICO konvertieren +3. Build-Skript verwendet automatisch die vorhandene Datei + +## Design-Richtlinien + +Falls Sie ein eigenes Icon erstellen: +- **Einfach und klar**: Funktioniert auch in kleinen Größen (16x16) +- **Professionell**: Passend zum Business-Kontext +- **Wiedererkennbar**: DocuMentor steht für Dokumenten-Management +- **Kontrast**: Gut sichtbar auf hellem und dunklem Hintergrund + +## Weitere Ressourcen + +In diesem Verzeichnis können später weitere Ressourcen abgelegt werden: +- Splash-Screen-Bilder +- Toolbar-Icons +- Dokumentations-Bilder +- etc. diff --git a/resources/gemini_icon_prompt.txt b/resources/gemini_icon_prompt.txt new file mode 100644 index 0000000..0934cf3 --- /dev/null +++ b/resources/gemini_icon_prompt.txt @@ -0,0 +1,45 @@ +Erstelle ein professionelles Icon für eine Desktop-Anwendung namens "DocuMentor". + +Die Anwendung wird verwendet für: +- Verwaltung von XSL-Transformationen +- Umwandlung von XML-Dokumenten zu PDF-Dateien +- Vergleich und Validierung von PDF-Dokumenten + +Design-Anforderungen: + +1. Stil: Minimalistisch, modern, professionell, business-orientiert + +2. Farben: + - Hauptfarbe: Blau (#2980B9 oder ähnlich) + - Akzentfarbe: Weiß oder helles Grau + - Maximal 2-3 Farben insgesamt + +3. Elemente (wähle eine Kombination): + - Dokument-Symbol (Papier/Seite) + - Transformation/Workflow-Element (Pfeil, Zahnrad) + - Optional: Stilisierter Buchstabe "M" oder "D" + +4. Technische Anforderungen: + - Quadratisches Format + - Einfache, klare Linien + - Hoher Kontrast + - Muss auch bei 16x16 Pixel noch erkennbar sein + - Flat Design (keine 3D-Effekte) + - Keine Farbverläufe + +5. Hintergrund: + - Transparent ODER + - Einfarbig (blau oder weiß) + +6. Referenz-Stil: + - Ähnlich wie Microsoft Office Icons + - Ähnlich wie Visual Studio Code Icons + - Moderne SaaS-Anwendungs-Icons + +Bitte erstelle ein Icon, das: +- Professionell und vertrauenswürdig wirkt +- Für technische Anwender geeignet ist +- Gut in einer Windows-Taskleiste aussieht +- Auch als Desktop-Verknüpfung funktioniert + +Format: PNG oder SVG, mindestens 512x512 Pixel diff --git a/resources/icon.ico b/resources/icon.ico new file mode 100644 index 0000000..4d020d3 Binary files /dev/null and b/resources/icon.ico differ diff --git a/resources/icon_prompt.md b/resources/icon_prompt.md new file mode 100644 index 0000000..e9500f1 --- /dev/null +++ b/resources/icon_prompt.md @@ -0,0 +1,150 @@ +# Icon-Prompt für Bild-Generierungs-KI + +## DocuMentor Logo/Icon + +### Deutsche Version (für deutsche KI-Tools) + +``` +Erstelle ein professionelles, minimalistisches SVG-Icon für eine Business-Software namens "DocuMentor". + +Anwendungsbeschreibung: +DocuMentor ist eine Desktop-Anwendung zur Verwaltung und Validierung von XSL-Transformationen. Die Software wird von technischen Redakteuren und Entwicklern verwendet, um XML-Dokumente in PDF-Dateien zu transformieren und diese zu vergleichen. + +Design-Anforderungen: +- Stil: Professionell, modern, technisch, business-orientiert +- Farben: Blaue Töne (z.B. #2980B9, #3498DB) kombiniert mit neutralen Grautönen oder Weiß +- Elemente: Kombination aus Dokumenten-Symbol und Transformations-/Workflow-Elementen +- Einfachheit: Muss auch in sehr kleinen Größen (16x16 Pixel) erkennbar sein +- Klare Linien und hoher Kontrast + +Symbolik-Vorschläge: +- Ein Dokument mit Transformations-Pfeilen +- Gestapelte/verschachtelte Dokumente (XML → XSLT → PDF) +- Stilisiertes "D" oder "M" für DocuMentor +- Workflow-Diagramm mit Dokumenten-Symbolen +- Dokument mit Zahnrad (Verarbeitung/Transformation) + +Format: Vektorgrafik (SVG), quadratisch (1:1 Verhältnis), 512x512 Pixel oder größer +Hintergrund: Transparent oder einfarbig (blau/weiß) + +Stil-Referenzen: Microsoft Office Icons, Adobe Creative Cloud Icons, moderne SaaS-Anwendungen +``` + +### Englische Version (für internationale KI-Tools wie DALL-E, Midjourney, Stable Diffusion) + +``` +Create a professional, minimalist SVG icon for business software called "DocuMentor". + +Application Description: +DocuMentor is a desktop application for managing and validating XSL transformations. The software is used by technical writers and developers to transform XML documents into PDF files and compare them. + +Design Requirements: +- Style: Professional, modern, technical, business-oriented +- Colors: Blue tones (e.g., #2980B9, #3498DB) combined with neutral grays or white +- Elements: Combination of document symbol and transformation/workflow elements +- Simplicity: Must be recognizable even at very small sizes (16x16 pixels) +- Clean lines and high contrast + +Symbolism Suggestions: +- A document with transformation arrows +- Stacked/nested documents (XML → XSLT → PDF) +- Stylized "D" or "M" for DocuMentor +- Workflow diagram with document symbols +- Document with gear icon (processing/transformation) + +Format: Vector graphic (SVG), square (1:1 ratio), 512x512 pixels or larger +Background: Transparent or solid color (blue/white) + +Style References: Microsoft Office icons, Adobe Creative Cloud icons, modern SaaS applications + +Additional Instructions: +- Flat design, not 3D +- No gradients or complex shadows +- Maximum 3 colors +- Geometric shapes preferred +- Professional and trustworthy appearance +``` + +### Alternativer Prompt (detaillierter für KIs wie ChatGPT mit DALL-E) + +``` +Design a minimalist icon for "DocuMentor" - a professional XML/XSL transformation management software. + +Concept: A clean, modern icon that combines: +1. A document/page symbol (representing XML/PDF files) +2. An element suggesting transformation or workflow (arrows, gears, or connecting lines) +3. Professional color scheme: Primary blue (#2980B9) with white/gray accents + +Requirements: +- Vector style, flat design +- Must work well at 16x16, 48x48, and 256x256 pixels +- High contrast for visibility +- No text, icon only +- Square format (512x512px minimum) +- Transparent background preferred + +Style inspiration: Think Microsoft Office 365 icons, VS Code icons, or modern productivity app icons - clean, professional, instantly recognizable. + +Technical constraints: +- Simple enough to work as a favicon +- Clear silhouette when shown in monochrome +- Distinctive enough to stand out in a taskbar or dock +``` + +## Prompt für spezifische Konzepte + +### Konzept 1: Dokument mit Transformation + +``` +A minimalist icon showing a document page with a curved arrow pointing to another document, symbolizing transformation. Blue (#2980B9) and white color scheme. Flat design, professional, suitable for business software. SVG style, 512x512px, transparent background. +``` + +### Konzept 2: Gestapelte Dokumente + +``` +An icon with three overlapping document sheets in a cascading arrangement, representing XML to XSL to PDF transformation workflow. Modern flat design, blue gradient (#3498DB to #2980B9), white accents. Professional business software icon. 512x512px SVG format. +``` + +### Konzept 3: Dokument + Zahnrad + +``` +A clean icon combining a document page with a small gear/cog symbol in the corner, representing document processing. Minimalist design, blue (#2980B9) on white background. Professional style like Microsoft Office icons. 512x512px, vector art, high contrast. +``` + +### Konzept 4: Stilisiertes "M" + +``` +A stylized letter "M" for "Mentor" integrated with document/page elements. Modern, geometric, professional. Blue (#2980B9) color scheme. Suitable for small sizes. Flat design, vector style, 512x512px, transparent background. +``` + +## Verwendung + +1. Wähle einen der Prompts oben +2. Füge ihn in eine Bild-Generierungs-KI ein: + - **DALL-E 3** (ChatGPT Plus): Englischer Prompt empfohlen + - **Midjourney**: Englischer Prompt, evtl. kürzer + - **Adobe Firefly**: Deutscher oder englischer Prompt + - **Stable Diffusion**: Englischer Prompt mit detaillierten Tags + - **Leonardo.ai**: Englischer Prompt + +3. Lade das generierte Bild herunter (idealerweise als PNG) + +4. Konvertiere zu ICO: + ```bash + uv run python create_icon.py generiertes-icon.png + ``` + +## Tipps für beste Ergebnisse + +- **Iteriere**: Generiere mehrere Varianten +- **Einfachheit**: Betone "minimalist", "simple", "clean" +- **Größe**: Teste das Icon in verschiedenen Größen +- **Kontrast**: Achte auf gute Sichtbarkeit auf hellem und dunklem Hintergrund +- **Professionalität**: Vermeide zu verspielte oder kindliche Designs + +## Nachbearbeitung + +Falls die KI kein perfektes SVG erstellt: +1. PNG exportieren (hohe Auflösung, mind. 512x512px) +2. Mit Inkscape oder Adobe Illustrator zu SVG konvertieren +3. Oder direkt als PNG verwenden und mit `create_icon.py` konvertieren diff --git a/uv.lock b/uv.lock index da29d8b..b507c56 100644 --- a/uv.lock +++ b/uv.lock @@ -2,6 +2,15 @@ version = 1 revision = 3 requires-python = ">=3.13" +[[package]] +name = "altgraph" +version = "0.17.5" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7e/f8/97fdf103f38fed6792a1601dbc16cc8aac56e7459a9fff08c812d8ae177a/altgraph-0.17.5.tar.gz", hash = "sha256:c87b395dd12fabde9c99573a9749d67da8d29ef9de0125c7f536699b4a9bc9e7", size = 48428, upload-time = "2025-11-21T20:35:50.583Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a9/ba/000a1996d4308bc65120167c21241a3b205464a2e0b58deda26ae8ac21d1/altgraph-0.17.5-py2.py3-none-any.whl", hash = "sha256:f3a22400bce1b0c701683820ac4f3b159cd301acab067c51c653e06961600597", size = 21228, upload-time = "2025-11-21T20:35:49.444Z" }, +] + [[package]] name = "annotated-types" version = "0.7.0" @@ -46,6 +55,8 @@ dependencies = [ [package.dev-dependencies] dev = [ + { name = "pillow" }, + { name = "pyinstaller" }, { name = "ruff" }, ] @@ -59,7 +70,99 @@ requires-dist = [ ] [package.metadata.requires-dev] -dev = [{ name = "ruff", specifier = ">=0.14.8" }] +dev = [ + { name = "pillow", specifier = ">=10.0.0" }, + { name = "pyinstaller", specifier = ">=6.0.0" }, + { name = "ruff", specifier = ">=0.14.8" }, +] + +[[package]] +name = "macholib" +version = "1.16.4" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "altgraph" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/10/2f/97589876ea967487978071c9042518d28b958d87b17dceb7cdc1d881f963/macholib-1.16.4.tar.gz", hash = "sha256:f408c93ab2e995cd2c46e34fe328b130404be143469e41bc366c807448979362", size = 59427, upload-time = "2025-11-22T08:28:38.373Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c7/d1/a9f36f8ecdf0fb7c9b1e78c8d7af12b8c8754e74851ac7b94a8305540fc7/macholib-1.16.4-py2.py3-none-any.whl", hash = "sha256:da1a3fa8266e30f0ce7e97c6a54eefaae8edd1e5f86f3eb8b95457cae90265ea", size = 38117, upload-time = "2025-11-22T08:28:36.939Z" }, +] + +[[package]] +name = "packaging" +version = "25.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/d4/1fc4078c65507b51b96ca8f8c3ba19e6a61c8253c72794544580a7b6c24d/packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f", size = 165727, upload-time = "2025-04-19T11:48:59.673Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/20/12/38679034af332785aac8774540895e234f4d07f7545804097de4b666afd8/packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484", size = 66469, upload-time = "2025-04-19T11:48:57.875Z" }, +] + +[[package]] +name = "pefile" +version = "2024.8.26" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/03/4f/2750f7f6f025a1507cd3b7218691671eecfd0bbebebe8b39aa0fe1d360b8/pefile-2024.8.26.tar.gz", hash = "sha256:3ff6c5d8b43e8c37bb6e6dd5085658d658a7a0bdcd20b6a07b1fcfc1c4e9d632", size = 76008, upload-time = "2024-08-26T20:58:38.155Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/54/16/12b82f791c7f50ddec566873d5bdd245baa1491bac11d15ffb98aecc8f8b/pefile-2024.8.26-py3-none-any.whl", hash = "sha256:76f8b485dcd3b1bb8166f1128d395fa3d87af26360c2358fb75b80019b957c6f", size = 74766, upload-time = "2024-08-26T21:01:02.632Z" }, +] + +[[package]] +name = "pillow" +version = "12.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d0/02/d52c733a2452ef1ffcc123b68e6606d07276b0e358db70eabad7e40042b7/pillow-12.1.0.tar.gz", hash = "sha256:5c5ae0a06e9ea030ab786b0251b32c7e4ce10e58d983c0d5c56029455180b5b9", size = 46977283, upload-time = "2026-01-02T09:13:29.892Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dd/c7/2530a4aa28248623e9d7f27316b42e27c32ec410f695929696f2e0e4a778/pillow-12.1.0-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:7b5dd7cbae20285cdb597b10eb5a2c13aa9de6cde9bb64a3c1317427b1db1ae1", size = 4062543, upload-time = "2026-01-02T09:11:31.566Z" }, + { url = "https://files.pythonhosted.org/packages/8f/1f/40b8eae823dc1519b87d53c30ed9ef085506b05281d313031755c1705f73/pillow-12.1.0-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:29a4cef9cb672363926f0470afc516dbf7305a14d8c54f7abbb5c199cd8f8179", size = 4138373, upload-time = "2026-01-02T09:11:33.367Z" }, + { url = "https://files.pythonhosted.org/packages/d4/77/6fa60634cf06e52139fd0e89e5bbf055e8166c691c42fb162818b7fda31d/pillow-12.1.0-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:681088909d7e8fa9e31b9799aaa59ba5234c58e5e4f1951b4c4d1082a2e980e0", size = 3601241, upload-time = "2026-01-02T09:11:35.011Z" }, + { url = "https://files.pythonhosted.org/packages/4f/bf/28ab865de622e14b747f0cd7877510848252d950e43002e224fb1c9ababf/pillow-12.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:983976c2ab753166dc66d36af6e8ec15bb511e4a25856e2227e5f7e00a160587", size = 5262410, upload-time = "2026-01-02T09:11:36.682Z" }, + { url = "https://files.pythonhosted.org/packages/1c/34/583420a1b55e715937a85bd48c5c0991598247a1fd2eb5423188e765ea02/pillow-12.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:db44d5c160a90df2d24a24760bbd37607d53da0b34fb546c4c232af7192298ac", size = 4657312, upload-time = "2026-01-02T09:11:38.535Z" }, + { url = "https://files.pythonhosted.org/packages/1d/fd/f5a0896839762885b3376ff04878f86ab2b097c2f9a9cdccf4eda8ba8dc0/pillow-12.1.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6b7a9d1db5dad90e2991645874f708e87d9a3c370c243c2d7684d28f7e133e6b", size = 6232605, upload-time = "2026-01-02T09:11:40.602Z" }, + { url = "https://files.pythonhosted.org/packages/98/aa/938a09d127ac1e70e6ed467bd03834350b33ef646b31edb7452d5de43792/pillow-12.1.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:6258f3260986990ba2fa8a874f8b6e808cf5abb51a94015ca3dc3c68aa4f30ea", size = 8041617, upload-time = "2026-01-02T09:11:42.721Z" }, + { url = "https://files.pythonhosted.org/packages/17/e8/538b24cb426ac0186e03f80f78bc8dc7246c667f58b540bdd57c71c9f79d/pillow-12.1.0-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e115c15e3bc727b1ca3e641a909f77f8ca72a64fff150f666fcc85e57701c26c", size = 6346509, upload-time = "2026-01-02T09:11:44.955Z" }, + { url = "https://files.pythonhosted.org/packages/01/9a/632e58ec89a32738cabfd9ec418f0e9898a2b4719afc581f07c04a05e3c9/pillow-12.1.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6741e6f3074a35e47c77b23a4e4f2d90db3ed905cb1c5e6e0d49bff2045632bc", size = 7038117, upload-time = "2026-01-02T09:11:46.736Z" }, + { url = "https://files.pythonhosted.org/packages/c7/a2/d40308cf86eada842ca1f3ffa45d0ca0df7e4ab33c83f81e73f5eaed136d/pillow-12.1.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:935b9d1aed48fcfb3f838caac506f38e29621b44ccc4f8a64d575cb1b2a88644", size = 6460151, upload-time = "2026-01-02T09:11:48.625Z" }, + { url = "https://files.pythonhosted.org/packages/f1/88/f5b058ad6453a085c5266660a1417bdad590199da1b32fb4efcff9d33b05/pillow-12.1.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:5fee4c04aad8932da9f8f710af2c1a15a83582cfb884152a9caa79d4efcdbf9c", size = 7164534, upload-time = "2026-01-02T09:11:50.445Z" }, + { url = "https://files.pythonhosted.org/packages/19/ce/c17334caea1db789163b5d855a5735e47995b0b5dc8745e9a3605d5f24c0/pillow-12.1.0-cp313-cp313-win32.whl", hash = "sha256:a786bf667724d84aa29b5db1c61b7bfdde380202aaca12c3461afd6b71743171", size = 6332551, upload-time = "2026-01-02T09:11:52.234Z" }, + { url = "https://files.pythonhosted.org/packages/e5/07/74a9d941fa45c90a0d9465098fe1ec85de3e2afbdc15cc4766622d516056/pillow-12.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:461f9dfdafa394c59cd6d818bdfdbab4028b83b02caadaff0ffd433faf4c9a7a", size = 7040087, upload-time = "2026-01-02T09:11:54.822Z" }, + { url = "https://files.pythonhosted.org/packages/88/09/c99950c075a0e9053d8e880595926302575bc742b1b47fe1bbcc8d388d50/pillow-12.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:9212d6b86917a2300669511ed094a9406888362e085f2431a7da985a6b124f45", size = 2452470, upload-time = "2026-01-02T09:11:56.522Z" }, + { url = "https://files.pythonhosted.org/packages/b5/ba/970b7d85ba01f348dee4d65412476321d40ee04dcb51cd3735b9dc94eb58/pillow-12.1.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:00162e9ca6d22b7c3ee8e61faa3c3253cd19b6a37f126cad04f2f88b306f557d", size = 5264816, upload-time = "2026-01-02T09:11:58.227Z" }, + { url = "https://files.pythonhosted.org/packages/10/60/650f2fb55fdba7a510d836202aa52f0baac633e50ab1cf18415d332188fb/pillow-12.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7d6daa89a00b58c37cb1747ec9fb7ac3bc5ffd5949f5888657dfddde6d1312e0", size = 4660472, upload-time = "2026-01-02T09:12:00.798Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c0/5273a99478956a099d533c4f46cbaa19fd69d606624f4334b85e50987a08/pillow-12.1.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e2479c7f02f9d505682dc47df8c0ea1fc5e264c4d1629a5d63fe3e2334b89554", size = 6268974, upload-time = "2026-01-02T09:12:02.572Z" }, + { url = "https://files.pythonhosted.org/packages/b4/26/0bf714bc2e73d5267887d47931d53c4ceeceea6978148ed2ab2a4e6463c4/pillow-12.1.0-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f188d580bd870cda1e15183790d1cc2fa78f666e76077d103edf048eed9c356e", size = 8073070, upload-time = "2026-01-02T09:12:04.75Z" }, + { url = "https://files.pythonhosted.org/packages/43/cf/1ea826200de111a9d65724c54f927f3111dc5ae297f294b370a670c17786/pillow-12.1.0-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0fde7ec5538ab5095cc02df38ee99b0443ff0e1c847a045554cf5f9af1f4aa82", size = 6380176, upload-time = "2026-01-02T09:12:06.626Z" }, + { url = "https://files.pythonhosted.org/packages/03/e0/7938dd2b2013373fd85d96e0f38d62b7a5a262af21ac274250c7ca7847c9/pillow-12.1.0-cp313-cp313t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0ed07dca4a8464bada6139ab38f5382f83e5f111698caf3191cb8dbf27d908b4", size = 7067061, upload-time = "2026-01-02T09:12:08.624Z" }, + { url = "https://files.pythonhosted.org/packages/86/ad/a2aa97d37272a929a98437a8c0ac37b3cf012f4f8721e1bd5154699b2518/pillow-12.1.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:f45bd71d1fa5e5749587613037b172e0b3b23159d1c00ef2fc920da6f470e6f0", size = 6491824, upload-time = "2026-01-02T09:12:10.488Z" }, + { url = "https://files.pythonhosted.org/packages/a4/44/80e46611b288d51b115826f136fb3465653c28f491068a72d3da49b54cd4/pillow-12.1.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:277518bf4fe74aa91489e1b20577473b19ee70fb97c374aa50830b279f25841b", size = 7190911, upload-time = "2026-01-02T09:12:12.772Z" }, + { url = "https://files.pythonhosted.org/packages/86/77/eacc62356b4cf81abe99ff9dbc7402750044aed02cfd6a503f7c6fc11f3e/pillow-12.1.0-cp313-cp313t-win32.whl", hash = "sha256:7315f9137087c4e0ee73a761b163fc9aa3b19f5f606a7fc08d83fd3e4379af65", size = 6336445, upload-time = "2026-01-02T09:12:14.775Z" }, + { url = "https://files.pythonhosted.org/packages/e7/3c/57d81d0b74d218706dafccb87a87ea44262c43eef98eb3b164fd000e0491/pillow-12.1.0-cp313-cp313t-win_amd64.whl", hash = "sha256:0ddedfaa8b5f0b4ffbc2fa87b556dc59f6bb4ecb14a53b33f9189713ae8053c0", size = 7045354, upload-time = "2026-01-02T09:12:16.599Z" }, + { url = "https://files.pythonhosted.org/packages/ac/82/8b9b97bba2e3576a340f93b044a3a3a09841170ab4c1eb0d5c93469fd32f/pillow-12.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:80941e6d573197a0c28f394753de529bb436b1ca990ed6e765cf42426abc39f8", size = 2454547, upload-time = "2026-01-02T09:12:18.704Z" }, + { url = "https://files.pythonhosted.org/packages/8c/87/bdf971d8bbcf80a348cc3bacfcb239f5882100fe80534b0ce67a784181d8/pillow-12.1.0-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:5cb7bc1966d031aec37ddb9dcf15c2da5b2e9f7cc3ca7c54473a20a927e1eb91", size = 4062533, upload-time = "2026-01-02T09:12:20.791Z" }, + { url = "https://files.pythonhosted.org/packages/ff/4f/5eb37a681c68d605eb7034c004875c81f86ec9ef51f5be4a63eadd58859a/pillow-12.1.0-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:97e9993d5ed946aba26baf9c1e8cf18adbab584b99f452ee72f7ee8acb882796", size = 4138546, upload-time = "2026-01-02T09:12:23.664Z" }, + { url = "https://files.pythonhosted.org/packages/11/6d/19a95acb2edbace40dcd582d077b991646b7083c41b98da4ed7555b59733/pillow-12.1.0-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:414b9a78e14ffeb98128863314e62c3f24b8a86081066625700b7985b3f529bd", size = 3601163, upload-time = "2026-01-02T09:12:26.338Z" }, + { url = "https://files.pythonhosted.org/packages/fc/36/2b8138e51cb42e4cc39c3297713455548be855a50558c3ac2beebdc251dd/pillow-12.1.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:e6bdb408f7c9dd2a5ff2b14a3b0bb6d4deb29fb9961e6eb3ae2031ae9a5cec13", size = 5266086, upload-time = "2026-01-02T09:12:28.782Z" }, + { url = "https://files.pythonhosted.org/packages/53/4b/649056e4d22e1caa90816bf99cef0884aed607ed38075bd75f091a607a38/pillow-12.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3413c2ae377550f5487991d444428f1a8ae92784aac79caa8b1e3b89b175f77e", size = 4657344, upload-time = "2026-01-02T09:12:31.117Z" }, + { url = "https://files.pythonhosted.org/packages/6c/6b/c5742cea0f1ade0cd61485dc3d81f05261fc2276f537fbdc00802de56779/pillow-12.1.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e5dcbe95016e88437ecf33544ba5db21ef1b8dd6e1b434a2cb2a3d605299e643", size = 6232114, upload-time = "2026-01-02T09:12:32.936Z" }, + { url = "https://files.pythonhosted.org/packages/bf/8f/9f521268ce22d63991601aafd3d48d5ff7280a246a1ef62d626d67b44064/pillow-12.1.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d0a7735df32ccbcc98b98a1ac785cc4b19b580be1bdf0aeb5c03223220ea09d5", size = 8042708, upload-time = "2026-01-02T09:12:34.78Z" }, + { url = "https://files.pythonhosted.org/packages/1a/eb/257f38542893f021502a1bbe0c2e883c90b5cff26cc33b1584a841a06d30/pillow-12.1.0-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0c27407a2d1b96774cbc4a7594129cc027339fd800cd081e44497722ea1179de", size = 6347762, upload-time = "2026-01-02T09:12:36.748Z" }, + { url = "https://files.pythonhosted.org/packages/c4/5a/8ba375025701c09b309e8d5163c5a4ce0102fa86bbf8800eb0d7ac87bc51/pillow-12.1.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:15c794d74303828eaa957ff8070846d0efe8c630901a1c753fdc63850e19ecd9", size = 7039265, upload-time = "2026-01-02T09:12:39.082Z" }, + { url = "https://files.pythonhosted.org/packages/cf/dc/cf5e4cdb3db533f539e88a7bbf9f190c64ab8a08a9bc7a4ccf55067872e4/pillow-12.1.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:c990547452ee2800d8506c4150280757f88532f3de2a58e3022e9b179107862a", size = 6462341, upload-time = "2026-01-02T09:12:40.946Z" }, + { url = "https://files.pythonhosted.org/packages/d0/47/0291a25ac9550677e22eda48510cfc4fa4b2ef0396448b7fbdc0a6946309/pillow-12.1.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:b63e13dd27da389ed9475b3d28510f0f954bca0041e8e551b2a4eb1eab56a39a", size = 7165395, upload-time = "2026-01-02T09:12:42.706Z" }, + { url = "https://files.pythonhosted.org/packages/4f/4c/e005a59393ec4d9416be06e6b45820403bb946a778e39ecec62f5b2b991e/pillow-12.1.0-cp314-cp314-win32.whl", hash = "sha256:1a949604f73eb07a8adab38c4fe50791f9919344398bdc8ac6b307f755fc7030", size = 6431413, upload-time = "2026-01-02T09:12:44.944Z" }, + { url = "https://files.pythonhosted.org/packages/1c/af/f23697f587ac5f9095d67e31b81c95c0249cd461a9798a061ed6709b09b5/pillow-12.1.0-cp314-cp314-win_amd64.whl", hash = "sha256:4f9f6a650743f0ddee5593ac9e954ba1bdbc5e150bc066586d4f26127853ab94", size = 7176779, upload-time = "2026-01-02T09:12:46.727Z" }, + { url = "https://files.pythonhosted.org/packages/b3/36/6a51abf8599232f3e9afbd16d52829376a68909fe14efe29084445db4b73/pillow-12.1.0-cp314-cp314-win_arm64.whl", hash = "sha256:808b99604f7873c800c4840f55ff389936ef1948e4e87645eaf3fccbc8477ac4", size = 2543105, upload-time = "2026-01-02T09:12:49.243Z" }, + { url = "https://files.pythonhosted.org/packages/82/54/2e1dd20c8749ff225080d6ba465a0cab4387f5db0d1c5fb1439e2d99923f/pillow-12.1.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:bc11908616c8a283cf7d664f77411a5ed2a02009b0097ff8abbba5e79128ccf2", size = 5268571, upload-time = "2026-01-02T09:12:51.11Z" }, + { url = "https://files.pythonhosted.org/packages/57/61/571163a5ef86ec0cf30d265ac2a70ae6fc9e28413d1dc94fa37fae6bda89/pillow-12.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:896866d2d436563fa2a43a9d72f417874f16b5545955c54a64941e87c1376c61", size = 4660426, upload-time = "2026-01-02T09:12:52.865Z" }, + { url = "https://files.pythonhosted.org/packages/5e/e1/53ee5163f794aef1bf84243f755ee6897a92c708505350dd1923f4afec48/pillow-12.1.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8e178e3e99d3c0ea8fc64b88447f7cac8ccf058af422a6cedc690d0eadd98c51", size = 6269908, upload-time = "2026-01-02T09:12:54.884Z" }, + { url = "https://files.pythonhosted.org/packages/bc/0b/b4b4106ff0ee1afa1dc599fde6ab230417f800279745124f6c50bcffed8e/pillow-12.1.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:079af2fb0c599c2ec144ba2c02766d1b55498e373b3ac64687e43849fbbef5bc", size = 8074733, upload-time = "2026-01-02T09:12:56.802Z" }, + { url = "https://files.pythonhosted.org/packages/19/9f/80b411cbac4a732439e629a26ad3ef11907a8c7fc5377b7602f04f6fe4e7/pillow-12.1.0-cp314-cp314t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bdec5e43377761c5dbca620efb69a77f6855c5a379e32ac5b158f54c84212b14", size = 6381431, upload-time = "2026-01-02T09:12:58.823Z" }, + { url = "https://files.pythonhosted.org/packages/8f/b7/d65c45db463b66ecb6abc17c6ba6917a911202a07662247e1355ce1789e7/pillow-12.1.0-cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:565c986f4b45c020f5421a4cea13ef294dde9509a8577f29b2fc5edc7587fff8", size = 7068529, upload-time = "2026-01-02T09:13:00.885Z" }, + { url = "https://files.pythonhosted.org/packages/50/96/dfd4cd726b4a45ae6e3c669fc9e49deb2241312605d33aba50499e9d9bd1/pillow-12.1.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:43aca0a55ce1eefc0aefa6253661cb54571857b1a7b2964bd8a1e3ef4b729924", size = 6492981, upload-time = "2026-01-02T09:13:03.314Z" }, + { url = "https://files.pythonhosted.org/packages/4d/1c/b5dc52cf713ae46033359c5ca920444f18a6359ce1020dd3e9c553ea5bc6/pillow-12.1.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0deedf2ea233722476b3a81e8cdfbad786f7adbed5d848469fa59fe52396e4ef", size = 7191878, upload-time = "2026-01-02T09:13:05.276Z" }, + { url = "https://files.pythonhosted.org/packages/53/26/c4188248bd5edaf543864fe4834aebe9c9cb4968b6f573ce014cc42d0720/pillow-12.1.0-cp314-cp314t-win32.whl", hash = "sha256:b17fbdbe01c196e7e159aacb889e091f28e61020a8abeac07b68079b6e626988", size = 6438703, upload-time = "2026-01-02T09:13:07.491Z" }, + { url = "https://files.pythonhosted.org/packages/b8/0e/69ed296de8ea05cb03ee139cee600f424ca166e632567b2d66727f08c7ed/pillow-12.1.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27b9baecb428899db6c0de572d6d305cfaf38ca1596b5c0542a5182e3e74e8c6", size = 7182927, upload-time = "2026-01-02T09:13:09.841Z" }, + { url = "https://files.pythonhosted.org/packages/fc/f5/68334c015eed9b5cff77814258717dec591ded209ab5b6fb70e2ae873d1d/pillow-12.1.0-cp314-cp314t-win_arm64.whl", hash = "sha256:f61333d817698bdcdd0f9d7793e365ac3d2a21c1f1eb02b32ad6aefb8d8ea831", size = 2545104, upload-time = "2026-01-02T09:13:12.068Z" }, +] [[package]] name = "polars" @@ -176,6 +279,47 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ba/39/8d263fbcb409a8f5dd78ac8f89f1e6af1d4e4d9fbb7f856ca3245b354809/pydantic_yaml-1.6.0-py3-none-any.whl", hash = "sha256:02cb800b455b68daeeb74ad736c252a94a0b203da5fbbeef02539d468e1d98f8", size = 22511, upload-time = "2025-08-08T21:01:11.425Z" }, ] +[[package]] +name = "pyinstaller" +version = "6.17.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "altgraph" }, + { name = "macholib", marker = "sys_platform == 'darwin'" }, + { name = "packaging" }, + { name = "pefile", marker = "sys_platform == 'win32'" }, + { name = "pyinstaller-hooks-contrib" }, + { name = "pywin32-ctypes", marker = "sys_platform == 'win32'" }, + { name = "setuptools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/01/80/9e0dad9c69a7cfd4b5aaede8c6225d762bab7247a2a6b7651e1995522001/pyinstaller-6.17.0.tar.gz", hash = "sha256:be372bd911392b88277e510940ac32a5c2a6ce4b8d00a311c78fa443f4f27313", size = 4014147, upload-time = "2025-11-24T19:43:32.109Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/35/f5/37e419d84d5284ecab11ef8b61306a3b978fe6f0fd69a9541e16bfd72e65/pyinstaller-6.17.0-py3-none-macosx_10_13_universal2.whl", hash = "sha256:4e446b8030c6e5a2f712e3f82011ecf6c7ead86008357b0d23a0ec4bcde31dac", size = 1031880, upload-time = "2025-11-24T19:42:30.862Z" }, + { url = "https://files.pythonhosted.org/packages/9e/b6/2e184879ab9cf90a1d2867fdd34d507c4d246b3cc52ca05aad00bfc70ee7/pyinstaller-6.17.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:aa9fd87aaa28239c6f0d0210114029bd03f8cac316a90bab071a5092d7c85ad7", size = 731968, upload-time = "2025-11-24T19:42:35.421Z" }, + { url = "https://files.pythonhosted.org/packages/40/76/f529de98f7e5cce7904c19b224990003fc2267eda2ee5fdd8452acb420a9/pyinstaller-6.17.0-py3-none-manylinux2014_i686.whl", hash = "sha256:060b122e43e7c0b23e759a4153be34bd70914135ab955bb18a67181e0dca85a2", size = 743217, upload-time = "2025-11-24T19:42:39.286Z" }, + { url = "https://files.pythonhosted.org/packages/a3/10/c02bfbb050cafc4c353cf69baf95407e211e1372bd286ab5ce5cbc13a30a/pyinstaller-6.17.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:cd213d1a545c97dfe4a3c40e8213ff7c5127fc115c49229f27a3fa541503444b", size = 741119, upload-time = "2025-11-24T19:42:43.12Z" }, + { url = "https://files.pythonhosted.org/packages/11/9d/69fdacfd9335695f5900a376cfe3e4aed28f0720ffc15fee81fdb9d920bc/pyinstaller-6.17.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:89c0d18ba8b62c6607abd8cf2299ae5ffa5c36d8c47f39608ce8c3f357f6099f", size = 738111, upload-time = "2025-11-24T19:42:46.97Z" }, + { url = "https://files.pythonhosted.org/packages/5e/1e/e8e36e1568f6865ac706c6e1f875c1a346ddaa9f9a8f923d66545d2240ed/pyinstaller-6.17.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:2a147b83cdebb07855bd5a663600891550062373a2ca375c58eacead33741a27", size = 737795, upload-time = "2025-11-24T19:42:50.675Z" }, + { url = "https://files.pythonhosted.org/packages/8d/15/9dc0f81ccb746c27bfa6ee53164422fe47ee079c7a717d9c4791aba78797/pyinstaller-6.17.0-py3-none-musllinux_1_1_aarch64.whl", hash = "sha256:f8cfbbfa6708e54fb936df6dd6eafaf133e84efb0d2fe25b91cfeefa793c4ca4", size = 736891, upload-time = "2025-11-24T19:42:54.458Z" }, + { url = "https://files.pythonhosted.org/packages/97/e6/bed54821c1ebe1275c559661d3e7bfa23c406673b515252dfbf89db56c65/pyinstaller-6.17.0-py3-none-musllinux_1_1_x86_64.whl", hash = "sha256:97f4c1942f7b4cd73f9e38b49cc8f5f8a6fbb44922cb60dd3073a189b77ee1ae", size = 736752, upload-time = "2025-11-24T19:42:58.144Z" }, + { url = "https://files.pythonhosted.org/packages/c7/84/897d759198676b910d69d42640b6d25d50b449f2209e18127a974cf59dbe/pyinstaller-6.17.0-py3-none-win32.whl", hash = "sha256:ce0be227a037fd4be672226db709088565484f597d6b230bceec19850fdd4c85", size = 1317851, upload-time = "2025-11-24T19:43:04.361Z" }, + { url = "https://files.pythonhosted.org/packages/2d/f5/6a122efe024433ecc34aab6f499e0bd2bbe059c639b77b0045aa2421b0bf/pyinstaller-6.17.0-py3-none-win_amd64.whl", hash = "sha256:b019940dbf7a01489d6b26f9fb97db74b504e0a757010f7ad078675befc85a82", size = 1378685, upload-time = "2025-11-24T19:43:10.395Z" }, + { url = "https://files.pythonhosted.org/packages/c4/96/14991773c9e599707a53594429ccf372f9ee638df3b7d26b65fd1a7433f0/pyinstaller-6.17.0-py3-none-win_arm64.whl", hash = "sha256:3c92a335e338170df7e615f75279cfeea97ade89e6dd7694943c8c185460f7b7", size = 1320032, upload-time = "2025-11-24T19:43:16.388Z" }, +] + +[[package]] +name = "pyinstaller-hooks-contrib" +version = "2025.11" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, + { name = "setuptools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/45/2f/2c68b6722d233dae3e5243751aafc932940b836919cfaca22dd0c60d417c/pyinstaller_hooks_contrib-2025.11.tar.gz", hash = "sha256:dfe18632e06655fa88d218e0d768fd753e1886465c12a6d4bce04f1aaeec917d", size = 169183, upload-time = "2025-12-23T12:59:37.361Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a7/c4/3a096c6e701832443b957b9dac18a163103360d0c7f5842ca41695371148/pyinstaller_hooks_contrib-2025.11-py3-none-any.whl", hash = "sha256:777e163e2942474aa41a8e6d31ac1635292d63422c3646c176d584d04d971c34", size = 449478, upload-time = "2025-12-23T12:59:35.987Z" }, +] + [[package]] name = "pyqtdarktheme" version = "2.1.0" @@ -245,6 +389,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556, upload-time = "2025-06-24T04:21:06.073Z" }, ] +[[package]] +name = "pywin32-ctypes" +version = "0.2.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/85/9f/01a1a99704853cb63f253eea009390c88e7131c67e66a0a02099a8c917cb/pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755", size = 29471, upload-time = "2024-08-14T10:15:34.626Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/3d/8161f7711c017e01ac9f008dfddd9410dff3674334c233bde66e7ba65bbf/pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8", size = 30756, upload-time = "2024-08-14T10:15:33.187Z" }, +] + [[package]] name = "ruamel-yaml" version = "0.18.15" @@ -300,6 +453,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6d/63/8b41cea3afd7f58eb64ac9251668ee0073789a3bc9ac6f816c8c6fef986d/ruff-0.14.8-py3-none-win_arm64.whl", hash = "sha256:965a582c93c63fe715fd3e3f8aa37c4b776777203d8e1d8aa3cc0c14424a4b99", size = 13634522, upload-time = "2025-12-04T15:06:43.212Z" }, ] +[[package]] +name = "setuptools" +version = "80.9.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/18/5d/3bf57dcd21979b887f014ea83c24ae194cfcd12b9e0fda66b957c69d1fca/setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c", size = 1319958, upload-time = "2025-05-27T00:56:51.443Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a3/dc/17031897dae0efacfea57dfd3a82fdd2a2aeb58e0ff71b77b87e44edc772/setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922", size = 1201486, upload-time = "2025-05-27T00:56:49.664Z" }, +] + [[package]] name = "shiboken6" version = "6.9.2"