diff --git a/Dockerfile b/Dockerfile index 219a7be..adbebee 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,7 +4,7 @@ MAINTAINER Computer Science House ENV IMAGEIO_USERDIR /var/lib/gallery RUN apt-get update && \ - apt-get install -y libldap-dev libsasl2-dev libmagic-dev ghostscript libldap-common && \ + apt-get install -y libldap-dev libsasl2-dev libmagic-dev ghostscript libldap-common imagemagick libheif1 libheif-dev libraw-dev libraw20 dcraw && \ apt-get autoremove --yes && \ apt-get clean autoclean && \ sed -i \ diff --git a/gallery/file_modules/__init__.py b/gallery/file_modules/__init__.py index b2a8030..a54a6e9 100644 --- a/gallery/file_modules/__init__.py +++ b/gallery/file_modules/__init__.py @@ -3,6 +3,7 @@ from typing import Any, Dict, List, Optional, Tuple from wand.image import Image from wand.color import Color +import rawpy from gallery.util import DEFAULT_THUMBNAIL_NAME from gallery.util import hash_file @@ -65,6 +66,10 @@ def generate_thumbnail(self): from gallery.file_modules.txt import TXTFile from gallery.file_modules.mp3 import MP3File from gallery.file_modules.wav import WAVFile +from gallery.file_modules.heic import HEICFile +from gallery.file_modules.nef import NEFFile +from gallery.file_modules.mov import MOVFile +from gallery.file_modules.m4a import M4AFile file_mimetype_relation = { "image/jpeg": JPEGFile, @@ -76,20 +81,36 @@ def generate_thumbnail(self): "image/x-windows-bmp": BMPFile, "image/tiff": TIFFFile, "image/x-tiff": TIFFFile, + "image/heic": HEICFile, + "image/x-nikon-nef": NEFFile, "video/mp4": MP4File, "video/webm": WebMFile, "video/ogg": OggFile, + "video/quicktime": MOVFile, "application/pdf": PDFFile, "text/plain": TXTFile, "audio/mpeg": MP3File, - "audio/x-wav": WAVFile + "audio/x-wav": WAVFile, + "audio/mp4": M4AFile, + "audio/x-m4a": M4AFile, } # classism def parse_file_info(file_path: str, dir_path: str) -> Tuple[str, Optional[FileModule]]: print("entering parse_file_info") + mime_type = magic.from_file(file_path, mime=True) + + if "tif" in mime_type: # .nef is a special case, magic reads it as .tiff, but it is not processed correctly by the tiff module + # check if it is a raw file + try: + with rawpy.imread(file_path): # this may cause issues for other raw files + mime_type = "image/x-nikon-nef" + except rawpy.LibRawFileUnsupportedError: + pass + except rawpy.LibRawIOError: + pass print(mime_type) print(file_path) diff --git a/gallery/file_modules/heic.py b/gallery/file_modules/heic.py new file mode 100644 index 0000000..93c2034 --- /dev/null +++ b/gallery/file_modules/heic.py @@ -0,0 +1,30 @@ +import os +from PIL import Image as PILImage +import pillow_heif + +from gallery.file_modules import FileModule +from gallery.util import hash_file + +pillow_heif.register_heif_opener() + +class HEICFile(FileModule): + def __init__(self, file_path, dir_path): + FileModule.__init__(self, file_path, dir_path) + self.mime_type = "image/heic" + + self.generate_thumbnail() + + def generate_thumbnail(self): + self.thumbnail_uuid = hash_file(self.file_path) + ".jpg" + + thumb_path = os.path.join(self.dir_path, self.thumbnail_uuid) + + img = PILImage.open(self.file_path).convert("RGB") + + size = min(img.width, img.height) + left = (img.width - size) // 2 + top = (img.height - size) // 2 + img = img.crop((left, top, left + size, top + size)) + + img = img.resize((256, 256)) + img.save(thumb_path, "JPEG") \ No newline at end of file diff --git a/gallery/file_modules/m4a.py b/gallery/file_modules/m4a.py new file mode 100644 index 0000000..155f3ff --- /dev/null +++ b/gallery/file_modules/m4a.py @@ -0,0 +1,18 @@ +import os +from wand.image import Image + +from gallery.file_modules import FileModule +from gallery.util import hash_file + +class M4AFile(FileModule): + def __init__(self, file_path, dir_path): + FileModule.__init__(self, file_path, dir_path) + self.mime_type = "audio/mp4" + + self.generate_thumbnail() + + def generate_thumbnail(self): + self.thumbnail_uuid = hash_file(self.file_path) + ".jpg" + + with Image(filename="thumbnails/reedphoto.jpg") as bg: + bg.save(filename=os.path.join(self.dir_path, self.thumbnail_uuid)) diff --git a/gallery/file_modules/mov.py b/gallery/file_modules/mov.py new file mode 100644 index 0000000..a99be5d --- /dev/null +++ b/gallery/file_modules/mov.py @@ -0,0 +1,33 @@ +from moviepy.editor import VideoFileClip +import os +from wand.image import Image +from wand.color import Color + +from gallery.file_modules import FileModule +from gallery.util import hash_file + + +class MOVFile(FileModule): + + def __init__(self, file_path, dir_path): + FileModule.__init__(self, file_path, dir_path) + self.mime_type = "video/quicktime" + + self.generate_thumbnail() + + def generate_thumbnail(self): + self.thumbnail_uuid = hash_file(self.file_path) + ".jpg" + thumbnail_loc = os.path.join(self.dir_path, self.thumbnail_uuid) + + clip = VideoFileClip(self.file_path) + time_mark = clip.duration * 0.05 + clip.save_frame(thumbnail_loc, t=time_mark) + + with Image(filename=thumbnail_loc) as img: + with img.clone() as image: + size = image.width if image.width < image.height else image.height + image.crop(width=size, height=size, gravity='center') + image.resize(256, 256) + image.background_color = Color("#EEEEEE") + image.format = 'jpeg' + image.save(filename=thumbnail_loc) diff --git a/gallery/file_modules/nef.py b/gallery/file_modules/nef.py new file mode 100644 index 0000000..b880636 --- /dev/null +++ b/gallery/file_modules/nef.py @@ -0,0 +1,29 @@ +import os +import rawpy +import imageio + +from gallery.file_modules import FileModule +from gallery.util import hash_file + + +class NEFFile(FileModule): + def __init__(self, file_path, dir_path): + FileModule.__init__(self, file_path, dir_path) + self.mime_type = "image/x-nikon-nef" + + self.generate_thumbnail() + + def generate_thumbnail(self): + self.thumbnail_uuid = hash_file(self.file_path) + ".jpg" + thumb_path = os.path.join(self.dir_path, self.thumbnail_uuid) + + with rawpy.imread(self.file_path) as raw: + rgb = raw.postprocess(output_bps=8) + + h, w, _ = rgb.shape + size = min(h, w) + y = (h - size) // 2 + x = (w - size) // 2 + rgb = rgb[y:y+size, x:x+size] + + imageio.imwrite(thumb_path, rgb) \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index a5b9de1..ed75835 100644 --- a/requirements.txt +++ b/requirements.txt @@ -70,3 +70,8 @@ Werkzeug==3.1.3 wrapt==1.17.2 xmltodict==0.14.2 zipp==3.19.1 +# NEF and HEIC support +pillow==11.1.0 +pillow_heif==1.2.0 +rawpy==0.26.1 +imageio==2.4.0 \ No newline at end of file