From 589a35691663de6a0925081804dcec488ce73fcd Mon Sep 17 00:00:00 2001 From: MechTechnology <40597106+MechTechnology@users.noreply.github.com> Date: Sat, 3 Jul 2021 01:24:35 +0200 Subject: [PATCH] Adds Batch mode and QoL Changes - Adds Batch mode - Async thread for work - Better Progress bar interactions - Less freezing in the GUI, i hope - Accurate duration (removed the 2 digit formatting) --- SmartStitchGUI.py | 81 +++++++++++++++++++++++++++++++---------------- 1 file changed, 54 insertions(+), 27 deletions(-) diff --git a/SmartStitchGUI.py b/SmartStitchGUI.py index 3cd05d1..b88d746 100644 --- a/SmartStitchGUI.py +++ b/SmartStitchGUI.py @@ -7,6 +7,7 @@ import os import time import pickle +import threading class SmartStitch(Tk): def __init__(self, *args, **kwargs): @@ -16,10 +17,12 @@ def __init__(self, *args, **kwargs): # Global Variables self.input_folder = StringVar() self.output_folder = StringVar() + self.batch_mode = IntVar() self.split_height = StringVar(value="5000") self.senstivity = StringVar(value="90") self.status = StringVar(value="Idle") self.output_type = StringVar(value=".jpg") + self.num_of_inputs = 1 self.progress = "" self.actionbutton = "" @@ -41,7 +44,7 @@ def geticon(self, relative_path): # return os.path.join(base_path, relative_path) def SetupWindow(self): # Sets up Title and Logo - self.title('SmartStitch by MechTechnology [1.6]') + self.title('SmartStitch by MechTechnology [1.7]') self.iconbitmap(default=self.geticon("SmartStitchLogo.ico")) # Sets Window Size, centers it on Launch and Prevents Resize. @@ -76,7 +79,7 @@ def SaveCurrentSettings(self, *args): settings_pickle = "settings.pickle" with open(settings_pickle, 'wb') as settings_handle: - pickle.dump(settings, settings_handle) + pickle.dump(settings, settings_handle) def SetupBrowseFrame(self): # Browse Button and Input and Output Field @@ -87,11 +90,13 @@ def SetupBrowseFrame(self): browse_button = ttk.Button(browse_frame, text = 'Browse', command=self.BrowseToCommand) output_label = ttk.Label(browse_frame, text = 'Output Path') output_field = ttk.Entry(browse_frame, textvariable=self.output_folder) + batch_checkbox = ttk.Checkbutton(browse_frame, variable=self.batch_mode, text = 'Batch Mode [Input folder contains multiple chapter folders]') browse_label.grid(row = 0,column = 0, sticky="new") browse_field.grid(row = 1, column = 0, pady=(2,0), sticky="new") browse_button.grid(row = 1,column = 1, padx=(15, 0), sticky="ne") output_label.grid(row = 2, column = 0, sticky="new") output_field.grid(row = 3, column = 0, columnspan=2, pady=(2,0), sticky="new") + batch_checkbox.grid(row = 4, column = 0, columnspan=2, pady=(2,0), sticky="new") browse_frame.columnconfigure(0, weight=1) return browse_frame @@ -156,7 +161,7 @@ def SetupStatusFrame(self): def SetupActionFrame(self): action_frame = Frame(self) self.progress = ttk.Progressbar(action_frame) - self.actionbutton = ttk.Button(action_frame, text = 'Start Process', command=self.RunStitchProcess) + self.actionbutton = ttk.Button(action_frame, text = 'Start Process', command=self.RunStitchProcessAsync) self.progress.grid(row = 0, column = 0, columnspan = 2, pady=(2,0), sticky="new") self.actionbutton.grid(row = 0, column = 2, padx=(15, 0), sticky="new") action_frame.columnconfigure(0, weight=1) @@ -164,12 +169,19 @@ def SetupActionFrame(self): action_frame.columnconfigure(2, weight=1) return action_frame - def LoadImages(self): + def SetBatchFolders(self): + batch_input_folder = self.input_folder.get() + batch_output_folder = self.output_folder.get() + input_folders = [os.path.abspath(os.path.join(batch_input_folder, name)) for name in os.listdir(batch_input_folder) if os.path.isdir(os.path.join(batch_input_folder, name))] + output_folders = [os.path.abspath(os.path.join(batch_output_folder, name + " [Stitched]" )) for name in os.listdir(batch_input_folder) if os.path.isdir(os.path.join(batch_input_folder, name))] + return input_folders, output_folders + + def LoadImages(self, foldername): # Loads all image files in a given folder into a list of pillow image objects images = [] - if (self.input_folder.get() == ""): + if (foldername == ""): return images - folder = os.path.abspath(str(self.input_folder.get())) + folder = os.path.abspath(str(foldername)) files = natsorted(os.listdir(folder)) if len(files) == 0: return images @@ -244,17 +256,18 @@ def SplitVertical(self, combined_img): images.append(split_image) return images - def SaveData(self, data): + def SaveData(self, data, foldername): # Saves the given images/date in the output folder! - new_folder = str(self.output_folder.get()) + new_folder = str(foldername) if not os.path.exists(new_folder): os.makedirs(new_folder) imageIndex = 1 outputformat = self.output_type.get() + progress_value = self.progress['value'] for image in data: image.save(new_folder + '/' + str(f'{imageIndex:02}') + outputformat, quality=100) imageIndex += 1 - progress_value = 40 + (60 * imageIndex/len(data)) + progress_value += ((60 * 1/len(data)) / self.num_of_inputs) self.progress['value'] = progress_value Tk.update_idletasks(self) return @@ -275,28 +288,42 @@ def RunStitchProcess(self): self.status.set("Working - Loading Image Files!") self.progress['value'] = 0 Tk.update_idletasks(self) - images = self.LoadImages() - if len(images) == 0: - self.status.set("Idle - No Image Files Found!") - self.actionbutton['state'] = "normal" - return - self.status.set("Working - Combining Image Files!") - self.progress['value'] = 10 - Tk.update_idletasks(self) - combined_image = self.CombineVertically(images) - self.status.set("Working - Slicing Combined Image into Finalized Images!") - self.progress['value'] = 20 - Tk.update_idletasks(self) - final_images = self.SplitVertical(combined_image) - self.status.set("Working - Saving Finalized Images!") - self.progress['value'] = 40 - Tk.update_idletasks(self) - self.SaveData(final_images) + input_folders = [] + output_folders = [] + if self.batch_mode.get() == 0: + input_folders.append(self.input_folder.get()) + output_folders.append(self.output_folder.get()) + else: + input_folders , output_folders = self.SetBatchFolders() + self.num_of_inputs = len(input_folders) + for folder in input_folders: + images = self.LoadImages(folder) + if len(images) == 0: + self.status.set("Idle - No Image Files Found!") + self.actionbutton['state'] = "normal" + return + self.status.set("Working - Combining Image Files!") + self.progress['value'] += (10 / self.num_of_inputs) + Tk.update_idletasks(self) + combined_image = self.CombineVertically(images) + self.status.set("Working - Slicing Combined Image into Finalized Images!") + self.progress['value'] += (10 / self.num_of_inputs) + Tk.update_idletasks(self) + final_images = self.SplitVertical(combined_image) + self.status.set("Working - Saving Finalized Images!") + self.progress['value'] += (20 / self.num_of_inputs) + Tk.update_idletasks(self) + outfolder = output_folders[input_folders.index(folder)] + self.SaveData(final_images, outfolder) end = time.time() delta = end - start - self.status.set("Idle - Files successfully stitched in " + str(f'{delta:.2}') + "sec!") + self.status.set("Idle - Files successfully stitched in " + str(delta) + "sec!") self.progress['value'] = 100 self.actionbutton['state'] = "normal" + def RunStitchProcessAsync(self): + workthread = threading.Thread(target=self.RunStitchProcess) + workthread.start() + SmartStitch().mainloop() \ No newline at end of file