33"""NSIHDR to RAW Batch Converter"""
44import logging
55import os
6- import re
76import sys
7+ import tkinter as tk
88from multiprocessing import Pool , cpu_count
99from pprint import pformat
1010from time import time
11-
11+ from tkinter import (E , N , S , StringVar , Toplevel , W , filedialog , messagebox ,
12+ ttk )
13+ import threading
1214import numpy as np
1315from tqdm import tqdm
1416
1517from rawtools import dat
1618from rawtools .convert import scale
19+ from rawtools .gui import nsihdr
1720
1821# Load in NSI SDK
1922currentdir = os .path .dirname (os .path .realpath (__file__ ))
2225sys .path .append (includesdir )
2326from rawtools import nsiefx
2427
28+ # def check_progress(amount):
29+ # logging.info(amount)
30+ # # progress_text.set(str(round(total_slices_processed / args.total_slice_count * 100.0, 1)))
31+ # progress_text.set(str(total_slices_processed))
32+ # progress['value'] = total_slices_processed
33+ # logging.info(f"{progress_text.get()=}")
34+
35+
36+ def update_progress (increment ):
37+ logging .debug (f"{ increment = } " )
38+
39+ def start_progress_thread (event , pbar , root ):
40+ global progress_thread
41+ progress_thread = threading .Thread (target = update_progress , args = (1 ,))
42+ progress_thread .daemon = True
43+ # pbar.start()
44+ progress_thread .start ()
45+ root .after (20 , check_progress_thread (pbar , root ))
46+
47+ def check_progress_thread (pbar , root ):
48+ if progress_thread .is_alive ():
49+ logging .info ("Pbar is alive" )
50+ root .after (20 , check_progress_thread )
51+ else :
52+ logging .info ("Pbar is done" )
53+ pbar .stop ()
54+
55+
2556def process (args , fp , export_path ):
2657 """Converts NSIHDR files to a single .RAW + .DAT
2758
@@ -32,6 +63,9 @@ def process(args, fp, export_path):
3263 export_path (str): filepath to output .RAW file
3364 """
3465 logging .debug (f'{ fp = } ' )
66+ total_slices_processed = 0
67+ progress = None
68+ check_progress = None
3569
3670 with nsiefx .open (fp ) as volume :
3771 v = volume # for shorthand laziness
@@ -52,7 +86,6 @@ def process(args, fp, export_path):
5286 bname = os .path .basename (os .path .splitext (fp )[0 ])
5387 dat_path = os .path .join (dname , f'{ bname } .dat' )
5488
55-
5689 if os .path .exists (export_path ) and args .force == True :
5790 os .remove (export_path )
5891 logging .warning (f"Removed old '{ export_path } '" )
@@ -63,6 +96,7 @@ def process(args, fp, export_path):
6396 dat .write (dat_path , dimensions = (width , height , depth ), thickness = voxel_size )
6497 logging .debug (f"Generated '{ dat_path } '" )
6598
99+ pbar = None
66100 with open (export_path , 'ab' ) as raw_ofp :
67101 if not args .verbose :
68102 pbar = tqdm (total = depth , desc = f"Exporting { bname } " )
@@ -72,8 +106,11 @@ def process(args, fp, export_path):
72106 cross_section = scale (cross_section , data_min , data_max , 0 , 65535 ).astype (np .uint16 )
73107 cross_section .tofile (raw_ofp )
74108
109+ total_slices_processed += 1
110+
75111 if not args .verbose :
76112 pbar .update ()
113+ # logging.debug(f"Processed {total_slices_processed}")
77114 if not args .verbose :
78115 pbar .close ()
79116
@@ -141,9 +178,54 @@ def main(args):
141178 logging .error (err )
142179 raise err
143180 else :
181+
182+ # GUI Implementation
183+ if args .gui :
184+ # Determine the number of slices in advance
185+ args .total_slice_count = 0
186+ for fp in args .files :
187+ with nsiefx .open (fp ) as volume :
188+ args .total_slice_count += volume .num_slices ()
189+
190+ # Initialize progress bar
191+ progress_bar_prompt_title = "Placeholder Progress Bar"
192+ app = args .app
193+ root = app .root
194+ icon_fp = app .icon_fp
195+ progress_bar_prompt = Toplevel (root )
196+ progress_bar_prompt .title (progress_bar_prompt_title )
197+ progress_bar_prompt .iconbitmap (icon_fp )
198+ progress_bar_prompt .resizable (False , False )
199+ progress_bar_prompt_frame = ttk .Frame (progress_bar_prompt , padding = "16 16" )
200+ progress_bar_prompt_frame .grid (column = 0 , row = 0 , sticky = (N , S , E , W ))
201+
202+ progress = ttk .Progressbar (progress_bar_prompt_frame , orient = 'horizontal' , mode = 'indeterminate' , length = 200 , max = args .total_slice_count )
203+ progress .grid (row = 0 , column = 0 , columnspan = 2 , pady = "0 16" , sticky = (E ,W ))
204+ progress_text = tk .StringVar ()
205+ progress_text_label = ttk .Label (progress_bar_prompt_frame , textvariable = progress_text , width = 7 )
206+ progress_text_label .grid (row = 0 , column = 3 , columnspan = 1 , pady = "0 16" , sticky = E , padx = "8 0" )
207+ progress_text .set ('0%' )
208+
209+ def dismiss_progress_prompt ():
210+ progress_bar_prompt .grab_release ()
211+ progress_bar_prompt .destroy ()
212+
213+ # Orient window on screen
214+ nsihdr .center (root , progress_bar_prompt )
215+ # Disable interaction with parent window
216+ progress_bar_prompt .protocol ("WM_DELETE_WINDOW" , dismiss_progress_prompt )
217+ progress_bar_prompt .transient (root )
218+ progress_bar_prompt .wait_visibility ()
219+ progress_bar_prompt .grab_set ()
220+ progress_bar_prompt .wait_window ()
221+ start_progress_thread (None , progress , root )
222+
223+ # CLI Implementation
144224 # For each provided volume...
225+ pbar = None
145226 if not args .verbose :
146227 pbar = tqdm (total = len (args .files ), desc = f"Overall progress" )
228+
147229 for fp in args .files :
148230 logging .debug (f"Processing '{ fp } '" )
149231 dname = os .path .dirname (fp )
0 commit comments