Skip to content

Instantly share code, notes, and snippets.

@z3nth10n
Created March 26, 2025 08:36
Show Gist options
  • Save z3nth10n/596279bc59986220fe53b316acdccd71 to your computer and use it in GitHub Desktop.
Save z3nth10n/596279bc59986220fe53b316acdccd71 to your computer and use it in GitHub Desktop.
Photo Organizer

Photo Organizer

This tool is used to organize a lot of photos inside a folder into their subfolders.

You select the folder from the right folder list panel, and then press enter to move the photo into the folder.

It needs PyQt6 to run.

Remember to change this line window = ImageSorterApp("./images") into your desired folder path.

image

import sys
import os
import shutil
from PyQt6.QtWidgets import QApplication, QLabel, QListWidget, QVBoxLayout, QPushButton, QWidget, QProgressBar, QHBoxLayout
from PyQt6.QtGui import QPixmap, QKeyEvent, QTransform, QImage
from PyQt6.QtCore import Qt
class ImageSorterApp(QWidget):
def __init__(self, image_dir):
super().__init__()
self.image_dir = image_dir
self.image_files = [f for f in os.listdir(image_dir) if f.lower().endswith(('png', 'jpg', 'jpeg'))]
self.current_index = 0
self.folders = [d for d in os.listdir(image_dir) if os.path.isdir(os.path.join(image_dir, d))]
self.rotation_angle = 0
self.selected_folder_index = None
self.init_ui()
self.load_image()
def init_ui(self):
layout = QVBoxLayout()
# Botones
button_layout = QHBoxLayout()
self.rotate_left_btn = QPushButton("⟲ Rotar Izquierda", self)
self.rotate_left_btn.clicked.connect(self.rotate_left)
button_layout.addWidget(self.rotate_left_btn)
self.rotate_right_btn = QPushButton("⟳ Rotar derecha", self)
self.rotate_right_btn.clicked.connect(self.rotate_right)
button_layout.addWidget(self.rotate_right_btn)
self.previous_image_btn = QPushButton("◄ Anterior", self)
self.previous_image_btn.clicked.connect(self.previous_image)
button_layout.addWidget(self.previous_image_btn)
self.next_image_btn = QPushButton("► Siguiente", self)
self.next_image_btn.clicked.connect(self.next_image)
button_layout.addWidget(self.next_image_btn)
layout.addLayout(button_layout)
horizontal_layout = QHBoxLayout()
self.image_label = QLabel(self)
self.image_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
horizontal_layout.addWidget(self.image_label)
self.folder_list = QListWidget(self)
for i, folder in enumerate(self.folders):
self.folder_list.addItem(f"{i}: {folder}")
self.folder_list.currentRowChanged.connect(self.update_selected_folder)
self.folder_list.setMinimumWidth(150)
horizontal_layout.addWidget(self.folder_list)
layout.addLayout(horizontal_layout)
self.progress_bar = QProgressBar(self)
self.progress_bar.setMaximum(len(self.image_files))
self.progress_bar.setValue(self.current_index)
self.progress_bar.setFormat("%.2f%%" % self.progress_bar.value())
layout.addWidget(self.progress_bar)
self.label = QLabel(self)
# self.label.setFrameStyle(QFrame.Panel | QFrame.Sunken)
self.label.setText(self.get_progress_text())
self.label.setAlignment(Qt.AlignmentFlag.AlignVCenter | Qt.AlignmentFlag.AlignHCenter)
layout.addWidget(self.label)
self.setLayout(layout)
self.setWindowTitle("Image Sorter")
# self.adjustSize()
self.show()
def load_image(self):
if self.current_index < len(self.image_files):
img_path = os.path.join(self.image_dir, self.image_files[self.current_index])
pixmap = QPixmap(img_path).scaled(600, 600, Qt.AspectRatioMode.KeepAspectRatio)
self.image_label.setPixmap(pixmap.transformed(QTransform().rotate(self.rotation_angle)))
# self.adjustSize()
else:
self.image_label.setText("No more images to sort.")
def keyPressEvent(self, event: QKeyEvent):
# if event.key() == Qt.Key.Key_Backspace:
# self.cancel_move()
# el
if event.key() == Qt.Key.Key_Return and self.selected_folder_index is not None:
self.move_image()
elif event.key() == Qt.Key.Key_Q:
self.rotate_left()
elif event.key() == Qt.Key.Key_E:
self.rotate_right()
elif event.key() == Qt.Key.Key_Right:
self.next_image()
elif event.key() == Qt.Key.Key_Left:
self.previous_image()
def update_selected_folder(self, index):
self.selected_folder_index = index if index >= 0 else None
def move_image(self):
if self.selected_folder_index is not None:
folder = self.folders[self.selected_folder_index]
src = os.path.join(self.image_dir, self.image_files[self.current_index])
dst = os.path.join(self.image_dir, folder, self.image_files[self.current_index])
shutil.move(src, dst)
self.next_image()
self.progress_bar.setValue(self.current_index)
self.load_image()
self.label.setText(self.get_progress_text())
def cancel_move(self):
pass # No hacemos nada en este caso
def rotate_left(self):
self.rotation_angle -= 90
self.save_rotated_image()
self.load_image()
def rotate_right(self):
self.rotation_angle += 90
self.save_rotated_image()
self.load_image()
def save_rotated_image(self):
if self.current_index < len(self.image_files):
img_path = os.path.join(self.image_dir, self.image_files[self.current_index])
image = QImage(img_path)
if not image.isNull():
transform = QTransform().rotate(self.rotation_angle)
rotated_image = image.transformed(transform)
rotated_image.save(img_path)
def next_image(self):
if self.current_index < len(self.image_files) - 1:
self.current_index += 1
self.rotation_angle = 0
self.load_image()
def previous_image(self):
if self.current_index > 0:
self.current_index -= 1
self.rotation_angle = 0
self.load_image()
def get_progress_text(self):
return f"{self.current_index}/{len(self.image_files)}"
if __name__ == "__main__":
app = QApplication(sys.argv)
window = ImageSorterApp("./images") # Ruta del directorio con imágenes
sys.exit(app.exec())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment