Initial working thingy

This commit is contained in:
Paul Brinkmeier 2025-02-15 01:36:29 +01:00
parent 0ccf4cb603
commit 80f720c418
6 changed files with 191 additions and 0 deletions

3
.gitignore vendored
View File

@ -2,3 +2,6 @@
result result
# Vim swap files # Vim swap files
*.swp *.swp
# Generated website files
build
dist

48
Makefile Normal file
View File

@ -0,0 +1,48 @@
.PHONY: all, clean
ifeq ($(origin IMAGE_DIR),undefined)
$(error $$IMAGE_DIR is not set)
endif
# Files for distribution
DIST_DIR ?= dist
# Temporary build artifacts
BUILD_DIR ?= build
images := $(shell find $(IMAGE_DIR) -iname '*.jpg')
image_names_cs := $(notdir $(images))
image_names := $(shell echo $(image_names_cs) | tr A-Z a-z)
dist_images := $(addprefix $(DIST_DIR)/,$(image_names))
extra_files := $(wildcard extra/*)
dist_extra_files := $(extra_files:%=dist/%)
define copy_image_rule =
$(DIST_DIR)/$(1): $(shell find $(IMAGE_DIR) -iname $(1))
@mkdir -p $(DIST_DIR)
cp --preserve $$< $$@
endef
build_metas := $(dist_images:$(DIST_DIR)/%.jpg=$(BUILD_DIR)/%.meta.json)
dist_html := $(dist_images:$(DIST_DIR)/%.jpg=$(DIST_DIR)/%.html)
### RULES ###
all: $(dist_html) $(dist_extra_files)
clean:
rm -rf $(DIST_DIR) $(BUILD_DIR)
$(foreach f,$(image_names),$(eval $(call copy_image_rule,$(f))))
$(BUILD_DIR)/%.meta.json: $(DIST_DIR)/%.jpg extract-metadata.py
@mkdir -p $(BUILD_DIR)
./extract-metadata.py --root $(DIST_DIR) $< > $@
$(DIST_DIR)/%.html: $(BUILD_DIR)/%.meta.json photo.hbs
@mkdir -p $(DIST_DIR)
handlebars-cli photo.hbs "$$(cat $<)" > $@
$(DIST_DIR)/extra/%: extra/%
@mkdir -p $(DIST_DIR)/extra
cp -r $< $@

38
extra/photo.css Normal file
View File

@ -0,0 +1,38 @@
html {
font-size: 16px;
}
body {
margin: 0;
font-family: 'Source Sans Pro', sans-serif;
}
.my-epic-layout {
display: grid;
grid-template-columns: 1fr 20em;
grid-template-rows: 1fr;
width: 100vw;
height: 100vh;
}
.picture-frame {
padding: 1em;
background-color: #555;
}
.picture-frame img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
}
.text-frame {
padding: 1em;
background-color: #f0f0f0;
}
h1 {
font-weight: normal;
font-size: 1.5em;
margin-top: 0;
}

77
extract-metadata.py Executable file
View File

@ -0,0 +1,77 @@
#!/usr/bin/env python3
import clize
import exif
import json
from datetime import datetime
from enum import Enum
from pathlib import Path
from typing import Any
def exif_content_to_json(tag, content):
match content:
case Enum() as e:
return e.name
case int() as i:
return i
case float() as f:
return f
case str() as s:
if tag.startswith("datetime"):
dt = datetime.strptime(s, "%Y:%m:%d %H:%M:%S")
return dt.strftime("%Y-%m-%d %H:%M")
return s
case _:
return {"pyType": str(type(content)), "stringified": str(content)}
def extract_exif_data(image_path: Path) -> dict[str, Any]:
with image_path.open("rb") as image_file:
image = exif.Image(image_file)
exif_data = {}
for tag in image.list_all():
try:
content = image[tag]
except:
# Some keys are in list_all() but can't be accessed for my camera :(
# Skip them.
continue
exif_data[tag] = exif_content_to_json(tag, content)
return exif_data
def extract_stat_data(image_path: Path):
FIELDS = ["st_size"]
s = image_path.stat()
stat_data = {}
for field in FIELDS:
stat_data[field] = getattr(s, field)
return stat_data
def extract_metadata(image_path: Path, *, root: Path):
exif_data = extract_exif_data(image_path)
stat_data = extract_stat_data(image_path)
metadata = {
"exif": exif_data,
"stat": stat_data,
"path": {
"name": image_path.name,
"relativeToRoot": str(image_path.relative_to(root)),
},
}
print(json.dumps(metadata, indent=2))
if __name__ == "__main__":
clize.run(extract_metadata)

View File

@ -23,6 +23,7 @@
packages.handlebars-rust packages.handlebars-rust
pkgs.imagemagick pkgs.imagemagick
pkgs.gnumake pkgs.gnumake
(pkgs.python3.withPackages (ps: [ps.clize ps.exif]))
]; ];
}; };
} }

24
photo.hbs Normal file
View File

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{{ path.name }}</title>
<link rel="stylesheet" href="./extra/photo.css">
</head>
<body>
<div class="my-epic-layout">
<div class="picture-frame">
<img src="{{ path.relativeToRoot }}" alt="{{ path.name }}">
</div>
<div class="text-frame">
<h1>{{ path.name }}</h2>
<p>{{ exif.datetime }}</p>
<p>
Exposure Time <strong>{{ exif.exposure_time }}s</strong><br>
Aperture <strong>f{{ exif.aperture_value }}</strong><br>
ISO <strong>{{ exif.photographic_sensitivity }}</strong>
</p>
</div>
</div>
</body>
</html>