Loading bin/pyggle +101 −14 Original line number Diff line number Diff line Loading @@ -52,7 +52,7 @@ class GPSData: self.location = location class ThumbnailHTML: class ImageHTML: def __init__(self): self.gps = None self.datetime = None Loading @@ -60,36 +60,55 @@ class ThumbnailHTML: self.make = None self.focus = None self.f_num = None self.exposure = None self.exposure_mode = None self.exposure_program = None self.focal_length = None self.iso = None def set_datetime(self, dt): self.datetime = dt.strftime("""<span class="datetime">%d.%m.%Y %H:%M</span>""") def set_exposure_mode(self, exposure_mode): self.exposure_mode = f"""<span class="exposure-mode">{exposure_mode}</span>""" def set_exposure_program(self, exposure_program): self.exposure_program = ( f"""<span class="exposure-program">{exposure_program}</span>""" ) def set_focus(self, f_num, exposure, focal_length, focal_length35, iso): entries = list() if f_num is not None: entries.append(f"""<span class="fnumber">f/{format_f(f_num)}</span>""") self.f_num = f"""<span class="fnumber">f/{format_f(f_num)}</span>""" entries.append(self.f_num) if exposure is not None: if exposure >= 1: entries.append( self.exposure = ( f"""<span class="exposure">{format_f(exposure)}s</span>""" ) elif exposure >= 1e-3: entries.append( self.exposure = ( f"""<span class="exposure">{format_f(exposure * 1e3)}ms</span>""" ) else: entries.append( self.exposure = ( f"""<span class="exposure">{format_f(exposure * 1e6)}µs</span>""" ) entries.append(self.exposure) if focal_length is not None: entry = f"{format_f(focal_length)}mm" if focal_length35 is not None and focal_length35 != focal_length: entry += f" (≙ {format_f(focal_length35)}mm)" entries.append(f"""<span class="focal">{entry}</span>""") self.focal_length = f"""<span class="focal">{entry}</span>""" entries.append(self.focal_length) if iso is not None: entries.append(f"""<span class="iso">ISO{iso}</span>""") self.iso = f"""<span class="iso">ISO{iso}</span>""" entries.append(self.iso) self.focus = " ".join(entries) Loading @@ -99,7 +118,11 @@ class ThumbnailHTML: def set_makemodel(self, make, model): self.make = f"""<span class="makemodel">{make} {model}</span>""" def to_html(self, index, filename, thumbname): def to_thumbnail_html(self, index, filename, thumbname, with_detail_page=False): if with_detail_page: self.focus = f"""<a href="{filename}.html">{self.focus}</a>""" exif_lines = (self.datetime, self.gps, self.make, self.focus) exif_html = """ <span class="sep">•</span> """.join(filter(bool, exif_lines)) Loading @@ -117,6 +140,37 @@ class ThumbnailHTML: return buf def to_detail_html(self, filename): buf = """<div class="image-page">""" buf += f"""<a href="{filename}"><img src="{filename}"></a>""" buf += "</div>\n" buf += """<div class="image-details">\n""" buf += "<p><table>\n" if self.datetime: buf += f"<tr><th>Zeit</th><td>{self.datetime}</td></tr>\n" if self.gps: buf += f"<tr><th>Ort</th><td>{self.gps}</td></tr>\n" if self.make: buf += f"<tr><th>Kamera</th><td>{self.make}</td></tr>\n" buf += "<tr><th></th><td> </td></tr>\n" if self.f_num: buf += f"<tr><th>Blende</th><td>{self.f_num}</td></tr>\n" if self.exposure: buf += f"<tr><th>Belichtung</th><td>{self.exposure}</td></tr>\n" if self.iso: buf += f"<tr><th>Verstärkung</th><td>{self.iso}</td></tr>\n" if self.focal_length: buf += f"<tr><th>Brennweite</th><td>{self.focal_length}</td></tr>\n" buf += "<tr><th></th><td> </td></tr>\n" if self.exposure_program: buf += f"<tr><th>Modus</th><td>{self.exposure_program}</td></tr>\n" if self.exposure_mode: buf += f"<tr><th>Belichtung</th><td>{self.exposure_mode}</td></tr>\n" buf += "</table></p></div>\n" return buf class Thumbnail: def __init__(self, filename, im, size=250, with_gps=False): Loading @@ -136,7 +190,7 @@ class Thumbnail: im.thumbnail((self.size * 2, self.size * 2)) im.convert("RGB").save(self.thumbname, "JPEG") self.html = ThumbnailHTML() self.html = ImageHTML() self._get_datetime() self._get_focus() Loading Loading @@ -203,6 +257,16 @@ class Thumbnail: self.html.set_focus(f_num, exposure, focal_length, focal_length35, iso) try: self.html.set_exposure_mode(self.exif_tag["EXIF ExposureMode"]) except KeyError: pass try: self.html.set_exposure_program(self.exif_tag["EXIF ExposureProgram"]) except KeyError: pass def _get_gps(self): try: lat = self.exif_tag["GPS GPSLatitude"] Loading Loading @@ -283,8 +347,16 @@ class Thumbnail: self.html.set_makemodel(make, model) def to_html(self, index): return self.html.to_html(i, self.filename, self.thumbname) def to_html(self, index, with_detail_page=False): return self.html.to_thumbnail_html( i, self.filename, self.thumbname, with_detail_page ) def to_detail_html(self, html_prefix, html_postfix): with open(f"{self.filename}.html", "w") as f: f.write(html_prefix.replace("<!-- $title -->", self.filename)) f.write(self.html.to_detail_html(self.filename)) f.write(html_postfix) def copy_files(base_dir): Loading Loading @@ -334,13 +406,20 @@ if __name__ == "__main__": default=16, help="Zoom Level for reverse geocoding", ) parser.add_argument("--reverse", action="store_true") parser.add_argument("--reverse", action="store_true", help="Reverse sort order") parser.add_argument("--size", type=int, default=250, help="Thumbnail size [px]") parser.add_argument("--sort", type=str, default="none", help="sort images") parser.add_argument( "--sort", metavar="MODE", choices=["none", "time"], default="none", help="Sort images", ) parser.add_argument( "--spacing", type=float, default=1.1, help="Thumbnail spacing ratio" ) parser.add_argument("--title", type=str, help="HTML title", default="") parser.add_argument("--with-detail-page", action="store_true") parser.add_argument("--with-nominatim", action="store_true") parser.add_argument("images", type=str, nargs="+") Loading Loading @@ -374,7 +453,15 @@ if __name__ == "__main__": thumbnails = sorted(thumbnails, key=lambda t: t.exif_dt, reverse=args.reverse) for i, thumbnail in enumerate(thumbnails): html_buf += thumbnail.to_html(i) html_buf += thumbnail.to_html(i, args.with_detail_page) if args.with_detail_page: with open(f"{base_dir}/share/html_detail_start", "r") as f: detail_html_start = f.read() with open(f"{base_dir}/share/html_detail_end", "r") as f: detail_html_end = f.read() for thumbnail in thumbnails: thumbnail.to_detail_html(detail_html_start, detail_html_end) with open(f"{base_dir}/share/html_end", "r") as f: html_buf += f.read() Loading share/css/main.css +19 −4 Original line number Diff line number Diff line Loading @@ -10,8 +10,8 @@ div.image-container { text-align: center; font-size: 80%; float: left; width: /* $boxwidth */; height: /* $boxheight */; width: 275.0px; height: 275.0px; } div.image-container a { Loading @@ -19,8 +19,23 @@ div.image-container a { } div.image-container img { max-width: /* $imgwidth */; max-height: /* $imgheight */; max-width: 250px; max-height: 250px; } div.image-page img { max-width: 100%; } div.image-details { max-width: 50em; margin-top: 2em; margin-left: auto; margin-right: auto; } div.image-details th { text-align: left; } .gslide-desc p span { Loading share/html_detail_end 0 → 100644 +2 −0 Original line number Diff line number Diff line </body> </html> share/html_detail_start 0 → 100644 +34 −0 Original line number Diff line number Diff line <!DOCTYPE html> <html> <head> <title><!-- $title --></title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" type="text/css" href=".data/css/main.css"/> <link rel="stylesheet" type="text/css" href=".data/css/light.css" id="theme"/> <script> function addStyleSheet(name, id) { var path = '.data/css/' + name + '.css'; var old = document.getElementById(id); if (old && (old.href != path)) { old.href = path; } } var otherTheme = { 'dark': 'light', 'light': 'dark', }; var currentTheme = localStorage.getItem('theme'); if (!otherTheme.hasOwnProperty(currentTheme)) { currentTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; } addStyleSheet(currentTheme, 'theme'); function toggleTheme() { currentTheme = otherTheme[currentTheme] || 'light'; localStorage.setItem('theme', currentTheme); addStyleSheet(currentTheme, 'theme'); } </script> </head> <body> Loading
bin/pyggle +101 −14 Original line number Diff line number Diff line Loading @@ -52,7 +52,7 @@ class GPSData: self.location = location class ThumbnailHTML: class ImageHTML: def __init__(self): self.gps = None self.datetime = None Loading @@ -60,36 +60,55 @@ class ThumbnailHTML: self.make = None self.focus = None self.f_num = None self.exposure = None self.exposure_mode = None self.exposure_program = None self.focal_length = None self.iso = None def set_datetime(self, dt): self.datetime = dt.strftime("""<span class="datetime">%d.%m.%Y %H:%M</span>""") def set_exposure_mode(self, exposure_mode): self.exposure_mode = f"""<span class="exposure-mode">{exposure_mode}</span>""" def set_exposure_program(self, exposure_program): self.exposure_program = ( f"""<span class="exposure-program">{exposure_program}</span>""" ) def set_focus(self, f_num, exposure, focal_length, focal_length35, iso): entries = list() if f_num is not None: entries.append(f"""<span class="fnumber">f/{format_f(f_num)}</span>""") self.f_num = f"""<span class="fnumber">f/{format_f(f_num)}</span>""" entries.append(self.f_num) if exposure is not None: if exposure >= 1: entries.append( self.exposure = ( f"""<span class="exposure">{format_f(exposure)}s</span>""" ) elif exposure >= 1e-3: entries.append( self.exposure = ( f"""<span class="exposure">{format_f(exposure * 1e3)}ms</span>""" ) else: entries.append( self.exposure = ( f"""<span class="exposure">{format_f(exposure * 1e6)}µs</span>""" ) entries.append(self.exposure) if focal_length is not None: entry = f"{format_f(focal_length)}mm" if focal_length35 is not None and focal_length35 != focal_length: entry += f" (≙ {format_f(focal_length35)}mm)" entries.append(f"""<span class="focal">{entry}</span>""") self.focal_length = f"""<span class="focal">{entry}</span>""" entries.append(self.focal_length) if iso is not None: entries.append(f"""<span class="iso">ISO{iso}</span>""") self.iso = f"""<span class="iso">ISO{iso}</span>""" entries.append(self.iso) self.focus = " ".join(entries) Loading @@ -99,7 +118,11 @@ class ThumbnailHTML: def set_makemodel(self, make, model): self.make = f"""<span class="makemodel">{make} {model}</span>""" def to_html(self, index, filename, thumbname): def to_thumbnail_html(self, index, filename, thumbname, with_detail_page=False): if with_detail_page: self.focus = f"""<a href="{filename}.html">{self.focus}</a>""" exif_lines = (self.datetime, self.gps, self.make, self.focus) exif_html = """ <span class="sep">•</span> """.join(filter(bool, exif_lines)) Loading @@ -117,6 +140,37 @@ class ThumbnailHTML: return buf def to_detail_html(self, filename): buf = """<div class="image-page">""" buf += f"""<a href="{filename}"><img src="{filename}"></a>""" buf += "</div>\n" buf += """<div class="image-details">\n""" buf += "<p><table>\n" if self.datetime: buf += f"<tr><th>Zeit</th><td>{self.datetime}</td></tr>\n" if self.gps: buf += f"<tr><th>Ort</th><td>{self.gps}</td></tr>\n" if self.make: buf += f"<tr><th>Kamera</th><td>{self.make}</td></tr>\n" buf += "<tr><th></th><td> </td></tr>\n" if self.f_num: buf += f"<tr><th>Blende</th><td>{self.f_num}</td></tr>\n" if self.exposure: buf += f"<tr><th>Belichtung</th><td>{self.exposure}</td></tr>\n" if self.iso: buf += f"<tr><th>Verstärkung</th><td>{self.iso}</td></tr>\n" if self.focal_length: buf += f"<tr><th>Brennweite</th><td>{self.focal_length}</td></tr>\n" buf += "<tr><th></th><td> </td></tr>\n" if self.exposure_program: buf += f"<tr><th>Modus</th><td>{self.exposure_program}</td></tr>\n" if self.exposure_mode: buf += f"<tr><th>Belichtung</th><td>{self.exposure_mode}</td></tr>\n" buf += "</table></p></div>\n" return buf class Thumbnail: def __init__(self, filename, im, size=250, with_gps=False): Loading @@ -136,7 +190,7 @@ class Thumbnail: im.thumbnail((self.size * 2, self.size * 2)) im.convert("RGB").save(self.thumbname, "JPEG") self.html = ThumbnailHTML() self.html = ImageHTML() self._get_datetime() self._get_focus() Loading Loading @@ -203,6 +257,16 @@ class Thumbnail: self.html.set_focus(f_num, exposure, focal_length, focal_length35, iso) try: self.html.set_exposure_mode(self.exif_tag["EXIF ExposureMode"]) except KeyError: pass try: self.html.set_exposure_program(self.exif_tag["EXIF ExposureProgram"]) except KeyError: pass def _get_gps(self): try: lat = self.exif_tag["GPS GPSLatitude"] Loading Loading @@ -283,8 +347,16 @@ class Thumbnail: self.html.set_makemodel(make, model) def to_html(self, index): return self.html.to_html(i, self.filename, self.thumbname) def to_html(self, index, with_detail_page=False): return self.html.to_thumbnail_html( i, self.filename, self.thumbname, with_detail_page ) def to_detail_html(self, html_prefix, html_postfix): with open(f"{self.filename}.html", "w") as f: f.write(html_prefix.replace("<!-- $title -->", self.filename)) f.write(self.html.to_detail_html(self.filename)) f.write(html_postfix) def copy_files(base_dir): Loading Loading @@ -334,13 +406,20 @@ if __name__ == "__main__": default=16, help="Zoom Level for reverse geocoding", ) parser.add_argument("--reverse", action="store_true") parser.add_argument("--reverse", action="store_true", help="Reverse sort order") parser.add_argument("--size", type=int, default=250, help="Thumbnail size [px]") parser.add_argument("--sort", type=str, default="none", help="sort images") parser.add_argument( "--sort", metavar="MODE", choices=["none", "time"], default="none", help="Sort images", ) parser.add_argument( "--spacing", type=float, default=1.1, help="Thumbnail spacing ratio" ) parser.add_argument("--title", type=str, help="HTML title", default="") parser.add_argument("--with-detail-page", action="store_true") parser.add_argument("--with-nominatim", action="store_true") parser.add_argument("images", type=str, nargs="+") Loading Loading @@ -374,7 +453,15 @@ if __name__ == "__main__": thumbnails = sorted(thumbnails, key=lambda t: t.exif_dt, reverse=args.reverse) for i, thumbnail in enumerate(thumbnails): html_buf += thumbnail.to_html(i) html_buf += thumbnail.to_html(i, args.with_detail_page) if args.with_detail_page: with open(f"{base_dir}/share/html_detail_start", "r") as f: detail_html_start = f.read() with open(f"{base_dir}/share/html_detail_end", "r") as f: detail_html_end = f.read() for thumbnail in thumbnails: thumbnail.to_detail_html(detail_html_start, detail_html_end) with open(f"{base_dir}/share/html_end", "r") as f: html_buf += f.read() Loading
share/css/main.css +19 −4 Original line number Diff line number Diff line Loading @@ -10,8 +10,8 @@ div.image-container { text-align: center; font-size: 80%; float: left; width: /* $boxwidth */; height: /* $boxheight */; width: 275.0px; height: 275.0px; } div.image-container a { Loading @@ -19,8 +19,23 @@ div.image-container a { } div.image-container img { max-width: /* $imgwidth */; max-height: /* $imgheight */; max-width: 250px; max-height: 250px; } div.image-page img { max-width: 100%; } div.image-details { max-width: 50em; margin-top: 2em; margin-left: auto; margin-right: auto; } div.image-details th { text-align: left; } .gslide-desc p span { Loading
share/html_detail_end 0 → 100644 +2 −0 Original line number Diff line number Diff line </body> </html>
share/html_detail_start 0 → 100644 +34 −0 Original line number Diff line number Diff line <!DOCTYPE html> <html> <head> <title><!-- $title --></title> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link rel="stylesheet" type="text/css" href=".data/css/main.css"/> <link rel="stylesheet" type="text/css" href=".data/css/light.css" id="theme"/> <script> function addStyleSheet(name, id) { var path = '.data/css/' + name + '.css'; var old = document.getElementById(id); if (old && (old.href != path)) { old.href = path; } } var otherTheme = { 'dark': 'light', 'light': 'dark', }; var currentTheme = localStorage.getItem('theme'); if (!otherTheme.hasOwnProperty(currentTheme)) { currentTheme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; } addStyleSheet(currentTheme, 'theme'); function toggleTheme() { currentTheme = otherTheme[currentTheme] || 'light'; localStorage.setItem('theme', currentTheme); addStyleSheet(currentTheme, 'theme'); } </script> </head> <body>