python读取图片文件名_用Python读取图片的Exif时间给相册图片批量重命名

博主分享了如何使用Python批量修正手机照片的Exif时间信息,因某些旧照片在不同设备间传输导致时间信息丢失或错误。通过读取图片的Exif信息,利用PIL和piexif库进行时间校验与修复,最终实现按拍摄时间正确重命名图片。
摘要由CSDN通过智能技术生成

现代的智能手机拍出来的照片文件默认的命名方式是类似:“IMG_20191201_150800.jpg”这样的结构,但是我发现我手机里好多老照片没有遵循这一命名规则。

不仅前缀五花八门,而且很多老的手机默认不是以日期时间而是以一个递增的序号来命名。强迫症的我无法接受这些乱七八糟的命名,于是我写了一个Python程序来批量对这些图片来重命名。

读取一个图片文件的修改时间有两种方式,一是直接读取文件本身的修改时间,二是读取图像Exif信息中的时间。

第一种方式读取方法最简单,但是有一个很严重的问题:文件的修改时间并没有储存在文件本身,而是储存在磁盘文件系统的文件表里面,当你将一个文件从一个文件系统复制到另一个文件系统的时候,原来的时间戳会丢失:比如说当你把一个图片文件从手机拷贝到电脑或者当你把照片从电脑拷贝到手机的时候,文件的修改时间就会变成文件复制的时间。

所以要对图片文件按时间重命名只能读取Exif里面的信息,因为Exif信息是储存在文件内部的,不会因为拷贝或者通过网络传输而发生变化。

Python读取图片的Exif信息可以使用PIL这个库,读取方法很简单:

defget_exif_time(file):

img=Image.open(file)

date_time=''

try:

exif={

ExifTags.TAGS[k]: v

fork, vinimg._getexif().items()

ifkinExifTags.TAGS

}

date_time=exif['DateTime']

exceptExceptionaserr:

print(err)

print(traceback.format_exc())

date_time=date_time.replace(':','').replace(' ','_').strip()

returndate_time

好了,还是使用上一篇文章中的遍历方法:

defrename_jpg(file,date_time):

new_name='IMG_'+date_time+'.jpg'

new_name=os.path.join(WORK_DIR, new_name)

i=1

whileos.path.exists(new_name):

iffile.lower()==new_name.lower():

return'Not Renamed'

new_name='IMG_'+date_time+'_'+str(i)+'.jpg'

new_name=os.path.join(WORK_DIR, new_name)

i+=1

try:

os.rename(file, new_name)

exceptExceptionaserr:

print(err)

print(traceback.format_exc())

return'ERROR'

returnos.path.split(new_name)[1]

defrename_jpgs():

filecount=0

filetotal=len(glob.glob(JPG_FILTER))

forfileinglob.glob(JPG_FILTER):

filecount+=1

date_time=get_exif_time(file)

ifdate_time=='':

print(os.path.split(file)[1],'No Exif Date','(%d/%d)'%(filecount, filetotal))

else:

new_name=rename_jpg(file, date_time)

print(os.path.split(file)[1],'-->', new_name,'(%d/%d)'%(filecount, filetotal))

重命名比压缩快多了,一杯咖啡没喝完,程序就跑完了。当我点开图片文件夹的时候,我差点把一口咖啡喷到键盘上。

目录里除了有一些无法读取exif信息的图片没有重命名之外,还有大量的图片变成了如下的样子:

IMG_20021208_120000_1.jpg

IMG_20021208_120000_2.jpg

IMG_20021208_120000_3.jpg

IMG_20021208_120000_4.jpg

IMG_20021208_120000_5.jpg

……

……

打开图片一看,WTF! 这些图片的exif信息里的DateTime全都一样:“2002:12:08 12:00:00”

想必这是当年这个手机相机软件的一个BUG,怎么办?

我还得再写一个修复Exif时间的程序!

其实Exif信息里记录时间的Tag不止DateTime这一个,除了我们刚才读取的那个DateTime标签之外还有三个Tag也记录了图片的拍摄时间信息,分别是图像的拍摄时间(DateTimeOriginal)、数字化时间(DateTimeDigitized)和GPS时间。大多数情况下拍摄时间和数字化时间是一样的,这两个选择一个就可以,除此之外,有些文件名也能体现图片的拍摄时间。

我先依次读取图片的“修改时间”、“GPS时间”、“拍摄时间”、“文件名时间”这四个时间,然后用BAD_TIME列表和正则表达式来对读取的时间做校验,如果有效则采用,如果无效则尝试下一个。

思路有了,但是在写代码的时候突然发现PIL库居然不提供编辑EXIF的功能。晕!读都读出来了,为什么不加一个编辑的功能呢?

只好再次求助于度娘,终于找到一个能编辑exif信息的库:piexif。

pip install piexif

……

修复Exif时间的代码如下fixExifTime.py:

importdatetime

importglob

importos

importre

importtraceback

importpiexif

WORK_DIR='D:\\手机相册\\Sony Z1'

JPG_FILTER=os.path.join(WORK_DIR,'*.[jJ][pP][gG]')

deffix_exif_time(file):

BAD_TIME=['2002:12:08 12:00:00']

pattern=r'\d{4}:\d{2}:\d{2}\s\d{2}:\d{2}:\d{2}'

exif_dict={}

try:

exif_dict=piexif.load(file)

if41729inexif_dict['Exif']:

exif_dict['Exif'][41729]=b'1'

exceptExceptionaserr:

print(err)

print(traceback.format_exc())

return'LOAD ERROR'

date_time=''

if'0th'inexif_dict:

if306inexif_dict['0th']:

date_time=exif_dict['0th'][306].decode()

print('Read From 0th', date_time)

ifre.search(pattern, date_time)anddate_timenotinBAD_TIME:

return'Unmodified'

else:

exif_dict['0th'][306]=b''

else:

exif_dict['0th']={}

exif_dict['0th'][306]=b''

ifre.search(pattern, date_time)isNoneordate_timeinBAD_TIME:

if'GPS'inexif_dictand29inexif_dict['GPS']and7inexif_dict['GPS']:

gps_h=exif_dict['GPS'][7][0][0]

gps_m=exif_dict['GPS'][7][1][0]

gps_s=int(exif_dict['GPS'][7][2][0]/exif_dict['GPS'][7][2][1])

if0<=gps_h<=24and0<=gps_m<=60and0<=gps_s<=60:

gps_time=str(str(gps_h)+':'+str(gps_m)+':'+str(gps_s))

else:

gps_time='00:00:00'

date_time=exif_dict['GPS'][29].decode()+' '+gps_time

utc_date=datetime.datetime.strptime(date_time,"%Y:%m:%d%H:%M:%S")

local_date=utc_date+datetime.timedelta(hours=8)

date_time=datetime.datetime.strftime(local_date,'%Y:%m:%d%H:%M:%S')

print('Read From GPS', date_time)

ifre.search(pattern, date_time)isNoneordate_timeinBAD_TIME:

if'Exif'inexif_dictand36867inexif_dict["Exif"]:

date_time=exif_dict["Exif"][36867].decode()

print('Read From Exif', date_time)

ifre.search(pattern, date_time)isNoneordate_timeinBAD_TIME:

pattern2=r'(\d{4})[\-\:\s\_\/]?(1[0-2]|0[1-9])[\-\:\s\_\/]?([1-2]\d|3[0-1]|0[1-9])'

pattern2+=r'[\-\:\s\_\/]?([0-1]\d|2[0-4])[\-\:\s\_\/]?([0-5]\d)[\-\:\s\_\/]?([0-5]\d)'

find=re.search(pattern2, os.path.split(file)[1])

iffind:

date_time='%s:%s:%s%s:%s:%s'%find.groups()

print('Read From FileName', date_time)

ifre.search(pattern, date_time)anddate_timenotinBAD_TIME:

date_time=bytes(date_time,encoding="ascii")

exif_dict["Exif"][36867]=date_time

exif_dict["Exif"][36868]=date_time

exif_dict["0th"][306]=date_time

try:

exif_bytes=piexif.dump(exif_dict)

piexif.insert(exif_bytes,file)

exceptExceptionaserr:

print(os.path.split(file)[1],'Save ERROR!', err)

print(traceback.format_exc())

ifstr(err)=="Given data isn't JPEG.":

print('Del thumbnail')

delexif_dict['thumbnail']

exif_bytes=piexif.dump(exif_dict)

piexif.insert(exif_bytes,file)

returnstr(os.path.getsize(file))

deffix_exifs():

filecount=0

filetotal=len(glob.glob(JPG_FILTER))

forfileinglob.glob(JPG_FILTER):

filesize=os.path.getsize(file)

filecount+=1

new_size=fix_exif_time(file)

print(os.path.split(file)[1], filesize,'-->', new_size,'(%d/%d)'%(filecount, filetotal))

if__name__=='__main__':

fix_exifs()

再跑一遍,OK了!

安卓手机Pydroid 3也能完美运行

强迫症患者终于得到了救赎。

最后附上GitHub的链接:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值