From b55a361374c34c8755ebd1831ce13b19f31e0f16 Mon Sep 17 00:00:00 2001 From: Furen Date: Wed, 11 Dec 2024 06:40:17 +0800 Subject: [PATCH] first commit --- .gitignore | 2 + src/pacs.py | 275 +++++++++++++++++++++++++++++++++++++++++++++++ src/pituitary.py | 53 +++++++++ src/settings.py | 25 +++++ 4 files changed, 355 insertions(+) create mode 100644 src/pacs.py create mode 100644 src/pituitary.py create mode 100644 src/settings.py diff --git a/.gitignore b/.gitignore index ab3e8ce..f5763dd 100644 --- a/.gitignore +++ b/.gitignore @@ -162,3 +162,5 @@ cython_debug/ # option (not recommended) you can uncomment the following to ignore the entire idea folder. #.idea/ +# xfr +*.xlsx diff --git a/src/pacs.py b/src/pacs.py new file mode 100644 index 0000000..e29107d --- /dev/null +++ b/src/pacs.py @@ -0,0 +1,275 @@ + +import datetime +import glob +import logging +import os +import shutil +import time + +from pywinauto import Desktop, actionlogger, mouse, keyboard +from pywinauto.application import Application +from pywinauto.timings import Timings + +from settings import * + +def mouse_click(ws): + r = ws.rectangle() + coords = (r.left + r.right)//2, (r.top + r.bottom)//2 + mouse.click(coords=coords) + +def login(id=USER_ID, pw=PASSWORD): + # Timings.fast() + # Timings.window_find_timeout = 10 + + patterns = [ + # '另存新檔.*' + '.* - Microsoft​ Edge$', + '.*日期:.*', + ] + + for p in patterns: + + while True: + quit = False + try: + w = Desktop(backend="uia").window(title_re=p) + logging.warning(p + str(w)) + w.close() + except: + quit = True + if quit: + break + + app = Application(backend="uia").start(r'C:\Users\xfr\Desktop\PACS.exe') + + w = Desktop(backend="uia").window(title_re='.* - Microsoft​ Edge$') + w.wait('ready') + + # time.sleep(9) + + app = Application(backend="uia").connect(title_re='.* - Microsoft​ Edge$') + # app.wait_cpu_usage_lower(threshold=50) + + # dlg_spec = Desktop(backend="uia").window(title_re='.* - Microsoft​ Edge$') + window = app.window(title_re='.* - Microsoft​ Edge$') + # dlg_spec = app.top_window() + + window['使用者帳號: \xa0Edit'].set_text(id) + window['使用者密碼: \xa0Edit'].set_text(pw) + + # r = window['登入Static'].rectangle() + # coords = (r.left + r.right)//2, (r.top + r.bottom)//2 + # mouse.click(coords=coords) + mouse_click(window['登入Static']) + time.sleep(9) + + return app, window + +def dump(pane): + print(pane) + print(dir(pane)) + print(pane.element_info) + print(pane.get_properties()) + print(pane.print_control_identifiers()) + # print(len(pane.children())) + + + + +def save_study(chartno, outdir): + + while True: + logging.warning('connecting '+chartno) + try: + app = Application(backend="uia").connect(title_re='^%s.*'%chartno) + break + except: + time.sleep(1) + + logging.warning(str(app)) + window = app.top_window() + # window.maximize() + + index = 0 + while True: + TFlowPanel = window.child_window(class_name='TFlowPanel', found_index=index) + # dump(TFlowPanel) + if TFlowPanel.control_count(): + break + index += 1 + + series = sorted(TFlowPanel.children(), key=lambda x: x.rectangle().left) + c = series[0] + c.set_focus() + mouse_click(c) + keyboard.send_keys('^i') + + for c in series: + + logging.warning(str(c.element_info)) + c.set_focus() + mouse_click(c) + + mouse_click(window['註釋/標籤']) + TToolBar = window.child_window(class_name='TToolBar', found_index=2) + mouse_click(TToolBar.Button5) + time.sleep(1) + export_to_file = window['輸出至檔案'] + export_to_file.wait('ready') + export = export_to_file.wrapper_object() + export.click() + + TDicomTagListForm = window['DICOM 標籤清單Dialog'] + + dlg_save = Desktop(backend="uia").window(title='另存新檔') + NEdit = dlg_save['檔案名稱(N):Edit'] + NEdit.wait('ready') + edit = NEdit.wrapper_object() + pahtname = os.path.join(outdir, edit.get_value()) + for p in glob.glob(pahtname + '*'): + os.remove(p) + edit.set_text(pahtname) + dlg_save['存檔(S)Button'].wrapper_object().click() + + TDicomTagListForm.close() + # break + + + keyboard.send_keys('^s') + keyboard.send_keys('{DOWN}') + keyboard.send_keys('{DOWN}') + + # time.sleep(9) + + # logging.warning(str(datetime.datetime.now())) + TFormSaveBitmap = window['選項'] + # TFormSaveBitmap.dump_tree(filename='z-%s-TFormSaveBitmap.txt'%chartno) + TFormSaveBitmap.Edit5.set_text(outdir) + TFormSaveBitmap.Button2.click() + + logging.warning('button clicked') + time.sleep(1) + logging.warning('saving started') + saving = window.child_window(title_re='^另存新檔.*') + logging.warning('saving exists') + saving.wait_not("exists", timeout=999) + logging.warning('saving not exists') + + c.set_focus() + mouse_click(c) + keyboard.send_keys('^q') + + # while True: + # try: + # if not window.exists(): + # break + # except : + # break + + # logging.warning(str((datetime.datetime.now()))) + # c.set_focus() + # mouse_click(c) + # keyboard.send_keys('^q') + # time.sleep(9) + + +def save_patient(chartno, outdir, query = "CT,MR"): + + app = Application(backend="uia").connect(title_re='.* - Microsoft​ Edge$') + logging.warning(str(app)) + # window = app.window(title_re='.* - Microsoft​ Edge$') + window=app.top_window() + window.maximize() + + if query: + + window['病歷號:Edit'].set_text(chartno) + window['儀器種類:Edit'].set_text(query) + + r = window['ComboBox關閉'].rectangle() + coords = (r.left + r.right)//2, (r.top + r.bottom)//2 + mouse.click(coords=coords) + keyboard.send_keys('{UP}') + keyboard.send_keys('{UP}') + keyboard.send_keys('{ENTER}') + + window['Button'].click() + time.sleep(9) + + ListItem = window['開啟影像'].parent() + # print(ListItem.texts()) + + ListView = ListItem.parent() + + shutil.rmtree(outdir, ignore_errors=True) + os.makedirs(outdir, exist_ok=True) + + items =[] + + for item in ListView.items(): + if item.texts()[0] != '開啟影像': + continue + items.append(item) + logging.debug(str(item.rectangle())) + + for i, item in enumerate(items): + # if i < 7: + # continue + bottom = False + logging.debug(str(items[i].rectangle())) + + try: + if items[i+1].rectangle().top < 1: + bottom = True + except: + bottom = True + + if bottom: + item.set_focus() + keyboard.send_keys('{DOWN}') + + # r = item.rectangle() + # coords = (r.left + r.right)//2, (r.top + r.bottom)//2 + # mouse.scroll(coords=coords) + + time.sleep(1) + logging.debug(str(item.rectangle())) + + mouse_click(item) + + save_study(chartno, outdir) + logging.warning(chartno+" completed "+query) + return 0 + + # exit() + + +actionlogger.enable() + + +def main(): + # FORMAT = '%(asctime)s %(clientip)-15s %(user)-8s %(message)s' + + FORMAT = '%(asctime)s %(message)s' + + logging.basicConfig(filename=__file__.replace('.py','.%s.log'%str(datetime.datetime.now()).replace(':','')), + format=FORMAT) + + # logger = logging.getLogger('pywinauto') + # logger.handlers[0] = logging.FileHandler(__file__.replace('.py','.log')) + # logging.basicConfig(format=FORMAT) + # formatter = logging.Formatter(FORMAT) + # logger.handlers[0].setFormatter(formatter) + + app, window = login() + save_patient('5344141', r'T:\0\5344141', query="CT,MR") + # save_patient('5344141', r'T:\0\5344141', query="CT") + # save_patient('2380784', r'T:\3\2380784', query=False) + # save_study('2380784', outdir=r'T:\0\2380784') + + + +# step2() + +if __name__ == '__main__': + main() diff --git a/src/pituitary.py b/src/pituitary.py new file mode 100644 index 0000000..62b96be --- /dev/null +++ b/src/pituitary.py @@ -0,0 +1,53 @@ + +from pathlib import Path + +import datetime +import logging + +import pandas as pd + +import pacs + +def get_pacs(series, outdir, max_patients=10): + app, window = pacs.login() + num_patients = 0 + for index, row in series.items(): + if isinstance(row, float): + row = int(row) + chartno = str(int(row)).zfill(7) + + complete_file = Path(f'{outdir}\\{chartno}.complete') + if complete_file.is_file(): + logging.warning('skip '+chartno) + continue + + logging.warning('saving '+chartno) + pacs.save_patient(chartno, f'{outdir}\\{chartno}', query="CT,MR") + + complete_file.touch() + num_patients += 1 + if num_patients >= max_patients: + break + + return num_patients + + +def main(): + FORMAT = '%(asctime)s %(message)s' + logging.basicConfig(filename=__file__.replace('.py','.%s.log'%str(datetime.datetime.now()).replace(':','')), + format=FORMAT) + + # df = pd.read_excel('pituitary-op.xlsx') + # series = df['PatChartNo'].drop_duplicates().iloc[-1000:].iloc[::-1] + # outdir = r'T:\pituitary-op' + + df = pd.read_excel('pituitary-srs.xlsx', sheet_name='NFA Data (n=178)', header=1) + series = df[~df['Patient ID'].isna()]['Patient ID'].drop_duplicates() + outdir = r'T:\pituitary-srs' + + get_pacs(series, outdir) + return 0 + + +if __name__ == '__main__': + main() diff --git a/src/settings.py b/src/settings.py new file mode 100644 index 0000000..69211e5 --- /dev/null +++ b/src/settings.py @@ -0,0 +1,25 @@ +import os +# Build paths inside the project like this: os.path.join(BASE_DIR, ...) +PROJECT_APP_PATH = os.path.dirname(os.path.abspath(__file__)) +PROJECT_APP = os.path.basename(PROJECT_APP_PATH) +BASE_DIR = os.path.dirname(PROJECT_APP_PATH) + +DEBUG = False + +USER_ID = '123456' +PASSWORD = '123456' + +################## +# LOCAL SETTINGS # +################## + +# Allow any settings to be defined in local_settings.py which should be +# ignored in your version control system allowing for settings to be +# defined per machine. + +# from local_settings import * + +try: + from local_settings import * +except ImportError: + pass