Initial commit
This commit is contained in:
225
dist/dicom2pacs.app/Contents/Resources/dicom2pacs.py
vendored
Executable file
225
dist/dicom2pacs.app/Contents/Resources/dicom2pacs.py
vendored
Executable file
@@ -0,0 +1,225 @@
|
||||
import sys
|
||||
import os
|
||||
import asyncio
|
||||
from gui import GUI
|
||||
import file_management
|
||||
import threading
|
||||
import dicom_processing
|
||||
import shutil
|
||||
import network_utils
|
||||
from tkinter import filedialog
|
||||
import tkinter as tk
|
||||
|
||||
# Konfigurationsvariablen
|
||||
HOME_DIRECTORY = os.path.expanduser('~')
|
||||
TRANSFER_FOLDER = os.path.join(HOME_DIRECTORY, 'Downloads/D2OTrans')
|
||||
AUSGABE_DATEI = os.path.join(HOME_DIRECTORY, 't2o_modality.txt')
|
||||
|
||||
name = None
|
||||
vorname = None
|
||||
geburtsdatum = None
|
||||
patienten_id = None
|
||||
|
||||
CONFIG_PATH = os.path.join(HOME_DIRECTORY, '.dicom2pacs.conf')
|
||||
|
||||
# Standardkonfigurationswerte
|
||||
DEFAULT_CONFIG = {
|
||||
'server_url': 'http://192.168.188.23:8042/instances',
|
||||
'server_username': 'orthanc',
|
||||
'server_pw': 'Praxis'
|
||||
}
|
||||
|
||||
def save_default_config():
|
||||
"""Speichert die Standardkonfiguration in der Konfigurationsdatei."""
|
||||
try:
|
||||
with open(CONFIG_PATH, 'w', encoding='utf-8') as config_file:
|
||||
for key, value in DEFAULT_CONFIG.items():
|
||||
config_file.write(f'{key}={value}\n')
|
||||
except Exception as e:
|
||||
print(f"Fehler beim Speichern der Standardkonfiguration: {e}")
|
||||
|
||||
def load_config():
|
||||
"""Lädt die Konfiguration aus der Konfigurationsdatei. Erstellt die Datei mit Standardwerten, falls nicht vorhanden."""
|
||||
config = {}
|
||||
try:
|
||||
with open(CONFIG_PATH, 'r', encoding='utf-8') as config_file:
|
||||
for line in config_file:
|
||||
line = line.strip()
|
||||
if not line or line.startswith('#'): # Überspringe leere Zeilen und Kommentare
|
||||
continue
|
||||
if '=' in line:
|
||||
key, value = line.split('=', 1)
|
||||
config[key.strip()] = value.strip()
|
||||
except FileNotFoundError:
|
||||
print("Konfigurationsdatei nicht gefunden. Erstelle eine mit Standardwerten.")
|
||||
save_default_config()
|
||||
config = DEFAULT_CONFIG.copy() # Verwende Kopie der Standardwerte
|
||||
except Exception as e:
|
||||
print(f"Fehler beim Laden der Konfiguration: {e}")
|
||||
print("Verwende Standardwerte.")
|
||||
config = DEFAULT_CONFIG.copy()
|
||||
return config
|
||||
|
||||
config = load_config()
|
||||
server_url = config.get('server_url')
|
||||
server_username = config.get('server_username')
|
||||
server_pw = config.get('server_pw')
|
||||
|
||||
loop = asyncio.new_event_loop() # Initialisiere loop hier
|
||||
|
||||
# Erstelle den Event-Loop für asynchronen Code
|
||||
def start_asyncio_loop():
|
||||
global loop # Verweise auf die globale Variable loop
|
||||
asyncio.set_event_loop(loop)
|
||||
loop.run_forever()
|
||||
|
||||
asyncio_thread = threading.Thread(target=start_asyncio_loop, daemon=True)
|
||||
asyncio_thread.start()
|
||||
|
||||
async def on_folder_selected_coro(folder_path, gui):
|
||||
print("on_folder_selected gestartet")
|
||||
await get_patientfiles(folder_path, gui)
|
||||
upload_files = file_management.get_files_in_folder(TRANSFER_FOLDER)
|
||||
if upload_files == 'no_transfer_folder':
|
||||
results, folder_path = gui.ask_for_more("Bisher keine Bilder ausgewählt.\nAndere Orte durchsuchen?")
|
||||
if results is False:
|
||||
gui.on_app_close()
|
||||
else:
|
||||
if folder_path:
|
||||
await get_patientfiles(folder_path, gui)
|
||||
else:
|
||||
file_paths = upload_files
|
||||
print(file_paths)
|
||||
|
||||
if not file_paths or len(file_paths) == 0:
|
||||
gui.start_animation("Keine Dateien zum Hochladen gefunden")
|
||||
print("Keine Dateien zum Hochladen gefunden")
|
||||
gui.on_app_close()
|
||||
return
|
||||
|
||||
if not server_url:
|
||||
gui.start_animation("FEHLER: Server-URL nicht konfiguriert")
|
||||
print("FEHLER: Server-URL nicht konfiguriert")
|
||||
gui.on_app_close()
|
||||
return
|
||||
|
||||
availability = await network_utils.check_server_availability(server_url)
|
||||
if availability:
|
||||
print("Server ist verfügbar. Dateien werden hochgeladen.")
|
||||
# Hier wird die Funktion upload_single_file asynchron aufgerufen
|
||||
# In dicom_processing.process_dicom_files
|
||||
gui.start_animation("Lade DICOM Dateien zum PACS Server hoch")
|
||||
print(f"Starte Upload von {len(file_paths)} Dateien...")
|
||||
uploaded_count, failed_count = await network_utils.upload_multiple_files(file_paths, server_url, server_username, server_pw, gui.upload_success, gui.upload_progress)
|
||||
gui.stop_animation()
|
||||
|
||||
if failed_count == 0:
|
||||
gui.start_animation("Bilddaten Im PACS erfolgreich eingelesen!")
|
||||
await asyncio.sleep(3)
|
||||
else:
|
||||
gui.start_animation(f"Upload abgeschlossen: {uploaded_count}/{len(file_paths)} Dateien hochgeladen")
|
||||
await asyncio.sleep(5) # Mehr Zeit, damit Benutzer die Meldung lesen kann
|
||||
|
||||
shutil.rmtree(TRANSFER_FOLDER)
|
||||
print(f"Transferordner {TRANSFER_FOLDER} wurde gelöscht.")
|
||||
gui.on_app_close()
|
||||
else:
|
||||
gui.start_animation("PACS SERVER NICHT ERREICHBAR")
|
||||
print("Server ist nicht verfügbar.")
|
||||
print("on_folder_selected abgeschlossen") # Debugging-Ausgabe
|
||||
|
||||
async def get_patientfiles(folder_path, gui):
|
||||
print("Debugging-Ausgabe vor der Suche") # Debugging-Ausgabe
|
||||
gui.hint_label.pack_forget()
|
||||
while True:
|
||||
gui.disable_browse_button()
|
||||
gui.start_animation("Suche nach DICOM Dateien") # Starte die Suchanimation
|
||||
print(folder_path)
|
||||
files_found = file_management.find_dicom_files(folder_path)
|
||||
if files_found == 'non_found':
|
||||
gui.stop_animation()
|
||||
results, folder_path = gui.ask_for_more("In diesem Ordner wurde keine Bilddaten gefunden.\nAndere Orte durchsuchen?")
|
||||
if not results: # Wenn der Benutzer 'Nein' auswählt
|
||||
break
|
||||
else:
|
||||
dicom_files, total_files = files_found
|
||||
print(dicom_files)
|
||||
gui.stop_animation() # Erhalte Dateien und Anzahl
|
||||
print(f"Dicom-Dateien gefunden: {total_files}")
|
||||
gui.start_animation("Kopiere DICOM Dateien in den Transfer Ordner")
|
||||
await file_management.copy_dicom_files(dicom_files, folder_path, TRANSFER_FOLDER, gui.update_progress)
|
||||
gui.stop_animation()
|
||||
print(f"Dicom-Dateien wurden nach {TRANSFER_FOLDER} kopiert.")
|
||||
current_dat_folder = file_management.get_latest_dat_folder(TRANSFER_FOLDER)
|
||||
if not current_dat_folder:
|
||||
gui.stop_animation()
|
||||
gui.start_animation("FEHLER: Transferordner nicht gefunden")
|
||||
print("FEHLER: Transferordner nicht gefunden")
|
||||
break
|
||||
|
||||
gui.start_animation("Patienten ID wird mit Tomedo ID aktualisiert")
|
||||
dicom_processing.update_patient_id_in_transfer_folder(current_dat_folder, patienten_id)
|
||||
print("ID wurde aktualisiert")
|
||||
gui.stop_animation()
|
||||
print("Erstelle Ausgabedatei")
|
||||
acq_date, modality = dicom_processing.extract_modality(current_dat_folder)
|
||||
if acq_date and modality:
|
||||
file_management.write_to_file(acq_date, modality, AUSGABE_DATEI)
|
||||
else:
|
||||
print("Warnung: Konnte Modality-Daten nicht extrahieren")
|
||||
# Verarbeite die kopierten DICOM-Dateien synchron
|
||||
await dicom_processing.process_dicom_files(current_dat_folder, gui, name, vorname, geburtsdatum, server_url, server_username, server_pw)
|
||||
gui.stop_animation()
|
||||
gui.enable_browse_button()
|
||||
file_management.eject_cd_if_volume_path(folder_path)
|
||||
results, new_folder_path = gui.ask_for_more("Sollen mehr Bilddaten für den Patienten eingelesen werden?")
|
||||
print(f"Dialogergebnis: {results}")
|
||||
if results and new_folder_path: # Wenn der Benutzer 'Ja' auswählt
|
||||
gui.reset_progress(total_files)
|
||||
folder_path = new_folder_path
|
||||
if not results: # Wenn der Benutzer 'Nein' auswählt
|
||||
break
|
||||
|
||||
def main():
|
||||
global config, name, vorname, geburtsdatum, patienten_id
|
||||
# Argumente prüfen
|
||||
if len(sys.argv) != 5:
|
||||
print("Bitte genau vier Argumente angeben: Name, Vorname, Geburtsdatum, Patienten_ID")
|
||||
sys.exit(1)
|
||||
|
||||
# Argumente zuweisen
|
||||
_, name, vorname, geburtsdatum, patienten_id = sys.argv
|
||||
|
||||
print(f"Name: {name}, Vorname: {vorname}, Geburtsdatum: {geburtsdatum}, Patienten_ID: {patienten_id}")
|
||||
|
||||
|
||||
config = load_config() # Stellen Sie sicher, dass config geladen wird, bevor GUI initiiert wird
|
||||
gui = GUI(None, TRANSFER_FOLDER, lambda: None, config)
|
||||
|
||||
# Definiere den Callback nach der Erstellung der GUI-Instanz
|
||||
def on_folder_selected_callback(folder):
|
||||
# Plane die Coroutine im asyncio Event-Loop
|
||||
asyncio.run_coroutine_threadsafe(on_folder_selected_coro(folder, gui), loop)
|
||||
|
||||
# Setze den Callback in der GUI-Instanz
|
||||
gui.on_folder_selected = on_folder_selected_callback
|
||||
# Funktion, die überprüft, ob eine CD eingelegt ist, und diese verarbeitet
|
||||
def check_cd_and_select():
|
||||
cd_path = file_management.check_for_cd_at_start()
|
||||
if cd_path:
|
||||
print(f"CD gefunden: {cd_path}")
|
||||
gui.root.after(100, lambda: on_folder_selected_callback(cd_path))
|
||||
else:
|
||||
print("Keine CD gefunden, bitte Ordner manuell auswählen.")
|
||||
|
||||
# Stelle sicher, dass on_app_close als Methode der GUI-Klasse definiert ist
|
||||
gui.root.protocol("WM_DELETE_WINDOW", gui.on_app_close)
|
||||
# Überprüfe, ob eine CD eingelegt ist, bevor die GUI vollständig gestartet wird
|
||||
# Überprüfe die Einstellung und führe ggf. die CD-Überprüfung aus
|
||||
if config.get('check_for_cd', '0') == '1':
|
||||
check_cd_and_select()
|
||||
# Starte die GUI
|
||||
gui.start()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user