diff --git a/README.md b/README.md index 6a38501c8..db498ddaa 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ scrubbing](https://sjp.pwn.pl/sjp/;2527372). It is pronounced as *shoorubooru*. ## Features -- Post content: images (JPG, PNG, GIF, animated GIF), videos (MP4, WEBM), Flash animations +- Post content: images (JPG, PNG, GIF, animated GIF, PSD), videos (MP4, WEBM), Flash animations - Ability to retrieve web video content using [yt-dlp](https://github.com/yt-dlp/yt-dlp) - Post comments - Post notes / annotations, including arbitrary polygons diff --git a/server/szurubooru/func/files.py b/server/szurubooru/func/files.py index 6a8982698..50d986ef8 100644 --- a/server/szurubooru/func/files.py +++ b/server/szurubooru/func/files.py @@ -41,3 +41,11 @@ def save(path: str, content: bytes) -> None: os.makedirs(os.path.dirname(full_path), exist_ok=True) with open(full_path, "wb") as handle: handle.write(content) + if path.endswith(".psd"): + # Handle .psd files + handle_psd_file(full_path) + + +def handle_psd_file(path: str) -> None: + # Add specific handling for .psd files here + pass diff --git a/server/szurubooru/func/images.py b/server/szurubooru/func/images.py index e135d182e..7d0ce0625 100644 --- a/server/szurubooru/func/images.py +++ b/server/szurubooru/func/images.py @@ -24,6 +24,13 @@ def convert_heif_to_png(content: bytes) -> bytes: return img_byte_arr.getvalue() +def convert_psd_to_png(content: bytes) -> bytes: + img = PILImage.open(BytesIO(content)) + img_byte_arr = BytesIO() + img.save(img_byte_arr, format="PNG") + return img_byte_arr.getvalue() + + class Image: def __init__(self, content: bytes) -> None: self.content = content @@ -269,6 +276,8 @@ def _execute( # FFmpeg does not support HEIF. # https://trac.ffmpeg.org/ticket/6521 self.content = convert_heif_to_png(self.content) + elif mime_type == "image/vnd.adobe.photoshop": + self.content = convert_psd_to_png(self.content) extension = mime.get_extension(mime_type) assert extension with util.create_temp_file(suffix="." + extension) as handle: diff --git a/server/szurubooru/func/mime.py b/server/szurubooru/func/mime.py index 8fae56797..99c1bda97 100644 --- a/server/szurubooru/func/mime.py +++ b/server/szurubooru/func/mime.py @@ -33,6 +33,9 @@ def get_mime_type(content: bytes) -> str: if content[4:12] in (b"ftypheic", b"ftypheix"): return "image/heic" + if content[0:4] == b"8BPS": + return "image/vnd.adobe.photoshop" + if content[0:4] == b"\x1A\x45\xDF\xA3": return "video/webm" @@ -56,6 +59,7 @@ def get_extension(mime_type: str) -> Optional[str]: "image/avif": "avif", "image/heif": "heif", "image/heic": "heic", + "image/vnd.adobe.photoshop": "psd", "video/mp4": "mp4", "video/quicktime": "mov", "video/webm": "webm", @@ -87,6 +91,7 @@ def is_image(mime_type: str) -> bool: "image/avif", "image/heif", "image/heic", + "image/vnd.adobe.photoshop", ) diff --git a/server/szurubooru/func/posts.py b/server/szurubooru/func/posts.py index be2259cf4..89a98030b 100644 --- a/server/szurubooru/func/posts.py +++ b/server/szurubooru/func/posts.py @@ -617,6 +617,8 @@ def update_post_content(post: model.Post, content: Optional[bytes]) -> None: update_signature = True if mime.is_animated_gif(content): post.type = model.Post.TYPE_ANIMATION + elif post.mime_type == "image/vnd.adobe.photoshop": + post.type = model.Post.TYPE_IMAGE else: post.type = model.Post.TYPE_IMAGE elif mime.is_video(post.mime_type): diff --git a/server/szurubooru/func/psd_handler.py b/server/szurubooru/func/psd_handler.py new file mode 100644 index 000000000..a36d8f7e4 --- /dev/null +++ b/server/szurubooru/func/psd_handler.py @@ -0,0 +1,16 @@ +from PIL import Image +from io import BytesIO + +def handle_psd_file(path: str) -> None: + with open(path, "rb") as f: + psd_content = f.read() + png_content = convert_psd_to_png(psd_content) + png_path = path.replace(".psd", ".png") + with open(png_path, "wb") as f: + f.write(png_content) + +def convert_psd_to_png(content: bytes) -> bytes: + img = Image.open(BytesIO(content)) + img_byte_arr = BytesIO() + img.save(img_byte_arr, format="PNG") + return img_byte_arr.getvalue()