diff --git a/exif.py b/exif.py index 22993e5..356685d 100644 --- a/exif.py +++ b/exif.py @@ -1,85 +1,107 @@ import json +import logging +from datetime import datetime -import PIL.ExifTags +import pytz from PIL import Image, IptcImagePlugin, TiffImagePlugin +logger = logging.getLogger(__name__) + + +""" Required exif values """ +TAGS_EXIF = { + 0x9003: "DateTimeOriginal", + 0x829D: "FNumber", + 0x829A: "ExposureTime", + 0x8827: "ISOSpeedRatings", + 0x9204: "ExposureBiasValue", + 0x8822: "ExposureProgram", + 0x9207: "MeteringMode", + 0x920A: "FocalLength", + 0xA405: "FocalLengthIn35mmFilm", + 0x0110: "Model", + 0xA434: "LensModel", +} + +""" Required iptc values """ +TAGS_IPTC = { + (2, 25): "Keywords", + (2, 55): "DateCreated", + (2, 60): "TimeCreated", +} + class Exif: def __init__(self, filename: str): + self.filename = filename - self.exif = {} + self._exif = {} + self._iptc = {} + self.data = {} + + """ Open image file """ try: - self.img = Image.open(self.filename) - self.img.verify() - self._readExif() - self._readIptc() - except: - print("Error Couldn't open image: %s" % filename) + with Image.open(self.filename) as self.img: + self.img.verify() + except Exception: + logger.exception('Could not open image: %s', self.filename) - - def _readExif(self): - img = self.img._getexif() - for (key, value) in img.items(): - if key in PIL.ExifTags.TAGS: + """ Read exif tags """ + try: + self._exif = { + TAGS_EXIF[k]: v + for k, v in self.img._getexif().items() + if k in TAGS_EXIF + } + for (key, value) in self._exif.items(): if isinstance(value, TiffImagePlugin.IFDRational): - value = float(value) + self.data[key] = float(value) elif isinstance(value, tuple): - value = tuple(float(t) if isinstance(t, TiffImagePlugin.IFDRational) else t for t in value) + self.data[key] = tuple(float(t) if isinstance(t, TiffImagePlugin.IFDRational) else t for t in value) elif isinstance(value, bytes): - value = value.decode(errors="replace") - self.exif[PIL.ExifTags.TAGS[key]] = value - return self.exif + self.data[key] = value.decode('utf-8') + else: + self.data[key] = value + except Exception: + logger.warning('Could not read exif metadata from: %s', self.filename) - def _readIptc(self): - iptcTAGS = { - (1, 90): 'CodedCharacterSet', - (2, 0): 'RecordVersion', - (2, 5): 'ObjectName', - (2, 25): 'Keywords', - (2, 55): 'DateCreated', - (2, 60): 'TimeCreated', - (2, 62): 'DigitizationDate', - (2, 63): 'DigitizationTime', - (2, 80): 'Byline', - (2, 120): 'Caption', - (2, 90): 'City', - (2, 92): 'Sub location', - (2, 95): 'Province State', - (2, 100): 'Country Code', - (2, 101): 'Country Name', - } - img = IptcImagePlugin.getiptcinfo(self.img) - for (key, value) in img.items(): - decoded = iptcTAGS.get(key, str(key)) - if isinstance(value, list): - self.exif[decoded] = [x.decode('utf-8') for x in value] - else: - self.exif[decoded] = value.decode('utf-8') - return self.exif + """ Read iptc tags """ + try: + self._iptc = { + TAGS_IPTC[k]: v + for k, v in IptcImagePlugin.getiptcinfo(self.img).items() + if k in TAGS_IPTC + } + for (key, value) in self._iptc.items(): + if isinstance(value, list): + self.data[key] = [x.decode('utf-8') for x in value] + else: + self.data[key] = value.decode('utf-8') + except Exception: + logger.warning('Could not read iptc metadata from: %s', self.filename) - def getValue(self, value): - if value in self.exif.keys(): - return self.exif[value] + def datetimeoriginal(self, timezone='UTC'): + """ Return DateTimeOriginal with timezone """ + if 'DateTimeOriginal' in self.data: + try: + return datetime.strptime(self.data['DateTimeOriginal'], "%Y:%m:%d %H:%M:%S").astimezone(pytz.timezone(timezone)) + except ValueError as e: + logger.warning('Could not parse date from: %s', self.filename) else: - return {} + return datetime.now(pytz.timezone(timezone)) - def getJson(self): - return json.dumps(self.exif) + def json(self): + """ Return exif data in json format """ + return json.dumps(self.data) + + def keywords(self): + """ Return Keywords list """ + if 'Keywords' not in self.data: + return [] + if type(self.data['Keywords']) == list: + return self.data['Keywords'] + return [self.data['Keywords']] - def getDic(self): - return self.exif - def __str__(self): return self.filename - - - -xxx = Exif('./photo.jpg') - -print(xxx.getJson()) -print(xxx.getValue('Keywords')) -print(xxx.getValue('DateTimeOriginal')) -print(xxx.getDic()) -print(xxx) -