Refactoring
This commit is contained in:
parent
3c4996a747
commit
5824771012
1 changed files with 86 additions and 64 deletions
148
exif.py
148
exif.py
|
@ -1,85 +1,107 @@
|
||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
import PIL.ExifTags
|
import pytz
|
||||||
from PIL import Image, IptcImagePlugin, TiffImagePlugin
|
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:
|
class Exif:
|
||||||
|
|
||||||
def __init__(self, filename: str):
|
def __init__(self, filename: str):
|
||||||
|
|
||||||
self.filename = filename
|
self.filename = filename
|
||||||
self.exif = {}
|
self._exif = {}
|
||||||
|
self._iptc = {}
|
||||||
|
self.data = {}
|
||||||
|
|
||||||
|
""" Open image file """
|
||||||
try:
|
try:
|
||||||
self.img = Image.open(self.filename)
|
with Image.open(self.filename) as self.img:
|
||||||
self.img.verify()
|
self.img.verify()
|
||||||
self._readExif()
|
except Exception:
|
||||||
self._readIptc()
|
logger.exception('Could not open image: %s', self.filename)
|
||||||
except:
|
|
||||||
print("Error Couldn't open image: %s" % filename)
|
|
||||||
|
|
||||||
|
""" Read exif tags """
|
||||||
def _readExif(self):
|
try:
|
||||||
img = self.img._getexif()
|
self._exif = {
|
||||||
for (key, value) in img.items():
|
TAGS_EXIF[k]: v
|
||||||
if key in PIL.ExifTags.TAGS:
|
for k, v in self.img._getexif().items()
|
||||||
if isinstance(value, TiffImagePlugin.IFDRational):
|
if k in TAGS_EXIF
|
||||||
value = float(value)
|
|
||||||
elif isinstance(value, tuple):
|
|
||||||
value = 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
|
|
||||||
|
|
||||||
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 self._exif.items():
|
||||||
for (key, value) in img.items():
|
if isinstance(value, TiffImagePlugin.IFDRational):
|
||||||
decoded = iptcTAGS.get(key, str(key))
|
self.data[key] = float(value)
|
||||||
|
elif isinstance(value, tuple):
|
||||||
|
self.data[key] = tuple(float(t) if isinstance(t, TiffImagePlugin.IFDRational) else t for t in value)
|
||||||
|
elif isinstance(value, bytes):
|
||||||
|
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)
|
||||||
|
|
||||||
|
""" 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):
|
if isinstance(value, list):
|
||||||
self.exif[decoded] = [x.decode('utf-8') for x in value]
|
self.data[key] = [x.decode('utf-8') for x in value]
|
||||||
else:
|
else:
|
||||||
self.exif[decoded] = value.decode('utf-8')
|
self.data[key] = value.decode('utf-8')
|
||||||
return self.exif
|
except Exception:
|
||||||
|
logger.warning('Could not read iptc metadata from: %s', self.filename)
|
||||||
|
|
||||||
def getValue(self, value):
|
def datetimeoriginal(self, timezone='UTC'):
|
||||||
if value in self.exif.keys():
|
""" Return DateTimeOriginal with timezone """
|
||||||
return self.exif[value]
|
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:
|
else:
|
||||||
return {}
|
return datetime.now(pytz.timezone(timezone))
|
||||||
|
|
||||||
def getJson(self):
|
def json(self):
|
||||||
return json.dumps(self.exif)
|
""" Return exif data in json format """
|
||||||
|
return json.dumps(self.data)
|
||||||
|
|
||||||
def getDic(self):
|
def keywords(self):
|
||||||
return self.exif
|
""" 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 __str__(self):
|
def __str__(self):
|
||||||
return self.filename
|
return self.filename
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
xxx = Exif('./photo.jpg')
|
|
||||||
|
|
||||||
print(xxx.getJson())
|
|
||||||
print(xxx.getValue('Keywords'))
|
|
||||||
print(xxx.getValue('DateTimeOriginal'))
|
|
||||||
print(xxx.getDic())
|
|
||||||
print(xxx)
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue