<난장>
난장
<난장>
전체 방문자
오늘
어제
  • 난장 (153)
    • 난장 다이어리 (37)
      • Write (10)
    • 난장 Dev (3)
      • Flutter - Dart (11)
      • Mobile (0)
      • WEB (1)
      • Database (5)
      • Python (3)
    • 난장 핫플레이스 (47)
      • 국내 (32)
      • 국외 (14)
    • 난장 리뷰 (45)
      • 카페 리뷰 (30)
      • 맛집 리뷰 (2)
      • IT 리뷰 (1)
      • 문화 리뷰 (10)
      • ETC 리뷰 (2)
    • 난장 난(蘭) (1)
      • 난(蘭) 이야기 (0)
      • 꽃, 식물 (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

  • 모두 제가 찍은 사진입니다!
  • 2019년 2월 13일, 로고 사용합니다.
  • 2019년 1월 22일, 난장의 난(蘭) 이야기를 시작합니⋯

인기 글

태그

  • samyang14
  • 소니미러리스
  • 삼양
  • 화순
  • tamron2875
  • 14mm
  • sonya7iii
  • 미러리스
  • 여행
  • 커피
  • 소니
  • tamron2875fe
  • a7m2
  • A7M3
  • a7ii
  • Sony
  • samyang14mm
  • samyang
  • 카페
  • 전남

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
<난장>

난장

Python - 사진 파일의 EXIF를 확인하여 년도/월 폴더로 이동하기
난장 Dev/Python

Python - 사진 파일의 EXIF를 확인하여 년도/월 폴더로 이동하기

2024. 2. 4. 08:00

imageReDirectory.py
0.01MB

 

 

하위 폴더까지 조회해서 이동하는 거랑 실제 위치에서 실행 안되는 경우 파일을 찾을 수 없는 등의 오류가 있어 조금 변경해 보았다.

생각보다 속도도 빠른 편인듯.

 

참고로 pillow 패키지를 사용하는데 설치된 파이썬에 해당 패키지를 설치해야 하므로 아래와 같이 설치하고 진행한다.

python3 -m pip install pillow

 

 

Python 사진 자동 정리 프로그램 개발  - 참고 링크: https://hellojason.tistory.com/27

 

[Python] 사진 자동 정리 프로그램 개발 (EXIF)

핸드폰/디카로 사진 촬영하는 일은 이제 일상이 되었습니다. Google Photo 를 사용하면 간편하지만, 비용도 문제고 과거 파일도 업로드해야하고, 용량이 크면 비용도 문제가 됩니다. 저도 NAS에 아이

hellojason.tistory.com

 

개선 내용

 

1. 하위 폴더 조회해서 이동할 건지 설정 : subfolder = False > True

2. 중복된 파일의 접두사 : duplicatePrefix = 'dup_'

3. 실행 위치에 따른 선택:

    cur_dir = os.getcwd()  # python 을 실행한 위치

    cur_dir = ‘’ # 다른 곳에서 실행하지만 사진을 조회하고 실행하려는 위치

 

import os
import shutil

from PIL import Image
from PIL.ExifTags import TAGS
from datetime import datetime

# 디버그 모드 활성화 여부 - True, False
DEBUG = True

# 하위 폴더까지 확인하기
subfolder = False

# 이동하려는 곳의 파일이 존재한다면 추가하려는 앞자리
duplicatePrefix = 'dup_'

# 이미지 확장자
img_ext = ['.jpg', '.jpeg', '.JPG', '.JPEG', '.png', '.PNG', '.bmp', '.BMP']
# 영상 확장자
mov_ext = ['.mp4', '.MP4', '.avi', '.AVI', 'mts', '.MTS', '.m2ts', '.M2TS']

# 이미지 파일 저장 리스트
img_list = []
# 영상 파일 저장 리스트
mov_list = []
# 기타 파일 저장 리스트
etc_list = []

# 실행 현재 위치 - 하위 폴더 조회해서 모두 이동시켜 버림
# cur_dir = os.getcwd();

# 실행 위치(파일 검색하는 위치) 고정
cur_dir = '/Users/jymun/Desktop/Photo/PY_TestImage/'

# 디버그 모드 시작하기
if DEBUG :
    print('img_list length : ', len(img_list))
    print(f'current_dir : {cur_dir}')

# 이미지 날짜 정보 조회하기 - 함수
def getImageDate(image, DEBUG=False):
    '''
    이미지 EXIF 정보 읽기 - 이미지 생성 년, 월 리턴
    '''
    img = Image.open(image)
    img_date = []

    if DEBUG : print(img.filename)
    
    # EXIF 정보로 이미지 촬영일 체크
    img_info = img._getexif()
    if img_info is not None:
        for tag_id in img_info:
            tag = TAGS.get(tag_id, tag_id)
            data = img_info.get(tag_id)

            if tag == 'DateTime' or tag == 'DateTimeOriginal':      # 촬영일 존재하면 년,월 세팅
                data = data.replace('-',':')                        # '-' 일자 구분자를 :로 변환

                # meta정보 고려해서 10자리 끊고 -> 빈칸 0 trim후 0 채워넣기
                data = data[:11]                                    # yyyy:mm:dd 10자리만 읽기
                data = data.replace(' ','0')                        # 공백 '0' 채움
                date = data.split(':')                              # date = [년, 월, 일]
                if DEBUG: print(f'Data : {data}, Date : {date}')
                try:
                    img_date.append(date[0])
                    img_date.append(date[1])
                except:
                    print('!!!!!! ERRROR !!!!!!!!!')
                    print(f'img name : ', image)
                    print(f'data : {data}')
                    print(f'date : {date}')
                    img_date[0] = 'error'           # 강제 error 세팅
                    img_date.append('00')           # 두번째 값 '00' 추가
                    print(f'img_date : {img_date}')

            if DEBUG:
                print(f'>>>>> {tag:25}: {data}')
            
    # EXIF 값이 없으면, 파일 생성일 세팅
    if len(img_date) == 0 :
        date = datetime.fromtimestamp(os.path.getctime(image)).strftime('%Y:%m:%d').split(':')
        img_date.append(date[0])
        img_date.append(date[1])
            
    if(DEBUG):
        print(f'date : {date}')
        print(f'img_date : {img_date}')
                
    return img_date

# 이미지 파일 이동 관련
def moveImageFiles(img_list, DEBUG=False):
    count = 0
    img_cnt = len(img_list)
    print(f'Target file count : {img_cnt}')
    for img in img_list:
        img_date = getImageDate(img, DEBUG)
        if DEBUG : print(img_date[0], img_date[1], img)

        # 파일 위치 구분함
        imgPath = img.split('/')
        # 마지막 파일명을 반환
        imgName = imgPath.pop();
        # 파일명 앞 위치를 저장
        imgOrgPath = ('/').join(imgPath);

        if DEBUG : print(f'name= {imgName}, {imgOrgPath}')

        # 새로운 폴더 위치 - 년도 / 월
        dir_path = os.path.join(img_date[0], img_date[1])
        # 원래 파일 위치
        s_path = os.path.join(img)
        # 이동하려는 폴더 위치 - 시작 위치를 기본으로 함
        t_imgPath = os.path.join(cur_dir, dir_path);
        # 이동하려는 폴더와 파일 위치
        t_path = os.path.join(t_imgPath, imgName)

        if DEBUG:
            print(f'dir_path : {dir_path}')
            print(f'Source_path : {s_path}')
            print(f'Target_path : {t_path}')

        # 년도/월 폴더가 있는지 확인 - 없으면 생성
        if not os.path.exists(t_imgPath):
            os.makedirs(t_imgPath)

        # 년도/월 폴더와 파일이 재하는 경우 - (prefix : dup_ 추가)
        if os.path.isfile(t_path) :
            dup_name = duplicatePrefix + imgName
            t_path = os.path.join(t_imgPath, dup_name)

        # 파일 이동
        shutil.move(s_path, t_path)

        print(f'{img} ====> {t_path}')
        count = count+1

    print(f'{count} files moved!')

# 현재 폴더(하위까지 조회하기)
if subfolder:
    for (root, directories, files) in os.walk(cur_dir):
        for file in files:
            file_path = os.path.join(root, file)
            print(f' > file(s) Name: {file_path}')
            
            if os.path.isfile(file_path):
                name,ext = os.path.splitext(file)
                if ext in img_ext:
                    img_list.append(file_path)
                elif ext in mov_ext:
                    mov_list.append(file_path)
                else:
                    etc_list.append(file_path)
            else:
                print(f'[{file_path}] is not File')
else:
    # 현재 폴더만 조회하기
    for file in os.listdir(cur_dir):
        file_path = os.path.join(cur_dir, file)
        if os.path.isfile(file_path):
            name,ext = os.path.splitext(file)
            if ext in img_ext:
                img_list.append(file_path)
            elif ext in mov_ext:
                mov_list.append(file_path)
            else:
                etc_list.append(file_path)
        else:
            print(f'[{file_path}] is not File')

# 결과 조회       
print('====== 최종 결과 ======');
print(f'Working Directory : {cur_dir}');
print(f'{len(img_list)} file(s) detected.')

# 최종 결과 확인
'''
if DEBUG:
    print(f'img_list: {img_list}')
    print(f'mov_list: {mov_list}')
    print(f'etc_list: {etc_list}')
'''
# 실행
moveImageFiles(img_list, DEBUG)

 

저작자표시 비영리 변경금지 (새창열림)
    '난장 Dev/Python' 카테고리의 다른 글
    • Mac - Python 개발 - VSCODE 설정
    • Mac - Python 최신 버전 업데이트
    <난장>
    <난장>
    난장의 이모저모(화순 카페, 전남 카페, 일상)

    티스토리툴바