""" 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 "ƒ/" + 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: calculated = value[0] / value[1] except TypeError: calculated = value return str(calculated) + " 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: "Did not fire", 1: "Fired", 5: "Strobe return light not detected", 7: "Strobe return light detected", 9: "Fired, compulsory", 13: "Fired, compulsory, return light not detected", 15: "Fired, compulsory, return light detected", 16: "Did not fire, compulsory", 24: "Did not fire, auto mode", 25: "Fired, auto mode", 29: "Fired, auto mode, return light not detected", 31: "Fired, auto mode, return light detected", 32: "No function", 65: "Fired, red-eye reduction mode", 69: "Fired, red-eye reduction mode, return light not detected", 71: "Fired, red-eye reduction mode, return light detected", 73: "Fired, compulsory, red-eye reduction mode", 77: "Fired, compulsory, red-eye reduction mode, return light not detected", 79: "Fired, compulsory, red-eye reduction mode, return light detected", 89: "Fired, auto mode, red-eye reduction mode", 93: "Fired, auto mode, return light not detected, red-eye reduction mode", 95: "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 white_balance(value): """ Maps the value of the white balance to a human readable format """ value_map = { 0: "Auto", 1: "Manual", } 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", 1: "Manual", 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 """ try: return str(value[0] / value[1]) + "mm - " + str(value[2] / value[3]) + "mm" except TypeError: return None 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 = { 0: "Undefined", 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" def title(value): """ Maps the value of the title to a human readable format """ return str(value.title()) def subject_distance(value): """ Maps the value of the subject distance to a human readable format """ return str(value) + " m" def subject_distance_range(value): """ Maps the value of the subject distance range to a human readable format """ value_map = { 0: "Unknown", 1: "Macro", 2: "Close view", 3: "Distant view", } try: return value_map[int(value)] except KeyError: return None