diff --git a/gallery/__init__.py b/gallery/__init__.py index 47ac985..86c0a1b 100644 --- a/gallery/__init__.py +++ b/gallery/__init__.py @@ -96,8 +96,8 @@ def create_app(test_config=None): app.register_blueprint(auth.blueprint) # Load routes for home and images - from . import gallery - app.register_blueprint(gallery.blueprint) + from . import routing + app.register_blueprint(routing.blueprint) app.add_url_rule('/', endpoint='index') # Load APIs diff --git a/gallery/api.py b/gallery/api.py index 4109c69..b3cbc66 100644 --- a/gallery/api.py +++ b/gallery/api.py @@ -11,14 +11,6 @@ from uuid import uuid4 blueprint = Blueprint('viewsbp', __name__, url_prefix='/api') -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}" - - @blueprint.route('/uploads/<file>/<int:quality>', methods=['GET']) def uploads(file, quality): # If quality is 0, return original file @@ -127,6 +119,5 @@ def metadata(id): abort(404) exif = mt.metadata.yoink(os.path.join(current_app.config['UPLOAD_FOLDER'], img['file_name'])) - filesize = os.path.getsize(os.path.join(current_app.config['UPLOAD_FOLDER'], img['file_name'])) - return jsonify({'metadata': exif, 'filesize': {'bytes': filesize, 'human': human_size(filesize)}}) \ No newline at end of file + return jsonify(exif) \ No newline at end of file diff --git a/gallery/metadata.py b/gallery/metadata.py index 96e25e0..f688fff 100644 --- a/gallery/metadata.py +++ b/gallery/metadata.py @@ -2,38 +2,65 @@ 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: - formatted = metadata.format(exif) + unformatted_exif = metadata.format(exif, file_size, file_name, file_resolution) else: - return None + # 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] + }, + } + } - return metadata.deleteEmpty(formatted) - - def deleteEmpty(dict): - new_dict = {} + formatted_exif = {} - for section in dict: + for section in unformatted_exif: tmp = {} - for value in dict[section]: - if dict[section][value]['raw'] != None: - if isinstance(dict[section][value]['raw'], PIL.TiffImagePlugin.IFDRational): - dict[section][value]['raw'] = dict[section][value]['raw'].__float__() - elif isinstance(dict[section][value]['raw'], bytes): - dict[section][value]['raw'] = dict[section][value]['raw'].decode('utf-8') + + 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] = dict[section][value] - + tmp[value] = unformatted_exif[section][value] if len(tmp) > 0: - new_dict[section] = tmp + formatted_exif[section] = tmp - return new_dict + return formatted_exif def getFile(filename): try: @@ -54,9 +81,9 @@ class metadata: return exif except Exception as e: - return None + return False - def format(raw): + def format(raw, file_size, file_name, file_resolution): exif = {} exif['Photographer'] = { @@ -72,11 +99,6 @@ class metadata: 'type': 'text', 'raw': raw["ImageDescription"]["raw"] }, - 'Date Digitized': { - 'type': 'date', - 'raw': raw["DateTimeDigitized"]["raw"], - 'formatted': metadata.date(raw["DateTimeDigitized"]["raw"]) - }, 'Copyright': { 'type': 'text', 'raw': raw["Copyright"]["raw"] @@ -91,6 +113,14 @@ class metadata: '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'], @@ -110,24 +140,28 @@ class metadata: 'raw': raw['DateTime']['raw'], 'formatted': metadata.date(raw['DateTime']['raw']) }, - } - exif['Software'] = { - 'Software': { + 'Date Digitized': { + 'type': 'date', + 'raw': raw["DateTimeDigitized"]["raw"], + 'formatted': metadata.date(raw["DateTimeDigitized"]["raw"]) + }, + 'Time Offset': { 'type': 'text', - 'raw': raw['Software']['raw'] + 'raw': raw["OffsetTime"]["raw"] }, - 'Colour Space': { - 'type': 'number', - 'raw': raw['ColorSpace']['raw'], - 'formatted': metadata.colorSpace(raw['ColorSpace']['raw']) + 'Time Offset - Original': { + 'type': 'text', + 'raw': raw["OffsetTimeOriginal"]["raw"] }, - 'Compression': { - 'type': 'number', - 'raw': raw['Compression']['raw'], - 'formatted': metadata.compression(raw['Compression']['raw']) + 'Time Offset - Digitized': { + 'type': 'text', + 'raw': raw["OffsetTimeDigitized"]["raw"] + }, + 'Date Original': { + 'type': 'date', + 'raw': raw["DateTimeOriginal"]["raw"], + 'formatted': metadata.date(raw["DateTimeOriginal"]["raw"]) }, - } - exif['Photo'] = { 'FNumber': { 'type': 'fnumber', 'raw': raw["FNumber"]["raw"], @@ -135,11 +169,13 @@ class metadata: }, 'Focal Length': { 'type': 'focal', - 'raw': raw["FocalLength"]["raw"] + 'raw': raw["FocalLength"]["raw"], + 'formatted': metadata.focal(raw["FocalLength"]["raw"]) }, - 'Focal Length - Film': { + 'Focal Length (35mm format)': { 'type': 'focal', - 'raw': raw["FocalLengthIn35mmFilm"]["raw"] + 'raw': raw["FocalLengthIn35mmFilm"]["raw"], + 'formatted': metadata.focal(raw["FocalLengthIn35mmFilm"]["raw"]) }, 'Max Aperture': { 'type': 'fnumber', @@ -220,16 +256,55 @@ class metadata: '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': raw["ImageWidth"]["raw"] + 'raw': file_resolution[0] }, 'Height': { 'type': 'number', - 'raw': raw["ImageLength"]["raw"] + 'raw': file_resolution[1] }, 'Orientation': { 'type': 'number', @@ -250,8 +325,27 @@ class metadata: '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' @@ -281,7 +375,10 @@ class metadata: def focal(value): if value != None: - return str(value[0] / value[1]) + 'mm' + try: + return str(value[0] / value[1]) + 'mm' + except: + return str(value) + 'mm' else: return None @@ -297,7 +394,6 @@ class metadata: 65535: 'Uncalibrated', 0: 'Reserved' } - try: return types[int(value)] except: @@ -328,7 +424,6 @@ class metadata: 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: @@ -346,7 +441,6 @@ class metadata: 7: 'Portrait mode', 8: 'Landscape mode' } - try: return types[int(value)] except: @@ -363,7 +457,6 @@ class metadata: 6: 'Partial', 255: 'Other' } - try: return types[int(value)] except: @@ -375,7 +468,6 @@ class metadata: 2: 'Inch', 3: 'Centimeter' } - try: return types[int(value)] except: @@ -405,7 +497,6 @@ class metadata: 24: 'ISO studio tungsten', 255: 'Other light source', } - try: return types[int(value)] except: @@ -418,7 +509,6 @@ class metadata: 2: 'Portrait', 3: 'Night scene', } - try: return types[int(value)] except: @@ -435,7 +525,6 @@ class metadata: 0: 'Auto white balance', 1: 'Manual white balance', } - try: return types[int(value)] except: @@ -447,7 +536,6 @@ class metadata: 1: 'Manual exposure', 2: 'Auto bracket', } - try: return types[int(value)] except: @@ -464,7 +552,6 @@ class metadata: 6: 'Recommended Exposure Index and ISO Speed', 7: 'Standard Output Sensitivity, Recommended Exposure Index and ISO Speed', } - try: return types[int(value)] except: @@ -479,9 +566,55 @@ class metadata: def compression(value): types = { 1: 'Uncompressed', - 6: 'JPEG compression', + 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: @@ -498,7 +631,6 @@ class metadata: 7: 'Mirror horizontal and rotate 90 CW', 8: 'Rotate 270 CW', } - try: return types[int(value)] except: @@ -514,8 +646,13 @@ class metadata: 5: 'G', 6: 'B', } - try: return ''.join([types[int(x)] for x in value]) except: - return None \ No newline at end of file + return None + + def rating(value): + return str(value) + ' stars' + + def ratingPercent(value): + return str(value) + '%' \ No newline at end of file diff --git a/gallery/gallery.py b/gallery/routing.py similarity index 65% rename from gallery/gallery.py rename to gallery/routing.py index d641bd9..7107b07 100644 --- a/gallery/gallery.py +++ b/gallery/routing.py @@ -15,14 +15,6 @@ dt = datetime.now() blueprint = Blueprint('gallery', __name__) -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}" - - @blueprint.route('/') def index(): db = get_db() @@ -42,18 +34,8 @@ def image(id): abort(404) exif = mt.metadata.yoink(os.path.join(current_app.config['UPLOAD_FOLDER'], image['file_name'])) - file_size = human_size(os.path.getsize(os.path.join(current_app.config['UPLOAD_FOLDER'], image['file_name']))) - - try: - width = exif['File']['Width']['value'] - height = exif['File']['Height']['value'] - except: - try: - width, height = Image.open(os.path.join(current_app.config['UPLOAD_FOLDER'], image['file_name'])).size - except: - width, height = 0, 0 - return render_template('image.html', image=image, exif=exif, file_size=file_size, width=width, height=height) + return render_template('image.html', image=image, exif=exif) @blueprint.route('/group') diff --git a/gallery/templates/image.html b/gallery/templates/image.html index 77a5c4d..243e448 100644 --- a/gallery/templates/image.html +++ b/gallery/templates/image.html @@ -19,8 +19,8 @@ src="/api/uploads/{{ image['file_name'] }}/1000" onload="imgFade(this)" style="opacity:0;" onerror="this.src='/static/images/error.png'" - width="{{ width }}" - height="{{ height }}" + width="{{ exif['File']['Width']['raw'] }}" + height="{{ exif['File']['Height']['raw'] }}" /> </div> @@ -121,86 +121,69 @@ <td>Upload date</td> <td><span class="time">{{ image['created_at'] }}</span></td> </tr> - <tr> - <td>Filename</td> - <td>{{ image['file_name'] }}</td> - </tr> - <tr> - <td>File size</td> - <td>{{ file_size }}</td> - </tr> </table> </div> - </div> - {% if exif %} - {% for tag in exif %} - <div class="image-info"> - {% if tag == 'Photographer' %} - <div class="image-info__header"> - <svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -2 24 24" fill="currentColor"> - <path d="M3.534 10.07a1 1 0 1 1 .733 1.86A3.579 3.579 0 0 0 2 15.26V17a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-1.647a3.658 3.658 0 0 0-2.356-3.419 1 1 0 1 1 .712-1.868A5.658 5.658 0 0 1 14 15.353V17a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3v-1.74a5.579 5.579 0 0 1 3.534-5.19zM7 0a4 4 0 0 1 4 4v2a4 4 0 1 1-8 0V4a4 4 0 0 1 4-4zm0 2a2 2 0 0 0-2 2v2a2 2 0 1 0 4 0V4a2 2 0 0 0-2-2z"></path> - </svg> - <h2>Photographer</h2> - </div> - {% elif tag == 'Camera' %} - <div class="image-info__header"> - <svg xmlns="http://www.w3.org/2000/svg" viewBox="-2 -4 24 24" fill="currentColor"> - <path d="M5.676 5H4a2 2 0 0 0-2 2v5a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-1.676l-.387-1.501A2.002 2.002 0 0 0 12 2H8a2 2 0 0 0-1.937 1.499L5.676 5zm-1.55-2C4.57 1.275 6.136 0 8 0h4a4.002 4.002 0 0 1 3.874 3H16a4 4 0 0 1 4 4v5a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V7a4 4 0 0 1 4-4h.126zM10 13a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm0-2a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm6-3a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"></path> - </svg> - <h2>Camera</h2> - </div> - {% elif tag == 'Software' %} - <div class="image-info__header"> - <svg xmlns="http://www.w3.org/2000/svg" viewBox="-2 -4 24 24" fill="currentColor"> - <path d="M2 13v1h3V2H2v9h1v2H2zM1 0h5a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1V1a1 1 0 0 1 1-1zm9 3h8a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2h-8a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2zm0 2v6h8V5h-8zm2 9h4a1 1 0 0 1 0 2h-4a1 1 0 0 1 0-2z"></path> - </svg> - <h2>Software</h2> - </div> - {% elif tag == 'Photo' %} - <div class="image-info__header"> - <svg xmlns="http://www.w3.org/2000/svg" viewBox="-4 -2 24 24" fill="currentColor"> - <path d="M14 8.322V2H2v12h3.576l3.97-5.292A3 3 0 0 1 14 8.322zm0 3.753l-1.188-2.066a1 1 0 0 0-1.667-.101L8.076 14H14v-1.925zM14 16H2v2h12v-2zM2 0h12a2 2 0 0 1 2 2v16a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2zm4 9a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0-2a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"></path> - </svg> - <h2>Photo</h2> - </div> - {% elif tag == 'File' %} - <div class="image-info__header"> - <svg xmlns="http://www.w3.org/2000/svg" viewBox="-4 -2 24 24" fill="currentColor"> - <path d="M10.298 2H3a1 1 0 0 0-1 1v14a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V4.961L10.298 2zM3 0h8l5 4v13a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V3a3 3 0 0 1 3-3z"></path> - </svg> - <h2>File</h2> - </div> - {% else %} - <div class="image-info__header"> - <svg xmlns="http://www.w3.org/2000/svg" viewBox="-2 -2 24 24" fill="currentColor"> - <path d="M14.95 7.879l-.707-.707a1 1 0 0 1 1.414-1.415l.707.707 1.414-1.414-2.828-2.828L2.222 14.95l2.828 2.828 1.414-1.414L5.05 14.95a1 1 0 0 1 1.414-1.414L7.88 14.95l1.414-1.414-.707-.708A1 1 0 0 1 10 11.414l.707.707 1.414-1.414-1.414-1.414a1 1 0 0 1 1.414-1.414l1.415 1.414 1.414-1.414zM.808 13.536L13.536.808a2 2 0 0 1 2.828 0l2.828 2.828a2 2 0 0 1 0 2.828L6.464 19.192a2 2 0 0 1-2.828 0L.808 16.364a2 2 0 0 1 0-2.828z"></path> - </svg> - <h2>{{tag}}</h2> - </div> - {% endif %} - <div class="image-info__content"> - <table> - {% for subtag in exif[tag] %} - <tr> - <td>{{subtag}}</td> - {% if exif[tag][subtag]['formatted'] %} - {% if exif[tag][subtag]['type'] == 'date' %} - <td><span class="time">{{exif[tag][subtag]['formatted']}}</span></td> - {% else %} - <td>{{exif[tag][subtag]['formatted']}}</td> - {% endif %} - {% elif exif[tag][subtag]['raw'] %} - <td>{{exif[tag][subtag]['raw']}}</td> - {% else %} - <td class="empty-table">sad noises</td> - {% endif %} - </tr> - {% endfor %} - </table> + </div> + {% for tag in exif %} + <div class="image-info"> + {% if tag == 'Photographer' %} + <div class="image-info__header"> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="-5 -2 24 24" fill="currentColor"> + <path d="M3.534 10.07a1 1 0 1 1 .733 1.86A3.579 3.579 0 0 0 2 15.26V17a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-1.647a3.658 3.658 0 0 0-2.356-3.419 1 1 0 1 1 .712-1.868A5.658 5.658 0 0 1 14 15.353V17a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3v-1.74a5.579 5.579 0 0 1 3.534-5.19zM7 0a4 4 0 0 1 4 4v2a4 4 0 1 1-8 0V4a4 4 0 0 1 4-4zm0 2a2 2 0 0 0-2 2v2a2 2 0 1 0 4 0V4a2 2 0 0 0-2-2z"></path> + </svg> + <h2>Photographer</h2> </div> + {% elif tag == 'Camera' %} + <div class="image-info__header"> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="-2 -4 24 24" fill="currentColor"> + <path d="M5.676 5H4a2 2 0 0 0-2 2v5a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-1.676l-.387-1.501A2.002 2.002 0 0 0 12 2H8a2 2 0 0 0-1.937 1.499L5.676 5zm-1.55-2C4.57 1.275 6.136 0 8 0h4a4.002 4.002 0 0 1 3.874 3H16a4 4 0 0 1 4 4v5a4 4 0 0 1-4 4H4a4 4 0 0 1-4-4V7a4 4 0 0 1 4-4h.126zM10 13a4 4 0 1 1 0-8 4 4 0 0 1 0 8zm0-2a2 2 0 1 0 0-4 2 2 0 0 0 0 4zm6-3a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"></path> + </svg> + <h2>Camera</h2> + </div> + {% elif tag == 'Software' %} + <div class="image-info__header"> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="-2 -4 24 24" fill="currentColor"> + <path d="M2 13v1h3V2H2v9h1v2H2zM1 0h5a1 1 0 0 1 1 1v14a1 1 0 0 1-1 1H1a1 1 0 0 1-1-1V1a1 1 0 0 1 1-1zm9 3h8a2 2 0 0 1 2 2v6a2 2 0 0 1-2 2h-8a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2zm0 2v6h8V5h-8zm2 9h4a1 1 0 0 1 0 2h-4a1 1 0 0 1 0-2z"></path> + </svg> + <h2>Software</h2> + </div> + {% elif tag == 'Photo' %} + <div class="image-info__header"> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="-4 -2 24 24" fill="currentColor"> + <path d="M14 8.322V2H2v12h3.576l3.97-5.292A3 3 0 0 1 14 8.322zm0 3.753l-1.188-2.066a1 1 0 0 0-1.667-.101L8.076 14H14v-1.925zM14 16H2v2h12v-2zM2 0h12a2 2 0 0 1 2 2v16a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2V2a2 2 0 0 1 2-2zm4 9a3 3 0 1 1 0-6 3 3 0 0 1 0 6zm0-2a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"></path> + </svg> + <h2>Photo</h2> + </div> + {% else %} + <div class="image-info__header"> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="-2 -2 24 24" fill="currentColor"> + <path d="M14.95 7.879l-.707-.707a1 1 0 0 1 1.414-1.415l.707.707 1.414-1.414-2.828-2.828L2.222 14.95l2.828 2.828 1.414-1.414L5.05 14.95a1 1 0 0 1 1.414-1.414L7.88 14.95l1.414-1.414-.707-.708A1 1 0 0 1 10 11.414l.707.707 1.414-1.414-1.414-1.414a1 1 0 0 1 1.414-1.414l1.415 1.414 1.414-1.414zM.808 13.536L13.536.808a2 2 0 0 1 2.828 0l2.828 2.828a2 2 0 0 1 0 2.828L6.464 19.192a2 2 0 0 1-2.828 0L.808 16.364a2 2 0 0 1 0-2.828z"></path> + </svg> + <h2>{{tag}}</h2> + </div> + {% endif %} + <div class="image-info__content"> + <table> + {% for subtag in exif[tag] %} + <tr> + <td>{{subtag}}</td> + {% if exif[tag][subtag]['formatted'] %} + {% if exif[tag][subtag]['type'] == 'date' %} + <td><span class="time">{{exif[tag][subtag]['formatted']}}</span></td> + {% else %} + <td>{{exif[tag][subtag]['formatted']}}</td> + {% endif %} + {% elif exif[tag][subtag]['raw'] %} + <td>{{exif[tag][subtag]['raw']}}</td> + {% else %} + <td class="empty-table">Oops, an error</td> + {% endif %} + </tr> + {% endfor %} + </table> </div> - {% endfor %} - {% endif %} + </div> + {% endfor %} </div> {% endblock %} diff --git a/gallery/user/themes/default/ui/wrappers/image.sass b/gallery/user/themes/default/ui/wrappers/image.sass index f34abc9..fefb157 100644 --- a/gallery/user/themes/default/ui/wrappers/image.sass +++ b/gallery/user/themes/default/ui/wrappers/image.sass @@ -170,7 +170,7 @@ overflow: hidden table - margin: 0 0 0 1rem + margin: 0 padding: 0 max-width: 100% @@ -190,7 +190,10 @@ padding: 0.25rem 1rem 0.25rem 0 width: 50% + max-width: 0 + overflow: hidden + text-overflow: ellipsis white-space: nowrap font-size: 1rem @@ -264,15 +267,6 @@ .image-wrapper padding-bottom: 4rem - .image-info__content - table - margin: 0 - - tr - td:first-child - width: auto - td:last-child - width: 75% .image-info__header background-image: none background-color: $black2 \ No newline at end of file