[Python] jpg, jpeg Exif 정보에서 촬영 날짜 추출하기. (Big Endian, Little Endian 이미지)
PIL이나 기타 모듈을 사용하지 않고, jpg Exif에서 직접 촬영 날짜를 추출
Big Endian인지 Little Endian인지에 따라 tag의 byte 순서가 바뀐다! 주의 필요!
두 가지 Endian 형식 이미지 첨부
intel.jpg
0.04MB
motorola.jpg
0.15MB
코드 문제점:
프로그램 개요:
import os
# byte를 십진수로 변경
def bytes_to_decimal(ifd_offset_bytes,big_endian):
if big_endian:
ifd_offset = int.from_bytes(ifd_offset_bytes, byteorder='big') # motorola
else:
ifd_offset = int.from_bytes(ifd_offset_bytes, byteorder='little') # intel
return ifd_offset
# 문자가 숫자인지 검사
def is_numeric_string(text):
for char in text:
if not (48 <= ord(char) <= 57): # ASCII 코드에서 숫자 범위는 48부터 57까지입니다.
return False
return True
# jpg에서 exif header에서 촬영 날짜 추출
def get_date_from_jpg(file_path):
with open(file_path, 'rb') as f:
data = f.read()
# Find SOI marker
soi_marker = data.find(b'\xFF\xD8')
if soi_marker>=0:
# JIFF에서 APP0 마커 영역을 사용함. 그래서 Exif Format에서 APP1(마커 번호 0xFFE1)을 사용함
# https://nightohl.tistory.com/entry/EXIF-Format
# https://exiftool.org/TagNames/EXIF.html
# Find APP1 marker
app1_marker = data.find(b'\xFF\xE1', soi_marker)
# exif_marker = data.find(b'\xFF\xE1')
if app1_marker ==-1:
return None
# Check for EXIF identifier code
if data[app1_marker + 4:app1_marker + 10] == b'Exif\x00\x00':
tiff_offset = app1_marker + 10
# Check the byte order
# tiff_offset is starting point of offset !
byte_allign=data[tiff_offset:tiff_offset + 2]
if byte_allign == b'\x4D\x4D':
big_endian = True
elif byte_allign == b'\x49\x49':
big_endian = False
else:
return None
# 썸네일까지 포함인가?
app1_size = bytes_to_decimal(data[app1_marker+2:app1_marker+4],big_endian)
# print(app1_size)
# data.find(b'\xFF\xE1', soi_marker)
app1_number_entry=bytes_to_decimal(data[tiff_offset+8:tiff_offset+10],big_endian)
# # ifd0 출력
# ifd0_size=app1_number_entry*12
# ifd0_start=tiff_offset+10
# for i in range(ifd0_start,ifd0_start+app1_number_entry*12,12):
# print(i,data[i:i+12])
# print(bytes_to_decimal(data[i:i+2],big_endian),
# bytes_to_decimal(data[i+2:i+4],big_endian),
# bytes_to_decimal(data[i+4:i+8],big_endian),
# bytes_to_decimal(data[i+8:i+12],big_endian),
# end='')
# print('\n')
# # hex_data = ''.join([hex(byte)[2:].zfill(2) for byte in data[i:i+12]])
# # print(hex_data[0:4],hex_data[4:8],hex_data[8:16],hex_data[16:24])
# Find the DateTimeOriginal tag (Tag ID: 0x9003)
# component is 1byte from format:02
if big_endian:
tag_id_bytes = b'\x90\x03' # motorola
else:
tag_id_bytes = b'\x03\x90' # intel
# app1_size내에서 tag 찾는다.
tag_offset=data.find(tag_id_bytes,tiff_offset,app1_size-4)
# print('tag offset:',tag_offset)
if tag_offset==-1:
return None
# component
DateTimeOriginal_componet_byte=data[tag_offset+4:tag_offset+8]
DateTimeOriginal_componet=bytes_to_decimal(DateTimeOriginal_componet_byte,big_endian)
DateTimeOriginal_componet_size=DateTimeOriginal_componet*1 # 1byte
# offset
DateTimeOriginal_offset_byte=data[tag_offset+8:tag_offset+12]
DateTimeOriginal_offset=bytes_to_decimal(DateTimeOriginal_offset_byte,big_endian)
# 12칸 뒤에 원하는 값이 있음
# 끝에서 \x00 제외
DateTimeOriginal_byte=data[tiff_offset+DateTimeOriginal_offset:tiff_offset+DateTimeOriginal_offset+DateTimeOriginal_componet-1]
DateTimeOriginal=DateTimeOriginal_byte.decode('utf-8')
DateTimeOriginal=DateTimeOriginal.replace(":","")
DateTimeOriginal_filename=DateTimeOriginal.replace(" ","_")+'.jpg'
picture_date=DateTimeOriginal_filename[:8]
picture_time=DateTimeOriginal_filename[9:14]
if is_numeric_string(picture_date) and is_numeric_string(picture_time):
return DateTimeOriginal_filename
return None
# 중복 이름 수정
def duplicate_name_check(filename):
# 변경할 파일 이름이 이미 존재하는지 확인
if os.path.exists(filename):
# 존재하는 경우에는 "_1"을 추가하여 새로운 이름 생성
base_name, extension = os.path.splitext(filename)
new_name = f'{base_name}_1{extension}'
new_name=duplicate_name_check(new_name)
return new_name
return filename
# jpg 이름 수정
def jpg_rename(file_path):
filename=get_date_from_jpg(file_path)
if filename == file_path:
print('SAME:', file_path)
elif filename != None:
new_name=duplicate_name_check(filename)
print("OK:", file_path, new_name)
os.rename(file_path, new_name)
else:
pass
print("HOLDING(head error):", file_path)
# *.jpg
def jpg_filelist():
# 현재 작업 디렉토리
directory = os.getcwd()
# 현재 디렉토리에서 모든 파일 및 디렉토리 목록 가져오기
all_files = os.listdir(directory)
# .jpg 파일 필터링 및 출력
jpg_files = [file for file in all_files if file.endswith(".jpg")]
return jpg_files
def main():
for jpg_file in jpg_filelist():
jpg_rename(jpg_file)
if __name__ == "__main__":
main()
[Python] 카카오톡(카톡)에서 받은 jpg 이미지 파일명 변경 (0) | 2023.07.21 |
---|
댓글 영역