【python初学者日记】用PIL批量给HEIC格式的照片,添加拍摄日期、拍摄地点的水印戳

最近在整理手机相册,发现以前在拍摄的时候,不喜欢给照片带水印,现在想在照片上面打上拍摄时间+地点的水印戳。之前有写过将exl中的内容,添加到照片的功能,所以这次的就简单多了。

问题合集

1、读取 HEIC 格式照片的拍摄信息

2、将已知坐标转码成具体省市地址的文字信息

3、将文字添加到HEIC格式的照片上

问题解决

一、问题分析

1、读取HEIC格式照片的拍摄信息:
现有版本python3.11,用exifread库即可将苹果导出的HEIC格式照片的拍摄信息。
2、将已知坐标转码成具体省市地址的文字信息:
这里我使用的是百度地图调起API,参考说明如图:
在这里插入图片描述传送门: https://lbsyun.baidu.com/index.php?title=uri/api/web
注:此方法无需注册开发者,可以直接使用。
3、将文字添加到HEIC格式的照片上:
这里偷个懒,我之前有写过将exl中的内容,添加到照片的功能,此处稍作修改即可实现功能。

二、代码实现

1、代码如下:

# -*- coding: utf-8 -*-
# 读取图片属性中的拍摄日期,并给图片添加拍摄日期、地点
import datetime
import os

import exifread
import requests
import json

from PIL import Image, ImageDraw, ImageFont, ImageFilter
from pillow_heif import register_heif_opener

register_heif_opener()

# 示例已知经纬度,利用百度地图,输出当前省市等信息
# http://api.map.baidu.com/geocoder?location=30.204891666666665,120.19970833333333&coord_type=gcj02&output=json


my_font = r"C:\Windows\Fonts\SIMYOU.TTF"

startTime_program = datetime.datetime.now()  # 开始时间


# 定义一个换算函数,功能:将输入的度(时)分秒,经过换算,返回度(时)。例如输入[30, 12, 1761/100],返回30.204891666666665
def Conversion(data):
    temp_data = [ele.strip() for ele in (str(data).replace('[', '').replace(']', '').split(','))]
    new_data = eval(temp_data[-1]) / 3600 + int(temp_data[1]) / 60 + int(temp_data[0])
    return new_data


# 在给定的照片中,提取时间戳:仅保留年月日;经纬度:通过在百度api上查找到省市,然后返回”年/月/日 省 市“的值。
def get_stamp(pic):
    # exifread读出的经纬度是列表[度,分,秒],需要转换成单位为度的小数
    # 获取图片拍摄时间
    time = pic['Image DateTime']
    # print(time) # 打印时间戳
    time_stamp = str(time)[0:4] + "/" + str(time)[5:7] + "/" + str(time)[8:10]  # 从拍摄时间中,提取日期
    # print(time_stamp) # 打印新格式的时间戳
    latitude = Conversion(pic['GPS GPSLatitude'])  # 从图片提取纬度并将单位度分秒换算成度
    # print(latitude)  # 打印纬度
    longitude = Conversion(pic['GPS GPSLongitude'])  # 从图片提取经度并将单位度分秒换算成度
    # print(longitude) # 打印经度
    coordinates = str(latitude) + ',' + str(longitude)
    # print(coordinates) # 打印坐标
    query_adStr = "http://api.map.baidu.com/geocoder?location=" + coordinates + "&coord_type=gcj02&output=json"  # 注意此链接,根据百度开发者平台,此处改为以json格式输出,更方便后续解码
    resp = requests.get(query_adStr)  # 向服务器请求数据
    url_text = resp.content.decode()  # 读取源文件字节流,随后将该字节流编码为Unicode编码
    location_data = json.loads(url_text)  # 用于解码 JSON 数据。该函数返回 Python 字段的数据类型
    address = location_data.get('result').get(
        'addressComponent')  # 在代码中找到addressComponent字段,此条可去浏览器粘贴链接查看:http://api.map.baidu.com/geocoder?location=30.204891666666665,120.19970833333333&coord_type=gcj02
    province = address.get('province')  # 从获取的地址信息中,找到省份的值
    city = address.get('city')  # 从获取的地址信息中,找到城市的值
    stamp = str(time_stamp) + '\n' + ' ' + str(province[:-1]) + ' ' + str(city[:-1])  # 将时间戳、地址戳按格式整合
    return stamp  # 返回新戳


# 定义在已给地址批量读图的信息,并存到数组里,并返回数组.修正:改为字典方式输出,即文件路径名:stamp
def pics_add_stamps(path):
    stamps = {}
    for each_pic in os.listdir(path):
        if os.path.splitext(each_pic)[1] == '.heic':
            each_pic_Path = path + "\\" + each_pic
            pic_data = exifread.process_file(open(each_pic_Path, 'rb'))
            temp_stamp = get_stamp(pic_data)
            stamp_key = each_pic_Path
            stamp_data = temp_stamp
            stamps[stamp_key] = stamp_data
    return stamps


# 读照片,并将提取到的时间位置信息,加到照片上,并存到新的文件夹
def deal_pic_1by1(pic, text, pic_newPath):
    # 打开初始图片
    image = Image.open(pic)
    # 设置字体
    size = 100  # 定义字体大小
    font = ImageFont.truetype(my_font, size)  # 设置字体的格式、大小
    # 创建Draw对象:
    draw = ImageDraw.Draw(image)
    # 计算文字要放置的位置:image.size:像素(宽,高);image.size[0]是指照片的宽,即距离左边最大水平距离;image.size[1]是指照片的高,即距离上边最大垂直距离
    site_x = image.size[0] - 650  # 距离左边水平距离:650像素(自定义,可根据自己喜好调整)
    site_y = image.size[1] - 320  # 距离上边垂直距离:320像素(自定义,可根据自己喜好调整)
    site = (site_x, site_y)  # 距离左上角距离

    # 输出文字(可以连续写入):
    draw.text(site, text, font=font, fill='#fff')  # 设置放置位置、文本内容、字体、颜色
    # 模糊并保存:
    image.filter(ImageFilter.BLUR)

    namePath = os.path.basename(pic)

    if not os.path.exists(pic_newPath):  # 判断存放图片的文件夹是否存在
        os.makedirs(pic_newPath)  # 若图片文件夹不存在就创建
    # 两种方式保存:
    # image.save(pic_newPath + "/" + namePath)  # 以默认的图片格式来存储:保留原图所有信息,但是会压缩文件大小,文件保存时间和原图拍摄保存的时间一致
    image.save(pic_newPath + "/" + namePath,
               "PNG")  # 缺省原图大部分信息,如拍照时间地点等,生成新的图片,由于save不能直接将heic转换为其他格式,所以保存的格式仍然是和原图一样,heic


if __name__ == "__main__":

    pic_path = r"F:\qin_ipad_pic"  # 待处理的图片所在路径
    pic_path_new = f"F:\\qin_ipad_pic\\qin_ipad_pic-NEW"  # 处理好的图片要保存的路径

    n = 0
    i = 1
    # 将pic_path路径下的heic照片提取信息,返回值保存到pic_stamps,类型是字典{图片1路径:图片1时间戳+地点戳;图片2路径:图片2时间戳+地点戳,...}
    pic_stamps = pics_add_stamps(pic_path)
    # print("pic_stamps的类型是:", type(pic_stamps))
    for item in pic_stamps:
        data = pic_stamps.get(item)  # dict.get(item)
        deal_pic_1by1(item, data, pic_path_new)
        n += 1

    print('共有{}个HEIC文件'.format(n))

endTime_program = datetime.datetime.now()  # 结束时间
print('本次处理照片一共用了:%0.2f秒' % (endTime_program - startTime_program).seconds)

2、运行结果如下:
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 可以使用PythonPIL库(Python Imaging Library)来读取照片的Exif信息,其中包含了照片拍摄日期。然后可以使用shutil库来将照片移动到对应的文件夹中,以实现按拍摄日期整理分类。 以下是一个简单的示例代码: ```python import os import shutil from PIL import Image # 遍历指定目录下的所有照片文件 for filename in os.listdir('path/to/photos'): if filename.endswith('.jpg') or filename.endswith('.jpeg'): filepath = os.path.join('path/to/photos', filename) # 读取照片的Exif信息 with Image.open(filepath) as img: exif = img._getexif() if exif: # 获取拍摄日期 date_str = exif.get(36867) if date_str: # 将日期格式化为yyyy-mm-dd date = '-'.join(date_str.split(' ')[0].split(':')) # 创建目标文件夹并移动照片 target_dir = os.path.join('path/to/sorted_photos', date) os.makedirs(target_dir, exist_ok=True) shutil.move(filepath, os.path.join(target_dir, filename)) ``` 在上述代码中,`path/to/photos`是存放原始照片的目录,`path/to/sorted_photos`是存放按拍摄日期整理分类后的照片的目录。通过遍历原始照片目录下的所有照片文件,并读取其Exif信息,获取照片拍摄日期,然后将照片移动到以拍摄日期为名称的目录中。如果目标文件夹不存在,则会自动创建。 ### 回答2: 使用Python照片进行按拍摄日期整理分类可通过以下步骤实现: 1. 导入所需的Python模块,如os、shutil等。 2. 使用os模块获取文件夹中的所有文件。 3. 循环遍历每个文件,使用os.path模块获取文件的创建时间或修改时间。 4. 转换时间格式为指定的年月日格式。 5. 创建以年月日为名称的文件夹,通过os模块创建文件夹。 6. 使用shutil模块将文件移动到对应的年月日文件夹中。 7. 完成整理分类后,输出提示信息。 下面是一个简单的示例代码: ```python import os import shutil # 获取文件夹路径 folder_path = "照片文件夹路径" # 遍历文件夹中的文件 for filename in os.listdir(folder_path): # 获取文件的创建时间 creation_time = os.path.getctime(os.path.join(folder_path, filename)) # 转换时间格式为年月日 date = time.strftime("%Y%m%d", time.localtime(creation_time)) # 创建以年月日为名称的文件夹 new_folder_path = os.path.join(folder_path, date) os.makedirs(new_folder_path, exist_ok=True) # 移动文件到对应的文件夹中 shutil.move(os.path.join(folder_path, filename), os.path.join(new_folder_path, filename)) print("照片已按拍摄日期整理分类完成!") ``` 需要注意的是,以上示例代码的前提是照片文件的元数据中包含了拍摄日期信息,如果照片文件没有拍摄日期信息,可以使用其他方式来获取拍摄日期,例如根据文件名或其他标识信息来判断和分类。 ### 回答3: 使用Python照片拍摄日期进行整理分类是非常简单的。首先,我们需要安装PIL库来处理图像。 首先,我们需要通过使用PIL库中的`Image.open()`函数打开图片文件。然后,我们可以使用`_getexif()`方法获取图像的元数据,其中包含了拍摄日期等信息。接下来,我们可以使用`DateTimeOriginal`键来提取拍摄日期。 接下来,我们可以使用`os`库的一些函数来创建和移动目录。首先,我们需要将所有图片移动到同一个文件夹中,然后创建一个用于存储分类后的照片的目录。 接下来,我们可以使用`glob`库的函数来获取所有文件夹中的照片文件。然后,我们可以使用之前获得的拍摄日期来将这些照片分类。 最后,我们可以使用`shutil`库的`move()`函数将每张照片移动到相应的目录中。 下面是一个简单的示例代码: ``` import os import glob import shutil from PIL import Image # 创建一个目录来存储分类后的照片 output_directory = '分类后的照片' os.makedirs(output_directory, exist_ok=True) # 获取所有的照片文件 photo_files = glob.glob('*.jpg') for photo_file in photo_files: photo = Image.open(photo_file) exif_data = photo._getexif() # 从元数据中获取拍摄日期 if 36867 in exif_data: capture_date = exif_data[36867] # 将日期格式化为年份和月份 year = capture_date[:4] month = capture_date[5:7] # 创建分类后的目录 output_directory_year = os.path.join(output_directory, year) output_directory_month = os.path.join(output_directory_year, month) os.makedirs(output_directory_year, exist_ok=True) os.makedirs(output_directory_month, exist_ok=True) # 移动照片到分类后的目录中 shutil.move(photo_file, output_directory_month) ``` 以上就是使用Python照片拍摄日期进行整理分类的简单示例代码。请注意,在使用之前,你需要将示例代码中的`*.jpg`替换为你照片的文件名模式,并确保你已经安装了相关的库。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值