#!/usr/bin/env python # -*- coding: utf-8 -*- from os import path, walk, remove, rename from imghdr import what from subprocess import call from tkinter import Frame, Tk, Button, Label, filedialog, ttk, font, PhotoImage import threading class Application(Frame): def __init__(self, master=None): Frame.__init__(self, master) master.title('Guetzli recursively GUI') master.minsize(width=500, height=140) master.maxsize(width=500, height=140) self.font_general = font.Font(family='Helvetica', size=14) self.font_run = font.Font(family='Helvetica', size=18) self.center(master) self.pack() self.create_widgets() self.top_dir = '' self.TEMP_FILE = 'temp.jpg' self.TYPES = ('jpeg',) self.num_images = 0 def create_widgets(self): # Button select folder self.button_select_folder = Button(self) self.button_select_folder['text'] = 'Choose folder' self.button_select_folder['pady'] = 10 self.button_select_folder['font'] = self.font_general self.button_select_folder['command'] = self.open_folder self.button_select_folder.pack(side='top') # Label path folder self.label_path = Label(self) self.label_path['text'] = '' self.label_path['pady'] = 10 self.label_path['font'] = self.font_general # Button run self.button_run = Button(self) self.button_run['text'] = 'Optimize' self.button_run['font'] = self.font_run self.button_run['pady'] = 10 self.button_run['state'] = 'disabled' self.button_run['command'] = self._start_optimize self.button_run.pack(side='top') # Progressbar self.progress_bar = ttk.Progressbar(self) self.progress_bar['length'] = 500 def center(self, toplevel): toplevel.update_idletasks() w = toplevel.winfo_screenwidth() h = toplevel.winfo_screenheight() size = tuple( int(_) for _ in toplevel.geometry().split('+')[0].split('x') ) x = w/2 - size[0]/2 y = h/2 - size[1]/2 toplevel.geometry('%dx%d+%d+%d' % (size + (x, y))) def open_folder(self): self.button_run['state'] = 'disabled' self.top_dir = filedialog.askdirectory(initialdir='.') self.label_path['text'] = 'Looking for images to optimize... Please, wait' self._start_count_images() def _update_label_num_files(self): self.label_path['text'] = f'{self.num_images} images found' if self.num_images > 0: self.button_run['state'] = 'normal' self.button_run.pack_forget() self.label_path.pack(side='top') self.button_run.pack(side='top') def _start_count_images(self): newthread = threading.Thread(target=self.count_images) newthread.start() def _start_optimize(self): newthread = threading.Thread(target=self.run_guetzli) newthread.start() def count_images(self): num = 0 for dirpath, dirnames, files in walk(self.top_dir): for name in files: url = path.join(dirpath, name) # Check type if what(url) in self.TYPES: num += 1 self.num_images = num self._update_label_num_files() def run_guetzli(self): # Show progress bar self.progress_bar['value'] = 0 self.progress_bar['maximum'] = self.num_images self.progress_bar.pack(side='bottom') self.button_run['state'] = 'disabled' self.button_select_folder['state'] = 'disabled' # Run guetzli for dirpath, dirnames, files in walk(self.top_dir): for name in files: # Info self.label_path['text'] = 'Preparing file' url = path.join(dirpath, name) # Check type if what(url) in self.TYPES: # Info self.label_path['text'] = f'Working... {name}' # Get urls url_out = path.join(self.top_dir, self.TEMP_FILE) # Remove temp image try: remove(url_out) except: pass # Execute guetzli call(['guetzli-osx', url, url_out]) # Check if it is cost effective to replace it size_source = path.getsize(url) size_out = 0 try: size_out = path.getsize(url_out) except: size_out = size_source size_acurate = 100 * size_out / size_source if size_acurate < 100: # Remove source try: remove(url) except: pass # Move temp to source rename(url_out, url) # Increment progress bar self.progress_bar['value'] += 1 # Message finish self.button_select_folder['state'] = 'normal' self.label_path['text'] = 'Finish!' self.progress_bar.pack_forget() root = Tk() app = Application(master=root) app.mainloop()