Python给照片添加水印时间和地点 Mac OS

您所在的位置:网站首页 苹果11照片上怎么才能显示时间和地点 Python给照片添加水印时间和地点 Mac OS

Python给照片添加水印时间和地点 Mac OS

2024-07-16 20:47| 来源: 网络整理| 查看: 265

这里写目录标题 效果需要用到的模块处理步骤以及代码讲解1、获得照片的拍摄时间2、获取拍照地点3、图片转正4、 添加水印 完整代码 我们平时想打印图片的时候,希望能给照片加上时间、地点,以便以后看到照片的时候不会忘记。 手工一张张添加太麻烦,而且容易出错。以下是使用代码获取原始图片的拍摄时间和地点,并添加水印的方法,在Mac OS下对jpeg、jpg文件处理已经测试通过了。

效果

首先我们看下效果,第一张是原图,第二张是添加水印时间和地点后的图:在这里插入图片描述 在这里插入图片描述

需要用到的模块

exifread PIL requests json

处理步骤以及代码讲解 1、获得照片的拍摄时间

这里我们需要用到exifread模块以获取照片的拍照时间。1

def getPhotoTime(filename): '''得到照片的拍照时间(如果获取不到拍照时间,则使用文件的创建时间) ''' try: if os.path.isfile(filename): fd = open(filename, 'rb') else: raise "[%s] is not a file!\n" % filename except: raise "unopen file[%s]\n" % filename #默认用图像文件的创建日期作为拍摄日期(如果有照片的拍摄日期,则修改为拍摄日期 state = os.stat(filename) dateStr = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(state[-2])) data = exifread.process_file( fd ) if data: #取得照片的拍摄日期,改为拍摄日期 try: t = data['EXIF DateTimeOriginal'] #转换成 yyyy-mm-dd_hh:mm:ss的格式 dateStr = str(t).replace(":","-")[:10] + str(t)[10:] except: pass return dateStr 2、获取拍照地点

这里我们依然要用到exifread模块以获取照片的拍照的经纬度,在使用baidu的api逆地理编码得到对应的具体位置。2 注意在使用baidu的api之前需要去百度地图开放平台注册账号,申请secret_key,可以参考别人的申请ak3。

def format_lat_lng(data): '将exif得到的经纬度转化成数值, 这个有点笨重' list_tmp=str(data).replace('[', '').replace(']', '').split(',') l= [ele.strip() for ele in list_tmp] data_sec = int(l[-1].split('/')[0]) /(int(l[-1].split('/')[1])*3600)# 秒的值 data_minute = int(l[1])/60 data_degree = int(l[0]) result=data_degree + data_minute + data_sec return result def getLocationBy_lat_lng(lat, lng): """ 使用Geocoding API把经纬度坐标转换为结构化地址。需要注册baidu map api的key """ secret_key = 'XXXXX你得ak密钥' # 请修改这里 # 使用说明http://lbsyun.baidu.com/index.php?title=webapi/guide/webservice-geocoding-abroad baidu_map_api = 'http://api.map.baidu.com/reverse_geocoding/v3/?ak={0}&output=json&coordtype=wgs84ll&location={1},{2}'.format( secret_key, lat, lng) response = requests.get(baidu_map_api) content = response.text baidu_map_address = json.loads(content) formatted_address = baidu_map_address["result"]["formatted_address"] return formatted_address def getLocation(filename): '得到照片的拍照位置(如果获取不到,则为空字符串)' try: if os.path.isfile(filename): fd = open(filename, 'rb') else: raise "[%s] is not a file!\n" % filename except: raise "unopen file[%s]\n" % filename # 图像文件的拍摄地址默认为空 locationStr= '' data = exifread.process_file( fd ) if data: #取得照片的拍摄位置 try: lat= format_lat_lng(data['GPS GPSLatitude']) # [34, 12, 9286743/200000] -> xx.xxxxx lng= format_lat_lng(data['GPS GPSLongitude']) # [108, 57, 56019287/1000000] -> xx.xxxx locationStr= getLocationBy_lat_lng(lat, lng) except: pass return locationStr 3、图片转正

对于手机、相机等设备拍摄的照片,由于手持方向的不同,拍出来的照片可能是旋转0°、90°、180°和270°。即使在电脑上利用软件将其转正,他们的exif信息中还是会保留方位信息。 在用PIL读取这些图像时,读取的是原始数据,也就是说,即使电脑屏幕上显示是正常的照片,用PIL读进来后,也可能是旋转的图像,并且图片的size也可能与屏幕上的不一样。 对于这种情况,可以利用PIL读取exif中的orientation信息,然后根据这个信息将图片转正后,再进行后续操作,具体如下。4

def orientate(img): '''利用PIL读取exif中的orientation信息,然后根据这个信息将图片转正后,再进行后续操作 ''' try: orientation= None for i in ExifTags.TAGS.keys() : if ExifTags.TAGS[i]=='Orientation' : # 肯定会找到orientation,所以不需要对None做处理 orientation= i break exif=dict(img._getexif().items()) if exif[orientation] == 3 : img=img.rotate(180, expand = True) elif exif[orientation] == 6 : img=img.rotate(270, expand = True) elif exif[orientation] == 8 : img=img.rotate(90, expand = True) except: pass return img 4、 添加水印

最后是添加水印,这一步是将上面的步骤整合起来,做处理。 这一步根据不同的图片需要调整字体大小(size),字体位置(d_width,d_height)和字体填充颜色(fillcolor)。5

def add_watermark(filename, text): '为照片文件添加水印,filename是照片文件名,text是水印时间和位置' # 创建输出文件夹 outdir= 'watermark/' mymkdir(outdir) # 创建绘画对象 image= Image.open(filename) image= orientate(image) # 将图片转正 draw= ImageDraw.Draw(image) width, height= image.size # 宽度,高度 size= int(0.04*width) # 字体大小(可以调整0.04) myfont= ImageFont.truetype('/Library/Fonts/Arial Unicode.ttf', size=size) # 80, 4032*3024 #fillcolor= '#000000' # RGB黑色 fillcolor= '#fbfafe' # 参数一:位置(x轴,y轴);参数二:填写内容;参数三:字体;参数四:颜色 d_width, d_height=0.5*width, 0.92*height # 字体的相对位置(0.5, 0.92可以根据图片调整) draw.text((d_width, d_height), text, font=myfont, fill=fillcolor) # (-1200, -320) new_filename= get_new_filename(filename) image.save(outdir + new_filename) 完整代码

以下是完整代码,并附上github的链接(链接中有原始的示例图片)。

''' 批量给图片增加时间水印的Python脚本程序【目前测试为Mac OS X下的jpeg文件】。 遍历指定目录(含子目录)的照片文件,根据拍照时间给照片在右下角添加时间和地点的水印。 !该程序需要安装exifread,PIL,requests等模块,否则无法使用。 例如,Linux/Mac OS X下命令行安装该模块:sudo pip install exifread !该程序需要加baidu api的secret_key(在getLocationBy_lat_lng函数中); !该程序可以手动调整字体大小(size),字体位置(d_width,d_height)和字体填充颜色(fillcolor)(在add_watermark函数中)。 获取拍照时间 From 'https://www.racksam.com/2014/05/14/python-script-to-change-pictures-filenames/' 拍照地点 参考 http://lbsyun.baidu.com/index.php?title=webapi/guide/webservice-geocoding-abroad watermark 参考 https://blog.csdn.net/weixin_30561177/article/details/97609897 orientation 参考 https://blog.csdn.net/mizhenpeng/article/details/82794112 ''' #!/usr/bin/env python # -*- coding: utf-8 -*- import os import stat import time import math import exifread from PIL import Image, ImageDraw, ImageFont, ExifTags import requests import json '=================分割线===================' # 创建文件夹 def mymkdir(path): if not os.path.exists(path): os.mkdir(path) # 判断是否是支持的文件类型 SUFFIX_FILTER = ['.jpg','.png','.mpg','.mp4','.thm','.bmp','.jpeg','.avi','.mov'] # 仅测试了jpeg,jpg def isTargetedFileType(filename): '根据文件扩展名,判断是否是需要处理的文件类型;仅支持x.x格式' filename_nopath = os.path.basename(filename) f,e = os.path.splitext(filename_nopath) if e.lower() in SUFFIX_FILTER: return True else: return False # 新文件的名字 def get_new_filename(filename): f, e= filename.split('.') return "%s_watermark.%s" % (f, e) '=================分割线===================' '=================begin{得到照片的拍摄时间}===================' def getPhotoTime(filename): '''得到照片的拍照时间(如果获取不到拍照时间,则使用文件的创建时间) ''' try: if os.path.isfile(filename): fd = open(filename, 'rb') else: raise "[%s] is not a file!\n" % filename except: raise "unopen file[%s]\n" % filename #默认用图像文件的创建日期作为拍摄日期(如果有照片的拍摄日期,则修改为拍摄日期 state = os.stat(filename) dateStr = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(state[-2])) data = exifread.process_file( fd ) if data: #取得照片的拍摄日期,改为拍摄日期 try: t = data['EXIF DateTimeOriginal'] #转换成 yyyy-mm-dd_hh:mm:ss的格式 dateStr = str(t).replace(":","-")[:10] + str(t)[10:] except: pass return dateStr '=================end{得到照片的拍摄时间}===================' '=================begin{得到照片的拍摄地点}===================' def format_lat_lng(data): '将exif得到的经纬度转化成数值, 这个有点笨重' list_tmp=str(data).replace('[', '').replace(']', '').split(',') l= [ele.strip() for ele in list_tmp] data_sec = int(l[-1].split('/')[0]) /(int(l[-1].split('/')[1])*3600)# 秒的值 data_minute = int(l[1])/60 data_degree = int(l[0]) result=data_degree + data_minute + data_sec return result def getLocationBy_lat_lng(lat, lng): """ 使用Geocoding API把经纬度坐标转换为结构化地址。需要注册baidu map api的key """ secret_key = 'XXXXX你得ak密钥' # 请修改这里 # 使用说明http://lbsyun.baidu.com/index.php?title=webapi/guide/webservice-geocoding-abroad baidu_map_api = 'http://api.map.baidu.com/reverse_geocoding/v3/?ak={0}&output=json&coordtype=wgs84ll&location={1},{2}'.format( secret_key, lat, lng) response = requests.get(baidu_map_api) content = response.text baidu_map_address = json.loads(content) formatted_address = baidu_map_address["result"]["formatted_address"] return formatted_address def getLocation(filename): '得到照片的拍照位置(如果获取不到,则为空字符串)' try: if os.path.isfile(filename): fd = open(filename, 'rb') else: raise "[%s] is not a file!\n" % filename except: raise "unopen file[%s]\n" % filename # 图像文件的拍摄地址默认为空 locationStr= '' data = exifread.process_file( fd ) if data: #取得照片的拍摄位置 try: lat= format_lat_lng(data['GPS GPSLatitude']) # [34, 12, 9286743/200000] -> xx.xxxxx lng= format_lat_lng(data['GPS GPSLongitude']) # [108, 57, 56019287/1000000] -> xx.xxxx locationStr= getLocationBy_lat_lng(lat, lng) except: pass return locationStr '=================end{得到照片的拍摄地点}===================' def orientate(img): '''对于手机、相机等设备拍摄的照片,由于手持方向的不同,拍出来的照片可能是旋转0°、90°、180°和270°。即使在电脑上利用软件将其转正,他们的exif信息中还是会保留方位信息。 在用PIL读取这些图像时,读取的是原始数据,也就是说,即使电脑屏幕上显示是正常的照片,用PIL读进来后,也可能是旋转的图像,并且图片的size也可能与屏幕上的不一样。 对于这种情况,可以利用PIL读取exif中的orientation信息,然后根据这个信息将图片转正后,再进行后续操作,具体如下。 ''' try: orientation= None for i in ExifTags.TAGS.keys() : if ExifTags.TAGS[i]=='Orientation' : # 肯定会找到orientation,所以不需要对None做处理 orientation= i break exif=dict(img._getexif().items()) if exif[orientation] == 3 : img=img.rotate(180, expand = True) elif exif[orientation] == 6 : img=img.rotate(270, expand = True) elif exif[orientation] == 8 : img=img.rotate(90, expand = True) except: pass return img def add_watermark(filename, text): '为照片文件添加水印,filename是照片文件名,text是水印时间和位置' # 创建输出文件夹 outdir= 'watermark/' mymkdir(outdir) # 创建绘画对象 image= Image.open(filename) image= orientate(image) # 将图片转正 draw= ImageDraw.Draw(image) width, height= image.size # 宽度,高度 size= int(0.04*width) # 字体大小(可以调整0.04) myfont= ImageFont.truetype('/Library/Fonts/Arial Unicode.ttf', size=size) # 80, 4032*3024 #fillcolor= '#000000' # RGB黑色 fillcolor= '#fbfafe' # 参数一:位置(x轴,y轴);参数二:填写内容;参数三:字体;参数四:颜色 d_width, d_height=0.5*width, 0.92*height # 字体的相对位置(0.5, 0.92可以根据图片调整) draw.text((d_width, d_height), text, font=myfont, fill=fillcolor) # (-1200, -320) new_filename= get_new_filename(filename) image.save(outdir + new_filename) def scandir(startdir): '遍历指定目录,对满足条件的文件进行改名或删除处理' os.chdir(startdir) # 改变当前工作目录 for obj in os.listdir(os.curdir) : if os.path.isfile(obj): if isTargetedFileType(obj): # 对满足过滤条件的文件,加时间和地点水印 photoTime = getPhotoTime(obj) # 获得照片的拍摄时间,当作水印的内容 location= getLocation(obj) # 获得照片的拍摄位置,当作水印的内容 print("%s %s" % (obj, photoTime+' '+location)) add_watermark(obj, location +'\n'+ photoTime) #加时间和地点水印 if __name__ == "__main__": path = "./fig" # 照片位置 scandir(path)

https://www.racksam.com/2014/05/14/python-script-to-change-pictures-filenames/ ↩︎

http://lbsyun.baidu.com/index.php?title=webapi/guide/webservice-geocoding-abroad ↩︎

https://www.jianshu.com/p/6ad61317d988 ↩︎

https://blog.csdn.net/mizhenpeng/article/details/82794112 ↩︎

https://blog.csdn.net/weixin_30561177/article/details/97609897 ↩︎



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3