Images HD Maker – DarkCorners

Date: 17/12/2025

Category: Python

  • Phần mềm hỗ trợ thay đổi kích thước ảnh hàng loạt.
  • Hỗ trợ nhiều kích thước khác nhau.
  1. Khởi động phần mềm.
  2. Chọn thư mục chứa toàn bộ ảnh cần chỉnh sửa.
  3. Chọn thư mục xuất file đã chỉnh sửa.
  4. Chọn kích thước ảnh mà bạn muốn.
  5. Nhấn nút [Bắt Đầu].
  6. Theo dõi lịch trình xử lý.
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()
pyinstaller --noconsole --onefile --windowed --add-data "4-ImagesHDMaker-icon.ico;." --icon=4-ImagesHDMaker-icon.ico 4-ImagesHDMaker-Source.py

Để lại một bình luận