In this tutorial, we’ll build PixelSqueeze, a modern desktop image compression tool using Python.
By the end, you’ll have:
A drag & drop GUI
Batch image compression (JPG / PNG / WEBP)
Live progress tracking
A portable Windows EXE
👉 Source code:
https://github.com/rogers-cyber/PixelSqueeze
👉 Windows EXE (Release):
https://github.com/rogers-cyber/PixelSqueeze/releases/tag/v1.0.0
🚀 What Is PixelSqueeze?
PixelSqueeze is a lightweight, open-source desktop app that compresses images without noticeable quality loss.
Features
Drag & drop files and folders
Batch image processing
JPG / PNG / WEBP output
Adjustable JPG quality
Live progress & speed display
Portable Windows EXE (no install)
🧰 Step 1: Install Dependencies
Create a virtual environment (optional but recommended), then install:
pip install pillow ttkbootstrap tkinterdnd2 pillow-heif
Notes:
Tkinter comes bundled with Python
pillow-heif enables HEIC support (optional)
tkinterdnd2 enables drag & drop
🧱 Step 2: Project Structure
A simple structure is enough:
PixelSqueeze/
├── PixelSqueeze.py
├── requirements.txt
├── README.md
├── LICENSE
└── assets/
└── logo.ico
🖥️ Step 3: Create the Main Application Class
We start with a class-based design, which keeps the app clean and scalable.
class PixelSqueezeApp:
APP_NAME = "PixelSqueeze Free Version"
APP_VERSION = "1.0.0"
Using constants makes it easy to update branding and versions later.
🎨 Step 4: Initialize the Tkinter Window
We use ttkbootstrap for a modern dark UI and enable drag & drop if available.
self.root = TkinterDnD.Tk() if DND_ENABLED else tk.Tk()
tb.Style(theme="darkly")
self.root.title(f"{self.APP_NAME} v{self.APP_VERSION}")
self.root.geometry("1020x630")
Why ttkbootstrap?
Modern themes
Better widgets
Cleaner UI with minimal effort
📦 Step 5: Define Supported Formats
This allows safe filtering of files:
SUPPORTED_FORMATS = (
".png", ".jpg", ".jpeg", ".bmp", ".gif",
".tif", ".tiff", ".webp", ".heic"
)
Output formats are mapped for flexibility:
OUTPUT_FORMATS = {
"JPG (Best for Photos)": "JPEG",
"PNG (Best for Graphics)": "PNG",
"WEBP (Best for Web)": "WEBP"
}
🧩 Step 6: Build the File List UI
A simple Listbox shows queued files:
self.listbox = tk.Listbox(box)
self.listbox.pack(side="left", fill="both", expand=True)
Enable drag & drop if available:
self.listbox.drop_target_register(DND_FILES)
self.listbox.dnd_bind("<<Drop>>", self.on_drop)
This makes the app feel native and modern.
🎛️ Step 7: Options Panel (Format & Quality)
Users can choose output format and quality:
self.format_var = tk.StringVar(value="JPG (Best for Photos)")
self.quality_var = tk.IntVar(value=90)
Disable the quality slider for non-JPG formats:
def on_format_change(self, _=None):
is_jpg = self.OUTPUT_FORMATS[self.format_var.get()] == "JPEG"
self.quality_scale.config(state="normal" if is_jpg else "disabled")
⚙️ Step 8: Background Image Conversion (Threaded)
To keep the UI responsive, compression runs in a background thread.
threading.Thread(
target=self.convert_images,
daemon=True
).start()
Inside convert_images():
with Image.open(src) as img:
if fmt in ("JPEG", "WEBP"):
img = img.convert("RGB")
Saving with optimization:
img.save(
dst,
"JPEG",
quality=self.quality_var.get(),
optimize=True,
progressive=True
)
📊 Step 9: Live Progress & Speed Tracking
We use a queue to safely update the UI from the worker thread.
self.ui_queue.put(("progress", done))
self.ui_queue.put(("speed", f"{speed:.2f} files/sec"))
Processed in the main loop:
def process_ui_queue(self):
while not self.ui_queue.empty():
key, value = self.ui_queue.get()
if key == "progress":
self.progress_var.set(value)
elif key == "speed":
self.speed_var.set(value)
This avoids Tkinter threading crashes.
ℹ️ Step 10: About Dialog (No Minimize Button)
A clean modal About window:
win = tb.Toplevel(self.root)
win.resizable(False, False)
win.grab_set()
win.attributes("-toolwindow", True)
Perfect for:
App description
Feature list
Developer info
📦 Step 11: Build a Portable Windows EXE
Use PyInstaller:
pyinstaller --onefile --windowed PixelSqueeze.py
Your EXE will appear in:
dist/PixelSqueeze.exe
👉 Download ready-made EXE here:
https://github.com/rogers-cyber/PixelSqueeze/releases/tag/v1.0.0
🏁 Final Thoughts
PixelSqueeze shows how powerful Python + Tkinter can be for real desktop apps.
You learned how to:
Build a modern GUI
Handle batch image processing
Use threading safely
Ship a real Windows application
⭐ If you found this useful, consider starring the repo:
https://github.com/rogers-cyber/PixelSqueeze
Happy coding 🚀

Top comments (0)