Image resizer tool

 This image resizer tool is highly powered by advanced GUI and can work efficiently.

source code :

import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from PIL import Image
import os
from pathlib import Path
import math
import shutil
import threading

class ImageResizer:
    def __init__(self, root):
        self.root = root
        self.root.title("πŸš€ Futuristic Image Resizer v3.0 - ERROR FREE")
        self.root.geometry("1200x800")
        self.root.configure(bg='#0a0a0a')
       
        self.colors = {
            'bg': '#0a0a0a', 'panel': '#1a1a2e', 'accent': '#00d4ff',
            'accent2': '#ff00ff', 'text': '#ffffff', 'glow': '#1a1a2e'
        }
       
        self.images = []
        self.setup_ui()
       
    def setup_ui(self):
        # Title
        title = tk.Label(self.root, text="🌌 NEON IMAGE RESIZER v3.0",
                        font=('Arial', 24, 'bold'), bg=self.colors['bg'],
                        fg=self.colors['accent'])
        title.pack(pady=20)
       
        # Main frame
        main_frame = tk.Frame(self.root, bg=self.colors['bg'])
        main_frame.pack(fill='both', expand=True, padx=20, pady=10)
       
        # Left panel - Images
        left_panel = tk.LabelFrame(main_frame, text="πŸ“ Image Queue",
                                  font=('Arial', 12, 'bold'), bg=self.colors['panel'],
                                  fg=self.colors['accent'])
        left_panel.pack(side='left', fill='both', expand=True, padx=(0,10))
       
        # Add button
        btn_frame = tk.Frame(left_panel, bg=self.colors['panel'])
        btn_frame.pack(fill='x', padx=20, pady=20)
       
        tk.Button(btn_frame, text="➕ ADD IMAGES", command=self.add_images,
                 bg=self.colors['accent'], fg='black', font=('Arial', 12, 'bold'),
                 relief='flat', pady=10).pack(fill='x')
       
        # Listbox
        list_frame = tk.Frame(left_panel, bg=self.colors['panel'])
        list_frame.pack(fill='both', expand=True, padx=20, pady=10)
       
        scrollbar = tk.Scrollbar(list_frame)
        scrollbar.pack(side='right', fill='y')
       
        self.image_listbox = tk.Listbox(list_frame, yscrollcommand=scrollbar.set,
                                       bg=self.colors['panel'], fg=self.colors['text'],
                                       selectbackground=self.colors['accent'],
                                       font=('Arial', 10))
        self.image_listbox.pack(side='left', fill='both', expand=True)
        scrollbar.config(command=self.image_listbox.yview)
        self.image_listbox.bind('<Delete>', self.remove_selected)
       
        # Right panel - Settings
        right_panel = tk.LabelFrame(main_frame, text="⚙️ Settings",
                                   font=('Arial', 12, 'bold'), bg=self.colors['panel'],
                                   fg=self.colors['accent2'])
        right_panel.pack(side='right', fill='both', expand=True)
       
        # Size input
        tk.Label(right_panel, text="Target Size:", font=('Arial', 12, 'bold'),
                bg=self.colors['panel'], fg=self.colors['text']).pack(anchor='w', padx=20, pady=(20,5))
       
        size_frame = tk.Frame(right_panel, bg=self.colors['panel'])
        size_frame.pack(fill='x', padx=20, pady=5)
       
        self.size_var = tk.StringVar(value="500")
        tk.Entry(size_frame, textvariable=self.size_var, font=('Arial', 12),
                bg='#2a2a3e', fg=self.colors['accent'], relief='flat').pack(side='left', fill='x', expand=True, padx=(0,10))
       
        self.unit_var = tk.StringVar(value="KB")
        ttk.Combobox(size_frame, textvariable=self.unit_var, values=["KB", "MB"],
                    state="readonly", font=('Arial', 10), width=8).pack(side='right')
       
        # Quality
        tk.Label(right_panel, text="Quality:", font=('Arial', 12, 'bold'),
                bg=self.colors['panel'], fg=self.colors['text']).pack(anchor='w', padx=20, pady=(20,5))
       
        self.quality_var = tk.IntVar(value=85)
        tk.Scale(right_panel, from_=50, to=95, orient='horizontal', variable=self.quality_var,
                bg=self.colors['panel'], fg=self.colors['accent'],
                highlightthickness=0, troughcolor='#2a2a3e').pack(fill='x', padx=20, pady=5)
       
        # Process button
        self.process_btn = tk.Button(right_panel, text="πŸš€ RESIZE ALL",
                                   command=self.start_resize, state='disabled',
                                   bg=self.colors['accent2'], fg='black',
                                   font=('Arial', 14, 'bold'), relief='flat', pady=15)
        self.process_btn.pack(fill='x', padx=20, pady=30)
       
        # Progress
        self.progress = ttk.Progressbar(right_panel, mode='determinate')
        self.progress.pack(fill='x', padx=20, pady=10)
       
        self.status_label = tk.Label(right_panel, text="Add images to start",
                                   font=('Arial', 11), bg=self.colors['panel'],
                                   fg=self.colors['text'])
        self.status_label.pack(pady=10)
       
    def add_images(self):
        files = filedialog.askopenfilenames(
            title="Select Images",
            filetypes=[("Images", "*.jpg *.jpeg *.png *.bmp *.tiff *.webp *.gif")]
        )
        self.load_images(files)
       
    def load_images(self, file_paths):
        for path in file_paths:
            if path not in [img['path'] for img in self.images]:
                if os.path.exists(path):
                    try:
                        size = os.path.getsize(path)
                        self.images.append({
                            'path': path,
                            'name': os.path.basename(path),
                            'size': size
                        })
                    except:
                        pass
        self.update_listbox()
       
    def update_listbox(self):
        self.image_listbox.delete(0, tk.END)
        for img in self.images:
            kb = img['size'] / 1024
            size_str = f"{img['name']} ({kb:.1f} KB)"
            self.image_listbox.insert(tk.END, size_str)
           
        count = len(self.images)
        self.process_btn.config(state='normal' if count > 0 else 'disabled')
        self.status_label.config(text=f"Loaded {count} images ✓")
       
    def remove_selected(self, event=None):
        selection = list(self.image_listbox.curselection())
        for i in reversed(selection):
            del self.images[i]
        self.update_listbox()
       
    def parse_size(self):
        try:
            num = float(self.size_var.get())
            unit = self.unit_var.get()
            if unit == "KB": return int(num * 1024)
            return int(num * 1024 * 1024)  # MB
        except:
            return 500 * 1024  # 500KB default
   
    def resize_image(self, img_path, target_size, quality=85):
        try:
            with Image.open(img_path) as img:
                # Get original dimensions
                orig_w, orig_h = img.size
               
                # Try different scales to hit target size
                for scale in [1.0, 0.8, 0.6, 0.5, 0.4, 0.3, 0.2]:
                    new_w = max(100, int(orig_w * scale))
                    new_h = max(100, int(orig_h * scale))
                   
                    # Resize and test
                    test_img = img.resize((new_w, new_h), Image.Resampling.LANCZOS)
                    if test_img.mode != 'RGB':
                        test_img = test_img.convert('RGB')
                   
                    temp_path = img_path + '.tmp'
                    test_img.save(temp_path, 'JPEG', quality=quality, optimize=True)
                   
                    if os.path.getsize(temp_path) <= target_size:
                        os.rename(temp_path, img_path.rsplit('.', 1)[0] + '_resized.jpg')
                        return True
                    os.remove(temp_path)
               
                # Fallback
                final_img = img.resize((400, 400), Image.Resampling.LANCZOS).convert('RGB')
                output_path = img_path.rsplit('.', 1)[0] + '_resized.jpg'
                final_img.save(output_path, 'JPEG', quality=quality, optimize=True)
                return True
               
        except Exception as e:
            print(f"Error processing {img_path}: {e}")
            return False
   
    def start_resize(self):
        if not self.images:
            return
           
        target_size = self.parse_size()
        quality = self.quality_var.get()
       
        def process():
            self.process_btn.config(state='disabled')
            total = len(self.images)
            self.progress['maximum'] = total
           
            # Get output folder
            output_dir = filedialog.askdirectory(title="Save Resized Images")
            if not output_dir:
                self.process_btn.config(state='normal')
                return
           
            success = 0
            for i, img in enumerate(self.images):
                # Update progress
                self.root.after(0, lambda v=i+1: self.progress.config(value=v))
                self.root.after(0, lambda t=f"Resizing {i+1}/{total}": setattr(self.status_label, 'text', t))
               
                if self.resize_image(img['path'], target_size, quality):
                    # Copy to output folder
                    resized_path = img['path'].rsplit('.', 1)[0] + '_resized.jpg'
                    if os.path.exists(resized_path):
                        shutil.copy2(resized_path, os.path.join(output_dir, os.path.basename(resized_path)))
                        success += 1
           
            # Final update
            self.root.after(0, lambda: self.progress.config(value=0))
            self.root.after(0, lambda: setattr(self.status_label, 'text', f"✅ Done! {success}/{total} resized"))
            self.root.after(0, lambda: self.process_btn.config(state='normal'))
       
        threading.Thread(target=process, daemon=True).start()

if __name__ == "__main__":
    try:
        root = tk.Tk()
        app = ImageResizer(root)
        root.mainloop()
    except ImportError as e:
        print("ERROR: Install Pillow first!")
        print("Run: pip install Pillow")
        input("Press Enter to exit...")

Comments