From f2f9d08acc29150bb0f8a9220ff1632854a8ab08 Mon Sep 17 00:00:00 2001
From: Erwan Rouchet <rouchet@teklia.com>
Date: Tue, 23 Nov 2021 15:03:38 +0100
Subject: [PATCH] Add rotation and mirroring to IIIF thumbnail URLs

---
 arkindex/documents/models.py             | 19 +++++--
 arkindex/documents/tests/test_element.py | 70 ++++++++++++++++++++++++
 2 files changed, 85 insertions(+), 4 deletions(-)
 create mode 100644 arkindex/documents/tests/test_element.py

diff --git a/arkindex/documents/models.py b/arkindex/documents/models.py
index be9bdb05f4..713103e9e5 100644
--- a/arkindex/documents/models.py
+++ b/arkindex/documents/models.py
@@ -370,11 +370,22 @@ class Element(IndexableModel):
     @property
     def iiif_thumbnail_url(self):
         """
-        Same as `iiif_url`, but resized to up to 400 pixels
+        Same as `iiif_url`, but resized to up to 400 pixels and with rotation and mirroring
         """
-        iiif_url = self.iiif_url
-        if iiif_url:
-            return self.iiif_url.replace('full', ',400')
+        if not self.polygon or not self.image_id:
+            return
+
+        from arkindex.project.tools import bounding_box
+        x, y, width, height = bounding_box(self.polygon)
+
+        rotation_param = str(self.rotation_angle)
+        if self.mirrored:
+            rotation_param = f'!{rotation_param}'
+
+        return urljoin(
+            self.image.url + '/',
+            f'{x},{y},{width},{height}/,400/{rotation_param}/default.jpg'
+        )
 
     def __str__(self):
         return '{}: {}'.format(self.type.display_name, self.name)
diff --git a/arkindex/documents/tests/test_element.py b/arkindex/documents/tests/test_element.py
new file mode 100644
index 0000000000..251da5e06a
--- /dev/null
+++ b/arkindex/documents/tests/test_element.py
@@ -0,0 +1,70 @@
+from arkindex.documents.models import Element
+from arkindex.project.tests import FixtureTestCase
+
+
+class TestElement(FixtureTestCase):
+
+    @classmethod
+    def setUpTestData(cls):
+        super().setUpTestData()
+        cls.element_type = cls.corpus.types.first()
+        cls.image = cls.imgsrv.images.get(path='img1')
+
+    def test_iiif_url(self):
+        # Rotation and mirroring should be ignored in iiif_url
+        cases = [
+            (0, False),
+            (0, True),
+            (180, False),
+            (180, True),
+        ]
+        for rotation_angle, mirrored in cases:
+            with self.subTest(rotation_angle=rotation_angle, mirrored=mirrored):
+                element = Element(
+                    name='Something',
+                    type=self.element_type,
+                    image=self.image,
+                    polygon=[
+                        [10, 20],
+                        [40, 20],
+                        [40, 60],
+                        [10, 60],
+                        [10, 20],
+                    ],
+                    rotation_angle=rotation_angle,
+                    mirrored=mirrored,
+                )
+                self.assertEqual(element.iiif_url, 'http://server/img1/10,20,30,40/full/0/default.jpg')
+
+    def test_iiif_thumbnail_url(self):
+        cases = [
+            (0, False, 'http://server/img1/10,20,30,40/,400/0/default.jpg'),
+            (0, True, 'http://server/img1/10,20,30,40/,400/!0/default.jpg'),
+            (180, False, 'http://server/img1/10,20,30,40/,400/180/default.jpg'),
+            (180, True, 'http://server/img1/10,20,30,40/,400/!180/default.jpg'),
+        ]
+        for rotation_angle, mirrored, expected_url in cases:
+            with self.subTest(rotation_angle=rotation_angle, mirrored=mirrored):
+                element = Element(
+                    name='Something',
+                    type=self.element_type,
+                    image=self.image,
+                    polygon=[
+                        [10, 20],
+                        [40, 20],
+                        [40, 60],
+                        [10, 60],
+                        [10, 20],
+                    ],
+                    rotation_angle=rotation_angle,
+                    mirrored=mirrored,
+                )
+                self.assertEqual(element.iiif_thumbnail_url, expected_url)
+
+    def test_no_image_no_url(self):
+        element = Element(
+            name='Something',
+            type=self.element_type,
+        )
+        self.assertIsNone(element.iiif_url)
+        self.assertIsNone(element.iiif_thumbnail_url)
-- 
GitLab