diff --git a/.gitignore b/.gitignore index 8c9a365..77ff6bf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -/config.enc +config.enc /__pycache__ */__pycache__ /build diff --git a/config/decrypt_config.py b/config/decrypt_config.py new file mode 100644 index 0000000..712deed --- /dev/null +++ b/config/decrypt_config.py @@ -0,0 +1,30 @@ +from cryptography.fernet import Fernet +import json +import os + +class ConfigDecryptor: + def __init__(self, key): + self.key = key + + def decrypt(self): + if not os.path.exists("config.enc"): + raise FileNotFoundError("The encrypted configuration file 'config.enc' does not exist.") + + fernet = Fernet(self.key) + with open("config.enc", "rb") as encrypted_file: + encrypted = encrypted_file.read() + decrypted = fernet.decrypt(encrypted).decode() + return json.loads(decrypted) +# Define your key here +key = b'u4xTBY5Ns4WYdLvqMjEr138mpMmDEhhqTszKCcDy2cI=' # Replace with your actual key + +if __name__ == "__main__": + key = b'u4xTBY5Ns4WYdLvqMjEr138mpMmDEhhqTszKCcDy2cI=' # Replace with your actual key + decryptor = ConfigDecryptor(key) + try: + config = decryptor.decrypt() + print(config) + except FileNotFoundError as e: + print(e) + except Exception as e: + print(f"An error occurred: {e}") diff --git a/config/encrypt_config.py b/config/encrypt_config.py new file mode 100644 index 0000000..934695c --- /dev/null +++ b/config/encrypt_config.py @@ -0,0 +1,28 @@ +from cryptography.fernet import Fernet + +class ConfigEncryptor: + def __init__(self): + self.key = Fernet.generate_key() + + def encrypt_config(self, data): + fernet = Fernet(self.key) + encrypted = fernet.encrypt(data.encode()) + with open("config.enc", "wb") as encrypted_file: + encrypted_file.write(encrypted) + + def get_key(self): + return self.key.decode() + +if __name__ == "__main__": + config_data = """ + { + "url": "https://yourstore.com", + "consumer_key": "ck_yourconsumerkey", + "consumer_secret": "cs_yoursecret", + "username": "yourusername", + "password": "yourpassword" + } + """ + encryptor = ConfigEncryptor() + print(f"Encryption key: {encryptor.get_key()}") + encryptor.encrypt_config(config_data) diff --git a/decrypt_config.py b/decrypt_config.py deleted file mode 100644 index 97e858c..0000000 --- a/decrypt_config.py +++ /dev/null @@ -1,25 +0,0 @@ -from cryptography.fernet import Fernet -import json -import os - -# Hardcoded key (replace with your generated key) -key = b'u4xTBY5Ns4WYdLvqMjEr138mpMmDEhhqTszKCcDy2cI=' - -def decrypt_config(key): - if not os.path.exists("config.enc"): - raise FileNotFoundError("The encrypted configuration file 'config.enc' does not exist.") - - fernet = Fernet(key) - with open("config.enc", "rb") as encrypted_file: - encrypted = encrypted_file.read() - decrypted = fernet.decrypt(encrypted).decode() - return json.loads(decrypted) - -if __name__ == "__main__": - try: - config = decrypt_config(key) - print(config) # Use the decrypted config - except FileNotFoundError as e: - print(e) - except Exception as e: - print(f"An error occurred: {e}") diff --git a/encrypt_config.py b/encrypt_config.py deleted file mode 100644 index 53a1650..0000000 --- a/encrypt_config.py +++ /dev/null @@ -1,22 +0,0 @@ -from cryptography.fernet import Fernet - -# Generate a key and print it -key = Fernet.generate_key() -print(f"Encryption key: {key.decode()}") # Save this key securely - -# Function to encrypt the configuration data -def encrypt_config(data, key): - fernet = Fernet(key) - encrypted = fernet.encrypt(data.encode()) - with open("config.enc", "wb") as encrypted_file: - encrypted_file.write(encrypted) - -if __name__ == "__main__": - config_data = """{ - "url": "https://yourstore.com", - "consumer_key": "ck_yourconsumerkey", - "consumer_secret": "cs_yoursecret", - "username": "yourusername", - "password": "yourpassword" - }""" - encrypt_config(config_data, key) diff --git a/main.py b/main.py index 67f6564..8bc85f6 100644 --- a/main.py +++ b/main.py @@ -1,47 +1,47 @@ import tkinter as tk from tkinter import ttk -from ui.local_processing_tab import create_tab_local -from ui.settings_tab import create_tab_settings from ui.log_window import LogWindow +from ui.local_processing_tab import LocalProcessingTab +from ui.settings_tab import SettingsTab +from config.decrypt_config import ConfigDecryptor, key +class ImageProcessorApp: + def __init__(self, root): + self.root = root + self.root.title("Image Processor") + self.root.geometry("700x400") + + self.tab_parent = ttk.Notebook(self.root) + self.log_window = None -from decrypt_config import decrypt_config, key + self.local_processing_tab = LocalProcessingTab(self.tab_parent, "Local Processing", self.open_log_window) + self.settings_tab = SettingsTab(self.tab_parent, "Settings") -try: - config = decrypt_config(key) - wc_url = config['url'] - wc_consumer_key = config['consumer_key'] - wc_consumer_secret = config['consumer_secret'] - wp_username = config['username'] - wp_password = config['password'] + self.tab_parent.pack(expand=True, fill='both') - # Now use these variables to create your WooCommerce API instance + def open_log_window(self): + if self.log_window is None or not self.log_window.winfo_exists(): + self.log_window = LogWindow(self.root) + else: + self.log_window.lift() -except FileNotFoundError as e: - print(e) - # Handle the missing file case, e.g., by prompting the user to create it -except Exception as e: - print(f"An error occurred: {e}") - # Handle other potential errors -log_window = None - -def open_log_window(): - global log_window - if log_window is None or not log_window.winfo_exists(): - log_window = LogWindow(window) - else: - log_window.lift() + def run(self): + self.root.mainloop() if __name__ == "__main__": - window = tk.Tk() - window.title("Image Processor") - window.geometry("700x400") + try: + decryptor = ConfigDecryptor(key) + config = decryptor.decrypt() + wc_url = config['url'] + wc_consumer_key = config['consumer_key'] + wc_consumer_secret = config['consumer_secret'] + wp_username = config['username'] + wp_password = config['password'] + except FileNotFoundError as e: + print(f"File not found: {e}") + except Exception as e: + print(f"An error occurred: {e}") - tab_parent = ttk.Notebook(window) - - create_tab_local(tab_parent, "Local Processing", open_log_window) - create_tab_settings(tab_parent, "Settings") - - tab_parent.pack(expand=True, fill='both') - - window.mainloop() + root = tk.Tk() + app = ImageProcessorApp(root) + app.run() diff --git a/readme.md b/readme.md index c288775..12ef16f 100644 --- a/readme.md +++ b/readme.md @@ -1,59 +1,48 @@ -Image Processing Application - -This application is a graphical user interface (GUI) tool designed for processing images either from a local directory or from a WooCommerce product catalog. It supports resizing images, renaming them based on customizable templates, and uploading them to a WooCommerce site. -Features - - Resize images to specified dimensions. - Rename images using customizable templates with placeholders for various attributes. - Upload processed images to WooCommerce. - Process images from a local directory or WooCommerce products. +Image Processing Application Documentation +Overview +This Image Processing Application provides a GUI for selecting directories containing image files, setting canvas sizes, adding suffixes to filenames, and processing images. It logs all found images, displays how many images were found, and provides previews of the first image before and after processing. Prerequisites - Python 3.10 or later - - Required Python Packages - - You can install the required packages using pip: + Python 3.10+: Ensure Python is installed on your machine. + Tkinter: This should come with Python, but ensure it's installed. + Pillow: For image handling. Install via pip: sh - pip install -r requirements.txt + pip install pillow - ImageMagick + Additional Libraries: Ensure you have any additional libraries your utility functions (file_operations, image_processing) depend on. - ImageMagick is required for image processing. You can download and install it from ImageMagick's official website. +Application Setup - WooCommerce API Credentials - - You need to have WooCommerce API credentials to interact with the WooCommerce site. These include the URL, consumer key, consumer secret, username, and password. - -Setting Up - - Clone the Repository - - Clone this repository to your local machine: + Install Required Packages: sh -git clone https://github.com/your-username/image-processing-app.git -cd image-processing-app +pip install pillow -Install Dependencies +Directory Structure: +Ensure your project directory looks something like this: -Install the required Python packages: +arduino -sh + image-processor/ + ├── ui/ + │ └── local_processing_tab.py + ├── utils/ + │ ├── file_operations.py + │ └── image_processing.py + └── main.py - pip install -r requirements.txt - - Configure WooCommerce API Credentials - - Run the application and navigate to the Settings tab to enter and save your WooCommerce API credentials. + Script Files: + main.py: The main entry point of the application containing the script provided above. + file_operations.py: Contains browse_directory and other directory-related utility functions. + image_processing.py: Contains set_canvas_size and other image processing utility functions. Running the Application -Run the main application script: +To run the application, navigate to the project directory and execute: sh @@ -61,75 +50,23 @@ python main.py Creating an Executable -To create a standalone executable from this project, you can use PyInstaller. Follow the steps below: +To create an executable for this application, you can use pyinstaller. Follow the steps below: - Install PyInstaller - - You can install PyInstaller using pip: + Install PyInstaller: sh pip install pyinstaller -Generate the Executable - -Navigate to the project directory and run PyInstaller: +Create the Executable: +Navigate to the directory containing your main.py script and run: sh - pyinstaller --onefile --noconsole main.py +pyinstaller --onefile --windowed main.py - Find the Executable + --onefile: Packages everything into a single executable file. + --windowed: Ensures the console window does not appear when running the GUI application. - After PyInstaller finishes, you can find the executable in the dist directory. - -File Structure - - main.py: Entry point for the application. - api/: Contains the woocommerce.py file for interacting with WooCommerce API. - utils/: Contains utility scripts for file operations and image processing. - ui/: Contains the UI components for the application. - config.enc: Encrypted file storing WooCommerce API credentials. - -Requirements - -Create a requirements.txt file with the following content: - -tk -Pillow -requests -woocommerce -cryptography -pyinstaller - -Usage - - Select Source Type - Choose between local directory and WooCommerce product. - - Set Canvas Size - Specify the dimensions to resize the images. - - Filename Template - Define a template for renaming the images using placeholders like {name}, {sku}, {width}, {height}. - - Start Processing - Click the "Start Processing" button to process the images. The log will appear in a separate window. - -Notes - - Ensure ImageMagick is correctly installed and added to your system's PATH. - The application uses the cryptography library to encrypt WooCommerce API credentials for security. - -Support - -If you encounter any issues or have questions, feel free to open an issue in the repository or contact the maintainer. -License - -This project is licensed under the MIT License. -Acknowledgements - - ImageMagick - WooCommerce - -With this information, you should be able to set up, run, and create an executable for the Image Processing Application. Enjoy processing your images with ease! \ No newline at end of file +Locate the Executable: +After running the command, you will find the executable in the dist folder within your project directory. \ No newline at end of file diff --git a/ui/local_processing_tab.py b/ui/local_processing_tab.py index 771a87c..0c41112 100644 --- a/ui/local_processing_tab.py +++ b/ui/local_processing_tab.py @@ -1,7 +1,6 @@ import tkinter as tk from tkinter import ttk from tkinter.scrolledtext import ScrolledText -from tkinter import filedialog from PIL import Image, ImageTk import tempfile import os @@ -9,196 +8,161 @@ from utils.file_operations import browse_directory, process_directory_with_loggi from utils.image_processing import set_canvas_size, resize_image from api.woocommerce import process_product_images, process_all_products +class LocalProcessingTab: + def __init__(self, tab_parent, text, log): + self.log = log + self.tab = ttk.Frame(tab_parent) + tab_parent.add(self.tab, text=text) + + self.log_window = None + self.create_log_window() -canvas_width = 900 -canvas_height = 900 + self.canvas_width = 900 + self.canvas_height = 900 + self.source_type = tk.StringVar(value="local") + self.checkbox_var = tk.BooleanVar(value=False) -def create_tab_local(tab_parent, text, log): - tab = ttk.Frame(tab_parent) - tab_parent.add(tab, text=text) + self.setup_ui() + self.update_source_fields() - log_window = None - - def create_log_window(): - nonlocal log_window - if log_window and tk.Toplevel.winfo_exists(log_window): + def create_log_window(self): + if self.log_window and tk.Toplevel.winfo_exists(self.log_window): return - log_window = tk.Toplevel() - log_window.title("Processing Log") - log_text = ScrolledText(log_window, state='disabled', wrap='word', height=20, width=80) - log_text.pack(expand=True, fill='both') + self.log_window = tk.Toplevel() + self.log_window.title("Processing Log") + self.log_text = ScrolledText(self.log_window, state='disabled', wrap='word', height=20, width=80) + self.log_text.pack(expand=True, fill='both') - def log_message(message): - log_text.config(state='normal') - log_text.insert(tk.END, message + "\n") - log_text.see(tk.END) - log_text.config(state='disabled') - log_text.update_idletasks() # Ensure the GUI updates - return log_message + def log_message(self, message): + self.log_text.config(state='normal') + self.log_text.insert(tk.END, message + "\n") + self.log_text.see(tk.END) + self.log_text.config(state='disabled') + self.log_text.update_idletasks() - # Source selection section - source_label = tk.Label(tab, text="Source Type:") - source_label.grid(row=0, column=0, padx=5, pady=5, sticky='w') - - source_type = tk.StringVar(value="local") - source_dropdown = ttk.Combobox(tab, textvariable=source_type, values=["local", "product", "all_products"], state="readonly") - source_dropdown.grid(row=1, column=0, padx=5, pady=5, sticky='w') - source_dropdown.bind("<>", lambda e: update_source_fields()) + def setup_ui(self): - # Local Directory selection section - def update_directory(): - directory = browse_directory() - if directory: - # Show only the last directory name with ../ - truncated_directory = f"../{os.path.basename(directory)}" - button_browse.config(text=truncated_directory) - update_previews() + # Source selection section + self.source_label = tk.Label(self.tab, text="Source Type:") + self.source_label.grid(row=0, column=0, padx=5, pady=5, sticky='w') + + self.source_type = tk.StringVar(value="local") + self.source_dropdown = ttk.Combobox(self.tab, textvariable=self.source_type, values=["local", "product", "all_products"], state="readonly") + self.source_dropdown.grid(row=1, column=0, padx=5, pady=5, sticky='w') + self.source_dropdown.bind("<>", lambda e: self.update_source_fields()) - button_browse = tk.Button(tab, text="Browse", command=update_directory) - button_browse.grid(row=2, column=0, padx=5, pady=5, sticky='nw') - - # WooCommerce Product ID section - product_id_label = tk.Label(tab, text="Product ID:") - product_id_label.grid(row=2, column=0, padx=5, pady=5, sticky='w') - - product_id_entry = tk.Entry(tab) - product_id_entry.grid(row=3, column=0, padx=5, pady=5, sticky='w') - # SKU section - additional_name_label = tk.Label(tab, text="Add suffix:") - additional_name_label.grid(row=3, column=1, padx=5, pady=5, sticky='w') - - additional_name_entry = tk.Entry(tab) - additional_name_entry.grid(row=3, column=2, padx=5, pady=5, sticky='w') + self.browse_button = ttk.Button(self.tab, text="Browse", command=self.browse_directory_command) + self.browse_button.grid(row=2, column=0, padx=5, pady=5, sticky='w') + + # WooCommerce Product ID section + self.product_id_label = tk.Label(self.tab, text="Product ID:") + self.product_id_label.grid(row=2, column=0, padx=5, pady=5, sticky='w') + + self.product_id_entry = tk.Entry(self.tab) + self.product_id_entry.grid(row=3, column=0, padx=5, pady=5, sticky='w') + + # SKU section + self.additional_name_label = tk.Label(self.tab, text="Add suffix:") + self.additional_name_label.grid(row=3, column=1, padx=5, pady=5, sticky='w') + + self.additional_name_entry = tk.Entry(self.tab) + self.additional_name_entry.grid(row=3, column=2, padx=5, pady=5, sticky='w') - # Template section - template_label = tk.Label(tab, text="Filename Template:") - template_label.grid(row=3, column=1, padx=5, pady=5, sticky='w') - - template_entry = tk.Entry(tab) - template_entry.insert(0, "{slug}_{sku}_{width}x{height}") - template_entry.grid(row=3, column=2, padx=5, columnspan=2, pady=5, sticky='w') + # Template section + self.template_label = tk.Label(self.tab, text="Filename Template:") + self.template_label.grid(row=3, column=1, padx=5, pady=5, sticky='w') + + self.template_entry = tk.Entry(self.tab) + self.template_entry.insert(0, "{slug}_{sku}_{width}x{height}") + self.template_entry.grid(row=3, column=2, padx=5, columnspan=2, pady=5, sticky='w') - - def update_source_fields(): - print(source_type.get()) - if source_type.get() == "local": - button_browse.grid() - product_id_label.grid_remove() - product_id_entry.grid_remove() - additional_name_label.grid() - additional_name_entry.grid() - template_entry.grid_remove() - template_label.grid_remove() - elif source_type.get() == "product": - button_browse.grid_remove() - product_id_label.grid() - product_id_entry.grid() - additional_name_label.grid_remove() - additional_name_entry.grid_remove() + # Canvas size section + width_label = tk.Label(self.tab, text="Canvas Width:") + width_label.grid(row=0, column=1, padx=5, pady=5, sticky='w') + + self.width_entry = tk.Entry(self.tab) + self.width_entry.insert(0, "900") + self.width_entry.grid(row=0, column=2, padx=5, pady=5, sticky='w') + + self.height_label = tk.Label(self.tab, text="Canvas Height:") + self.height_label.grid(row=1, column=1, padx=5, pady=5, sticky='w') + + self.height_entry = tk.Entry(self.tab) + self.height_entry.insert(0, "900") + self.height_entry.grid(row=1, column=2, padx=5, pady=5, sticky='w') + self.button_set_size = tk.Button(self.tab, text="Save Size", command=self.apply_canvas_size) + self.button_set_size.grid(row=2, column=1, columnspan=2, padx=5, pady=5, sticky='w') + + # Checkbox for deleting images + self.checkbox_var = tk.BooleanVar() + self.checkbox = tk.Checkbutton(self.tab, text="Delete image when done", variable=self.checkbox_var) + self.checkbox.grid(row=0, column=3, columnspan=2, padx=5, pady=5, sticky='w') + + self.button_start = tk.Button(self.tab, text="Start Processing", command=self.start_processing) + self.button_start.grid(row=1, column=3, columnspan=2, padx=5, pady=5, sticky='w') + + # Image previews + self.before_label = tk.Label(self.tab, text="Before:") + self.before_label.grid(row=5, column=0, padx=5, pady=5, sticky='w') + self.before_image_label = tk.Label(self.tab) + self.before_image_label.grid(row=6, column=0, padx=5, pady=5, sticky='w') + + self.after_label = tk.Label(self.tab, text="After:") + self.after_label.grid(row=5, column=1, padx=5, pady=5, sticky='w') + self.after_image_label = tk.Label(self.tab) + self.after_image_label.grid(row=6, column=1, padx=5, pady=5, sticky='w') + + + def update_source_fields(self): + source = self.source_type.get() + if source == "local": + self.browse_button.grid() + self.product_id_label.grid_remove() + self.product_id_entry.grid_remove() + self.update_previews() else: - button_browse.grid_remove() - product_id_label.grid_remove() - product_id_entry.grid_remove() - product_id_label.grid() - product_id_entry.grid() - additional_name_label.grid_remove() - additional_name_entry.grid_remove() + self.browse_button.grid_remove() + self.product_id_label.grid() + self.product_id_entry.grid() - update_source_fields() # Initial call to set correct fields - - # Canvas size section - width_label = tk.Label(tab, text="Canvas Width:") - width_label.grid(row=0, column=1, padx=5, pady=5, sticky='w') - - width_entry = tk.Entry(tab) - width_entry.insert(0, "900") - width_entry.grid(row=0, column=2, padx=5, pady=5, sticky='w') - - height_label = tk.Label(tab, text="Canvas Height:") - height_label.grid(row=1, column=1, padx=5, pady=5, sticky='w') - - height_entry = tk.Entry(tab) - height_entry.insert(0, "900") - height_entry.grid(row=1, column=2, padx=5, pady=5, sticky='w') - - def apply_canvas_size(): - global canvas_width, canvas_height - canvas_width = int(width_entry.get()) - canvas_height = int(height_entry.get()) - set_canvas_size(canvas_width, canvas_height) - update_previews() - - button_set_size = tk.Button(tab, text="Save Size", command=apply_canvas_size) - button_set_size.grid(row=2, column=1, columnspan=2, padx=5, pady=5, sticky='w') - - - - - # Checkbox for deleting images - checkbox_var = tk.BooleanVar() - checkbox = tk.Checkbutton(tab, text="Delete image when done", variable=checkbox_var) - checkbox.grid(row=0, column=3, columnspan=2, padx=5, pady=5, sticky='w') - - # Start Processing button - def start_processing(): - log_message = None # create_log_window() - if source_type.get() == "local": - process_directory_with_logging(additional_name_entry.get(), checkbox_var.get(), log_message, update_previews) - elif source_type.get() == "product": - product_id = product_id_entry.get() - process_product_images(product_id, template_entry.get(), canvas_width, canvas_height) - else: - process_all_products(template_entry.get(), canvas_width, canvas_height) - - button_start = tk.Button(tab, text="Start Processing", command=start_processing) - button_start.grid(row=1, column=3, columnspan=2, padx=5, pady=5, sticky='w') - - # Image previews - before_label = tk.Label(tab, text="Before:") - before_label.grid(row=5, column=0, columnspan=2, padx=5, pady=5, sticky='w') - before_image_label = tk.Label(tab) - before_image_label.grid(row=6, columnspan=2, column=0, padx=5, pady=5, sticky='w') - - after_label = tk.Label(tab, text="After:") - after_label.grid(row=5, columnspan=2, column=2, padx=5, pady=5, sticky='w') - after_image_label = tk.Label(tab) - after_image_label.grid(row=6, columnspan=2, column=2, padx=5, pady=5, sticky='w') - - def update_previews(before_path=None, after_path=None): + def update_previews(self, before_path=None, after_path=None): if before_path and after_path: - before_img = Image.open(before_path) - before_img.thumbnail((150, 150)) - before_photo = ImageTk.PhotoImage(before_img) - before_image_label.config(image=before_photo) - before_image_label.image = before_photo - - after_img = Image.open(after_path) - after_img.thumbnail((150, 150)) - after_photo = ImageTk.PhotoImage(after_img) - after_image_label.config(image=after_photo) - after_image_label.image = after_photo + self.set_image_preview(before_path, self.before_image_label) + self.set_image_preview(after_path, self.after_image_label) else: first_image_path = get_first_image_path() if first_image_path: - with tempfile.NamedTemporaryFile(suffix='.jpg', delete=False) as temp_file: - output_path = temp_file.name - resize_image(first_image_path, output_path, additional_name_entry.get()) - before_img = Image.open(first_image_path) - before_img.thumbnail((150, 150)) - before_photo = ImageTk.PhotoImage(before_img) - before_image_label.config(image=before_photo) - before_image_label.image = before_photo + self.set_image_preview(first_image_path, self.before_image_label) + self.after_image_label.config(image='') - after_img = Image.open(output_path) - after_img.thumbnail((150, 150)) - after_photo = ImageTk.PhotoImage(after_img) - after_image_label.config(image=after_photo) - after_image_label.image = after_photo + def set_image_preview(self, image_path, label): + img = Image.open(image_path) + img.thumbnail((150, 150)) + photo = ImageTk.PhotoImage(img) + label.config(image=photo) + label.image = photo - # Configure column weights to allow the log_text to expand - tab.columnconfigure(0, weight=1) - tab.columnconfigure(1, weight=1) - tab.columnconfigure(2, weight=1) - tab.columnconfigure(3, weight=1) - tab.rowconfigure(6, weight=1) \ No newline at end of file + def browse_directory_command(self): + directory = browse_directory() + if directory: + self.browse_button.config(text=directory) + self.update_previews() + + + def apply_canvas_size(self): + self.canvas_width = int(self.width_entry.get()) + self.canvas_height = int(self.height_entry.get()) + set_canvas_size(self.canvas_width, self.canvas_height) + self.update_previews() + + def start_processing(self): + source = self.source_type.get() + print(self.checkbox_var.get()) + if source == "local": + process_directory_with_logging(self.browse_button.cget("text"), self.additional_name_entry.get(), self.checkbox_var.get(), self.log_message, self.update_previews) + elif source == "product": + process_product_images(self.product_id_entry.get(), self.canvas_width, self.canvas_height, self.log_message) + elif source == "all_products": + process_all_products(self.canvas_width, self.canvas_height, self.log_message) + self.update_previews() diff --git a/ui/log_window.py b/ui/log_window.py index 745990b..91dd43a 100644 --- a/ui/log_window.py +++ b/ui/log_window.py @@ -1,16 +1,17 @@ -import tkinter as tk -from tkinter.scrolledtext import ScrolledText +from tkinter import Toplevel, Text -class LogWindow(tk.Toplevel): - def __init__(self, parent): - super().__init__(parent) - self.title("Processing Log") - self.geometry("600x400") - self.log_text = ScrolledText(self, state='disabled', wrap='word') - self.log_text.pack(expand=True, fill='both') +class LogWindow(Toplevel): + def __init__(self, master=None, **kwargs): + super().__init__(master, **kwargs) + self.title("Log Window") + self.geometry("500x300") + self.text = Text(self) + self.text.pack(expand=True, fill='both') + self.protocol("WM_DELETE_WINDOW", self.hide) def log(self, message): - self.log_text.config(state='normal') - self.log_text.insert(tk.END, message + "\n") - self.log_text.see(tk.END) - self.log_text.config(state='disabled') + self.text.insert('end', message + '\n') + self.text.see('end') + + def hide(self): + self.withdraw() diff --git a/ui/settings_tab.py b/ui/settings_tab.py index 939bad1..51191fe 100644 --- a/ui/settings_tab.py +++ b/ui/settings_tab.py @@ -2,57 +2,58 @@ import tkinter as tk from tkinter import ttk from api.woocommerce import save_credentials, load_credentials -def create_tab_settings(tab_parent, text): - tab = ttk.Frame(tab_parent) - tab_parent.add(tab, text=text) +class SettingsTab: + def __init__(self, tab_parent, text): + self.tab = ttk.Frame(tab_parent) + tab_parent.add(self.tab, text=text) - credentials = load_credentials() - url_value = credentials['url'] if credentials else '' - consumer_key_value = credentials['consumer_key'] if credentials else '' - consumer_secret_value = credentials['consumer_secret'] if credentials else '' - username_value = credentials['username'] if credentials else '' - password_value = credentials['password'] if credentials else '' - - url_label = tk.Label(tab, text="WooCommerce URL:") - url_label.pack(pady=5) - - url_entry = tk.Entry(tab) - url_entry.insert(0, url_value) - url_entry.pack() - - consumer_key_label = tk.Label(tab, text="Consumer Key:") - consumer_key_label.pack(pady=5) - - consumer_key_entry = tk.Entry(tab) - consumer_key_entry.insert(0, consumer_key_value) - consumer_key_entry.pack() - - consumer_secret_label = tk.Label(tab, text="Consumer Secret:") - consumer_secret_label.pack(pady=5) - - consumer_secret_entry = tk.Entry(tab, show="*") - consumer_secret_entry.insert(0, consumer_secret_value) - consumer_secret_entry.pack() - - username_label = tk.Label(tab, text="Username:") - username_label.pack(pady=5) - - username_entry = tk.Entry(tab) - username_entry.insert(0, username_value) - username_entry.pack() - - password_label = tk.Label(tab, text="Password:") - password_label.pack(pady=5) - - password_entry = tk.Entry(tab, show="*") - password_entry.insert(0, password_value) - password_entry.pack() - - button_save = tk.Button(tab, text="Save Credentials", command=lambda: save_credentials( - url_entry.get(), - consumer_key_entry.get(), - consumer_secret_entry.get(), - username_entry.get(), - password_entry.get() - )) - button_save.pack(pady=5) + self.credentials = load_credentials() + self.setup_ui() + + def setup_ui(self): + url_label = tk.Label(self.tab, text="WooCommerce URL:") + url_label.pack(pady=5) + + self.url_entry = tk.Entry(self.tab) + self.url_entry.insert(0, self.credentials.get('url', '')) + self.url_entry.pack(pady=5) + + consumer_key_label = tk.Label(self.tab, text="Consumer Key:") + consumer_key_label.pack(pady=5) + + self.consumer_key_entry = tk.Entry(self.tab) + self.consumer_key_entry.insert(0, self.credentials.get('consumer_key', '')) + self.consumer_key_entry.pack(pady=5) + + consumer_secret_label = tk.Label(self.tab, text="Consumer Secret:") + consumer_secret_label.pack(pady=5) + + self.consumer_secret_entry = tk.Entry(self.tab, show="*") + self.consumer_secret_entry.insert(0, self.credentials.get('consumer_secret', '')) + self.consumer_secret_entry.pack(pady=5) + + username_label = tk.Label(self.tab, text="Username:") + username_label.pack(pady=5) + + self.username_entry = tk.Entry(self.tab) + self.username_entry.insert(0, self.credentials.get('username', '')) + self.username_entry.pack(pady=5) + + password_label = tk.Label(self.tab, text="Password:") + password_label.pack(pady=5) + + self.password_entry = tk.Entry(self.tab, show="*") + self.password_entry.insert(0, self.credentials.get('password', '')) + self.password_entry.pack(pady=5) + + save_button = tk.Button(self.tab, text="Save Credentials", command=self.save_credentials) + save_button.pack(pady=5) + + def save_credentials(self): + save_credentials( + self.url_entry.get(), + self.consumer_key_entry.get(), + self.consumer_secret_entry.get(), + self.username_entry.get(), + self.password_entry.get() + ) diff --git a/utils/file_operations.py b/utils/file_operations.py index ba3e455..a379a9c 100644 --- a/utils/file_operations.py +++ b/utils/file_operations.py @@ -23,7 +23,8 @@ def get_first_image_path(): return os.path.join(root, file) return None -def process_directory_with_logging(additional_name, is_checked, log, update_previews): +def process_directory_with_logging(selected_directory: str, additional_name: str = '', is_checked: bool = False, log = None, update_previews = None): + print(f"is_checked: {is_checked}") if not selected_directory: messagebox.showwarning("No Directory", "Please select a directory.") return @@ -55,13 +56,10 @@ def process_directory_with_logging(additional_name, is_checked, log, update_prev output_path = os.path.join(output_directory, os.path.relpath(file_path, selected_directory)) os.makedirs(os.path.dirname(output_path), exist_ok=True) resize_image(file_path, output_path, additional_name) - - # with tempfile.NamedTemporaryFile(suffix='.jpg', delete=False) as temp_file: - # temp_output_path = temp_file.name - # resize_image(file_path, temp_output_path, additional_name) - # update_previews(file_path, temp_output_path) - + if os.path.exists(file_path) and is_checked: + if log: + log(f"removing: {file_path}") os.remove(file_path) if log: log(f"Processed: {file_path}") diff --git a/utils/image_processing.py b/utils/image_processing.py index a38a1d2..66852c2 100644 --- a/utils/image_processing.py +++ b/utils/image_processing.py @@ -1,10 +1,6 @@ +import os from wand.image import Image from wand.color import Color -import os - - -canvas_width = 900 -canvas_height = 900 def set_canvas_size(width, height): global canvas_width, canvas_height @@ -12,6 +8,11 @@ def set_canvas_size(width, height): canvas_height = int(height) def resize_image(image_path, output_path, additional_name): + + # Normalize the paths to ensure consistency + image_path = os.path.normpath(image_path) + output_path = os.path.normpath(output_path) + with Image(filename=image_path) as img: img.transform(resize=f'{canvas_width}x{canvas_height}>') @@ -20,9 +21,14 @@ def resize_image(image_path, output_path, additional_name): with Image(width=canvas_width, height=canvas_height, background=Color('transparent')) as canvas: canvas.composite(img, left=x_offset, top=y_offset) + # Create a new filename new_filename = os.path.splitext(os.path.basename(output_path))[0] if additional_name: new_filename += " - " + additional_name.strip() new_filename += os.path.splitext(output_path)[1] - output_path = os.path.join(os.path.dirname(output_path), new_filename) - canvas.save(filename=output_path) + # Construct the final output path + final_output_path = os.path.join(os.path.dirname(output_path), new_filename) + # Save the image to the final output path + canvas.save(filename=final_output_path) + print(f"Saved to: {final_output_path}") +set_canvas_size(900, 900) \ No newline at end of file