Python案例如何用Pillow读取EXIF信息

wen python案例 1

本文目录导读:

Python案例如何用Pillow读取EXIF信息

  1. 基础读取方法
  2. 使用EXIF标签名称读取
  3. 读取常用EXIF信息
  4. 读取GPS位置信息
  5. 完整的EXIF读取工具类
  6. 批量处理多个图片
  7. 注意事项

我来详细说明如何使用Pillow(PIL)读取图片的EXIF信息。

基础读取方法

from PIL import Image
# 打开图片
img = Image.open('example.jpg')
# 获取EXIF信息
exif_data = img._getexif()
if exif_data:
    print("EXIF信息:")
    for tag_id, value in exif_data.items():
        print(f"Tag {tag_id}: {value}")
else:
    print("该图片没有EXIF信息")

使用EXIF标签名称读取

from PIL import Image
from PIL.ExifTags import TAGS
def get_exif_info(image_path):
    """获取图片的EXIF信息,使用可读的标签名称"""
    img = Image.open(image_path)
    exif_data = img._getexif()
    if not exif_data:
        print("没有EXIF信息")
        return None
    exif_info = {}
    for tag_id, value in exif_data.items():
        # 获取标签名称
        tag_name = TAGS.get(tag_id, tag_id)
        exif_info[tag_name] = value
    return exif_info
# 使用示例
image_path = 'photo.jpg'
exif_info = get_exif_info(image_path)
if exif_info:
    for key, value in exif_info.items():
        print(f"{key}: {value}")

读取常用EXIF信息

from PIL import Image
from PIL.ExifTags import TAGS, GPSTAGS
def get_common_exif_info(image_path):
    """获取常用的EXIF信息"""
    img = Image.open(image_path)
    exif_data = img._getexif()
    if not exif_data:
        return {}
    info = {}
    for tag_id, value in exif_data.items():
        tag_name = TAGS.get(tag_id, tag_id)
        # 提取常用信息
        if tag_name == "Make":  # 相机制造商
            info['camera_make'] = value
        elif tag_name == "Model":  # 相机型号
            info['camera_model'] = value
        elif tag_name == "DateTime":  # 拍摄时间
            info['datetime'] = value
        elif tag_name == "ExifImageWidth":  # 图片宽度
            info['width'] = value
        elif tag_name == "ExifImageLength":  # 图片高度
            info['height'] = value
        elif tag_name == "ISOSpeedRatings":  # ISO值
            info['iso'] = value
        elif tag_name == "FNumber":  # 光圈值
            info['aperture'] = float(value)
        elif tag_name == "ExposureTime":  # 曝光时间
            info['exposure_time'] = str(value)
        elif tag_name == "FocalLength":  # 焦距
            info['focal_length'] = float(value)
        elif tag_name == "GPSInfo":  # GPS信息
            gps_info = {}
            for gps_tag_id, gps_value in value.items():
                gps_tag_name = GPSTAGS.get(gps_tag_id, gps_tag_id)
                gps_info[gps_tag_name] = gps_value
            info['gps_info'] = gps_info
    return info
# 使用示例
info = get_common_exif_info('photo.jpg')
print("常用EXIF信息:")
for key, value in info.items():
    print(f"{key}: {value}")

读取GPS位置信息

from PIL import Image
from PIL.ExifTags import TAGS, GPSTAGS
def get_gps_coordinates(image_path):
    """从EXIF中提取GPS坐标"""
    def convert_to_degrees(value):
        """将GPS坐标格式转换为十进制度数"""
        d, m, s = value
        return d + (m / 60.0) + (s / 3600.0)
    img = Image.open(image_path)
    exif_data = img._getexif()
    if not exif_data:
        return None
    gps_info = {}
    for tag_id, value in exif_data.items():
        tag_name = TAGS.get(tag_id, tag_id)
        if tag_name == "GPSInfo":
            for gps_tag_id, gps_value in value.items():
                gps_tag_name = GPSTAGS.get(gps_tag_id, gps_tag_id)
                gps_info[gps_tag_name] = gps_value
    if not gps_info:
        return None
    # 提取经纬度
    try:
        lat = convert_to_degrees(gps_info.get('GPSLatitude', [0, 0, 0]))
        lon = convert_to_degrees(gps_info.get('GPSLongitude', [0, 0, 0]))
        # 处理南北纬和东西经
        if gps_info.get('GPSLatitudeRef') == 'S':
            lat = -lat
        if gps_info.get('GPSLongitudeRef') == 'W':
            lon = -lon
        return {'latitude': lat, 'longitude': lon}
    except:
        return None
# 使用示例
coordinates = get_gps_coordinates('photo.jpg')
if coordinates:
    print(f"纬度: {coordinates['latitude']}")
    print(f"经度: {coordinates['longitude']}")
    print(f"Google Maps: https://maps.google.com/?q={coordinates['latitude']},{coordinates['longitude']}")

完整的EXIF读取工具类

from PIL import Image
from PIL.ExifTags import TAGS, GPSTAGS
from datetime import datetime
class ExifReader:
    """EXIF信息读取器"""
    def __init__(self, image_path):
        self.image_path = image_path
        self.exif_data = self._load_exif()
    def _load_exif(self):
        """加载EXIF数据"""
        try:
            img = Image.open(self.image_path)
            return img._getexif()
        except:
            return None
    def get_raw_exif(self):
        """获取原始EXIF数据"""
        if not self.exif_data:
            return {}
        return {TAGS.get(tag_id, tag_id): value 
                for tag_id, value in self.exif_data.items()}
    def get_camera_info(self):
        """获取相机信息"""
        if not self.exif_data:
            return {}
        camera_info = {}
        for tag_id, value in self.exif_data.items():
            tag_name = TAGS.get(tag_id, tag_id)
            if tag_name in ['Make', 'Model', 'Software']:
                camera_info[tag_name] = value
        return camera_info
    def get_photo_settings(self):
        """获取拍摄设置"""
        if not self.exif_data:
            return {}
        settings = {}
        for tag_id, value in self.exif_data.items():
            tag_name = TAGS.get(tag_id, tag_id)
            if tag_name in ['ISOSpeedRatings', 'FNumber', 
                          'ExposureTime', 'FocalLength', 'Flash']:
                settings[tag_name] = value
        # 格式化的曝光时间
        if 'ExposureTime' in settings:
            exp_time = settings['ExposureTime']
            if isinstance(exp_time, tuple) and len(exp_time) == 2:
                settings['ExposureTime_str'] = f"{exp_time[0]}/{exp_time[1]}s"
        return settings
    def get_datetime(self):
        """获取拍摄时间"""
        if not self.exif_data:
            return None
        for tag_id, value in self.exif_data.items():
            tag_name = TAGS.get(tag_id, tag_id)
            if tag_name == 'DateTime':
                return value
        return None
    def has_gps(self):
        """检查是否有GPS信息"""
        if not self.exif_data:
            return False
        for tag_id in self.exif_data:
            tag_name = TAGS.get(tag_id, tag_id)
            if tag_name == 'GPSInfo':
                return True
        return False
# 使用示例
reader = ExifReader('photo.jpg')
print("=== 相机信息 ===")
print(reader.get_camera_info())
print("\n=== 拍摄设置 ===")
print(reader.get_photo_settings())
print("\n=== 拍摄时间 ===")
print(reader.get_datetime())
print("\n=== 是否有GPS信息 ===")
print(reader.has_gps())

批量处理多个图片

import os
from PIL import Image
from PIL.ExifTags import TAGS
def batch_extract_exif(folder_path, output_file='exif_info.txt'):
    """批量提取文件夹中所有图片的EXIF信息"""
    results = []
    for filename in os.listdir(folder_path):
        if filename.lower().endswith(('.jpg', '.jpeg', '.tiff', '.tif')):
            file_path = os.path.join(folder_path, filename)
            try:
                img = Image.open(file_path)
                exif_data = img._getexif()
                if exif_data:
                    info = {'filename': filename}
                    for tag_id, value in exif_data.items():
                        tag_name = TAGS.get(tag_id, tag_id)
                        if tag_name in ['Make', 'Model', 'DateTime']:
                            info[tag_name] = value
                    results.append(info)
                else:
                    results.append({'filename': filename, 'exif': 'No EXIF data'})
            except Exception as e:
                results.append({'filename': filename, 'error': str(e)})
    # 保存到文件
    with open(output_file, 'w', encoding='utf-8') as f:
        for result in results:
            f.write(f"文件: {result.get('filename', 'Unknown')}\n")
            for key, value in result.items():
                if key != 'filename':
                    f.write(f"  {key}: {value}\n")
            f.write("\n")
    print(f"已将结果保存到 {output_file}")
    return results
# 使用示例
batch_extract_exif('./photos/', 'exif_analysis.txt')

注意事项

  1. 图片格式支持:JPG、TIFF等格式支持EXIF,PNG、GIF等不支持
  2. 隐私问题:EXIF可能包含位置信息,分享图片时注意隐私
  3. 处理错误:有些图片可能损坏或没有EXIF数据,需要适当处理
  4. 编码问题:某些EXIF信息可能包含非ASCII字符

这些示例涵盖了大部分常见的EXIF读取需求,你可以根据具体场景选择合适的实现方式。

抱歉,评论功能暂时关闭!