summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xbin/pyggle295
1 files changed, 162 insertions, 133 deletions
diff --git a/bin/pyggle b/bin/pyggle
index 08c23ec..fb167f3 100755
--- a/bin/pyggle
+++ b/bin/pyggle
@@ -11,8 +11,8 @@ import exifread
import json
import os
import PIL
+from multiprocessing import Pool
from PIL import Image
-from progress.bar import Bar
import shutil
import subprocess
import sys
@@ -73,10 +73,6 @@ def format_f(value, precision=1):
return f"{value:.{precision}f}"
-class ProgressBar(Bar):
- suffix = "%(percent).0f%% [%(elapsed_td)s/%(eta_td)s]"
-
-
class GPSData:
def __init__(self, lat, lon, location):
self.lat = lat
@@ -141,7 +137,7 @@ class ImageHTML:
self, f_num, exposure, focal_length, focal_length35, crop_factor, iso
):
entries = list()
- if f_num is not None:
+ if f_num is not None and float(f_num) > 0:
self.f_num = f"""<span class="fnumber">f/{format_f(f_num)}</span>"""
entries.append(self.f_num)
@@ -160,7 +156,7 @@ class ImageHTML:
)
entries.append(self.exposure)
- if focal_length is not None:
+ if focal_length is not None and float(focal_length) > 0:
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)"
@@ -296,6 +292,8 @@ class Thumbnail:
self.group_key = None
self.file_key = None
+ self.kept_thumbnails = list()
+
with open(filename, "rb") as f:
try:
self.exif_tag = exifread.process_file(f)
@@ -334,7 +332,13 @@ class Thumbnail:
if not self.thumbname.lower().endswith((".jpeg", ".jpg")):
self.thumbname += ".jpg"
- if not have_thumbnail.pop(self.thumbname, False):
+ if have_thumbnail.pop(f".thumbnails/{thumb_filename}.p.jpg", None):
+ self.jpegname = f".thumbnails/{thumb_filename}.p.jpg"
+ self.kept_thumbnails.append(self.jpegname)
+
+ if have_thumbnail.pop(self.thumbname, False):
+ self.kept_thumbnails.append(self.thumbname)
+ else:
if not filename.lower().endswith((".cr2", ".cr3", ".rw2")):
im = rotate_image(im, self.exif_tag)
@@ -342,7 +346,9 @@ class Thumbnail:
im = im.convert("RGB")
im.save(self.thumbname, "JPEG")
- if filename.lower().endswith((".cr2", ".cr3", ".rw2")):
+ if not self.jpegname and filename.lower().endswith(
+ (".cr2", ".cr3", ".rw2")
+ ):
try:
jpegname = f".thumbnails/{thumb_filename}.p.jpg"
subprocess.run(
@@ -372,8 +378,6 @@ class Thumbnail:
rotate_preview(jpegname, self.exif_tag)
except FileNotFoundError:
pass
- elif have_thumbnail.pop(f".thumbnails/{thumb_filename}.p.jpg", None):
- self.jpegname = f".thumbnails/{thumb_filename}.p.jpg"
if args.with_detail_page and 0:
self.average_color = im.resize((1, 1)).getpixel((0, 0))
@@ -410,7 +414,7 @@ class Thumbnail:
def _get_caption(self):
try:
- with open(f".captions/{filename}.txt", "r") as f:
+ with open(f".captions/{self.filename}.txt", "r") as f:
self.html.set_caption(f.read())
except FileNotFoundError:
pass
@@ -568,10 +572,12 @@ class Thumbnail:
global location_cache
global geocoder
- latlon = f"{lat:.3f}/{lon:.3f}"
+ latlon = f"{lat:.4f}/{lon:.4f}"
- if latlon in location_cache:
- self.gps = GPSData(lat, lon, location_cache[latlon])
+ if str(args.nominatim_zoom) in location_cache.get(latlon, dict()):
+ self.gps = GPSData(
+ lat, lon, location_cache[latlon][str(args.nominatim_zoom)]
+ )
self.html.set_gps(self.gps)
return
@@ -584,9 +590,14 @@ class Thumbnail:
try:
res = geocoder.reverse((lat, lon), zoom=args.nominatim_zoom)
location = res.address.split(",")[0]
- location_cache[latlon] = location
+ if latlon not in location_cache:
+ location_cache[latlon] = dict()
+ location_cache[latlon][str(args.nominatim_zoom)] = location
except TypeError as e:
location = latlon
+ except Exception as e:
+ print(e)
+ return
self.gps = GPSData(lat, lon, location)
self.html.set_gps(self.gps)
@@ -605,7 +616,7 @@ class Thumbnail:
try:
lens = self.exif_tag["EXIF LensModel"]
- if lens:
+ if lens and str(lens):
model += f" + {lens}"
except KeyError:
# Unknown or built-in lens
@@ -711,6 +722,120 @@ def write_gallery(
f.write(file_buf)
+def _make_thumbnail(args):
+ filename, args, thumb_arg = args
+ try:
+ im = Image.open(filename)
+ except PIL.UnidentifiedImageError:
+ try:
+ im = Image.open(f".thumbnail.for.{filename}")
+ except FileNotFoundError:
+ im = None
+ except PIL.UnidentifiedImageError:
+ # perhaps raise a warning?
+ im = None
+
+ if not im:
+ try:
+ _, jpegname = tempfile.mkstemp(suffix="jpg")
+ subprocess.run(
+ [
+ "exiftool",
+ "-quiet",
+ "-binary",
+ "-tagOut!",
+ jpegname,
+ "-PreviewImage",
+ filename,
+ ]
+ )
+ # JpgFromRaw tends to have higher resolution, so overwrite PreviewImage if it is present
+ subprocess.run(
+ [
+ "exiftool",
+ "-quiet",
+ "-binary",
+ "-tagOut!",
+ jpegname,
+ "-JpgFromRaw",
+ filename,
+ ]
+ )
+
+ im = Image.open(jpegname)
+ os.remove(jpegname)
+ except FileNotFoundError:
+ im = None
+ except PIL.UnidentifiedImageError:
+ # perhaps raise a warning?
+ os.remove(jpegname)
+ im = None
+
+ if not im:
+ return None, None
+
+ try:
+ im_copy = im.copy()
+ except Exception as e:
+ print(f"Cannot load image '{filename}': {e}", file=sys.stderr)
+ return None, None
+
+ thumbnail = Thumbnail(
+ filename,
+ im_copy,
+ size=args.size,
+ group_key_template=args.group,
+ file_key_template=args.group_files,
+ **thumb_arg,
+ )
+
+ if (
+ args.edit_in_place
+ and args.resize
+ and (im.size[0] > args.resize or im.size[1] > args.resize)
+ ):
+ subprocess.run(
+ [
+ "mogrify",
+ "-resize",
+ f"{args.resize}x{args.resize}",
+ filename,
+ ]
+ )
+
+ exiftool_args = list()
+
+ if args.caption_to_exif and thumbnail.html.caption:
+ exiftool_args.append(f"-File:Comment={thumbnail.html.caption}")
+
+ if args.exif_copyright:
+ exiftool_args.append(f"-EXIF:Copyright={args.exif_copyright}")
+
+ if args.scrub_metadata:
+ exiftool_args.extend(
+ [
+ "-EXIF:SerialNumber=",
+ "-EXIF:LensSerialNumber=",
+ "-Makernotes:all=",
+ "-geotag=",
+ "-ThumbnailImage=",
+ ]
+ )
+
+ if args.edit_in_place and exiftool_args:
+ subprocess.run(
+ [
+ "exiftool",
+ "-q",
+ "-overwrite_original",
+ ]
+ + exiftool_args
+ + [filename]
+ )
+
+ return (filename, thumbnail)
+
+
if __name__ == "__main__":
parser = argparse.ArgumentParser(
@@ -761,7 +886,6 @@ if __name__ == "__main__":
default=16,
help="Zoom Level for reverse geocoding",
)
- parser.add_argument("--quiet", action="store_true", help="Do not show progress bar")
parser.add_argument(
"--resize",
metavar="N",
@@ -817,6 +941,10 @@ if __name__ == "__main__":
if not args.cdn:
copy_files(f"{base_dir}/share")
+ if args.with_nominatim and os.path.exists(".thumbnails/location_cache.json"):
+ with open(".thumbnails/location_cache.json", "r") as f:
+ location_cache = json.load(f)
+
with open(f"{base_dir}/share/html_start", "r") as f:
html_buf = f.read().replace("<!-- $title -->", args.title)
@@ -832,122 +960,19 @@ if __name__ == "__main__":
filenames = args.images
thumbnails = list()
- if args.quiet:
- file_iter = filenames
- else:
- file_iter = ProgressBar(max=len(filenames)).iter(filenames)
-
- for i, filename in enumerate(file_iter):
- try:
- im = Image.open(filename)
- except PIL.UnidentifiedImageError:
- try:
- im = Image.open(f".thumbnail.for.{filename}")
- except FileNotFoundError:
- im = None
- except PIL.UnidentifiedImageError:
- # perhaps raise a warning?
- im = None
-
- if not im:
- try:
- _, jpegname = tempfile.mkstemp(suffix="jpg")
- subprocess.run(
- [
- "exiftool",
- "-quiet",
- "-binary",
- "-tagOut!",
- jpegname,
- "-PreviewImage",
- filename,
- ]
- )
- # JpgFromRaw tends to have higher resolution, so overwrite PreviewImage if it is present
- subprocess.run(
- [
- "exiftool",
- "-quiet",
- "-binary",
- "-tagOut!",
- jpegname,
- "-JpgFromRaw",
- filename,
- ]
- )
-
- im = Image.open(jpegname)
- os.remove(jpegname)
- except FileNotFoundError:
- im = None
- except PIL.UnidentifiedImageError:
- # perhaps raise a warning?
- os.remove(jpegname)
- im = None
-
- if not im:
- continue
-
- try:
- im_copy = im.copy()
- except Exception as e:
- print(f"Cannot load image '{filename}': {e}", file=sys.stderr)
- continue
-
- thumbnail = Thumbnail(
- filename,
- im_copy,
- size=args.size,
- with_gps=args.with_nominatim,
- group_key_template=args.group,
- file_key_template=args.group_files,
- have_thumbnail=rm_thumbnail,
- )
- thumbnails.append(thumbnail)
-
- if (
- args.edit_in_place
- and args.resize
- and (im.size[0] > args.resize or im.size[1] > args.resize)
- ):
- subprocess.run(
- [
- "mogrify",
- "-resize",
- f"{args.resize}x{args.resize}",
- filename,
- ]
- )
-
- exiftool_args = list()
-
- if args.caption_to_exif and thumbnail.html.caption:
- exiftool_args.append(f"-File:Comment={thumbnail.html.caption}")
-
- if args.exif_copyright:
- exiftool_args.append(f"-EXIF:Copyright={args.exif_copyright}")
-
- if args.scrub_metadata:
- exiftool_args.extend(
- [
- "-EXIF:SerialNumber=",
- "-EXIF:LensSerialNumber=",
- "-Makernotes:all=",
- "-geotag=",
- "-ThumbnailImage=",
- ]
- )
+ mkthumb_args = list(
+ map(lambda fn: (fn, args, {"have_thumbnail": rm_thumbnail}), filenames)
+ )
+ with Pool() as pool:
+ raw_thumbnails = pool.map(_make_thumbnail, mkthumb_args)
- if args.edit_in_place and exiftool_args:
- subprocess.run(
- [
- "exiftool",
- "-q",
- "-overwrite_original",
- ]
- + exiftool_args
- + [filename]
- )
+ for filename, thumbnail in raw_thumbnails:
+ if thumbnail is not None:
+ if args.with_nominatim:
+ thumbnail._get_gps()
+ thumbnails.append(thumbnail)
+ for kept_thumbnail in thumbnail.kept_thumbnails:
+ rm_thumbnail.pop(kept_thumbnail)
for rm_file in rm_thumbnail.keys():
os.remove(rm_file)
@@ -978,6 +1003,10 @@ if __name__ == "__main__":
write_gallery(html_buf, "index.html", thumbnails, group=args.group)
+ if args.with_nominatim:
+ with open(".thumbnails/location_cache.json", "w") as f:
+ json.dump(location_cache, f)
+
if args.group_files != "none":
thumbnail_keys = list(sorted(set(map(lambda t: t.file_key, thumbnails))))
for i, thumbnail_key in enumerate(thumbnail_keys):