个人图片分类-按照年分文件夹管理 python处理个人图片

这几年拍了很多照片,有60G数据,很乱,想要按照年分文件夹管理保存起来存储到百度云盘去。

python 复制代码
import os
import shutil
from PIL import Image
from PIL.ExifTags import TAGS
import re
import exifread
import datetime
import time
import pillow_heif
import sys
import zipfile


# 注册 HEIF 插件
pillow_heif.register_heif_opener()


# 源目录和目标目录(分别是桌面的两个文件夹,imagessource里面放了原始图片数据,imagesprocess是处理后的结果)
source_dir = os.path.join(os.path.expanduser('~'), 'Desktop', 'imagessource')
target_dir = os.path.join(os.path.expanduser('~'), 'Desktop', 'imagesprocess')


# 创建目标目录
if not os.path.exists(target_dir):
    os.makedirs(target_dir)

# 创建截屏文件夹
screenshot_dir = os.path.join(target_dir, 'screenshots')
if not os.path.exists(screenshot_dir):
    os.makedirs(screenshot_dir)


def extract_year_from_filename(filename):
    # 定义匹配年份的正则表达式模式
    pattern = r'\d{4}'
    # 使用正则表达式在文件名中查找匹配项
    match = re.search(pattern, filename)
    if match:
        # 如果找到匹配项,返回匹配的年份
        return match.group()
    return None

def get_heic_type_file_date(image_path):
    try:
        # 打开图片
        with Image.open(image_path) as image:
            # 获取 EXIF 数据
            exif_data = image.getexif()

            if exif_data is not None:
                # 遍历 EXIF 数据
                for tag, value in exif_data.items():
                    tag_name = TAGS.get(tag)
                    if tag_name == 'DateTime':
                        return value[:4]
    except Exception as e:
        print(f"Error getting EXIF data: {e}")

    return None

def get_creation_date(filename):
    if filename.endswith(('.heic')):
        return get_heic_type_file_date(filename)
    try:
        fd = open(filename, 'rb')
    except:
        print("Cannot open: ", filename)
        raise ReadFailException
    try:
        data = exifread.process_file(fd)
        if data:
            try:
                t = data['EXIF DateTimeOriginal']
                return str(t).replace(":", ".")[:4]
            except:
                print("No exif: ", filename)
                pass
    finally:
        fd.close()
    state = os.stat(filename)
    print("get state", filename)

    fileNameYear = extract_year_from_filename(filename);
    if fileNameYear:
        return str(fileNameYear)
    return time.strftime("%Y", time.localtime(state[-2]))




def is_screenshot(file_name):
    # 简单判断是否为截屏文件,可根据实际情况调整
    patterns = [r'screenshot', r'screencapture', r'snap']
    for pattern in patterns:
        if re.search(pattern, file_name, re.IGNORECASE):
            return True
    return False


# 遍历源目录,分类处理文件
def processFile():
    for root, dirs, files in os.walk(source_dir):
        for file in files:
            file_path = os.path.join(root, file)
            if file.lower().endswith(('.png', '.jpg', '.jpeg','.heic')):
                if is_screenshot(file):
                    shutil.move(file_path, os.path.join(screenshot_dir, file))
                else:
                    year = get_creation_date(file_path)
                    if year:
                        year_dir = os.path.join(target_dir, year)
                        if not os.path.exists(year_dir):
                            os.makedirs(year_dir)
                        shutil.move(file_path, os.path.join(year_dir, file))
                    else:
                        # 如果无法获取拍摄日期,放到一个单独的文件夹
                        unknown_dir = os.path.join(target_dir, 'unknown_date')
                        if not os.path.exists(unknown_dir):
                            os.makedirs(unknown_dir)
                        shutil.move(file_path, os.path.join(unknown_dir, file))
    


def extract_first_heic(livp_path):
    """
    从.livp文件中提取第一张HEIC图片
    
    参数:
        livp_path (str): .livp文件的路径
        output_dir (str): 输出目录(默认当前目录)
        
    返回:
        str: 提取的HEIC文件路径
        
    异常:
        ValueError: 如果文件无效或无HEIC文件
    """
    # 检查文件是否存在
    if not os.path.isfile(livp_path):
        raise FileNotFoundError(f"文件 '{livp_path}' 不存在")
    
    processSucess = False
    
    try:
        with zipfile.ZipFile(livp_path, 'r') as zf:
            # 筛选HEIC文件(不区分大小写)
            heic_files = [
                f for f in zf.namelist() 
                if os.path.splitext(f)[1].lower() == '.heic'
            ]
            
            if not heic_files:
                return
            
            # 按文件名排序(默认升序)
            heic_files.sort()
            first_heic = heic_files[0]
            
            # 提取文件
            livp_dir = os.path.dirname(livp_path)
            zf.extract(first_heic, livp_dir)
            extracted_path = os.path.join(livp_dir, first_heic)


            # 获取livp_path文件名
            livp_filename = os.path.basename(livp_path)
            print(f"LIVP文件名: {livp_filename}")

            # 修改文件名为 aaa.jpg
            new_path = os.path.join(livp_dir, os.path.basename(livp_path) + first_heic)

            if not os.path.exists(new_path):
                os.rename(extracted_path, new_path)
                # 删除 extracted_path 文件
                if os.path.isfile(extracted_path):
                    os.remove(extracted_path)
                extracted_path = new_path
            
            processSucess = True
            # 返回完整路径
            return os.path.abspath(extracted_path)
    
    except zipfile.BadZipFile:
        raise ValueError("无效的LIVP文件(非ZIP格式)")
    finally:
        # 删除原始文件
        if os.path.isfile(livp_path) and processSucess:
            os.remove(livp_path)

# 格式转换文件 :python 提取 .livp 里面的第一张 heic 图片,并且删除原始 .livp 文件
def livp_to_jpgProcess():
    for root, dirs, files in os.walk(source_dir):
        for file in files:
            file_path = os.path.join(root, file)
            if file.lower().endswith(('.livp')):
                extract_first_heic(file_path)
                

# 第一步 提取 .livp 里面的第一张 heic 图片
# livp_to_jpgProcess()
# 第二步处理数据
processFile()


 
相关推荐
Answer_ism9 分钟前
【SpringMVC】SpringMVC进阶,类型转换器源码分析,json转换,视图解析器,以及操作各种域的API
xml·java·开发语言·后端·spring·tomcat·json
uhakadotcom21 分钟前
火山引擎函数服务(veFaaS)入门指南
后端·架构·github
uhakadotcom25 分钟前
使用阿里云PyODPS3和MaxFrame构建高效本地开发环境
后端·面试·github
uhakadotcom32 分钟前
火山引擎EMR:大数据处理的强大工具
后端·架构·github
小奏技术38 分钟前
Apache Kafka 4.0正式发布,首个默认KRaft模式运行,移除单独维护Zookeeper降低复杂性
后端·消息队列
uhakadotcom42 分钟前
YOLOv12:提升性能和新能力的目标检测模型
后端·面试·github
南雨北斗1 小时前
jquery ajax 返回TP6错误信息的调试方法
前端·后端
崔婉凝1 小时前
Ruby语言的工业物联网
开发语言·后端·golang
小杨4041 小时前
springboot框架项目实践应用九(多数据源路由)
spring boot·后端·架构