summaryrefslogtreecommitdiff
path: root/server
diff options
context:
space:
mode:
Diffstat (limited to 'server')
-rw-r--r--server/requirements.txt2
-rw-r--r--server/szurubooru/func/image_hash.py4
-rw-r--r--server/szurubooru/func/mime.py10
-rw-r--r--server/szurubooru/func/posts.py3
-rw-r--r--server/szurubooru/tests/assets/avif-avis.avifbin0 -> 2698 bytes
-rw-r--r--server/szurubooru/tests/assets/avif-similar.avifbin0 -> 2281 bytes
-rw-r--r--server/szurubooru/tests/assets/avif.avifbin0 -> 2698 bytes
-rw-r--r--server/szurubooru/tests/assets/heic-mif1.heicbin0 -> 2806 bytes
-rw-r--r--server/szurubooru/tests/assets/heic.heicbin0 -> 2806 bytes
-rw-r--r--server/szurubooru/tests/assets/heif-similar.heifbin0 -> 3480 bytes
-rw-r--r--server/szurubooru/tests/assets/heif.heifbin0 -> 3489 bytes
-rw-r--r--server/szurubooru/tests/func/test_image_hash.py50
-rw-r--r--server/szurubooru/tests/func/test_mime.py11
13 files changed, 79 insertions, 1 deletions
diff --git a/server/requirements.txt b/server/requirements.txt
index 043c4f1..2a09b24 100644
--- a/server/requirements.txt
+++ b/server/requirements.txt
@@ -9,4 +9,6 @@ pillow>=4.3.0
pynacl>=1.2.1
pytz>=2018.3
pyRFC3339>=1.0
+pillow-avif-plugin>=1.1.0
+pyheif-pillow-opener>=0.1.0
youtube_dl
diff --git a/server/szurubooru/func/image_hash.py b/server/szurubooru/func/image_hash.py
index fc7d141..8d1cd2a 100644
--- a/server/szurubooru/func/image_hash.py
+++ b/server/szurubooru/func/image_hash.py
@@ -6,6 +6,10 @@ from typing import Any, Callable, List, Optional, Set, Tuple
import numpy as np
from PIL import Image
+import pillow_avif
+import pyheif
+from pyheif_pillow_opener import register_heif_opener
+register_heif_opener()
from szurubooru import config, errors
diff --git a/server/szurubooru/func/mime.py b/server/szurubooru/func/mime.py
index bd553fc..f1d9fbb 100644
--- a/server/szurubooru/func/mime.py
+++ b/server/szurubooru/func/mime.py
@@ -21,6 +21,12 @@ def get_mime_type(content: bytes) -> str:
if content[8:12] == b"WEBP":
return "image/webp"
+ if content[4:12] in (b"ftypavif", b"ftypavis"):
+ return "image/avif"
+
+ if content[4:12] in (b"ftypheic", b"ftypmif1"):
+ return "image/heic"
+
if content[0:4] == b"\x1A\x45\xDF\xA3":
return "video/webm"
@@ -37,6 +43,8 @@ def get_extension(mime_type: str) -> Optional[str]:
"image/jpeg": "jpg",
"image/png": "png",
"image/webp": "webp",
+ "image/avif": "avif",
+ "image/heic": "heic",
"video/mp4": "mp4",
"video/webm": "webm",
"application/octet-stream": "dat",
@@ -58,6 +66,8 @@ def is_image(mime_type: str) -> bool:
"image/png",
"image/gif",
"image/webp",
+ "image/avif",
+ "image/heic",
)
diff --git a/server/szurubooru/func/posts.py b/server/szurubooru/func/posts.py
index 0493681..be2259c 100644
--- a/server/szurubooru/func/posts.py
+++ b/server/szurubooru/func/posts.py
@@ -650,7 +650,8 @@ def update_post_content(post: model.Post, content: Optional[bytes]) -> None:
image = images.Image(content)
post.canvas_width = image.width
post.canvas_height = image.height
- except errors.ProcessingError:
+ except errors.ProcessingError as ex:
+ logger.exception(ex)
if not config.config["allow_broken_uploads"]:
raise InvalidPostContentError("Unable to process image metadata")
else:
diff --git a/server/szurubooru/tests/assets/avif-avis.avif b/server/szurubooru/tests/assets/avif-avis.avif
new file mode 100644
index 0000000..3b27f29
--- /dev/null
+++ b/server/szurubooru/tests/assets/avif-avis.avif
Binary files differ
diff --git a/server/szurubooru/tests/assets/avif-similar.avif b/server/szurubooru/tests/assets/avif-similar.avif
new file mode 100644
index 0000000..476f3f5
--- /dev/null
+++ b/server/szurubooru/tests/assets/avif-similar.avif
Binary files differ
diff --git a/server/szurubooru/tests/assets/avif.avif b/server/szurubooru/tests/assets/avif.avif
new file mode 100644
index 0000000..edf4960
--- /dev/null
+++ b/server/szurubooru/tests/assets/avif.avif
Binary files differ
diff --git a/server/szurubooru/tests/assets/heic-mif1.heic b/server/szurubooru/tests/assets/heic-mif1.heic
new file mode 100644
index 0000000..b370c6b
--- /dev/null
+++ b/server/szurubooru/tests/assets/heic-mif1.heic
Binary files differ
diff --git a/server/szurubooru/tests/assets/heic.heic b/server/szurubooru/tests/assets/heic.heic
new file mode 100644
index 0000000..f1d2ed0
--- /dev/null
+++ b/server/szurubooru/tests/assets/heic.heic
Binary files differ
diff --git a/server/szurubooru/tests/assets/heif-similar.heif b/server/szurubooru/tests/assets/heif-similar.heif
new file mode 100644
index 0000000..26acdc9
--- /dev/null
+++ b/server/szurubooru/tests/assets/heif-similar.heif
Binary files differ
diff --git a/server/szurubooru/tests/assets/heif.heif b/server/szurubooru/tests/assets/heif.heif
new file mode 100644
index 0000000..ad1fd77
--- /dev/null
+++ b/server/szurubooru/tests/assets/heif.heif
Binary files differ
diff --git a/server/szurubooru/tests/func/test_image_hash.py b/server/szurubooru/tests/func/test_image_hash.py
index e7028b6..5a5dc71 100644
--- a/server/szurubooru/tests/func/test_image_hash.py
+++ b/server/szurubooru/tests/func/test_image_hash.py
@@ -27,3 +27,53 @@ def test_signature_functions(read_asset, config_injector):
words2 = image_hash.generate_words(sig2)
words_match = sum(word1 == word2 for word1, word2 in zip(words1, words2))
assert words_match == 18
+
+
+def test_signature_heif(read_asset, config_injector):
+ sig1 = image_hash.generate_signature(read_asset("heif.heif"))
+ sig2 = image_hash.generate_signature(read_asset("heif-similar.heif"))
+
+ sig1_repacked = image_hash.unpack_signature(
+ image_hash.pack_signature(sig1)
+ )
+ sig2_repacked = image_hash.unpack_signature(
+ image_hash.pack_signature(sig2)
+ )
+ assert array_equal(sig1, sig1_repacked)
+ assert array_equal(sig2, sig2_repacked)
+
+ dist1 = image_hash.normalized_distance([sig1], sig2)
+ assert abs(dist1[0] - 0.136777724290135) < 1e-8
+
+ dist2 = image_hash.normalized_distance([sig2], sig2)
+ assert abs(dist2[0]) < 1e-8
+
+ words1 = image_hash.generate_words(sig1)
+ words2 = image_hash.generate_words(sig2)
+ words_match = sum(word1 == word2 for word1, word2 in zip(words1, words2))
+ assert words_match == 43
+
+
+def test_signature_avif(read_asset, config_injector):
+ sig1 = image_hash.generate_signature(read_asset("avif.avif"))
+ sig2 = image_hash.generate_signature(read_asset("avif-similar.avif"))
+
+ sig1_repacked = image_hash.unpack_signature(
+ image_hash.pack_signature(sig1)
+ )
+ sig2_repacked = image_hash.unpack_signature(
+ image_hash.pack_signature(sig2)
+ )
+ assert array_equal(sig1, sig1_repacked)
+ assert array_equal(sig2, sig2_repacked)
+
+ dist1 = image_hash.normalized_distance([sig1], sig2)
+ assert abs(dist1[0] - 0.22628712858355998) < 1e-8
+
+ dist2 = image_hash.normalized_distance([sig2], sig2)
+ assert abs(dist2[0]) < 1e-8
+
+ words1 = image_hash.generate_words(sig1)
+ words2 = image_hash.generate_words(sig2)
+ words_match = sum(word1 == word2 for word1, word2 in zip(words1, words2))
+ assert words_match == 12
diff --git a/server/szurubooru/tests/func/test_mime.py b/server/szurubooru/tests/func/test_mime.py
index 0d8f645..d5238a1 100644
--- a/server/szurubooru/tests/func/test_mime.py
+++ b/server/szurubooru/tests/func/test_mime.py
@@ -13,6 +13,11 @@ from szurubooru.func import mime
("jpeg.jpg", "image/jpeg"),
("gif.gif", "image/gif"),
("webp.webp", "image/webp"),
+ ("avif.avif", "image/avif"),
+ ("avif-avis.avif", "image/avif"),
+ ("heic.heic", "image/heic"),
+ ("heic-mif1.heic", "image/heic"),
+ ("heif.heif", "image/heic"),
("text.txt", "application/octet-stream"),
],
)
@@ -34,6 +39,8 @@ def test_get_mime_type_for_empty_file():
("image/jpeg", "jpg"),
("image/gif", "gif"),
("image/webp", "webp"),
+ ("image/avif", "avif"),
+ ("image/heic", "heic"),
("application/octet-stream", "dat"),
],
)
@@ -75,9 +82,13 @@ def test_is_video(input_mime_type, expected_state):
("image/gif", True),
("image/png", True),
("image/jpeg", True),
+ ("image/avif", True),
+ ("image/heic", True),
("IMAGE/GIF", True),
("IMAGE/PNG", True),
("IMAGE/JPEG", True),
+ ("IMAGE/AVIF", True),
+ ("IMAGE/HEIC", True),
("image/anything_else", False),
("not an image", False),
],