@allmaps/annotation
Version:
Functions for generating and parsing IIIF georeference annotations
253 lines (156 loc) • 7.42 kB
Markdown
# @allmaps/annotation
Parsing and Generating Georeference Annotations.
## How it works
This module that can generate and parse [Georeference Annotations](https://iiif.io/api/extension/georef/).
A **Georeference Annotation** is a [Web Annotation](https://www.w3.org/TR/annotation-model/) that stores the metadata needed to [georeference](https://en.wikipedia.org/wiki/Georeferencing) a [IIIF image](https://iiif.io/api/image/3.0/). See this [example](./examples/annotation.example.json).
A Georeference Annotation contains the following data:
* The [URI of an IIIF Image](https://iiif.io/api/image/3.0/#3-identifier), as well as its dimensions in pixels.
* A polygonal resource mask that defines the cartographic part of the image.
* A list of ground control points (GCPs) that define the mapping between resource coordinates and geospatial coordinates.
Multiple maps can be defined in an **Annotation Page** (see [spec](https://iiif.io/api/presentation/3.0/#2-resource-type-overview)).
Allmaps offers apps and packages for working with Georeference Annotations. [Allmaps Viewer](../../apps/viewer/) can [for example](https://viewer.allmaps.org/#data=data%3Atext%2Fx-url%2Chttps%3A%2F%2Fraw.githubusercontent.com%2Fallmaps%2Fannotation%2Fdevelop%2Fexamples%2Fannotation.example.json) warp IIIF maps in the browser, just by loading a Georeference Annotation.
A **Georeferenced Map** is the format Allmaps uses internally to describe a map and pass it between functions and packages. It contains the same information in a more practical form. See this [example](./examples/map.example.json).
This module allows **parsing** Georeference Annotations to Georeferenced Maps and **generating** Georeference Annotations from Georeferenced Maps.
This module is written in TypeScript and is built using Zod.
<!-- TODO: create Observable notebook that allows you to try out this module! -->
## Installation
This is an ESM-only module that works in browsers and in Node.js.
Node.js:
Install with npm:
```sh
npm install @allmaps/annotation
```
Browser:
```html
<script type="module">
import { Annotation } from 'https://unpkg.com/@allmaps/annotation?module'
</script>
```
## Usage
```js
import { parseAnnotation, generateAnnotation } from '@allmaps/annotation'
// Fetch an annotation
const annotation = await fetch(annoationUrl).then((response) => response.json())
// Create a georeferencedMap from the annotation
const georeferencedMaps = parseAnnotation(annotation)
const georeferencedMap = georeferencedMaps[0]
// Use or modify the georeferencedMap(s)
// ...
// Generate Georeference Annotation
// Note: returns an annotation or annotation page based on input
const georeferenceAnnotation = generateAnnotation(georeferencedMap)
const georeferenceAnnotationPage = generateAnnotation(georeferencedMaps)
```
See the API below for more details.
## License
MIT
## API
### `Annotation`
###### Type
```ts
{ type: "Annotation"; target: { type: "SpecificResource"; source: { type: "ImageService1" | "ImageService2" | "ImageService3"; height: number; width: number; '@id': string; partOf?: Array<PartOfItem> | undefined; } | { ...; } | { ...; }; selector: { ...; }; }; ... 5 more ...; motivation?: string | undefined; }
```
### `AnnotationPage`
###### Type
```ts
{ type: "AnnotationPage"; items: Array<{ type: "Annotation"; target: { type: "SpecificResource"; source: { type: "ImageService1" | "ImageService2" | "ImageService3"; height: number; width: number; '@id': string; partOf?: Array<PartOfItem> | undefined; } | { ...; } | { ...; }; selector: { ...; }; }; ... 5 more ...; m...
```
### `AnnotationPageSchema`
###### Type
```ts
AnnotationPage1Schema
```
### `AnnotationSchema`
###### Type
```ts
Annotation1Schema
```
### `FeaturePropertiesSchema`
###### Type
```ts
Annotation1FeaturePropertiesSchema
```
### `GCPSchema`
###### Type
```ts
GeoreferencedMap2GCPSchema
```
### `GeoreferencedMap`
###### Type
```ts
{ type: "GeoreferencedMap"; resource: { type: "ImageService1" | "ImageService2" | "ImageService3" | "Canvas"; id: string; height?: number | undefined; width?: number | undefined; partOf?: Array<PartOfItem> | undefined; }; ... 7 more ...; resourceCrs?: { ...; } | undefined; }
```
### `GeoreferencedMapSchema`
###### Type
```ts
GeoreferencedMap2Schema
```
### `GeoreferencedMapsSchema`
###### Type
```ts
GeoreferencedMaps2Schema
```
### `PartOf`
###### Type
```ts
Array<PartOfItem> | undefined
```
### `PartOfItem`
###### Type
```ts
{
type: string
id: string
label?: Record<string, Array<string | number | boolean>> | undefined
} & {partOf?: PartOfItem[]}
```
### `ResourceSchema`
###### Type
```ts
GeoreferencedMap2ResourceSchema
```
### `SvgSelectorSchema`
###### Type
```ts
SvgSelector1Schema
```
### `generateAnnotation(mapOrMaps)`
Generates a Georeference Annotation from a single Georeferenced Map or
an Annotation Page containing multiple Georeference Annotations from an array of Georeferenced Maps.
###### Parameters
* `mapOrMaps` (`unknown`)
* Single Georeferenced Map, or an array of Georeferenced Maps
###### Returns
Georeference Annotation or Annotation Page (`{ type: "Annotation"; target: { type: "SpecificResource"; source: { type: "ImageService1" | "ImageService2" | "ImageService3"; height: number; width: number; '@id': string; partOf?: Array<PartOfItem> | undefined; } | { ...; } | { ...; }; selector: { ...; }; }; ... 5 more ...; motivation?: string | undefined; } | { ....`).
###### Examples
```ts
import fs from 'fs'
import { generateAnnotation } from '@allmaps/annotation'
const map = JSON.parse(fs.readFileSync('./examples/map.example.json'))
const annotation = generateAnnotation(map)
```
### `parseAnnotation(annotation)`
Parses a Georeference Annotation or an Annotation Page containing multiple Georeference Annotations
and returns an array of Georeferenced Maps.
###### Parameters
* `annotation` (`unknown`)
* Georeference Annotation or Annotation Page containing multiple Georeference Annotations
###### Returns
Array of maps (`Array<{ type: "GeoreferencedMap"; resource: { type: "ImageService1" | "ImageService2" | "ImageService3" | "Canvas"; id: string; height?: number | undefined; width?: number | undefined; partOf?: Array<PartOfItem> | undefined; }; ... 7 more ...; resourceCrs?: { ...; } | undefined; }>`).
###### Examples
```ts
import fs from 'fs'
import { parseAnnotation } from '@allmaps/annotation'
const annotation = JSON.parse(fs.readFileSync('./examples/annotation.example.json'))
const maps = parseAnnotation(annotation)
```
### `validateAnnotation(annotation)`
###### Parameters
* `annotation` (`unknown`)
###### Returns
`{ type: "Annotation"; target: { type: "SpecificResource"; source: { type: "ImageService1" | "ImageService2" | "ImageService3"; height: number; width: number; '@id': string; partOf?: Array<PartOfItem> | undefined; } | { ...; } | { ...; }; selector: { ...; }; }; ... 5 more ...; motivation?: string | undefined; } | { ....`.
### `validateGeoreferencedMap(mapOrMaps)`
###### Parameters
* `mapOrMaps` (`unknown`)
###### Returns
`{ type: "GeoreferencedMap"; resource: { type: "ImageService1" | "ImageService2" | "ImageService3" | "Canvas"; id: string; height?: number | undefined; width?: number | undefined; partOf?: Array<PartOfItem> | undefined; }; ... 7 more ...; resourceCrs?: { ...; } | undefined; } | Array<{ type: "GeoreferencedMap"; resou...`.