Refactored code to be more maintainable

This commit is contained in:
2024-07-13 17:58:27 +02:00
parent 1183327e7e
commit 901daf6c06
12 changed files with 355 additions and 437 deletions

2
.gitignore vendored
View File

@@ -1,4 +1,4 @@
/config.enc config.enc
/__pycache__ /__pycache__
*/__pycache__ */__pycache__
/build /build

30
config/decrypt_config.py Normal file
View File

@@ -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}")

28
config/encrypt_config.py Normal file
View File

@@ -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)

View File

@@ -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}")

View File

@@ -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)

68
main.py
View File

@@ -1,47 +1,47 @@
import tkinter as tk import tkinter as tk
from tkinter import ttk 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.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")
from decrypt_config import decrypt_config, key self.tab_parent = ttk.Notebook(self.root)
self.log_window = None
try: self.local_processing_tab = LocalProcessingTab(self.tab_parent, "Local Processing", self.open_log_window)
config = decrypt_config(key) self.settings_tab = SettingsTab(self.tab_parent, "Settings")
self.tab_parent.pack(expand=True, fill='both')
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()
def run(self):
self.root.mainloop()
if __name__ == "__main__":
try:
decryptor = ConfigDecryptor(key)
config = decryptor.decrypt()
wc_url = config['url'] wc_url = config['url']
wc_consumer_key = config['consumer_key'] wc_consumer_key = config['consumer_key']
wc_consumer_secret = config['consumer_secret'] wc_consumer_secret = config['consumer_secret']
wp_username = config['username'] wp_username = config['username']
wp_password = config['password'] wp_password = config['password']
except FileNotFoundError as e:
# Now use these variables to create your WooCommerce API instance print(f"File not found: {e}")
except Exception as e:
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}") print(f"An error occurred: {e}")
# Handle other potential errors
log_window = None
def open_log_window(): root = tk.Tk()
global log_window app = ImageProcessorApp(root)
if log_window is None or not log_window.winfo_exists(): app.run()
log_window = LogWindow(window)
else:
log_window.lift()
if __name__ == "__main__":
window = tk.Tk()
window.title("Image Processor")
window.geometry("700x400")
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()

133
readme.md
View File

@@ -1,59 +1,48 @@
Image Processing Application Image Processing Application Documentation
Overview
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.
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 Prerequisites
Python 3.10 or later Python 3.10+: Ensure Python is installed on your machine.
Tkinter: This should come with Python, but ensure it's installed.
Required Python Packages Pillow: For image handling. Install via pip:
You can install the required packages using pip:
sh 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 Install Required Packages:
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:
sh sh
git clone https://github.com/your-username/image-processing-app.git pip install pillow
cd image-processing-app
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 Script Files:
main.py: The main entry point of the application containing the script provided above.
Configure WooCommerce API Credentials 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.
Run the application and navigate to the Settings tab to enter and save your WooCommerce API credentials.
Running the Application Running the Application
Run the main application script: To run the application, navigate to the project directory and execute:
sh sh
@@ -61,75 +50,23 @@ python main.py
Creating an Executable 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 Install PyInstaller:
You can install PyInstaller using pip:
sh sh
pip install pyinstaller pip install pyinstaller
Generate the Executable Create the Executable:
Navigate to the directory containing your main.py script and run:
Navigate to the project directory and run PyInstaller:
sh 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. Locate the Executable:
After running the command, you will find the executable in the dist folder within your project 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!

View File

@@ -1,7 +1,6 @@
import tkinter as tk import tkinter as tk
from tkinter import ttk from tkinter import ttk
from tkinter.scrolledtext import ScrolledText from tkinter.scrolledtext import ScrolledText
from tkinter import filedialog
from PIL import Image, ImageTk from PIL import Image, ImageTk
import tempfile import tempfile
import os 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 utils.image_processing import set_canvas_size, resize_image
from api.woocommerce import process_product_images, process_all_products 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)
canvas_width = 900 self.log_window = None
canvas_height = 900 self.create_log_window()
self.canvas_width = 900
self.canvas_height = 900
def create_tab_local(tab_parent, text, log): self.source_type = tk.StringVar(value="local")
tab = ttk.Frame(tab_parent) self.checkbox_var = tk.BooleanVar(value=False)
tab_parent.add(tab, text=text)
log_window = None self.setup_ui()
self.update_source_fields()
def create_log_window(): def create_log_window(self):
nonlocal log_window if self.log_window and tk.Toplevel.winfo_exists(self.log_window):
if log_window and tk.Toplevel.winfo_exists(log_window):
return return
log_window = tk.Toplevel() self.log_window = tk.Toplevel()
log_window.title("Processing Log") self.log_window.title("Processing Log")
log_text = ScrolledText(log_window, state='disabled', wrap='word', height=20, width=80) self.log_text = ScrolledText(self.log_window, state='disabled', wrap='word', height=20, width=80)
log_text.pack(expand=True, fill='both') self.log_text.pack(expand=True, fill='both')
def log_message(message): def log_message(self, message):
log_text.config(state='normal') self.log_text.config(state='normal')
log_text.insert(tk.END, message + "\n") self.log_text.insert(tk.END, message + "\n")
log_text.see(tk.END) self.log_text.see(tk.END)
log_text.config(state='disabled') self.log_text.config(state='disabled')
log_text.update_idletasks() # Ensure the GUI updates self.log_text.update_idletasks()
return log_message
def setup_ui(self):
# Source selection section # Source selection section
source_label = tk.Label(tab, text="Source Type:") self.source_label = tk.Label(self.tab, text="Source Type:")
source_label.grid(row=0, column=0, padx=5, pady=5, sticky='w') self.source_label.grid(row=0, column=0, padx=5, pady=5, sticky='w')
source_type = tk.StringVar(value="local") self.source_type = tk.StringVar(value="local")
source_dropdown = ttk.Combobox(tab, textvariable=source_type, values=["local", "product", "all_products"], state="readonly") self.source_dropdown = ttk.Combobox(self.tab, textvariable=self.source_type, values=["local", "product", "all_products"], state="readonly")
source_dropdown.grid(row=1, column=0, padx=5, pady=5, sticky='w') self.source_dropdown.grid(row=1, column=0, padx=5, pady=5, sticky='w')
source_dropdown.bind("<<ComboboxSelected>>", lambda e: update_source_fields()) self.source_dropdown.bind("<<ComboboxSelected>>", lambda e: self.update_source_fields())
# Local Directory selection section self.browse_button = ttk.Button(self.tab, text="Browse", command=self.browse_directory_command)
def update_directory(): self.browse_button.grid(row=2, column=0, padx=5, pady=5, sticky='w')
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()
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 # WooCommerce Product ID section
product_id_label = tk.Label(tab, text="Product ID:") self.product_id_label = tk.Label(self.tab, text="Product ID:")
product_id_label.grid(row=2, column=0, padx=5, pady=5, sticky='w') 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')
product_id_entry = tk.Entry(tab)
product_id_entry.grid(row=3, column=0, padx=5, pady=5, sticky='w')
# SKU section # SKU section
additional_name_label = tk.Label(tab, text="Add suffix:") self.additional_name_label = tk.Label(self.tab, text="Add suffix:")
additional_name_label.grid(row=3, column=1, padx=5, pady=5, sticky='w') self.additional_name_label.grid(row=3, column=1, padx=5, pady=5, sticky='w')
additional_name_entry = tk.Entry(tab) self.additional_name_entry = tk.Entry(self.tab)
additional_name_entry.grid(row=3, column=2, padx=5, pady=5, sticky='w') self.additional_name_entry.grid(row=3, column=2, padx=5, pady=5, sticky='w')
# Template section # Template section
template_label = tk.Label(tab, text="Filename Template:") self.template_label = tk.Label(self.tab, text="Filename Template:")
template_label.grid(row=3, column=1, padx=5, pady=5, sticky='w') self.template_label.grid(row=3, column=1, padx=5, pady=5, sticky='w')
template_entry = tk.Entry(tab) self.template_entry = tk.Entry(self.tab)
template_entry.insert(0, "{slug}_{sku}_{width}x{height}") self.template_entry.insert(0, "{slug}_{sku}_{width}x{height}")
template_entry.grid(row=3, column=2, padx=5, columnspan=2, pady=5, sticky='w') 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()
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()
update_source_fields() # Initial call to set correct fields
# Canvas size section # Canvas size section
width_label = tk.Label(tab, text="Canvas Width:") width_label = tk.Label(self.tab, text="Canvas Width:")
width_label.grid(row=0, column=1, padx=5, pady=5, sticky='w') width_label.grid(row=0, column=1, padx=5, pady=5, sticky='w')
width_entry = tk.Entry(tab) self.width_entry = tk.Entry(self.tab)
width_entry.insert(0, "900") self.width_entry.insert(0, "900")
width_entry.grid(row=0, column=2, padx=5, pady=5, sticky='w') self.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')
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 # Checkbox for deleting images
checkbox_var = tk.BooleanVar() self.checkbox_var = tk.BooleanVar()
checkbox = tk.Checkbutton(tab, text="Delete image when done", variable=checkbox_var) self.checkbox = tk.Checkbutton(self.tab, text="Delete image when done", variable=self.checkbox_var)
checkbox.grid(row=0, column=3, columnspan=2, padx=5, pady=5, sticky='w') self.checkbox.grid(row=0, column=3, columnspan=2, padx=5, pady=5, sticky='w')
# Start Processing button self.button_start = tk.Button(self.tab, text="Start Processing", command=self.start_processing)
def start_processing(): self.button_start.grid(row=1, column=3, columnspan=2, padx=5, pady=5, sticky='w')
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 # Image previews
before_label = tk.Label(tab, text="Before:") self.before_label = tk.Label(self.tab, text="Before:")
before_label.grid(row=5, column=0, columnspan=2, padx=5, pady=5, sticky='w') self.before_label.grid(row=5, column=0, padx=5, pady=5, sticky='w')
before_image_label = tk.Label(tab) self.before_image_label = tk.Label(self.tab)
before_image_label.grid(row=6, columnspan=2, column=0, padx=5, pady=5, sticky='w') self.before_image_label.grid(row=6, column=0, padx=5, pady=5, sticky='w')
after_label = tk.Label(tab, text="After:") self.after_label = tk.Label(self.tab, text="After:")
after_label.grid(row=5, columnspan=2, column=2, padx=5, pady=5, sticky='w') self.after_label.grid(row=5, column=1, padx=5, pady=5, sticky='w')
after_image_label = tk.Label(tab) self.after_image_label = tk.Label(self.tab)
after_image_label.grid(row=6, columnspan=2, column=2, padx=5, pady=5, sticky='w') self.after_image_label.grid(row=6, column=1, padx=5, pady=5, sticky='w')
def update_previews(before_path=None, after_path=None):
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:
self.browse_button.grid_remove()
self.product_id_label.grid()
self.product_id_entry.grid()
def update_previews(self, before_path=None, after_path=None):
if before_path and after_path: if before_path and after_path:
before_img = Image.open(before_path) self.set_image_preview(before_path, self.before_image_label)
before_img.thumbnail((150, 150)) self.set_image_preview(after_path, self.after_image_label)
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
else: else:
first_image_path = get_first_image_path() first_image_path = get_first_image_path()
if first_image_path: if first_image_path:
with tempfile.NamedTemporaryFile(suffix='.jpg', delete=False) as temp_file: self.set_image_preview(first_image_path, self.before_image_label)
output_path = temp_file.name self.after_image_label.config(image='')
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
after_img = Image.open(output_path) def set_image_preview(self, image_path, label):
after_img.thumbnail((150, 150)) img = Image.open(image_path)
after_photo = ImageTk.PhotoImage(after_img) img.thumbnail((150, 150))
after_image_label.config(image=after_photo) photo = ImageTk.PhotoImage(img)
after_image_label.image = after_photo label.config(image=photo)
label.image = photo
# Configure column weights to allow the log_text to expand def browse_directory_command(self):
tab.columnconfigure(0, weight=1) directory = browse_directory()
tab.columnconfigure(1, weight=1) if directory:
tab.columnconfigure(2, weight=1) self.browse_button.config(text=directory)
tab.columnconfigure(3, weight=1) self.update_previews()
tab.rowconfigure(6, weight=1)
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()

View File

@@ -1,16 +1,17 @@
import tkinter as tk from tkinter import Toplevel, Text
from tkinter.scrolledtext import ScrolledText
class LogWindow(tk.Toplevel): class LogWindow(Toplevel):
def __init__(self, parent): def __init__(self, master=None, **kwargs):
super().__init__(parent) super().__init__(master, **kwargs)
self.title("Processing Log") self.title("Log Window")
self.geometry("600x400") self.geometry("500x300")
self.log_text = ScrolledText(self, state='disabled', wrap='word') self.text = Text(self)
self.log_text.pack(expand=True, fill='both') self.text.pack(expand=True, fill='both')
self.protocol("WM_DELETE_WINDOW", self.hide)
def log(self, message): def log(self, message):
self.log_text.config(state='normal') self.text.insert('end', message + '\n')
self.log_text.insert(tk.END, message + "\n") self.text.see('end')
self.log_text.see(tk.END)
self.log_text.config(state='disabled') def hide(self):
self.withdraw()

View File

@@ -2,57 +2,58 @@ import tkinter as tk
from tkinter import ttk from tkinter import ttk
from api.woocommerce import save_credentials, load_credentials from api.woocommerce import save_credentials, load_credentials
def create_tab_settings(tab_parent, text): class SettingsTab:
tab = ttk.Frame(tab_parent) def __init__(self, tab_parent, text):
tab_parent.add(tab, text=text) self.tab = ttk.Frame(tab_parent)
tab_parent.add(self.tab, text=text)
credentials = load_credentials() self.credentials = load_credentials()
url_value = credentials['url'] if credentials else '' self.setup_ui()
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:") def setup_ui(self):
url_label = tk.Label(self.tab, text="WooCommerce URL:")
url_label.pack(pady=5) url_label.pack(pady=5)
url_entry = tk.Entry(tab) self.url_entry = tk.Entry(self.tab)
url_entry.insert(0, url_value) self.url_entry.insert(0, self.credentials.get('url', ''))
url_entry.pack() self.url_entry.pack(pady=5)
consumer_key_label = tk.Label(tab, text="Consumer Key:") consumer_key_label = tk.Label(self.tab, text="Consumer Key:")
consumer_key_label.pack(pady=5) consumer_key_label.pack(pady=5)
consumer_key_entry = tk.Entry(tab) self.consumer_key_entry = tk.Entry(self.tab)
consumer_key_entry.insert(0, consumer_key_value) self.consumer_key_entry.insert(0, self.credentials.get('consumer_key', ''))
consumer_key_entry.pack() self.consumer_key_entry.pack(pady=5)
consumer_secret_label = tk.Label(tab, text="Consumer Secret:") consumer_secret_label = tk.Label(self.tab, text="Consumer Secret:")
consumer_secret_label.pack(pady=5) consumer_secret_label.pack(pady=5)
consumer_secret_entry = tk.Entry(tab, show="*") self.consumer_secret_entry = tk.Entry(self.tab, show="*")
consumer_secret_entry.insert(0, consumer_secret_value) self.consumer_secret_entry.insert(0, self.credentials.get('consumer_secret', ''))
consumer_secret_entry.pack() self.consumer_secret_entry.pack(pady=5)
username_label = tk.Label(tab, text="Username:") username_label = tk.Label(self.tab, text="Username:")
username_label.pack(pady=5) username_label.pack(pady=5)
username_entry = tk.Entry(tab) self.username_entry = tk.Entry(self.tab)
username_entry.insert(0, username_value) self.username_entry.insert(0, self.credentials.get('username', ''))
username_entry.pack() self.username_entry.pack(pady=5)
password_label = tk.Label(tab, text="Password:") password_label = tk.Label(self.tab, text="Password:")
password_label.pack(pady=5) password_label.pack(pady=5)
password_entry = tk.Entry(tab, show="*") self.password_entry = tk.Entry(self.tab, show="*")
password_entry.insert(0, password_value) self.password_entry.insert(0, self.credentials.get('password', ''))
password_entry.pack() self.password_entry.pack(pady=5)
button_save = tk.Button(tab, text="Save Credentials", command=lambda: save_credentials( save_button = tk.Button(self.tab, text="Save Credentials", command=self.save_credentials)
url_entry.get(), save_button.pack(pady=5)
consumer_key_entry.get(),
consumer_secret_entry.get(), def save_credentials(self):
username_entry.get(), save_credentials(
password_entry.get() self.url_entry.get(),
)) self.consumer_key_entry.get(),
button_save.pack(pady=5) self.consumer_secret_entry.get(),
self.username_entry.get(),
self.password_entry.get()
)

View File

@@ -23,7 +23,8 @@ def get_first_image_path():
return os.path.join(root, file) return os.path.join(root, file)
return None 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: if not selected_directory:
messagebox.showwarning("No Directory", "Please select a directory.") messagebox.showwarning("No Directory", "Please select a directory.")
return return
@@ -56,12 +57,9 @@ def process_directory_with_logging(additional_name, is_checked, log, update_prev
os.makedirs(os.path.dirname(output_path), exist_ok=True) os.makedirs(os.path.dirname(output_path), exist_ok=True)
resize_image(file_path, output_path, additional_name) 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 os.path.exists(file_path) and is_checked:
if log:
log(f"removing: {file_path}")
os.remove(file_path) os.remove(file_path)
if log: if log:
log(f"Processed: {file_path}") log(f"Processed: {file_path}")

View File

@@ -1,10 +1,6 @@
import os
from wand.image import Image from wand.image import Image
from wand.color import Color from wand.color import Color
import os
canvas_width = 900
canvas_height = 900
def set_canvas_size(width, height): def set_canvas_size(width, height):
global canvas_width, canvas_height global canvas_width, canvas_height
@@ -12,6 +8,11 @@ def set_canvas_size(width, height):
canvas_height = int(height) canvas_height = int(height)
def resize_image(image_path, output_path, additional_name): 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: with Image(filename=image_path) as img:
img.transform(resize=f'{canvas_width}x{canvas_height}>') 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: with Image(width=canvas_width, height=canvas_height, background=Color('transparent')) as canvas:
canvas.composite(img, left=x_offset, top=y_offset) canvas.composite(img, left=x_offset, top=y_offset)
# Create a new filename
new_filename = os.path.splitext(os.path.basename(output_path))[0] new_filename = os.path.splitext(os.path.basename(output_path))[0]
if additional_name: if additional_name:
new_filename += " - " + additional_name.strip() new_filename += " - " + additional_name.strip()
new_filename += os.path.splitext(output_path)[1] new_filename += os.path.splitext(output_path)[1]
output_path = os.path.join(os.path.dirname(output_path), new_filename) # Construct the final output path
canvas.save(filename=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)