From 501470a3d58b41e8ee8dcade907f454040e47d64 Mon Sep 17 00:00:00 2001 From: Trip Kirkpatrick Date: Wed, 10 Sep 2025 11:50:59 -0400 Subject: [PATCH 1/8] =?UTF-8?q?Adjusted=20origin=20per=20#631=20h/t=20@ste?= =?UTF-8?q?phenwf=20=F0=9F=9B=A0=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit To get the rotation we want, the point of rotation cannot be the center of a rectangle, given that the implicit overlap between the vertical rectangle of the resource and the horizontal rectangle of the Canvas share a corner rather than their center. Fortunately, figuring the rotation point is, in this case and many others, just figuring the center of the imaginary square formed by the overlap of the resource and Canvas. In turn this center is half the narrower dimension of the resource or Canvas, provided they are the same dimensions --- recipe/0040-image-rotation-service/manifest-css.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipe/0040-image-rotation-service/manifest-css.json b/recipe/0040-image-rotation-service/manifest-css.json index b2585cffa..be923cd57 100644 --- a/recipe/0040-image-rotation-service/manifest-css.json +++ b/recipe/0040-image-rotation-service/manifest-css.json @@ -29,7 +29,7 @@ "motivation": "painting", "stylesheet": { "type": "CssStylesheet", - "value": ".rotated { transform-origin: center; transform: rotate(90deg); }" + "value": ".rotated { transform-origin: 130px 130px; transform: rotate(90deg); }" }, "body": { "id": "{{ id.path }}/body/sr1", From 1917fd090fbee4b9505a23f2ce9a28bdf1420690 Mon Sep 17 00:00:00 2001 From: Trip Kirkpatrick Date: Wed, 10 Sep 2025 11:52:03 -0400 Subject: [PATCH 2/8] =?UTF-8?q?Added=20text=20about=20setting=20a=20rotati?= =?UTF-8?q?on=20centroid=20properly=20h/t/=20@stephenwf=20=F0=9F=93=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- recipe/0040-image-rotation-service/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipe/0040-image-rotation-service/index.md b/recipe/0040-image-rotation-service/index.md index 9b29a7481..884694064 100644 --- a/recipe/0040-image-rotation-service/index.md +++ b/recipe/0040-image-rotation-service/index.md @@ -31,7 +31,7 @@ Finally, you may use an image service to rotate a region — rather than a whol If your resource is not being served from an image server that supports the desired rotation (or rotation at all) through the IIIF Image API, then you can use CSS for the rotation. Using CSS for rotation depends on the viewer to rotate the image rather than the server. This approach is used when your image server does not have a IIIF Image API service for the image, or if your image server does not allow rotation through service calls. -By using CSS, you may specify arbitrary rotation figures as well as incorporate additional styling values. +By using CSS, you may specify arbitrary rotation figures as well as incorporate additional styling values. In order for the rotated image to line up properly with the Canvas, the `transform-origin` CSS property must have the correct value. For rectilinear resources, the value will very often be represented as a pair of points in x, y order where each is half the smaller dimension of the resource. This value may differ meaningfully if other styling that affects the box model is applied. Using CSS to alter resource presentation styles is not specified in the [IIIF Presentation 3.0 API](https://iiif.io/api/presentation/3.0/). The Presentation API section is provided as a convenient but light explanation of this approach. For a more detailed look at styles in Web Annotations, see [the W3C Web Annotation Data Model's Styles section](https://www.w3.org/TR/annotation-model/#styles). From 2ec50ab7b540d528104587513fa81cd036aeacfc Mon Sep 17 00:00:00 2001 From: Trip Kirkpatrick Date: Fri, 3 Oct 2025 08:36:51 -0400 Subject: [PATCH 3/8] =?UTF-8?q?Corrected=20image=20service=20ID=20?= =?UTF-8?q?=F0=9F=9B=A0=EF=B8=8F=F0=9F=A4=A6=F0=9F=8F=BB=E2=80=8D=E2=99=82?= =?UTF-8?q?=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- recipe/0040-image-rotation-service/manifest-css.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipe/0040-image-rotation-service/manifest-css.json b/recipe/0040-image-rotation-service/manifest-css.json index be923cd57..d10781fad 100644 --- a/recipe/0040-image-rotation-service/manifest-css.json +++ b/recipe/0040-image-rotation-service/manifest-css.json @@ -43,7 +43,7 @@ "height": 2105, "service": [ { - "id": "https://iiif.io/api/image/3.0/example/reference/85a96c630f077e6ac6cb984f1b752bbf-0-21198-zz00022840-1-master", + "id": "https://iiif.io/api/image/3.0/example/reference/85a96c630f077e6ac6cb984f1b752bbf-0-21198-zz00022840-1-page1", "type": "ImageService3", "profile": "level1" } From d5835617c8b5774283c4f43d2c146a946e080a48 Mon Sep 17 00:00:00 2001 From: Trip Kirkpatrick Date: Fri, 3 Oct 2025 08:37:42 -0400 Subject: [PATCH 4/8] =?UTF-8?q?Corrected=20transform-origin=20value=20?= =?UTF-8?q?=F0=9F=9B=A0=EF=B8=8F=F0=9F=A4=A6=F0=9F=8F=BB=E2=80=8D=E2=99=82?= =?UTF-8?q?=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- recipe/0040-image-rotation-service/manifest-css.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipe/0040-image-rotation-service/manifest-css.json b/recipe/0040-image-rotation-service/manifest-css.json index d10781fad..cae861f45 100644 --- a/recipe/0040-image-rotation-service/manifest-css.json +++ b/recipe/0040-image-rotation-service/manifest-css.json @@ -29,7 +29,7 @@ "motivation": "painting", "stylesheet": { "type": "CssStylesheet", - "value": ".rotated { transform-origin: 130px 130px; transform: rotate(90deg); }" + "value": ".rotated { transform-origin: 761px 762px; transform: rotate(90deg); }" }, "body": { "id": "{{ id.path }}/body/sr1", From e9b3d4eff632276c2e9328443ba064c3da5962fa Mon Sep 17 00:00:00 2001 From: Trip Kirkpatrick Date: Fri, 3 Oct 2025 09:58:22 -0400 Subject: [PATCH 5/8] =?UTF-8?q?Corrected=20direction=20of=20rotation=20to?= =?UTF-8?q?=20counter-/anticlockwise=20=F0=9F=9B=A0=EF=B8=8F=F0=9F=A4=A6?= =?UTF-8?q?=F0=9F=8F=BB=E2=80=8D=E2=99=82=EF=B8=8F=F0=9F=94=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- recipe/0040-image-rotation-service/manifest-css.json | 2 +- recipe/0040-image-rotation-service/manifest-service.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/recipe/0040-image-rotation-service/manifest-css.json b/recipe/0040-image-rotation-service/manifest-css.json index cae861f45..c546e94fc 100644 --- a/recipe/0040-image-rotation-service/manifest-css.json +++ b/recipe/0040-image-rotation-service/manifest-css.json @@ -29,7 +29,7 @@ "motivation": "painting", "stylesheet": { "type": "CssStylesheet", - "value": ".rotated { transform-origin: 761px 762px; transform: rotate(90deg); }" + "value": ".rotated { transform-origin: 761px 762px; transform: rotate(-90deg); }" }, "body": { "id": "{{ id.path }}/body/sr1", diff --git a/recipe/0040-image-rotation-service/manifest-service.json b/recipe/0040-image-rotation-service/manifest-service.json index 5d617645b..0c0eb5512 100644 --- a/recipe/0040-image-rotation-service/manifest-service.json +++ b/recipe/0040-image-rotation-service/manifest-service.json @@ -46,7 +46,7 @@ }, "selector": { "type": "ImageApiSelector", - "rotation": "90" + "rotation": "270" } }, "target": "{{ id.path }}/canvas/p1" From e6e21da754afece58bfdbce9a9c0b908a0050b70 Mon Sep 17 00:00:00 2001 From: Trip Kirkpatrick Date: Fri, 3 Oct 2025 11:58:45 -0400 Subject: [PATCH 6/8] =?UTF-8?q?Expanded=20discussion=20of=20proportions=20?= =?UTF-8?q?x=20orientation=20=F0=9F=93=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- recipe/0040-image-rotation-service/index.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/recipe/0040-image-rotation-service/index.md b/recipe/0040-image-rotation-service/index.md index 884694064..3865cadb6 100644 --- a/recipe/0040-image-rotation-service/index.md +++ b/recipe/0040-image-rotation-service/index.md @@ -31,7 +31,15 @@ Finally, you may use an image service to rotate a region — rather than a whol If your resource is not being served from an image server that supports the desired rotation (or rotation at all) through the IIIF Image API, then you can use CSS for the rotation. Using CSS for rotation depends on the viewer to rotate the image rather than the server. This approach is used when your image server does not have a IIIF Image API service for the image, or if your image server does not allow rotation through service calls. -By using CSS, you may specify arbitrary rotation figures as well as incorporate additional styling values. In order for the rotated image to line up properly with the Canvas, the `transform-origin` CSS property must have the correct value. For rectilinear resources, the value will very often be represented as a pair of points in x, y order where each is half the smaller dimension of the resource. This value may differ meaningfully if other styling that affects the box model is applied. +By using CSS, you may specify arbitrary rotation figures as well as incorporate additional styling values. In order for the rotated image to line up properly with the Canvas, the `transform-origin` and `transform` CSS properties must have the correct value. Without claiming to be exhaustive, we can present suggestions for 4 common cases, with slight variations: +1. Reorienting a non-square rectilinear resource from portrait orientation to landscape orientation. + 1. If the right side of the original resource should be at the top, the CSS should be `transform-origin: Xpx Xpx; transform: rotate(-90deg);` where X is a value equal to half of the resource's smaller dimension. + 1. If the left side of the original resource should be at the top, the CSS should be `transform-origin: Xpx Ypx; transform: rotate(90deg) translateY(-Zpx);` where X is a value equal to half of the resource's smaller dimension, Y is a value equal to the resource's larger dimension less half of its smaller dimension, and Z is a value equal to the mathematical difference between the dimensions. +1. Reorienting a non-square rectilinear resource from landscape orientation to portrait orientation. + 1. If the right side of the original resource should be at the top, the CSS should be `transform-origin: Xpx Ypx; transform: rotate(90deg) translateX(-Zpx);` where X is a value equal to half of the resource's smaller dimension, Y is a value equal to the resource's larger dimension less half of its smaller dimension, and Z is a value equal to the mathematical difference between the dimensions. + 1. If the left side of the original resource should be at the top, the CSS should be `transform-origin: Xpx Xpx; transform: rotate(90deg);` where X is a value equal to half of the resource's smaller dimension. +1. Rotating a square image 90º or 270º and rotating any rectilinear image 180º. In this case, set the `transform-origin` value to the coordinates of the resource's center and the `transform` to be the correct rotation value. +1. Rotating other resources by other degree amounts/directions. Using the models above, manifest creators should have a start on how to craft CSS transformations, including setting an appropriate transformation point, but further discussion of other cases is outside the scope of this recipe. Using CSS to alter resource presentation styles is not specified in the [IIIF Presentation 3.0 API](https://iiif.io/api/presentation/3.0/). The Presentation API section is provided as a convenient but light explanation of this approach. For a more detailed look at styles in Web Annotations, see [the W3C Web Annotation Data Model's Styles section](https://www.w3.org/TR/annotation-model/#styles). From 26549851cf764bb3a5f8e571263d7f5db7f79180 Mon Sep 17 00:00:00 2001 From: Trip Kirkpatrick Date: Fri, 3 Oct 2025 11:59:38 -0400 Subject: [PATCH 7/8] =?UTF-8?q?Added=20additional=20caution=20to=20Restric?= =?UTF-8?q?tions=20=F0=9F=93=9D=E2=9A=A0=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- recipe/0040-image-rotation-service/index.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/recipe/0040-image-rotation-service/index.md b/recipe/0040-image-rotation-service/index.md index 3865cadb6..39ebbbb37 100644 --- a/recipe/0040-image-rotation-service/index.md +++ b/recipe/0040-image-rotation-service/index.md @@ -53,6 +53,8 @@ The image service approach is not usable if you do not have a IIIF Image API ser The CSS approach depends wholly on viewer implementation of CSS as applied to a resource. Viewers have no requirement to support CSS styling. +Be aware that values, especially `transform-origin` and translation, may differ meaningfully if other styling affecting the box model is applied. Translations may differ from the above in use of `translateX` or `translateY`, whether a translation has a positive value or negative value. + ## Example For this recipe, we conveniently had a work on hand that had a page whose text direction was oriented perpendicularly to the facing page. For simplicity's sake, we are using the page in isolation. Because no viewers currently support rotation, we have included here a picture of the page in its original orientation followed by a picture of the page oriented according to the manifests' declarations for rotation. From 188827c650b5aca200d63233a6f1781905630300 Mon Sep 17 00:00:00 2001 From: Trip Kirkpatrick Date: Fri, 3 Oct 2025 12:19:38 -0400 Subject: [PATCH 8/8] =?UTF-8?q?Corrected=20error=20in=20rotation=20directi?= =?UTF-8?q?on=20and=20added=20translation=20=F0=9F=9B=A0=EF=B8=8F?= =?UTF-8?q?=F0=9F=A4=A6=F0=9F=8F=BB=E2=80=8D=E2=99=82=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit m a t h i s h a r d --- recipe/0040-image-rotation-service/manifest-css.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/recipe/0040-image-rotation-service/manifest-css.json b/recipe/0040-image-rotation-service/manifest-css.json index c546e94fc..47702fca3 100644 --- a/recipe/0040-image-rotation-service/manifest-css.json +++ b/recipe/0040-image-rotation-service/manifest-css.json @@ -29,7 +29,7 @@ "motivation": "painting", "stylesheet": { "type": "CssStylesheet", - "value": ".rotated { transform-origin: 761px 762px; transform: rotate(-90deg); }" + "value": ".rotated { transform-origin: 761px 1344px; transform: rotate(90deg) translateY(-582px); }" }, "body": { "id": "{{ id.path }}/body/sr1",