Initial working thingy
This commit is contained in:
parent
0ccf4cb603
commit
80f720c418
3
.gitignore
vendored
3
.gitignore
vendored
@ -2,3 +2,6 @@
|
|||||||
result
|
result
|
||||||
# Vim swap files
|
# Vim swap files
|
||||||
*.swp
|
*.swp
|
||||||
|
# Generated website files
|
||||||
|
build
|
||||||
|
dist
|
||||||
|
48
Makefile
Normal file
48
Makefile
Normal 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
38
extra/photo.css
Normal 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
77
extract-metadata.py
Executable 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)
|
@ -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
24
photo.hbs
Normal 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>
|
Loading…
x
Reference in New Issue
Block a user