summaryrefslogtreecommitdiffstatshomepage
path: root/src/hircine/thumbnailer.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/hircine/thumbnailer.py')
-rw-r--r--src/hircine/thumbnailer.py75
1 files changed, 75 insertions, 0 deletions
diff --git a/src/hircine/thumbnailer.py b/src/hircine/thumbnailer.py
new file mode 100644
index 0000000..ed565d5
--- /dev/null
+++ b/src/hircine/thumbnailer.py
@@ -0,0 +1,75 @@
+import os
+from typing import NamedTuple
+
+from PIL import Image
+
+pillow_extensions = {
+ ext for ext, f in Image.registered_extensions().items() if f in Image.OPEN
+}
+
+
+class ThumbnailParameters(NamedTuple):
+ bounds: tuple[int, int]
+ options: dict
+
+
+def params_from(config):
+ return {
+ "full": ThumbnailParameters(
+ bounds=(
+ config.getint("import.scale.full", "width", fallback=4200),
+ config.getint("import.scale.full", "height", fallback=2000),
+ ),
+ options={"quality": 82, "method": 5},
+ ),
+ "thumb": ThumbnailParameters(
+ bounds=(
+ config.getint("import.scale.thumb", "width", fallback=1680),
+ config.getint("import.scale.thumb", "height", fallback=800),
+ ),
+ options={"quality": 75, "method": 5},
+ ),
+ }
+
+
+def object_path(directory, hash, suffix):
+ return os.path.join(directory, hash[:2], f"{hash[2:]}_{suffix}.webp")
+
+
+class Thumbnailer:
+ def __init__(self, directory, params):
+ self.directory = directory
+ self.params = params
+
+ @classmethod
+ def can_process(cls, extension):
+ return extension in pillow_extensions
+
+ def object(self, hash, suffix):
+ return object_path(self.directory, hash, suffix)
+
+ def process(self, handle, hash, reprocess=False):
+ size = None
+
+ for suffix, parameters in self.params.items():
+ source = Image.open(handle, mode="r")
+
+ if not size:
+ size = source.size
+
+ output = self.object(hash, suffix)
+
+ if os.path.exists(output) and not reprocess:
+ continue
+ else:
+ os.makedirs(os.path.dirname(output), exist_ok=True)
+
+ if source.mode != "RGB":
+ target = source.convert()
+ else:
+ target = source
+
+ target.thumbnail(parameters.bounds, resample=Image.Resampling.LANCZOS)
+ target.save(output, **parameters.options)
+
+ return size