AI生成应用:图片批量重命名工具 - 自动化整理您的图片库

图片批量重命名工具 - 自动化整理您的图片库

GitHub项目地址: github.com/dependon/re...

项目介绍

这是一个基于Python开发的图形界面工具,用于批量重命名文件夹中的图片文件。它能够递归处理选定文件夹及其所有子文件夹中的图片,按照"文件夹名_序号.扩展名"的格式进行智能重命名。

主要功能

  • 递归处理: 自动扫描并处理选定文件夹及其所有子文件夹
  • 智能重命名: 将图片重命名为"文件夹名_序号.扩展名"的统一格式
  • 多语言支持: 提供7种语言界面(中文、英文、俄语、日语、德语、葡萄牙语和法语)
  • 实时日志: 显示详细的处理进度和结果
  • 用户友好: 简洁直观的图形界面,操作简单

支持的图片格式

  • JPG/JPEG
  • PNG
  • GIF
  • BMP
  • TIFF
  • WEBP

技术实现

项目主要使用Python标准库开发,无需额外安装第三方库。核心功能包括:

  1. 递归文件处理 : 使用os.walk遍历文件夹结构
  2. 多语言支持: 通过JSON文件存储翻译文本,动态加载
  3. 线程处理 : 使用threading模块防止界面卡顿
  4. GUI界面 : 基于tkinter构建用户友好的图形界面

完整代码

python 复制代码
# rename_images_gui.py
import os
import tkinter as tk
from tkinter import filedialog, messagebox, scrolledtext, ttk
import threading
from language_manager import LanguageManager

SUPPORTED_EXTENSIONS = {'.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.webp'}

# --- 核心重命名逻辑 ---
def rename_images_in_folder(folder_path, log_callback):
    try:
        folder_name = os.path.basename(folder_path)
        if not folder_name:
             log_callback(lang_manager.get_text('skip_root').format(folder_path=folder_path))
             return 0

        count = 1
        renamed_count = 0
        log_callback(lang_manager.get_text('start_processing').format(folder_path=folder_path))

        items = sorted(os.listdir(folder_path))

        for filename in items:
            original_full_path = os.path.join(folder_path, filename)

            if os.path.isfile(original_full_path):
                _, ext = os.path.splitext(filename)
                if ext.lower() in SUPPORTED_EXTENSIONS:
                    new_filename = f"{folder_name}_{count}{ext}"
                    new_full_path = os.path.join(folder_path, new_filename)

                    if original_full_path == new_full_path:
                        log_callback(lang_manager.get_text('skip_same_name').format(filename=filename))
                        count += 1
                        continue
                    elif os.path.exists(new_full_path):
                         log_callback(lang_manager.get_text('warning_existing_file').format(filename=filename, new_filename=new_filename))
                         continue

                    try:
                        os.rename(original_full_path, new_full_path)
                        log_callback(lang_manager.get_text('success').format(filename=filename, new_filename=new_filename))
                        renamed_count += 1
                        count += 1
                    except OSError as e:
                        log_callback(lang_manager.get_text('error_rename').format(filename=filename, error=str(e)))

        log_callback(lang_manager.get_text('folder_processed').format(folder_path=folder_path, renamed_count=renamed_count))
        return renamed_count

    except Exception as e:
        log_callback(lang_manager.get_text('unexpected_error').format(error=str(e)))
        return 0

def rename_images_recursively(root_dir, log_callback):
    total_renamed = 0
    if not os.path.isdir(root_dir):
        log_callback(lang_manager.get_text('invalid_folder_error'))
        return 0

    log_callback(lang_manager.get_text('recursive_start').format(root_dir=root_dir))

    for dirpath, dirnames, filenames in os.walk(root_dir, topdown=True):
        renamed_in_folder = rename_images_in_folder(dirpath, log_callback)
        total_renamed += renamed_in_folder

    log_callback(lang_manager.get_text('recursive_complete').format(total_renamed=total_renamed))
    return total_renamed

# --- GUI 部分 ---
class RenamerApp:
    def __init__(self, master):
        self.master = master
        self.lang_manager = LanguageManager()
        self.update_window_title()

        self.selected_folder = tk.StringVar()
        self.is_running = False

        # 创建语言选择下拉框
        self.create_language_selector()

        # 文件夹选择部分
        tk.Label(master, text=self.lang_manager.get_text('select_folder')).grid(row=1, column=0, padx=5, pady=5)
        self.folder_entry = tk.Entry(master, textvariable=self.selected_folder, width=50, state='readonly')
        self.folder_entry.grid(row=1, column=1, padx=5, pady=5, sticky="ew")
        self.browse_button = tk.Button(master, text=self.lang_manager.get_text('browse'), command=self.browse_folder)
        self.browse_button.grid(row=1, column=2, padx=5, pady=5)

        # 开始按钮
        self.rename_button = tk.Button(master, text=self.lang_manager.get_text('start_rename'), command=self.start_renaming_thread)
        self.rename_button.grid(row=2, column=0, columnspan=3, padx=5, pady=10)

        # 日志区域
        tk.Label(master, text=self.lang_manager.get_text('log')).grid(row=3, column=0, padx=5, pady=5, sticky="w")
        self.log_area = scrolledtext.ScrolledText(master, wrap=tk.WORD, height=15, width=70)
        self.log_area.grid(row=4, column=0, columnspan=3, padx=5, pady=5, sticky="nsew")
        self.log_area.config(state='disabled')

        # 布局配置
        master.grid_columnconfigure(1, weight=1)
        master.grid_rowconfigure(4, weight=1)

    def create_language_selector(self):
        languages = self.lang_manager.get_supported_languages()
        current_lang = self.lang_manager.get_current_language()
        
        frame = tk.Frame(self.master)
        frame.grid(row=0, column=0, columnspan=3, padx=5, pady=5, sticky="e")
        
        # 获取当前语言的本地化名称
        current_lang_name = languages[current_lang]
        self.lang_var = tk.StringVar(value=current_lang_name)
        
        # 创建语言代码到本地化名称的映射
        self.lang_code_to_name = languages
        self.lang_name_to_code = {v: k for k, v in languages.items()}
        
        self.lang_combobox = ttk.Combobox(frame, textvariable=self.lang_var, values=list(languages.values()), state='readonly', width=10)
        self.lang_combobox.bind('<<ComboboxSelected>>', self.on_language_change)
        self.lang_combobox.pack(side=tk.RIGHT)

    def on_language_change(self, event=None):
        selected_lang_name = self.lang_var.get()
        selected_lang_code = self.lang_name_to_code[selected_lang_name]
        if self.lang_manager.load_language(selected_lang_code):
            self.update_ui_texts()

    def update_ui_texts(self):
        self.update_window_title()
        self.browse_button.config(text=self.lang_manager.get_text('browse'))
        self.rename_button.config(text=self.lang_manager.get_text('start_rename') if not self.is_running else self.lang_manager.get_text('processing'))
        
        # Update label texts
        for widget in self.master.grid_slaves():
            if isinstance(widget, tk.Label):
                if widget.grid_info()['row'] == 1:  # Select folder label
                    widget.config(text=self.lang_manager.get_text('select_folder'))
                elif widget.grid_info()['row'] == 3:  # Log label
                    widget.config(text=self.lang_manager.get_text('log'))

    def update_window_title(self):
        self.master.title(self.lang_manager.get_text('title'))

    def log(self, message):
        def _update_log():
            self.log_area.config(state='normal')
            self.log_area.insert(tk.END, message + "\n")
            self.log_area.see(tk.END)
            self.log_area.config(state='disabled')
        self.master.after(0, _update_log)

    def browse_folder(self):
        if self.is_running:
            messagebox.showwarning(self.lang_manager.get_text('title'), self.lang_manager.get_text('task_running'))
            return
        folder = filedialog.askdirectory()
        if folder:
            self.selected_folder.set(folder)

    def start_renaming_thread(self):
        if self.is_running:
            messagebox.showwarning(self.lang_manager.get_text('title'), self.lang_manager.get_text('task_running'))
            return

        root_dir = self.selected_folder.get()
        if not root_dir:
            messagebox.showerror(self.lang_manager.get_text('title'), self.lang_manager.get_text('select_folder_error'))
            return
        if not os.path.isdir(root_dir):
            messagebox.showerror(self.lang_manager.get_text('title'), self.lang_manager.get_text('invalid_folder_error'))
            return

        if not messagebox.askyesno(self.lang_manager.get_text('title'),
                                  self.lang_manager.get_text('confirm_operation').format(folder=os.path.basename(root_dir))):
            return

        self.log_area.config(state='normal')
        self.log_area.delete('1.0', tk.END)
        self.log_area.config(state='disabled')
        self.rename_button.config(state='disabled', text=self.lang_manager.get_text('processing'))
        self.browse_button.config(state='disabled')
        self.is_running = True

        self.rename_thread = threading.Thread(target=self.run_rename_task, args=(root_dir,))
        self.rename_thread.daemon = True
        self.rename_thread.start()

    def run_rename_task(self, root_dir):
        try:
            rename_images_recursively(root_dir, self.log)
        except Exception as e:
            self.log(self.lang_manager.get_text('unexpected_error').format(error=str(e)))
        finally:
            self.master.after(0, self.on_rename_complete)

    def on_rename_complete(self):
        messagebox.showinfo(self.lang_manager.get_text('title'), self.lang_manager.get_text('completed'))
        self.rename_button.config(state='normal', text=self.lang_manager.get_text('start_rename'))
        self.browse_button.config(state='normal')
        self.is_running = False

# --- 主程序入口 ---
if __name__ == "__main__":
    lang_manager = LanguageManager()
    root = tk.Tk()
    app = RenamerApp(root)
    root.mainloop()
python 复制代码
# language_manager.py
import os
import json
import locale

class LanguageManager:
    def __init__(self):
        self.current_language = None
        self.translations = {}
        self.locales_dir = os.path.join(os.path.dirname(__file__), 'locales')
        self.supported_languages = {
            'en': 'English',
            'zh': '中文',
            'ru': 'Русский',
            'ja': '日本語',
            'de': 'Deutsch',
            'pt': 'Português',
            'fr': 'Français'
        }
        
        # 初始化时自动检测系统语言
        system_lang = locale.getdefaultlocale()[0]
        self.default_language = 'en'  # 默认使用英语
        self.load_language(self.default_language)
    
    def load_language(self, lang_code):
        """加载指定的语言文件"""
        if lang_code not in self.supported_languages:
            lang_code = 'en'  # 默认使用英语
        
        try:
            file_path = os.path.join(self.locales_dir, f'{lang_code}.json')
            with open(file_path, 'r', encoding='utf-8') as f:
                self.translations = json.load(f)
            self.current_language = lang_code
            return True
        except Exception as e:
            print(f'Error loading language file: {e}')
            return False
    
    def get_text(self, key):
        """获取翻译文本"""
        return self.translations.get(key, key)
    
    def get_current_language(self):
        """获取当前语言代码"""
        return self.current_language
    
    def get_supported_languages(self):
        """获取支持的语言列表"""
        return self.supported_languages

使用方法

  1. 克隆或下载项目代码
  2. 运行程序: python rename_images_gui.py
  3. 选择要处理的根文件夹
  4. 点击"开始重命名"按钮
  5. 在日志区域查看处理结果

声明

本项目介绍、博客文章和所有相关内容均由AI生成。


这个工具非常适合摄影师、设计师或需要整理大量图片的用户。它的递归处理和多语言支持使其成为一个非常实用的工具。

本文由博客一文多发平台 OpenWrite 发布!

相关推荐
Python私教9 分钟前
Java手写链表全攻略:从单链表到双向链表的底层实现艺术
java·python·链表
Stara05119 分钟前
YOLO11改进——融合BAM注意力机制增强图像分类与目标检测能力
人工智能·python·深度学习·目标检测·计算机视觉·yolov11
xiongmaodaxia_z737 分钟前
python每日一练
开发语言·python·算法
zy_destiny1 小时前
【非机动车检测】用YOLOv8实现非机动车及驾驶人佩戴安全帽检测
人工智能·python·算法·yolo·机器学习·安全帽·非机动车
仙人掌_lz1 小时前
详解如何复现DeepSeek R1:从零开始利用Python构建
开发语言·python·ai·llm·deepseek
小宁学技术1 小时前
MATLAB在哪些特定领域比Python更有优势?
开发语言·python·matlab
松前卡气加超级漂1 小时前
Django:高效构建现代Web应用的利器
前端·python·django
Ma_si1 小时前
用python写一个简单的射击游戏
python·游戏·pygame
stormsha1 小时前
使用Python进行AI图像生成:从GAN到风格迁移的完整指南
人工智能·python·生成对抗网络
怪兽小2 小时前
在PyCharm中配置Anaconda虚拟环境作为终端环境
ide·python·pycharm