import os
import threading
import tkinter as tk
from tkinter import filedialog, messagebox
from PIL import Image, ImageOps, ImageFilter
RESIZE_OPTIONS = {
"Poster 1 (720x1280)": (720, 1280),
"Poster 2 (360x640)": (360, 640),
"Poster 3 (360x540)": (360, 540),
"Ngang HD (1280x720)": (1280, 720),
"Ngang SD (640x360)": (640, 360),
}
def center_window(root, width=800, height=600):
# Lấy kích thước màn hình
screen_width = root.winfo_screenwidth()
screen_height = root.winfo_screenheight()
# Tính vị trí bắt đầu trục ngang và trục đứng
aaaxxx = (screen_width // 2) - (width // 2)
bbbyyy = (screen_height // 2) - (height // 2) - (40)
# Đặt geometry
root.geometry(f"{width}x{height}+{aaaxxx}+{bbbyyy}")
class ImageResizerApp:
def __init__(self, master):
self.master = master
self.master.title("Images HD Maker - DarkCorners")
self.master.resizable(False, False)
center_window(self.master, 800, 600)
self.input_folder = ""
self.output_folder = ""
self.selected_size = tk.StringVar(value=list(RESIZE_OPTIONS.keys())[0])
self.running = False
self.total_files = 0
self.created = 0
self.waiting = 0
self.failed = 0
self.build_ui()
def build_ui(self):
tk.Label(self.master, text="Images HD Maker - DarkCorners", font=("Arial", 16, "bold")).pack(pady=5)
frame_path = tk.Frame(self.master)
frame_path.pack(pady=5, fill="x", padx=10)
frame_input = tk.Frame(frame_path)
frame_input.pack(side="left", fill="x", expand=True)
self.input_entry = tk.Entry(frame_input)
self.input_entry.pack(side="left", fill="x", expand=True, padx=(0,5))
tk.Button(frame_input, text="Chọn Input", command=self.choose_input).pack(side="left")
frame_output = tk.Frame(frame_path)
frame_output.pack(side="left", fill="x", expand=True, padx=(10,0))
self.output_entry = tk.Entry(frame_output)
self.output_entry.pack(side="left", fill="x", expand=True, padx=(0,5))
tk.Button(frame_output, text="Chọn Output", command=self.choose_output).pack(side="left")
frame_action = tk.Frame(self.master)
frame_action.pack(pady=5, fill="x", padx=10)
frame_radio = tk.LabelFrame(frame_action, text="Chọn Kích Thước Ảnh", font=("Arial", 10, "bold"), bd=2, relief="groove")
frame_radio.pack(side="left", fill="x", expand=True)
rb_poster1 = tk.Radiobutton(frame_radio, text="Poster 1 (720x1280)", variable=self.selected_size, value="Poster 1 (720x1280)")
rb_poster2 = tk.Radiobutton(frame_radio, text="Poster 2 (360x640)", variable=self.selected_size, value="Poster 2 (360x640)")
rb_poster3 = tk.Radiobutton(frame_radio, text="Poster 3 (360x540)", variable=self.selected_size, value="Poster 3 (360x540)")
rb_poster1.grid(row=0, column=0, sticky="w", padx=5, pady=2)
rb_poster2.grid(row=0, column=1, sticky="w", padx=5, pady=2)
rb_poster3.grid(row=0, column=2, sticky="w", padx=5, pady=2)
rb_ngang_hd = tk.Radiobutton(frame_radio, text="Ngang HD (1280x720)", variable=self.selected_size, value="Ngang HD (1280x720)")
rb_ngang_sd = tk.Radiobutton(frame_radio, text="Ngang SD (640x360)", variable=self.selected_size, value="Ngang SD (640x360)")
rb_ngang_hd.grid(row=1, column=0, sticky="w", padx=5, pady=2)
rb_ngang_sd.grid(row=1, column=1, sticky="w", padx=5, pady=2)
frame_controls = tk.LabelFrame(frame_action, text="Điều Khiển Phần Mềm", font=("Arial", 10, "bold"), bd=2, relief="groove")
frame_controls.pack(side="right", fill="both", expand=True, padx=(10, 0))
frame_stats = tk.Frame(frame_controls)
frame_stats.pack(fill="x", pady=5)
self.label_total = tk.Label(frame_stats, text="Tất Cả: 0", font=("Arial", 10, "bold"), fg="red")
self.label_created = tk.Label(frame_stats, text="Đã Tạo: 0", font=("Arial", 10, "bold"), fg="green")
self.label_waiting = tk.Label(frame_stats, text="Đang Đợi: 0", font=("Arial", 10, "bold"), fg="blue")
self.label_failed = tk.Label(frame_stats, text="Bị Lỗi: 0", font=("Arial", 10, "bold"), fg="black")
self.label_total.pack(side="left", padx=5)
self.label_created.pack(side="left", padx=5)
self.label_waiting.pack(side="left", padx=5)
self.label_failed.pack(side="left", padx=5)
frame_buttons = tk.Frame(frame_controls)
frame_buttons.pack(fill="x", pady=(5, 0))
btn_start = tk.Button(frame_buttons, text="Bắt Đầu", command=self.start)
btn_pause = tk.Button(frame_buttons, text="Tạm Dừng", command=self.stop)
btn_exit = tk.Button(frame_buttons, text="Thoát", command=self.master.quit)
frame_buttons.columnconfigure((0,1,2), weight=1, uniform="a")
btn_start.grid(row=0, column=0, sticky="ew", padx=5)
btn_pause.grid(row=0, column=1, sticky="ew", padx=5)
btn_exit.grid(row=0, column=2, sticky="ew", padx=5)
self.log_text = tk.Text(self.master, height=20, state="disabled", bg="#111", fg="#0f0")
self.log_text.pack(fill="both", padx=10, pady=5, expand=True)
def choose_input(self):
folder = filedialog.askdirectory()
if folder:
self.input_folder = folder
self.input_entry.delete(0, tk.END)
self.input_entry.insert(0, folder)
def choose_output(self):
folder = filedialog.askdirectory()
if folder:
self.output_folder = folder
self.output_entry.delete(0, tk.END)
self.output_entry.insert(0, folder)
def log(self, msg):
self.log_text.config(state="normal")
self.log_text.insert("end", msg + "\n")
self.log_text.see("end")
self.log_text.config(state="disabled")
def update_status(self):
self.label_total.config(text=f"Tất Cả: {self.total_files}")
self.label_created.config(text=f"Đã Tạo: {self.created}")
self.label_waiting.config(text=f"Đang Đợi: {self.waiting}")
self.label_failed.config(text=f"Bị Lỗi: {self.failed}")
def stop(self):
self.running = False
self.log("Đã dừng xử lý.")
def start(self):
if not self.input_folder or not self.output_folder:
messagebox.showwarning("Thiếu thông tin", "Vui lòng chọn thư mục Input và Output.")
return
os.makedirs(self.output_folder, exist_ok=True)
self.running = True
threading.Thread(target=self.process_images, daemon=True).start()
def process_images(self):
self.created = self.failed = 0
files = [f for f in os.listdir(self.input_folder) if f.lower().endswith(('.jpg', '.jpeg', '.png'))]
self.total_files = len(files)
self.waiting = self.total_files
self.update_status()
size_name = self.selected_size.get()
target_size = RESIZE_OPTIONS[size_name]
for i, filename in enumerate(files):
if not self.running:
break
input_path = os.path.join(self.input_folder, filename)
output_path = os.path.join(self.output_folder, filename)
try:
with Image.open(input_path) as img:
img = img.convert("RGB")
if "Poster" in size_name:
new_img = img.resize(target_size, Image.Resampling.LANCZOS)
else:
width, height = img.size
is_landscape = width >= height
if is_landscape:
new_img = img.resize(target_size, Image.Resampling.LANCZOS)
else:
new_img = self.create_blurred_side_image(img, target_size)
new_img.save(output_path)
self.created += 1
self.log(f"[✓] Đã xử lý: {filename}")
except Exception as e:
self.failed += 1
self.log(f"[X] Lỗi với {filename}: {str(e)}")
self.waiting -= 1
self.update_status()
self.log("✔️ Hoàn tất xử lý tất cả ảnh!")
def create_blurred_side_image(self, original, target_size):
target_w, target_h = target_size
ratio = target_h / original.height
new_w = int(original.width * ratio)
resized_original = original.resize((new_w, target_h), Image.Resampling.LANCZOS)
blurred_bg = original.resize(target_size, Image.Resampling.BILINEAR)
blurred_bg = blurred_bg.filter(ImageFilter.GaussianBlur(15))
result = blurred_bg.copy()
paste_x = (target_w - new_w) // 2
result.paste(resized_original, (paste_x, 0))
return result
if __name__ == "__main__":
root = tk.Tk()
app = ImageResizerApp(root)
root.mainloop()