调用json.dumps序列化EXIF信息时遇IFDRational类型不可序列化错误
解决EXIF信息JSON序列化报错(IFDRational类型)
问题原因
你碰到的TypeError: Object of type IFDRational is not JSON serializable,是因为部分图片的EXIF字段值是PIL库的IFDRational分数对象,而Python标准json.dumps()无法直接序列化这种自定义类型。你打印的字典里XResolution和YResolution是72.0(float类型),但出错的图片中这类字段实际是IFDRational实例,而非直接数值。
解决方案
方式1:生成EXIF字典时直接转换类型
在构建字典的过程中,判断并转换IFDRational为可序列化的数值类型:
from PIL import Image, ExifTags import json image_open = Image.open(self.image) image_open.verify() image_getexif = image_open.getexif() if image_getexif: exif = {} for k, v in image_getexif.items(): if k not in ExifTags.TAGS: continue # 处理IFDRational类型,转成float if hasattr(v, 'numerator') and hasattr(v, 'denominator'): v = float(v.numerator / v.denominator) elif isinstance(v, bytes): continue exif[ExifTags.TAGS[k]] = v print(json.dumps(exif, indent=4))
方式2:自定义JSON编码器
如果需要兼容更多PIL自定义类型,可编写专属编码器:
from PIL import Image, ExifTags import json from PIL.ExifTags import IFDRational class ExifJSONEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, IFDRational): return float(obj.numerator / obj.denominator) # 如需处理GPS相关的分数类型,可添加GPSIFDRational的判断 return super().default(obj) # 使用示例 image_open = Image.open(self.image) image_open.verify() image_getexif = image_open.getexif() if image_getexif: exif = { ExifTags.TAGS[k]: v for k, v in image_getexif.items() if k in ExifTags.TAGS and not isinstance(v, bytes) } print(json.dumps(exif, indent=4, cls=ExifJSONEncoder))
补充说明
不同设备生成的EXIF存储格式存在差异:部分设备直接存储数值,部分设备会以IFDRational分数形式存储分辨率等参数,这就是为什么只有部分图片报错。
内容的提问来源于stack exchange,提问作者SaeX
相关产品推荐
相关产品推荐

