mirror of
https://github.com/Derpy-Leggies/OnlyLegs.git
synced 2025-06-29 03:26:16 +00:00
Submitted to PyLint
This commit is contained in:
parent
7ed3b455dd
commit
de2d72e5de
7 changed files with 591 additions and 710 deletions
|
@ -180,8 +180,8 @@ def metadata(img_id):
|
||||||
if img is None:
|
if img is None:
|
||||||
abort(404)
|
abort(404)
|
||||||
|
|
||||||
exif = mt.metadata.yoink(
|
img_path = os.path.join(current_app.config['UPLOAD_FOLDER'], img.file_name)
|
||||||
os.path.join(current_app.config['UPLOAD_FOLDER'], img.file_name))
|
exif = mt.Metadata(img_path).yoink()
|
||||||
|
|
||||||
return jsonify(exif)
|
return jsonify(exif)
|
||||||
|
|
||||||
|
|
|
@ -1,705 +0,0 @@
|
||||||
import PIL
|
|
||||||
from PIL import Image
|
|
||||||
from PIL.ExifTags import TAGS, GPSTAGS
|
|
||||||
from datetime import datetime
|
|
||||||
import os
|
|
||||||
|
|
||||||
|
|
||||||
class metadata:
|
|
||||||
def yoink(filename):
|
|
||||||
exif = metadata.getFile(filename)
|
|
||||||
file_size = os.path.getsize(filename)
|
|
||||||
file_name = os.path.basename(filename)
|
|
||||||
file_resolution = Image.open(filename).size
|
|
||||||
|
|
||||||
if exif:
|
|
||||||
unformatted_exif = metadata.format(exif, file_size, file_name,
|
|
||||||
file_resolution)
|
|
||||||
else:
|
|
||||||
# No EXIF data, get some basic informaton from the file
|
|
||||||
unformatted_exif = {
|
|
||||||
'File': {
|
|
||||||
'Name': {
|
|
||||||
'type': 'text',
|
|
||||||
'raw': file_name
|
|
||||||
},
|
|
||||||
'Size': {
|
|
||||||
'type': 'number',
|
|
||||||
'raw': file_size,
|
|
||||||
'formatted': metadata.human_size(file_size)
|
|
||||||
},
|
|
||||||
'Format': {
|
|
||||||
'type': 'text',
|
|
||||||
'raw': file_name.split('.')[-1]
|
|
||||||
},
|
|
||||||
'Width': {
|
|
||||||
'type': 'number',
|
|
||||||
'raw': file_resolution[0]
|
|
||||||
},
|
|
||||||
'Height': {
|
|
||||||
'type': 'number',
|
|
||||||
'raw': file_resolution[1]
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
formatted_exif = {}
|
|
||||||
|
|
||||||
for section in unformatted_exif:
|
|
||||||
tmp = {}
|
|
||||||
|
|
||||||
for value in unformatted_exif[section]:
|
|
||||||
if unformatted_exif[section][value]['raw'] != None:
|
|
||||||
raw_type = unformatted_exif[section][value]['raw']
|
|
||||||
if isinstance(raw_type, PIL.TiffImagePlugin.IFDRational):
|
|
||||||
raw_type = raw_type.__float__()
|
|
||||||
elif isinstance(raw_type, bytes):
|
|
||||||
raw_type = raw_type.decode('utf-8')
|
|
||||||
|
|
||||||
tmp[value] = unformatted_exif[section][value]
|
|
||||||
|
|
||||||
if len(tmp) > 0:
|
|
||||||
formatted_exif[section] = tmp
|
|
||||||
|
|
||||||
return formatted_exif
|
|
||||||
|
|
||||||
def getFile(filename):
|
|
||||||
try:
|
|
||||||
file = Image.open(filename)
|
|
||||||
raw = file._getexif()
|
|
||||||
exif = {}
|
|
||||||
|
|
||||||
for tag, value in TAGS.items():
|
|
||||||
|
|
||||||
if tag in raw:
|
|
||||||
data = raw[tag]
|
|
||||||
else:
|
|
||||||
data = None
|
|
||||||
|
|
||||||
exif[value] = {"tag": tag, "raw": data}
|
|
||||||
|
|
||||||
file.close()
|
|
||||||
|
|
||||||
return exif
|
|
||||||
except Exception as e:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def format(raw, file_size, file_name, file_resolution):
|
|
||||||
exif = {}
|
|
||||||
|
|
||||||
exif['Photographer'] = {
|
|
||||||
'Artist': {
|
|
||||||
'type': 'text',
|
|
||||||
'raw': raw["Artist"]["raw"]
|
|
||||||
},
|
|
||||||
'Comment': {
|
|
||||||
'type': 'text',
|
|
||||||
'raw': raw["UserComment"]["raw"]
|
|
||||||
},
|
|
||||||
'Description': {
|
|
||||||
'type': 'text',
|
|
||||||
'raw': raw["ImageDescription"]["raw"]
|
|
||||||
},
|
|
||||||
'Copyright': {
|
|
||||||
'type': 'text',
|
|
||||||
'raw': raw["Copyright"]["raw"]
|
|
||||||
},
|
|
||||||
}
|
|
||||||
exif['Camera'] = {
|
|
||||||
'Model': {
|
|
||||||
'type': 'text',
|
|
||||||
'raw': raw['Model']['raw']
|
|
||||||
},
|
|
||||||
'Make': {
|
|
||||||
'type': 'text',
|
|
||||||
'raw': raw['Make']['raw']
|
|
||||||
},
|
|
||||||
'Camera Type': {
|
|
||||||
'type': 'text',
|
|
||||||
'raw': raw['BodySerialNumber']['raw']
|
|
||||||
},
|
|
||||||
'Lens Make': {
|
|
||||||
'type': 'text',
|
|
||||||
'raw': raw['LensMake']['raw'],
|
|
||||||
},
|
|
||||||
'Lense Model': {
|
|
||||||
'type': 'text',
|
|
||||||
'raw': raw['LensModel']['raw'],
|
|
||||||
},
|
|
||||||
'Lense Spec': {
|
|
||||||
'type':
|
|
||||||
'text',
|
|
||||||
'raw':
|
|
||||||
raw['LensSpecification']['raw'],
|
|
||||||
'formatted':
|
|
||||||
metadata.lensSpecification(raw['LensSpecification']['raw'])
|
|
||||||
},
|
|
||||||
'Component Config': {
|
|
||||||
'type':
|
|
||||||
'text',
|
|
||||||
'raw':
|
|
||||||
raw['ComponentsConfiguration']['raw'],
|
|
||||||
'formatted':
|
|
||||||
metadata.componentsConfiguration(
|
|
||||||
raw['ComponentsConfiguration']['raw'])
|
|
||||||
},
|
|
||||||
'Date Processed': {
|
|
||||||
'type': 'date',
|
|
||||||
'raw': raw['DateTime']['raw'],
|
|
||||||
'formatted': metadata.date(raw['DateTime']['raw'])
|
|
||||||
},
|
|
||||||
'Date Digitized': {
|
|
||||||
'type': 'date',
|
|
||||||
'raw': raw["DateTimeDigitized"]["raw"],
|
|
||||||
'formatted': metadata.date(raw["DateTimeDigitized"]["raw"])
|
|
||||||
},
|
|
||||||
'Time Offset': {
|
|
||||||
'type': 'text',
|
|
||||||
'raw': raw["OffsetTime"]["raw"]
|
|
||||||
},
|
|
||||||
'Time Offset - Original': {
|
|
||||||
'type': 'text',
|
|
||||||
'raw': raw["OffsetTimeOriginal"]["raw"]
|
|
||||||
},
|
|
||||||
'Time Offset - Digitized': {
|
|
||||||
'type': 'text',
|
|
||||||
'raw': raw["OffsetTimeDigitized"]["raw"]
|
|
||||||
},
|
|
||||||
'Date Original': {
|
|
||||||
'type': 'date',
|
|
||||||
'raw': raw["DateTimeOriginal"]["raw"],
|
|
||||||
'formatted': metadata.date(raw["DateTimeOriginal"]["raw"])
|
|
||||||
},
|
|
||||||
'FNumber': {
|
|
||||||
'type': 'fnumber',
|
|
||||||
'raw': raw["FNumber"]["raw"],
|
|
||||||
'formatted': metadata.fnumber(raw["FNumber"]["raw"])
|
|
||||||
},
|
|
||||||
'Focal Length': {
|
|
||||||
'type': 'focal',
|
|
||||||
'raw': raw["FocalLength"]["raw"],
|
|
||||||
'formatted': metadata.focal(raw["FocalLength"]["raw"])
|
|
||||||
},
|
|
||||||
'Focal Length (35mm format)': {
|
|
||||||
'type': 'focal',
|
|
||||||
'raw': raw["FocalLengthIn35mmFilm"]["raw"],
|
|
||||||
'formatted':
|
|
||||||
metadata.focal(raw["FocalLengthIn35mmFilm"]["raw"])
|
|
||||||
},
|
|
||||||
'Max Aperture': {
|
|
||||||
'type': 'fnumber',
|
|
||||||
'raw': raw["MaxApertureValue"]["raw"],
|
|
||||||
'formatted': metadata.fnumber(raw["MaxApertureValue"]["raw"])
|
|
||||||
},
|
|
||||||
'Aperture': {
|
|
||||||
'type': 'fnumber',
|
|
||||||
'raw': raw["ApertureValue"]["raw"],
|
|
||||||
'formatted': metadata.fnumber(raw["ApertureValue"]["raw"])
|
|
||||||
},
|
|
||||||
'Shutter Speed': {
|
|
||||||
'type': 'shutter',
|
|
||||||
'raw': raw["ShutterSpeedValue"]["raw"],
|
|
||||||
'formatted': metadata.shutter(raw["ShutterSpeedValue"]["raw"])
|
|
||||||
},
|
|
||||||
'ISO Speed Ratings': {
|
|
||||||
'type': 'number',
|
|
||||||
'raw': raw["ISOSpeedRatings"]["raw"],
|
|
||||||
'formatted': metadata.iso(raw["ISOSpeedRatings"]["raw"])
|
|
||||||
},
|
|
||||||
'ISO Speed': {
|
|
||||||
'type': 'iso',
|
|
||||||
'raw': raw["ISOSpeed"]["raw"],
|
|
||||||
'formatted': metadata.iso(raw["ISOSpeed"]["raw"])
|
|
||||||
},
|
|
||||||
'Sensitivity Type': {
|
|
||||||
'type':
|
|
||||||
'number',
|
|
||||||
'raw':
|
|
||||||
raw["SensitivityType"]["raw"],
|
|
||||||
'formatted':
|
|
||||||
metadata.sensitivityType(raw["SensitivityType"]["raw"])
|
|
||||||
},
|
|
||||||
'Exposure Bias': {
|
|
||||||
'type': 'ev',
|
|
||||||
'raw': raw["ExposureBiasValue"]["raw"],
|
|
||||||
'formatted': metadata.ev(raw["ExposureBiasValue"]["raw"])
|
|
||||||
},
|
|
||||||
'Exposure Time': {
|
|
||||||
'type': 'shutter',
|
|
||||||
'raw': raw["ExposureTime"]["raw"],
|
|
||||||
'formatted': metadata.shutter(raw["ExposureTime"]["raw"])
|
|
||||||
},
|
|
||||||
'Exposure Mode': {
|
|
||||||
'type': 'number',
|
|
||||||
'raw': raw["ExposureMode"]["raw"],
|
|
||||||
'formatted': metadata.exposureMode(raw["ExposureMode"]["raw"])
|
|
||||||
},
|
|
||||||
'Exposure Program': {
|
|
||||||
'type':
|
|
||||||
'number',
|
|
||||||
'raw':
|
|
||||||
raw["ExposureProgram"]["raw"],
|
|
||||||
'formatted':
|
|
||||||
metadata.exposureProgram(raw["ExposureProgram"]["raw"])
|
|
||||||
},
|
|
||||||
'White Balance': {
|
|
||||||
'type': 'number',
|
|
||||||
'raw': raw["WhiteBalance"]["raw"],
|
|
||||||
'formatted': metadata.whiteBalance(raw["WhiteBalance"]["raw"])
|
|
||||||
},
|
|
||||||
'Flash': {
|
|
||||||
'type': 'number',
|
|
||||||
'raw': raw["Flash"]["raw"],
|
|
||||||
'formatted': metadata.flash(raw["Flash"]["raw"])
|
|
||||||
},
|
|
||||||
'Metering Mode': {
|
|
||||||
'type': 'number',
|
|
||||||
'raw': raw["MeteringMode"]["raw"],
|
|
||||||
'formatted': metadata.meteringMode(raw["MeteringMode"]["raw"])
|
|
||||||
},
|
|
||||||
'Light Source': {
|
|
||||||
'type': 'number',
|
|
||||||
'raw': raw["LightSource"]["raw"],
|
|
||||||
'formatted': metadata.lightSource(raw["LightSource"]["raw"])
|
|
||||||
},
|
|
||||||
'Scene Capture Type': {
|
|
||||||
'type':
|
|
||||||
'number',
|
|
||||||
'raw':
|
|
||||||
raw["SceneCaptureType"]["raw"],
|
|
||||||
'formatted':
|
|
||||||
metadata.sceneCaptureType(raw["SceneCaptureType"]["raw"])
|
|
||||||
},
|
|
||||||
'Scene Type': {
|
|
||||||
'type': 'number',
|
|
||||||
'raw': raw["SceneType"]["raw"],
|
|
||||||
'formatted': metadata.sceneType(raw["SceneType"]["raw"])
|
|
||||||
},
|
|
||||||
'Rating': {
|
|
||||||
'type': 'number',
|
|
||||||
'raw': raw["Rating"]["raw"],
|
|
||||||
'formatted': metadata.rating(raw["Rating"]["raw"])
|
|
||||||
},
|
|
||||||
'Rating Percent': {
|
|
||||||
'type': 'number',
|
|
||||||
'raw': raw["RatingPercent"]["raw"],
|
|
||||||
'formatted':
|
|
||||||
metadata.ratingPercent(raw["RatingPercent"]["raw"])
|
|
||||||
},
|
|
||||||
}
|
|
||||||
exif['Software'] = {
|
|
||||||
'Software': {
|
|
||||||
'type': 'text',
|
|
||||||
'raw': raw['Software']['raw']
|
|
||||||
},
|
|
||||||
'Colour Space': {
|
|
||||||
'type': 'number',
|
|
||||||
'raw': raw['ColorSpace']['raw'],
|
|
||||||
'formatted': metadata.colorSpace(raw['ColorSpace']['raw'])
|
|
||||||
},
|
|
||||||
'Compression': {
|
|
||||||
'type': 'number',
|
|
||||||
'raw': raw['Compression']['raw'],
|
|
||||||
'formatted': metadata.compression(raw['Compression']['raw'])
|
|
||||||
},
|
|
||||||
}
|
|
||||||
exif['File'] = {
|
|
||||||
'Name': {
|
|
||||||
'type': 'text',
|
|
||||||
'raw': file_name
|
|
||||||
},
|
|
||||||
'Size': {
|
|
||||||
'type': 'number',
|
|
||||||
'raw': file_size,
|
|
||||||
'formatted': metadata.human_size(file_size)
|
|
||||||
},
|
|
||||||
'Format': {
|
|
||||||
'type': 'text',
|
|
||||||
'raw': file_name.split('.')[-1]
|
|
||||||
},
|
|
||||||
'Width': {
|
|
||||||
'type': 'number',
|
|
||||||
'raw': file_resolution[0]
|
|
||||||
},
|
|
||||||
'Height': {
|
|
||||||
'type': 'number',
|
|
||||||
'raw': file_resolution[1]
|
|
||||||
},
|
|
||||||
'Orientation': {
|
|
||||||
'type': 'number',
|
|
||||||
'raw': raw["Orientation"]["raw"],
|
|
||||||
'formatted': metadata.orientation(raw["Orientation"]["raw"])
|
|
||||||
},
|
|
||||||
'Xresolution': {
|
|
||||||
'type': 'number',
|
|
||||||
'raw': raw["XResolution"]["raw"]
|
|
||||||
},
|
|
||||||
'Yresolution': {
|
|
||||||
'type': 'number',
|
|
||||||
'raw': raw["YResolution"]["raw"]
|
|
||||||
},
|
|
||||||
'Resolution Units': {
|
|
||||||
'type': 'number',
|
|
||||||
'raw': raw["ResolutionUnit"]["raw"],
|
|
||||||
'formatted':
|
|
||||||
metadata.resolutionUnit(raw["ResolutionUnit"]["raw"])
|
|
||||||
},
|
|
||||||
}
|
|
||||||
#exif['Raw'] = {}
|
|
||||||
#for key in raw:
|
|
||||||
# try:
|
|
||||||
# exif['Raw'][key] = {
|
|
||||||
# 'type': 'text',
|
|
||||||
# 'raw': raw[key]['raw'].decode('utf-8')
|
|
||||||
# }
|
|
||||||
# except:
|
|
||||||
# exif['Raw'][key] = {
|
|
||||||
# 'type': 'text',
|
|
||||||
# 'raw': str(raw[key]['raw'])
|
|
||||||
# }
|
|
||||||
|
|
||||||
return exif
|
|
||||||
|
|
||||||
def human_size(num, suffix="B"):
|
|
||||||
for unit in ["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"]:
|
|
||||||
if abs(num) < 1024.0:
|
|
||||||
return f"{num:3.1f}{unit}{suffix}"
|
|
||||||
num /= 1024.0
|
|
||||||
return f"{num:.1f}Yi{suffix}"
|
|
||||||
|
|
||||||
def date(date):
|
|
||||||
date_format = '%Y:%m:%d %H:%M:%S'
|
|
||||||
|
|
||||||
if date:
|
|
||||||
return str(datetime.strptime(date, date_format))
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def fnumber(value):
|
|
||||||
if value != None:
|
|
||||||
return 'f/' + str(value)
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def iso(value):
|
|
||||||
if value != None:
|
|
||||||
return 'ISO ' + str(value)
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def shutter(value):
|
|
||||||
if value != None:
|
|
||||||
return str(value) + 's'
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def focal(value):
|
|
||||||
if value != None:
|
|
||||||
try:
|
|
||||||
return str(value[0] / value[1]) + 'mm'
|
|
||||||
except:
|
|
||||||
return str(value) + 'mm'
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def ev(value):
|
|
||||||
if value != None:
|
|
||||||
return str(value) + 'EV'
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def colorSpace(value):
|
|
||||||
types = {1: 'sRGB', 65535: 'Uncalibrated', 0: 'Reserved'}
|
|
||||||
try:
|
|
||||||
return types[int(value)]
|
|
||||||
except:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def flash(value):
|
|
||||||
types = {
|
|
||||||
0:
|
|
||||||
'Flash did not fire',
|
|
||||||
1:
|
|
||||||
'Flash fired',
|
|
||||||
5:
|
|
||||||
'Strobe return light not detected',
|
|
||||||
7:
|
|
||||||
'Strobe return light detected',
|
|
||||||
9:
|
|
||||||
'Flash fired, compulsory flash mode',
|
|
||||||
13:
|
|
||||||
'Flash fired, compulsory flash mode, return light not detected',
|
|
||||||
15:
|
|
||||||
'Flash fired, compulsory flash mode, return light detected',
|
|
||||||
16:
|
|
||||||
'Flash did not fire, compulsory flash mode',
|
|
||||||
24:
|
|
||||||
'Flash did not fire, auto mode',
|
|
||||||
25:
|
|
||||||
'Flash fired, auto mode',
|
|
||||||
29:
|
|
||||||
'Flash fired, auto mode, return light not detected',
|
|
||||||
31:
|
|
||||||
'Flash fired, auto mode, return light detected',
|
|
||||||
32:
|
|
||||||
'No flash function',
|
|
||||||
65:
|
|
||||||
'Flash fired, red-eye reduction mode',
|
|
||||||
69:
|
|
||||||
'Flash fired, red-eye reduction mode, return light not detected',
|
|
||||||
71:
|
|
||||||
'Flash fired, red-eye reduction mode, return light detected',
|
|
||||||
73:
|
|
||||||
'Flash fired, compulsory flash mode, red-eye reduction mode',
|
|
||||||
77:
|
|
||||||
'Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected',
|
|
||||||
79:
|
|
||||||
'Flash fired, compulsory flash mode, red-eye reduction mode, return light detected',
|
|
||||||
89:
|
|
||||||
'Flash fired, auto mode, red-eye reduction mode',
|
|
||||||
93:
|
|
||||||
'Flash fired, auto mode, return light not detected, red-eye reduction mode',
|
|
||||||
95:
|
|
||||||
'Flash fired, auto mode, return light detected, red-eye reduction mode'
|
|
||||||
}
|
|
||||||
try:
|
|
||||||
return types[int(value)]
|
|
||||||
except:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def exposureProgram(value):
|
|
||||||
types = {
|
|
||||||
0: 'Not defined',
|
|
||||||
1: 'Manual',
|
|
||||||
2: 'Normal program',
|
|
||||||
3: 'Aperture priority',
|
|
||||||
4: 'Shutter priority',
|
|
||||||
5: 'Creative program',
|
|
||||||
6: 'Action program',
|
|
||||||
7: 'Portrait mode',
|
|
||||||
8: 'Landscape mode'
|
|
||||||
}
|
|
||||||
try:
|
|
||||||
return types[int(value)]
|
|
||||||
except:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def meteringMode(value):
|
|
||||||
types = {
|
|
||||||
0: 'Unknown',
|
|
||||||
1: 'Average',
|
|
||||||
2: 'Center-Weighted Average',
|
|
||||||
3: 'Spot',
|
|
||||||
4: 'Multi-Spot',
|
|
||||||
5: 'Pattern',
|
|
||||||
6: 'Partial',
|
|
||||||
255: 'Other'
|
|
||||||
}
|
|
||||||
try:
|
|
||||||
return types[int(value)]
|
|
||||||
except:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def resolutionUnit(value):
|
|
||||||
types = {
|
|
||||||
1: 'No absolute unit of measurement',
|
|
||||||
2: 'Inch',
|
|
||||||
3: 'Centimeter'
|
|
||||||
}
|
|
||||||
try:
|
|
||||||
return types[int(value)]
|
|
||||||
except:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def lightSource(value):
|
|
||||||
types = {
|
|
||||||
0: 'Unknown',
|
|
||||||
1: 'Daylight',
|
|
||||||
2: 'Fluorescent',
|
|
||||||
3: 'Tungsten (incandescent light)',
|
|
||||||
4: 'Flash',
|
|
||||||
9: 'Fine weather',
|
|
||||||
10: 'Cloudy weather',
|
|
||||||
11: 'Shade',
|
|
||||||
12: 'Daylight fluorescent (D 5700 - 7100K)',
|
|
||||||
13: 'Day white fluorescent (N 4600 - 5400K)',
|
|
||||||
14: 'Cool white fluorescent (W 3900 - 4500K)',
|
|
||||||
15: 'White fluorescent (WW 3200 - 3700K)',
|
|
||||||
17: 'Standard light A',
|
|
||||||
18: 'Standard light B',
|
|
||||||
19: 'Standard light C',
|
|
||||||
20: 'D55',
|
|
||||||
21: 'D65',
|
|
||||||
22: 'D75',
|
|
||||||
23: 'D50',
|
|
||||||
24: 'ISO studio tungsten',
|
|
||||||
255: 'Other light source',
|
|
||||||
}
|
|
||||||
try:
|
|
||||||
return types[int(value)]
|
|
||||||
except:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def sceneCaptureType(value):
|
|
||||||
types = {
|
|
||||||
0: 'Standard',
|
|
||||||
1: 'Landscape',
|
|
||||||
2: 'Portrait',
|
|
||||||
3: 'Night scene',
|
|
||||||
}
|
|
||||||
try:
|
|
||||||
return types[int(value)]
|
|
||||||
except:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def sceneType(value):
|
|
||||||
if value:
|
|
||||||
return 'Directly photographed image'
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def whiteBalance(value):
|
|
||||||
types = {
|
|
||||||
0: 'Auto white balance',
|
|
||||||
1: 'Manual white balance',
|
|
||||||
}
|
|
||||||
try:
|
|
||||||
return types[int(value)]
|
|
||||||
except:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def exposureMode(value):
|
|
||||||
types = {
|
|
||||||
0: 'Auto exposure',
|
|
||||||
1: 'Manual exposure',
|
|
||||||
2: 'Auto bracket',
|
|
||||||
}
|
|
||||||
try:
|
|
||||||
return types[int(value)]
|
|
||||||
except:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def sensitivityType(value):
|
|
||||||
types = {
|
|
||||||
0:
|
|
||||||
'Unknown',
|
|
||||||
1:
|
|
||||||
'Standard Output Sensitivity',
|
|
||||||
2:
|
|
||||||
'Recommended Exposure Index',
|
|
||||||
3:
|
|
||||||
'ISO Speed',
|
|
||||||
4:
|
|
||||||
'Standard Output Sensitivity and Recommended Exposure Index',
|
|
||||||
5:
|
|
||||||
'Standard Output Sensitivity and ISO Speed',
|
|
||||||
6:
|
|
||||||
'Recommended Exposure Index and ISO Speed',
|
|
||||||
7:
|
|
||||||
'Standard Output Sensitivity, Recommended Exposure Index and ISO Speed',
|
|
||||||
}
|
|
||||||
try:
|
|
||||||
return types[int(value)]
|
|
||||||
except:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def lensSpecification(value):
|
|
||||||
if value:
|
|
||||||
return str(value[0] / value[1]) + 'mm - ' + str(
|
|
||||||
value[2] / value[3]) + 'mm'
|
|
||||||
else:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def compression(value):
|
|
||||||
types = {
|
|
||||||
1: 'Uncompressed',
|
|
||||||
2: 'CCITT 1D',
|
|
||||||
3: 'T4/Group 3 Fax',
|
|
||||||
4: 'T6/Group 4 Fax',
|
|
||||||
5: 'LZW',
|
|
||||||
6: 'JPEG (old-style)',
|
|
||||||
7: 'JPEG',
|
|
||||||
8: 'Adobe Deflate',
|
|
||||||
9: 'JBIG B&W',
|
|
||||||
10: 'JBIG Color',
|
|
||||||
99: 'JPEG',
|
|
||||||
262: 'Kodak 262',
|
|
||||||
32766: 'Next',
|
|
||||||
32767: 'Sony ARW Compressed',
|
|
||||||
32769: 'Packed RAW',
|
|
||||||
32770: 'Samsung SRW Compressed',
|
|
||||||
32771: 'CCIRLEW',
|
|
||||||
32772: 'Samsung SRW Compressed 2',
|
|
||||||
32773: 'PackBits',
|
|
||||||
32809: 'Thunderscan',
|
|
||||||
32867: 'Kodak KDC Compressed',
|
|
||||||
32895: 'IT8CTPAD',
|
|
||||||
32896: 'IT8LW',
|
|
||||||
32897: 'IT8MP',
|
|
||||||
32898: 'IT8BL',
|
|
||||||
32908: 'PixarFilm',
|
|
||||||
32909: 'PixarLog',
|
|
||||||
32946: 'Deflate',
|
|
||||||
32947: 'DCS',
|
|
||||||
33003: 'Aperio JPEG 2000 YCbCr',
|
|
||||||
33005: 'Aperio JPEG 2000 RGB',
|
|
||||||
34661: 'JBIG',
|
|
||||||
34676: 'SGILog',
|
|
||||||
34677: 'SGILog24',
|
|
||||||
34712: 'JPEG 2000',
|
|
||||||
34713: 'Nikon NEF Compressed',
|
|
||||||
34715: 'JBIG2 TIFF FX',
|
|
||||||
34718: '(MDI) Binary Level Codec',
|
|
||||||
34719: '(MDI) Progressive Transform Codec',
|
|
||||||
34720: '(MDI) Vector',
|
|
||||||
34887: 'ESRI Lerc',
|
|
||||||
34892: 'Lossy JPEG',
|
|
||||||
34925: 'LZMA2',
|
|
||||||
34926: 'Zstd',
|
|
||||||
34927: 'WebP',
|
|
||||||
34933: 'PNG',
|
|
||||||
34934: 'JPEG XR',
|
|
||||||
65000: 'Kodak DCR Compressed',
|
|
||||||
65535: 'Pentax PEF Compressed',
|
|
||||||
}
|
|
||||||
try:
|
|
||||||
return types[int(value)]
|
|
||||||
except:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def orientation(value):
|
|
||||||
types = {
|
|
||||||
1: 'Horizontal (normal)',
|
|
||||||
2: 'Mirror horizontal',
|
|
||||||
3: 'Rotate 180',
|
|
||||||
4: 'Mirror vertical',
|
|
||||||
5: 'Mirror horizontal and rotate 270 CW',
|
|
||||||
6: 'Rotate 90 CW',
|
|
||||||
7: 'Mirror horizontal and rotate 90 CW',
|
|
||||||
8: 'Rotate 270 CW',
|
|
||||||
}
|
|
||||||
try:
|
|
||||||
return types[int(value)]
|
|
||||||
except:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def componentsConfiguration(value):
|
|
||||||
types = {
|
|
||||||
0: '',
|
|
||||||
1: 'Y',
|
|
||||||
2: 'Cb',
|
|
||||||
3: 'Cr',
|
|
||||||
4: 'R',
|
|
||||||
5: 'G',
|
|
||||||
6: 'B',
|
|
||||||
}
|
|
||||||
try:
|
|
||||||
return ''.join([types[int(x)] for x in value])
|
|
||||||
except:
|
|
||||||
return None
|
|
||||||
|
|
||||||
def rating(value):
|
|
||||||
return str(value) + ' stars'
|
|
||||||
|
|
||||||
def ratingPercent(value):
|
|
||||||
return str(value) + '%'
|
|
117
gallery/metadata/__init__.py
Normal file
117
gallery/metadata/__init__.py
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
"""
|
||||||
|
OnlyLegs - Metatada Parser
|
||||||
|
Parse metadata from images if available
|
||||||
|
otherwise get some basic information from the file
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from PIL import Image
|
||||||
|
from PIL.ExifTags import TAGS, GPSTAGS
|
||||||
|
|
||||||
|
from .helpers import *
|
||||||
|
from .mapping import *
|
||||||
|
|
||||||
|
class Metadata:
|
||||||
|
"""
|
||||||
|
Metadata parser
|
||||||
|
"""
|
||||||
|
def __init__(self, file_path):
|
||||||
|
"""
|
||||||
|
Initialize the metadata parser
|
||||||
|
"""
|
||||||
|
self.file_path = file_path
|
||||||
|
img_exif = {}
|
||||||
|
|
||||||
|
try:
|
||||||
|
file = Image.open(file_path)
|
||||||
|
tags = file._getexif()
|
||||||
|
img_exif = {}
|
||||||
|
|
||||||
|
for tag, value in TAGS.items():
|
||||||
|
if tag in tags:
|
||||||
|
img_exif[value] = tags[tag]
|
||||||
|
|
||||||
|
img_exif['FileName'] = os.path.basename(file_path)
|
||||||
|
img_exif['FileSize'] = os.path.getsize(file_path)
|
||||||
|
img_exif['FileFormat'] = img_exif['FileName'].split('.')[-1]
|
||||||
|
img_exif['FileWidth'], img_exif['FileHeight'] = file.size
|
||||||
|
|
||||||
|
file.close()
|
||||||
|
except TypeError:
|
||||||
|
img_exif['FileName'] = os.path.basename(file_path)
|
||||||
|
img_exif['FileSize'] = os.path.getsize(file_path)
|
||||||
|
img_exif['FileFormat'] = img_exif['FileName'].split('.')[-1]
|
||||||
|
img_exif['FileWidth'], img_exif['FileHeight'] = file.size
|
||||||
|
|
||||||
|
self.encoded = img_exif
|
||||||
|
|
||||||
|
def yoink(self):
|
||||||
|
"""
|
||||||
|
Yoinks the metadata from the image
|
||||||
|
"""
|
||||||
|
if not os.path.isfile(self.file_path):
|
||||||
|
return None
|
||||||
|
return self.format_data(self.encoded)
|
||||||
|
|
||||||
|
def format_data(self, encoded_exif): # pylint: disable=R0912 # For now, this is fine
|
||||||
|
"""
|
||||||
|
Formats the data into a dictionary
|
||||||
|
"""
|
||||||
|
exif = {
|
||||||
|
'Photographer': {},
|
||||||
|
'Camera': {},
|
||||||
|
'Software': {},
|
||||||
|
'File': {},
|
||||||
|
}
|
||||||
|
|
||||||
|
for data in encoded_exif:
|
||||||
|
if data in PHOTOGRAHER_MAPPING:
|
||||||
|
exif['Photographer'][PHOTOGRAHER_MAPPING[data][0]] = {
|
||||||
|
'raw': encoded_exif[data],
|
||||||
|
}
|
||||||
|
elif data in CAMERA_MAPPING:
|
||||||
|
if len(CAMERA_MAPPING[data]) == 2:
|
||||||
|
exif['Camera'][CAMERA_MAPPING[data][0]] = {
|
||||||
|
'raw': encoded_exif[data],
|
||||||
|
'formatted':
|
||||||
|
getattr(helpers, CAMERA_MAPPING[data][1])(encoded_exif[data]), # pylint: disable=E0602
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
exif['Camera'][CAMERA_MAPPING[data][0]] = {
|
||||||
|
'raw': encoded_exif[data],
|
||||||
|
}
|
||||||
|
elif data in SOFTWARE_MAPPING:
|
||||||
|
if len(SOFTWARE_MAPPING[data]) == 2:
|
||||||
|
exif['Software'][SOFTWARE_MAPPING[data][0]] = {
|
||||||
|
'raw': encoded_exif[data],
|
||||||
|
'formatted':
|
||||||
|
getattr(helpers, SOFTWARE_MAPPING[data][1])(encoded_exif[data]), # pylint: disable=E0602
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
exif['Software'][SOFTWARE_MAPPING[data][0]] = {
|
||||||
|
'raw': encoded_exif[data],
|
||||||
|
}
|
||||||
|
elif data in FILE_MAPPING:
|
||||||
|
if len(FILE_MAPPING[data]) == 2:
|
||||||
|
exif['File'][FILE_MAPPING[data][0]] = {
|
||||||
|
'raw': encoded_exif[data],
|
||||||
|
'formatted':
|
||||||
|
getattr(helpers, FILE_MAPPING[data][1])(encoded_exif[data]), # pylint: disable=E0602
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
exif['File'][FILE_MAPPING[data][0]] = {
|
||||||
|
'raw': encoded_exif[data]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Remove empty keys
|
||||||
|
if len(exif['Photographer']) == 0:
|
||||||
|
del exif['Photographer']
|
||||||
|
if len(exif['Camera']) == 0:
|
||||||
|
del exif['Camera']
|
||||||
|
if len(exif['Software']) == 0:
|
||||||
|
del exif['Software']
|
||||||
|
if len(exif['File']) == 0:
|
||||||
|
del exif['File']
|
||||||
|
|
||||||
|
return exif
|
407
gallery/metadata/helpers.py
Normal file
407
gallery/metadata/helpers.py
Normal file
|
@ -0,0 +1,407 @@
|
||||||
|
"""
|
||||||
|
OnlyLegs - Metadata Parser
|
||||||
|
Metadata formatting helpers
|
||||||
|
"""
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
def human_size(value):
|
||||||
|
"""
|
||||||
|
Formats the size of a file in a human readable format
|
||||||
|
"""
|
||||||
|
for unit in ["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"]:
|
||||||
|
if abs(value) < 1024.0:
|
||||||
|
return f"{value:3.1f}{unit}B"
|
||||||
|
value /= 1024.0
|
||||||
|
|
||||||
|
return f"{value:.1f}YiB"
|
||||||
|
|
||||||
|
|
||||||
|
def date_format(value):
|
||||||
|
"""
|
||||||
|
Formats the date into a standard format
|
||||||
|
"""
|
||||||
|
return str(datetime.strptime(value, '%Y:%m:%d %H:%M:%S'))
|
||||||
|
|
||||||
|
|
||||||
|
def fnumber(value):
|
||||||
|
"""
|
||||||
|
Formats the f-number into a standard format
|
||||||
|
"""
|
||||||
|
return 'f/' + str(value)
|
||||||
|
|
||||||
|
|
||||||
|
def iso(value):
|
||||||
|
"""
|
||||||
|
Formats the ISO into a standard format
|
||||||
|
"""
|
||||||
|
return 'ISO ' + str(value)
|
||||||
|
|
||||||
|
|
||||||
|
def shutter(value):
|
||||||
|
"""
|
||||||
|
Formats the shutter speed into a standard format
|
||||||
|
"""
|
||||||
|
return str(value) + 's'
|
||||||
|
|
||||||
|
|
||||||
|
def focal_length(value):
|
||||||
|
"""
|
||||||
|
Formats the focal length into a standard format
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return str(value[0] / value[1]) + 'mm'
|
||||||
|
except TypeError:
|
||||||
|
return str(value) + 'mm'
|
||||||
|
|
||||||
|
|
||||||
|
def exposure(value):
|
||||||
|
"""
|
||||||
|
Formats the exposure value into a standard format
|
||||||
|
"""
|
||||||
|
return str(value) + 'EV'
|
||||||
|
|
||||||
|
|
||||||
|
def color_space(value):
|
||||||
|
"""
|
||||||
|
Maps the value of the color space to a human readable format
|
||||||
|
"""
|
||||||
|
value_map = {
|
||||||
|
0: 'Reserved',
|
||||||
|
1: 'sRGB',
|
||||||
|
65535: 'Uncalibrated'
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
return value_map[int(value)]
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def flash(value):
|
||||||
|
"""
|
||||||
|
Maps the value of the flash to a human readable format
|
||||||
|
"""
|
||||||
|
value_map = {
|
||||||
|
0: 'Flash did not fire',
|
||||||
|
1: 'Flash fired',
|
||||||
|
5: 'Strobe return light not detected',
|
||||||
|
7: 'Strobe return light detected',
|
||||||
|
9: 'Flash fired, compulsory flash mode',
|
||||||
|
13: 'Flash fired, compulsory flash mode, return light not detected',
|
||||||
|
15: 'Flash fired, compulsory flash mode, return light detected',
|
||||||
|
16: 'Flash did not fire, compulsory flash mode',
|
||||||
|
24: 'Flash did not fire, auto mode',
|
||||||
|
25: 'Flash fired, auto mode',
|
||||||
|
29: 'Flash fired, auto mode, return light not detected',
|
||||||
|
31: 'Flash fired, auto mode, return light detected',
|
||||||
|
32: 'No flash function',
|
||||||
|
65: 'Flash fired, red-eye reduction mode',
|
||||||
|
69: 'Flash fired, red-eye reduction mode, return light not detected',
|
||||||
|
71: 'Flash fired, red-eye reduction mode, return light detected',
|
||||||
|
73: 'Flash fired, compulsory flash mode, red-eye reduction mode',
|
||||||
|
77: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected',
|
||||||
|
79: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light detected',
|
||||||
|
89: 'Flash fired, auto mode, red-eye reduction mode',
|
||||||
|
93: 'Flash fired, auto mode, return light not detected, red-eye reduction mode',
|
||||||
|
95: 'Flash fired, auto mode, return light detected, red-eye reduction mode'
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
return value_map[int(value)]
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def exposure_program(value):
|
||||||
|
"""
|
||||||
|
Maps the value of the exposure program to a human readable format
|
||||||
|
"""
|
||||||
|
value_map = {
|
||||||
|
0: 'Not defined',
|
||||||
|
1: 'Manual',
|
||||||
|
2: 'Normal program',
|
||||||
|
3: 'Aperture priority',
|
||||||
|
4: 'Shutter priority',
|
||||||
|
5: 'Creative program',
|
||||||
|
6: 'Action program',
|
||||||
|
7: 'Portrait mode',
|
||||||
|
8: 'Landscape mode'
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
return value_map[int(value)]
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def metering_mode(value):
|
||||||
|
"""
|
||||||
|
Maps the value of the metering mode to a human readable format
|
||||||
|
"""
|
||||||
|
value_map = {
|
||||||
|
0: 'Unknown',
|
||||||
|
1: 'Average',
|
||||||
|
2: 'Center-Weighted Average',
|
||||||
|
3: 'Spot',
|
||||||
|
4: 'Multi-Spot',
|
||||||
|
5: 'Pattern',
|
||||||
|
6: 'Partial',
|
||||||
|
255: 'Other'
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
return value_map[int(value)]
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def resolution_unit(value):
|
||||||
|
"""
|
||||||
|
Maps the value of the resolution unit to a human readable format
|
||||||
|
"""
|
||||||
|
value_map = {
|
||||||
|
1: 'No absolute unit of measurement',
|
||||||
|
2: 'Inch',
|
||||||
|
3: 'Centimeter'
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
return value_map[int(value)]
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def light_source(value):
|
||||||
|
"""
|
||||||
|
Maps the value of the light source to a human readable format
|
||||||
|
"""
|
||||||
|
value_map = {
|
||||||
|
0: 'Unknown',
|
||||||
|
1: 'Daylight',
|
||||||
|
2: 'Fluorescent',
|
||||||
|
3: 'Tungsten (incandescent light)',
|
||||||
|
4: 'Flash',
|
||||||
|
9: 'Fine weather',
|
||||||
|
10: 'Cloudy weather',
|
||||||
|
11: 'Shade',
|
||||||
|
12: 'Daylight fluorescent (D 5700 - 7100K)',
|
||||||
|
13: 'Day white fluorescent (N 4600 - 5400K)',
|
||||||
|
14: 'Cool white fluorescent (W 3900 - 4500K)',
|
||||||
|
15: 'White fluorescent (WW 3200 - 3700K)',
|
||||||
|
17: 'Standard light A',
|
||||||
|
18: 'Standard light B',
|
||||||
|
19: 'Standard light C',
|
||||||
|
20: 'D55',
|
||||||
|
21: 'D65',
|
||||||
|
22: 'D75',
|
||||||
|
23: 'D50',
|
||||||
|
24: 'ISO studio tungsten',
|
||||||
|
255: 'Other light source',
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
return value_map[int(value)]
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def scene_capture_type(value):
|
||||||
|
"""
|
||||||
|
Maps the value of the scene capture type to a human readable format
|
||||||
|
"""
|
||||||
|
value_map = {
|
||||||
|
0: 'Standard',
|
||||||
|
1: 'Landscape',
|
||||||
|
2: 'Portrait',
|
||||||
|
3: 'Night scene',
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
return value_map[int(value)]
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def scene_type(value): # pylint: disable=W0613 # Itss fiiiineeee
|
||||||
|
"""
|
||||||
|
Maps the value of the scene type to a human readable format
|
||||||
|
"""
|
||||||
|
return 'Directly photographed image'
|
||||||
|
|
||||||
|
|
||||||
|
def white_balance(value):
|
||||||
|
"""
|
||||||
|
Maps the value of the white balance to a human readable format
|
||||||
|
"""
|
||||||
|
value_map = {
|
||||||
|
0: 'Auto white balance',
|
||||||
|
1: 'Manual white balance',
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
return value_map[int(value)]
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def exposure_mode(value):
|
||||||
|
"""
|
||||||
|
Maps the value of the exposure mode to a human readable format
|
||||||
|
"""
|
||||||
|
value_map = {
|
||||||
|
0: 'Auto exposure',
|
||||||
|
1: 'Manual exposure',
|
||||||
|
2: 'Auto bracket',
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
return value_map[int(value)]
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def sensitivity_type(value):
|
||||||
|
"""
|
||||||
|
Maps the value of the sensitivity type to a human readable format
|
||||||
|
"""
|
||||||
|
value_map = {
|
||||||
|
0:
|
||||||
|
'Unknown',
|
||||||
|
1:
|
||||||
|
'Standard Output Sensitivity',
|
||||||
|
2:
|
||||||
|
'Recommended Exposure Index',
|
||||||
|
3:
|
||||||
|
'ISO Speed',
|
||||||
|
4:
|
||||||
|
'Standard Output Sensitivity and Recommended Exposure Index',
|
||||||
|
5:
|
||||||
|
'Standard Output Sensitivity and ISO Speed',
|
||||||
|
6:
|
||||||
|
'Recommended Exposure Index and ISO Speed',
|
||||||
|
7:
|
||||||
|
'Standard Output Sensitivity, Recommended Exposure Index and ISO Speed',
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
return value_map[int(value)]
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def lens_specification(value):
|
||||||
|
"""
|
||||||
|
Maps the value of the lens specification to a human readable format
|
||||||
|
"""
|
||||||
|
return str(value[0] / value[1]) + 'mm - ' + str(value[2] / value[3]) + 'mm'
|
||||||
|
|
||||||
|
|
||||||
|
def compression_type(value):
|
||||||
|
"""
|
||||||
|
Maps the value of the compression type to a human readable format
|
||||||
|
"""
|
||||||
|
value_map = {
|
||||||
|
1: 'Uncompressed',
|
||||||
|
2: 'CCITT 1D',
|
||||||
|
3: 'T4/Group 3 Fax',
|
||||||
|
4: 'T6/Group 4 Fax',
|
||||||
|
5: 'LZW',
|
||||||
|
6: 'JPEG (old-style)',
|
||||||
|
7: 'JPEG',
|
||||||
|
8: 'Adobe Deflate',
|
||||||
|
9: 'JBIG B&W',
|
||||||
|
10: 'JBIG Color',
|
||||||
|
99: 'JPEG',
|
||||||
|
262: 'Kodak 262',
|
||||||
|
32766: 'Next',
|
||||||
|
32767: 'Sony ARW Compressed',
|
||||||
|
32769: 'Packed RAW',
|
||||||
|
32770: 'Samsung SRW Compressed',
|
||||||
|
32771: 'CCIRLEW',
|
||||||
|
32772: 'Samsung SRW Compressed 2',
|
||||||
|
32773: 'PackBits',
|
||||||
|
32809: 'Thunderscan',
|
||||||
|
32867: 'Kodak KDC Compressed',
|
||||||
|
32895: 'IT8CTPAD',
|
||||||
|
32896: 'IT8LW',
|
||||||
|
32897: 'IT8MP',
|
||||||
|
32898: 'IT8BL',
|
||||||
|
32908: 'PixarFilm',
|
||||||
|
32909: 'PixarLog',
|
||||||
|
32946: 'Deflate',
|
||||||
|
32947: 'DCS',
|
||||||
|
33003: 'Aperio JPEG 2000 YCbCr',
|
||||||
|
33005: 'Aperio JPEG 2000 RGB',
|
||||||
|
34661: 'JBIG',
|
||||||
|
34676: 'SGILog',
|
||||||
|
34677: 'SGILog24',
|
||||||
|
34712: 'JPEG 2000',
|
||||||
|
34713: 'Nikon NEF Compressed',
|
||||||
|
34715: 'JBIG2 TIFF FX',
|
||||||
|
34718: '(MDI) Binary Level Codec',
|
||||||
|
34719: '(MDI) Progressive Transform Codec',
|
||||||
|
34720: '(MDI) Vector',
|
||||||
|
34887: 'ESRI Lerc',
|
||||||
|
34892: 'Lossy JPEG',
|
||||||
|
34925: 'LZMA2',
|
||||||
|
34926: 'Zstd',
|
||||||
|
34927: 'WebP',
|
||||||
|
34933: 'PNG',
|
||||||
|
34934: 'JPEG XR',
|
||||||
|
65000: 'Kodak DCR Compressed',
|
||||||
|
65535: 'Pentax PEF Compressed',
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
return value_map[int(value)]
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def orientation(value):
|
||||||
|
"""
|
||||||
|
Maps the value of the orientation to a human readable format
|
||||||
|
"""
|
||||||
|
value_map = {
|
||||||
|
1: 'Horizontal (normal)',
|
||||||
|
2: 'Mirror horizontal',
|
||||||
|
3: 'Rotate 180',
|
||||||
|
4: 'Mirror vertical',
|
||||||
|
5: 'Mirror horizontal and rotate 270 CW',
|
||||||
|
6: 'Rotate 90 CW',
|
||||||
|
7: 'Mirror horizontal and rotate 90 CW',
|
||||||
|
8: 'Rotate 270 CW',
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
return value_map[int(value)]
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def components_configuration(value):
|
||||||
|
"""
|
||||||
|
Maps the value of the components configuration to a human readable format
|
||||||
|
"""
|
||||||
|
value_map = {
|
||||||
|
0: '',
|
||||||
|
1: 'Y',
|
||||||
|
2: 'Cb',
|
||||||
|
3: 'Cr',
|
||||||
|
4: 'R',
|
||||||
|
5: 'G',
|
||||||
|
6: 'B',
|
||||||
|
}
|
||||||
|
try:
|
||||||
|
return ''.join([value_map[int(x)] for x in value])
|
||||||
|
except KeyError:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def rating(value):
|
||||||
|
"""
|
||||||
|
Maps the value of the rating to a human readable format
|
||||||
|
"""
|
||||||
|
return str(value) + ' stars'
|
||||||
|
|
||||||
|
|
||||||
|
def rating_percent(value):
|
||||||
|
"""
|
||||||
|
Maps the value of the rating to a human readable format
|
||||||
|
"""
|
||||||
|
return str(value) + '%'
|
||||||
|
|
||||||
|
|
||||||
|
def pixel_dimension(value):
|
||||||
|
"""
|
||||||
|
Maps the value of the pixel dimension to a human readable format
|
||||||
|
"""
|
||||||
|
return str(value) + 'px'
|
62
gallery/metadata/mapping.py
Normal file
62
gallery/metadata/mapping.py
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
"""
|
||||||
|
OnlyLegs - Metatada Parser
|
||||||
|
Mapping for metadata
|
||||||
|
"""
|
||||||
|
PHOTOGRAHER_MAPPING = {
|
||||||
|
'Artist': ['Artist'],
|
||||||
|
'UserComment': ['Comment'],
|
||||||
|
'ImageDescription': ['Description'],
|
||||||
|
'Copyright': ['Copyright'],
|
||||||
|
}
|
||||||
|
CAMERA_MAPPING = {
|
||||||
|
'Model': ['Model'],
|
||||||
|
'Make': ['Make'],
|
||||||
|
'BodySerialNumber': ['Camera Type'],
|
||||||
|
'LensMake': ['Lens Make'],
|
||||||
|
'LenseModel': ['Lens Model'],
|
||||||
|
'LensSpecification': ['Lens Specification', 'lens_specification'],
|
||||||
|
'ComponentsConfiguration': ['Components Configuration', 'components_configuration'],
|
||||||
|
'DateTime': ['Date Processed', 'date_format'],
|
||||||
|
'DateTimeDigitized': ['Time Digitized', 'date_format'],
|
||||||
|
'OffsetTime': ['Time Offset'],
|
||||||
|
'OffsetTimeOriginal': ['Time Offset - Original'],
|
||||||
|
'OffsetTimeDigitized': ['Time Offset - Digitized'],
|
||||||
|
'DateTimeOriginal': ['Date Original', 'date_format'],
|
||||||
|
'FNumber': ['F-Stop', 'fnumber'],
|
||||||
|
'FocalLength': ['Focal Length', 'focal_length'],
|
||||||
|
'FocalLengthIn35mmFilm': ['Focal Length (35mm format)', 'focal_length'],
|
||||||
|
'MaxApertureValue': ['Max Aperture', 'fnumber'],
|
||||||
|
'ApertureValue': ['Aperture', 'fnumber'],
|
||||||
|
'ShutterSpeedValue': ['Shutter Speed', 'shutter'],
|
||||||
|
'ISOSpeedRatings': ['ISO Speed Ratings', 'iso'],
|
||||||
|
'ISOSpeed': ['ISO Speed', 'iso'],
|
||||||
|
'SensitivityType': ['Sensitivity Type', 'sensitivity_type'],
|
||||||
|
'ExposureBiasValue': ['Exposure Bias', 'ev'],
|
||||||
|
'ExposureTime': ['Exposure Time', 'shutter'],
|
||||||
|
'ExposureMode': ['Exposure Mode', 'exposure_mode'],
|
||||||
|
'ExposureProgram': ['Exposure Program', 'exposure_program'],
|
||||||
|
'WhiteBalance': ['White Balance', 'white_balance'],
|
||||||
|
'Flash': ['Flash', 'flash'],
|
||||||
|
'MeteringMode': ['Metering Mode', 'metering_mode'],
|
||||||
|
'LightSource': ['Light Source', 'light_source'],
|
||||||
|
'SceneCaptureType': ['Scene Capture Type', 'scene_capture_type'],
|
||||||
|
'SceneType': ['Scene Type', 'scene_type'],
|
||||||
|
'Rating': ['Rating', 'rating'],
|
||||||
|
'RatingPercent': ['Rating Percent', 'rating_percent'],
|
||||||
|
}
|
||||||
|
SOFTWARE_MAPPING = {
|
||||||
|
'Software': ['Software'],
|
||||||
|
'ColorSpace': ['Colour Space', 'color_space'],
|
||||||
|
'Compression': ['Compression', 'compression_type'],
|
||||||
|
}
|
||||||
|
FILE_MAPPING = {
|
||||||
|
'FileName': ['Name'],
|
||||||
|
'FileSize': ['Size', 'human_size'],
|
||||||
|
'FileFormat': ['Format'],
|
||||||
|
'FileWidth': ['Width', 'pixel_dimension'],
|
||||||
|
'FileHeight': ['Height', 'pixel_dimension'],
|
||||||
|
'Orientation': ['Orientation', 'orientation'],
|
||||||
|
'XResolution': ['X-resolution'],
|
||||||
|
'YResolution': ['Y-resolution'],
|
||||||
|
'ResolutionUnit': ['Resolution Units', 'resolution_unit'],
|
||||||
|
}
|
|
@ -40,8 +40,8 @@ def image(image_id):
|
||||||
if img is None:
|
if img is None:
|
||||||
abort(404)
|
abort(404)
|
||||||
|
|
||||||
exif = mt.metadata.yoink(
|
img_path = os.path.join(current_app.config['UPLOAD_FOLDER'], img.file_name)
|
||||||
os.path.join(current_app.config['UPLOAD_FOLDER'], img.file_name))
|
exif = mt.Metadata(img_path).yoink()
|
||||||
|
|
||||||
return render_template('image.html', image=img, exif=exif)
|
return render_template('image.html', image=img, exif=exif)
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ class CompileTheme():
|
||||||
print("No sass file found!")
|
print("No sass file found!")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
with open(os.path.join(css_dest, 'style.css'), encoding='utf-8') as file:
|
with open(os.path.join(css_dest, 'style.css'), 'w', encoding='utf-8') as file:
|
||||||
try:
|
try:
|
||||||
file.write(sass.compile(filename=sass_path,output_style='compressed'))
|
file.write(sass.compile(filename=sass_path,output_style='compressed'))
|
||||||
except sass.CompileError as err:
|
except sass.CompileError as err:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue