Introduction

Historical maps and old manuscripts contain characters oriented in various directions. This tool uses polygon annotations to accurately mark up tilted characters and leverages the tilt information to retrieve rotation-corrected images via the IIIF Image API.

How Tilt Calculation Works

Vertex Ordering Rules

When creating polygon annotations, vertices are specified in the following order:

  1. Top-left -> 2. Bottom-left -> 3. Bottom-right -> 4. Top-right

By following this counterclockwise order, the tilt angle can be uniquely calculated.

Top-left(1) ─────────── Top-right(4)
        │                   │
        │   Character area  │
        │                   │
     Bottom-left(2) ─────── Bottom-right(3)

Please also refer to the following demo video.

https://youtu.be/P9srTeynXuk?si=mJO1yu3IhR0QFV-2

How the Angle Is Calculated

The tilt angle is calculated from the vector of the top edge (top-left to top-right):

// Extract vertices from SVG path
// M x1,y1 L x2,y2 L x3,y3 L x4,y4 Z
// Vertex 0 (top-left), Vertex 1 (bottom-left), Vertex 2 (bottom-right), Vertex 3 (top-right)

const dx = topRight.x - topLeft.x;  // vertex3.x - vertex0.x
const dy = topRight.y - topLeft.y;  // vertex3.y - vertex0.y

const angle = Math.atan2(dy, dx) * (180 / Math.PI);

// IIIF rotation parameter (clockwise is positive)
let iiifRotation = -angle;
if (iiifRotation  0) iiifRotation += 360;

Practical Examples

Example 1: Horizontal Text, Nearly Level

Annotation data:

{
  "selector": [
    {
      "type": "FragmentSelector",
      "value": "xywh=9030,15590,1231,244"
    },
    {
      "type": "SvgSelector",
      "value": "\"http://www.w3.org/2000/svg\">\"M 9034.61 15828.17 L 10261.06 15835.12 L 10262.08 15596.18 L 9030.33 15590.72 Z\" />"
    }
  ]
}

Calculation:

Top-left: (9034.61, 15828.17)
Top-right: (9030.33, 15590.72)

dx = 9030.33 - 9034.61 = -4.28
dy = 15590.72 - 15828.17 = -237.45

angle = atan2(-237.45, -4.28) ≈ -91.0°
iiifRotation = 91°

Result:

  • region: 9030,15590,1231,244
  • rotation: 91

Example 2: Diagonally Tilted Characters

Annotation data:

{
  "selector": [
    {
      "type": "FragmentSelector",
      "value": "xywh=8843,18773,320,365"
    },
    {
      "type": "SvgSelector",
      "value": "\"http://www.w3.org/2000/svg\">\"M 9064.97 19139.05 L 9163.98 18836.97 L 8944.30 18773.62 L 8843.73 19059.54 Z\" />"
    }
  ]
}

Calculation:

Top-left: (9064.97, 19139.05)
Top-right: (8843.73, 19059.54)

dx = 8843.73 - 9064.97 = -221.24
dy = 19059.54 - 19139.05 = -79.51

angle = atan2(-79.51, -221.24) ≈ -160.2°
iiifRotation = 160°

Result:

  • region: 8843,18773,320,365
  • rotation: 160

Retrieving Images via the IIIF Image API

URL Structure

The IIIF Image API URL structure:

{scheme}://{server}{/prefix}/{identifier}/{region}/{size}/{rotation}/{quality}.{format}

Image Without Rotation

https://example.org/iiif/image/8843,18773,320,365/,200/0/default.png

Tilt-Corrected Image

https://example.org/iiif/image/8843,18773,320,365/,200/160/default.png

Retrieving with a Transparent Background

To make the whitespace caused by rotation transparent, use the PNG format:

https://example.org/iiif/image/8843,18773,320,365/,200/160/default.png

Note: With the JPEG format, whitespace is filled with white.

Rotation Feature Support

The rotation feature of the IIIF Image API is not supported by all image servers. The IIIF Image API defines the following Compliance Levels:

LevelRotation Feature
Level 0Only 0 degrees supported
Level 1Only 0 degrees supported
Level 20, 90, 180, 270 degrees supported (arbitrary angles are optional)

https://iiif.io/api/image/3.0/compliance/#33-rotation

https://iiif.io/api/image/2.1/compliance/#rotation

Many image servers operate at Level 1 or Level 2, and may not support arbitrary angle rotation. The support status can be checked in each image server’s info.json.

{
  "profile": [
    "http://iiif.io/api/image/2/level2.json",
    {
      "supports": ["rotationArbitrary"]
    }
  ]
}

Arbitrary angle rotation is only possible when rotationArbitrary is included.

Viewing in the IIIF Image Viewer

Even if an image server does not support rotation, you can view rotation-corrected images using the IIIF Image Viewer. This viewer rotates the image in the browser, so it does not depend on the server’s rotation capabilities.

URL Parameters

ParameterDescriptionExample
iiifIIIF Image API info.json URLhttps://example.org/iiif/image/info.json
xywhCropping region (x,y,width,height)8843,18773,320,365
rotationRotation angle (degrees)160

Usage Example

Open sample image

Best Practices for Creating Annotations

1. Follow the Vertex Order

Always specify vertices in the order “top-left -> bottom-left -> bottom-right -> top-right”. If this order is not followed, the tilt calculation will not work correctly.

2. Be Aware of Character Orientation

Create annotations so that the reading direction of the characters (the top edge) runs from top-left to top-right.

3. Include Adequate Margins

Rather than fitting the region exactly to the characters, including a small margin improves readability.

Technical Background

Why Both FragmentSelector and SvgSelector Are Needed

  • FragmentSelector: Provides the bounding box (xywh) for cropping images via the IIIF Image API
  • SvgSelector: Provides precise vertex coordinates for tilt calculation

FragmentSelector alone loses the tilt information, while SvgSelector alone requires computing the bounding box. By retaining both, efficient processing is possible.

About IIIF Image API Rotation

The rotation parameter of the IIIF Image API:

  • Clockwise is positive
  • Range is 0 to 360
  • Decimal values are allowed

The rotated image may be larger than the original rectangle. This is because the smallest axis-aligned rectangle that encloses the rotated rectangle is returned.