Загрузка...

Python
Resizer - MRICCRIPT, which reduces selected photos automatically

Thread in Your projects created by awaw Jun 4, 2025. (bumped Dec 5, 2025) 887 views

  1. awaw
    awaw Topic starter Jun 4, 2025 ну купи парсер чатов тг lolz.live/threads/9046721 11,294 Oct 8, 2017
    Нужно было сжимать фотки, вручную лень, понятно что существуют программы, но устанавливать лень, поэтому сделал свой скрипт и даже сделал GUI.
    UPD 05.12.25: переделал интерфейс с tkinter на pyqt5

    Python
    import os
    import shutil
    from PIL import Image
    from PyQt5.QtWidgets import (
    QApplication, QWidget, QVBoxLayout, QLabel, QPushButton,
    QTextEdit, QFileDialog, QSpacerItem, QSizePolicy
    )
    from PyQt5.QtCore import Qt, QCoreApplication
    from PyQt5.QtGui import QFont

    TEMP_DIR = "__temp__"
    os.makedirs(TEMP_DIR, exist_ok=True)

    GRAPHITE = "#1c1c1c"
    RED = "#ff0000"
    WHITE = "#ffffff"


    class DropTextEdit(QTextEdit):
    def __init__(self, parent=None):
    super().__init__(parent)
    self.setAcceptDrops(True)
    self.parent_window = parent

    def dragEnterEvent(self, event):
    if event.mimeData().hasUrls():
    event.accept()
    else:
    event.ignore()

    def dragMoveEvent(self, event):
    if event.mimeData().hasUrls():
    event.accept()
    else:
    event.ignore()

    def dropEvent(self, event):
    if event.mimeData().hasUrls():
    for url in event.mimeData().urls():
    path = url.toLocalFile()
    self.parent_window.add_file(path)
    event.accept()
    else:
    event.ignore()



    class ImageResizerApp(QWidget):
    def __init__(self):
    super().__init__()

    self.selected_files = []
    self.supported_formats = [".jpg", ".jpeg", ".png", ".bmp", ".webp", ".jfif"]

    self.init_ui()

    def init_ui(self):
    self.setWindowTitle("Resizer")

    QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
    QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps)

    self.resize(1200, 900)
    self.setStyleSheet(f"background-color: {GRAPHITE};")

    layout = QVBoxLayout()

    title = QLabel("выбери картинку и нажми обработать")
    title.setStyleSheet(f"color: {RED};")
    title.setAlignment(Qt.AlignCenter)
    font = QFont()
    font.setPointSize(16)
    font.setBold(True)
    title.setFont(font)
    layout.addWidget(title)

    self.drop_zone = DropTextEdit(self)
    self.drop_zone.setStyleSheet(
    f"""
    QTextEdit {{
    background-color: #2a2a2a;
    color: {WHITE};
    border: 2px solid {RED};
    border-radius: 6px;
    }}
    """
    )
    self.drop_zone.setReadOnly(True)
    self.drop_zone.setText("перетащи сюда картинку\nили нажми для выбора")
    self.drop_zone.setFont(QFont("Arial", 12))
    layout.addWidget(self.drop_zone)

    select_btn = QPushButton("выбрать фото")
    select_btn.setStyleSheet(
    f"""
    QPushButton {{
    background-color: {GRAPHITE};
    color: {RED};
    border: 2px solid {RED};
    padding: 8px;
    border-radius: 5px;
    }}
    QPushButton:hover {{
    background-color: #2e2e2e;
    }}
    """
    )
    select_btn.setFont(QFont("Arial", 12))
    select_btn.clicked.connect(self.select_files)
    layout.addWidget(select_btn)

    process_btn = QPushButton("обработать")
    process_btn.setStyleSheet(
    f"""
    QPushButton {{
    background-color: {RED};
    color: {WHITE};
    padding: 8px;
    border-radius: 5px;
    }}
    QPushButton:hover {{
    background-color: #cc0000;
    }}
    """
    )
    process_btn.setFont(QFont("Arial", 12))
    process_btn.clicked.connect(self.process_images)
    layout.addWidget(process_btn)

    layout.addSpacerItem(QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding))

    self.setLayout(layout)

    self.center_on_screen()

    def center_on_screen(self):
    frame_gm = self.frameGeometry()
    screen = QApplication.desktop().screenNumber(QApplication.desktop().cursor().pos())
    center_point = QApplication.desktop().screenGeometry(screen).center()
    frame_gm.moveCenter(center_point)
    self.move(frame_gm.topLeft())

    def add_file(self, path):
    if not path:
    return
    path = os.path.normpath(path)
    if any(path.lower().endswith(ext) for ext in self.supported_formats):
    if path not in self.selected_files and os.path.exists(path):
    self.selected_files.append(path)
    self.update_drop_zone()

    def update_drop_zone(self):
    if self.selected_files:
    text = ""
    for i, f in enumerate(self.selected_files):
    text += f"{i+1}. {os.path.basename(f)}\n"
    self.drop_zone.setText(text)
    else:
    self.drop_zone.setText("перетащи сюда картинку\nили нажми для выбора")

    def select_files(self):
    files, _ = QFileDialog.getOpenFileNames(
    self,
    "выбери картинку",
    "",
    "Image files (*.jpg *.jpeg *.png *.bmp *.webp *.jfif)"
    )
    for f in files:
    self.add_file(f)

    def process_images(self):
    if not self.selected_files:
    return
    try:
    for file in self.selected_files:
    self.resize_and_convert(file)
    self.cleanup_temp_folder()
    self.close()
    except Exception as e:
    print("ошибка:", e)

    def resize_and_convert(self, input_path):
    if not os.path.exists(input_path):
    print("файл не найден:", input_path)
    return
    base, _ = os.path.splitext(input_path)
    temp_path = os.path.join(TEMP_DIR, os.path.basename(base) + ".temp.jpg")
    with Image.open(input_path) as img:
    original_width, original_height = img.size
    new_width = int(original_width * (1600 / original_height))
    resized_img = img.resize((new_width, 1600), Image.LANCZOS)
    if resized_img.mode in ("RGBA", "P"):
    resized_img = resized_img.convert("RGB")
    resized_img.save(temp_path, "JPEG", quality=80)
    os.remove(input_path)
    shutil.move(temp_path, input_path)
    print("готово:", input_path)

    def cleanup_temp_folder(self):
    try:
    for f in os.listdir(TEMP_DIR):
    os.remove(os.path.join(TEMP_DIR, f))
    os.rmdir(TEMP_DIR)
    except Exception as e:
    print("", e)


    if __name__ == "__main__":
    import sys
    app = QApplication(sys.argv)
    window = ImageResizerApp()
    window.show()
    sys.exit(app.exec_())

    Как работает:
    Сжимает фото любого формата до .jpg 80% в разрешении х1600 пикселей по высоте.
    В строках "new_width = int(original_width * (1600 / original_height))" и "resized_img = img.resize((new_width, 1600), Image.LANCZOS)" можно изменить размер на свой, например 720 - будет сжимать до 720пкс по высоте.
    В строке resized_img.save(temp_path, "JPEG", quality=80) можно изменить степень сжатия, с 80% до условных 100% (без сжатия, просто переформат в .jpg) или вообще до 5, до степени 10 шакалов из 10.
    Оригинальные фото ЗАМЕНЯЮТСЯ без предупреждения новыми, сжатыми.
    В окно можно поместить как 1 картинку, так и 100.
    В версии 2.0 обновил интерфейс
    В будущем в GUI добавлю возможность выбирать размер и степень сжатия


    как пользоваться:
    1. Скачиваете Python если ещё нет (Python 3.9.10 )
    2. Создаёте файл main.py , вписываете код в него
    3. Устанавливаете библиотеки pillow и tkinterdnd2
    4. Открываете main.py , перетаскиваете туда картинки, жмык "Обработать", на выходе получаются сжатые файлы

    [IMG]

    Python
    import os
    import shutil
    from PIL import Image
    import tkinter as tk
    from tkinter import filedialog
    from tkinterdnd2 import TkinterDnD, DND_FILES

    TEMP_DIR = "__temp__"
    os.makedirs(TEMP_DIR, exist_ok=True)

    GRAPHITE = "#1c1c1c"
    RED = "#ff0000"
    WHITE = "#ffffff"

    class ImageResizerApp:
    def __init__(self, root):
    self.root = root
    self.root.title("Resizer")
    self.root.geometry("500x400")
    self.root.resizable(False, False)
    self.root.configure(bg=GRAPHITE)

    title_label = tk.Label(root, text="выбери картинку и нажми обработать", font=("Arial", 14), bg=GRAPHITE, fg=RED)
    title_label.pack(pady=20)

    self.drop_zone = tk.Text(root, height=10, width=50, wrap=tk.WORD, relief="solid", bd=2, bg="#2a2a2a", fg=WHITE, insertbackground=WHITE, highlightbackground=RED, highlightcolor=RED)
    self.drop_zone.pack(pady=10)
    self.drop_zone.insert(tk.END, "перетащи сюда картинку\nили нажми для выбора")
    self.drop_zone.config(state=tk.DISABLED)

    select_button = tk.Button(root, text="выбрать фото", command=self.select_files, width=20, font=("Arial", 10),
    bg=GRAPHITE, fg=RED, activebackground="#2e2e2e", activeforeground=RED,
    highlightbackground=RED, highlightcolor=RED)
    select_button.pack(pady=10)

    process_button = tk.Button(root, text="обработать", command=self.process_images, width=20, font=("Arial", 10),
    bg=RED, fg=WHITE, activebackground="#cc0000", activeforeground=WHITE,
    highlightbackground=GRAPHITE, highlightcolor=GRAPHITE)
    process_button.pack(pady=10)

    self.selected_files = []
    self.supported_formats = [".jpg", ".jpeg", ".png", ".bmp", ".webp", ".jfif"]
    self.drop_zone.drop_target_register(DND_FILES)
    self.drop_zone.dnd_bind('<<Drop>>', self.on_drop)

    def on_drop(self, event):
    raw_files = self.root.tk.splitlist(event.data)
    for file in raw_files:
    file = file.strip("{").strip("}")
    if any(file.lower().endswith(ext) for ext in self.supported_formats) and os.path.exists(file):
    self.add_file_to_list(os.path.normpath(file))

    def add_file_to_list(self, file_path):
    if file_path not in self.selected_files:
    self.selected_files.append(file_path)
    self.update_drop_zone()

    def update_drop_zone(self):
    self.drop_zone.config(state=tk.NORMAL)
    self.drop_zone.delete(1.0, tk.END)
    if self.selected_files:
    for idx, f in enumerate(self.selected_files):
    self.drop_zone.insert(tk.END, f"{idx+1}. {os.path.basename(f)}\n")
    else:
    self.drop_zone.insert(tk.END, "перетащи сюда картинку\nили нажми для выбора")
    self.drop_zone.config(state=tk.DISABLED)

    def select_files(self):
    files = filedialog.askopenfilenames(
    title="выбери картинку",
    filetypes=[("Image files", "*.jpg *.jpeg *.png *.bmp *.webp *.jfif")]
    )
    for file in files:
    file = os.path.normpath(file)
    if any(file.lower().endswith(ext) for ext in self.supported_formats) and os.path.exists(file):
    self.add_file_to_list(file)

    def process_images(self):
    if not self.selected_files:
    return

    try:
    for file in self.selected_files:
    self.resize_and_convert(file)

    self.cleanup_temp_folder()
    self.root.destroy()

    except Exception as e:
    print(f"ошибка: {e}")

    def resize_and_convert(self, input_path):
    input_path = os.path.normpath(input_path)
    if not os.path.exists(input_path):
    print(f"файл не найден: {input_path}")
    return

    base, ext = os.path.splitext(input_path)
    temp_path = os.path.join(TEMP_DIR, os.path.basename(base) + ".temp.jpg")

    with Image.open(input_path) as img:
    original_width, original_height = img.size
    new_width = int(original_width * (1600 / original_height)) # фиксированная высота, 1600пкс
    resized_img = img.resize((new_width, 1600), Image.LANCZOS)

    if resized_img.mode in ('RGBA', 'P'):
    resized_img = resized_img.convert('RGB')

    resized_img.save(temp_path, "JPEG", quality=80)

    os.remove(input_path)
    shutil.move(temp_path, input_path)
    print(f"готово: {input_path}")

    def cleanup_temp_folder(self):
    for filename in os.listdir(TEMP_DIR):
    file_path = os.path.join(TEMP_DIR, filename)
    try:
    os.remove(file_path)
    except Exception as e:
    print(f"не удалился {file_path}: {e}")
    try:
    os.rmdir(TEMP_DIR)
    except Exception as e:
    print(f"не удалилась папка {TEMP_DIR}: {e}")

    if __name__ == "__main__":
    root = TkinterDnD.Tk()
    app = ImageResizerApp(root)
    root.mainloop()
    [IMG]
     
    1. Toil
      avatarawaw , ни стыда, ни совести, подсовывает тут всякие Ti!F18BC3798CD6 :animeshout: [IMG]
    2. awaw Topic starter
      avatarToil , :despair: ну скачай пж, я хотел твой акк взломать
    3. Toil
      avatarawaw , даже не дает скачать свои вирусы :ehh:
      [IMG]
    4. View the next comments (1)
  2. Gekyume
    Если гуи делал, то вынеси туда размер и степень сжатия
     
    1. awaw Topic starter
      avatarGekyume, мне надо было лишь в 1 размер, но спасибо за идею, в следующей версии запилю это
  3. nichind
    nichind Jun 4, 2025 full time free thinker
    Business card website, portfolio (3D,...
    на гитхаб ради приличия хотя бы
     
Loading...