Here we shall give you a brief introduction to what a IIIF manifest is. A IIIF manifest is at the very heart of MemoRekall-IIIF, and ensures, amongst other things, interoperability of content, lightweight referential creation of data and collections of documents, the integration of MemoRekall into an existing community. For more details about IIIF and how it works, we suggest taking a look at their website.
Form: JSON
So, what even is an IIIF Manifest? Technically, it is a JSON file. JSON is a lightweight, (quasi-)human-readable data format used by many different software both local and online to store, read and share data. Here is an example of a JSON file (suffix .json)
{
“key” : “value”,
“myNumber” : 20,
“myList” : [ 1, 2, 3, “foo”, “bar”],
“anotherLevel : {
“myString” : “hello world”
}
}
Everything is contained within curly brackets. Then, you give as many bits of data as you want. Each piece of data has a key, for example here we have the keys key, myNumber, myList and anotherLevel. Each key had a value associated with it, here the value of key is value, the value of myNumber is 20 and so on. Each key/value pair is separated by a comma. A value can also be a list of values contained within square brackets. You can also give your data hierarchies by making the value another JSON structure contained within curly brackets.
Once the JSON file is loaded into a piece of software, it is very easy to retrieve the values associated with each key. For example, in Python or JavaScript it works like this:
keyValue = myData[“key”]
lowerLevelValue = myData[“anotherLevel”][“myString”]
An IIIF Manifest is nothing more than a json file with a specific structure. Each time you Add a Resource to Mirador for example, you are telling Mirador which JSON file to use as a manifest.
Manifest Structure
An IIIF Manifest can have a large number of key/values. We shall only go over the most important ones here. We suggest reading the IIIF Presentation API for full documentation about a Manifest's structure.
The manifest is divided into items which will all have at least an ID and a type. Before anything, we define a Manifest item. Its type will always be “Manifest”, and its ID will be the URL to the JSON file. Here’s an example:
{
“id” : “www.my-server.com/link-to-my-manifest/manifest_name.json”,
“type” : “Manifest”,
“@context": "http://iiif.io/api/presentation/3/context.json"
}
Notice that there is also a key called @context – this is a link to another JSON file that’s stored on the IIIF servers that tells the interpreter to process the manifest according to the IIIF Presentation API 3.0: this will always be the same.
Next, we give the manifest a label, which is interpreted as its title. Things like labels, descriptions and other texts are given multiple values corresponding to their language. The value will be another JSON structure (between curly brackets) where each key is a language code, and the value is a list containing the data. For example, we can give our manifest a title in English and in French by adding this:
{
“label” : {
“en” : [“The title of my manifest”],
“fr” : [“Le titre de mon manifest"]
}
}
This can be used by a viewer like Mirador to change the title according to the environment's language.
Finally, most IIIF Resources will have an items key whose value will be a list that is populated with different resources (as JSON structures) according to the type of resource. A manifest’s items will typically be populated with Canvases.
Canvas
A Canvas if a container for different resources. A manifest can have several canvases – think of them as pages in a book (in a viewer like Mirador, these canvases can be navigated through with the arrows at the bottom of a window, or seen all at once in Gallery view). Like a manifest, we first define a type and an ID. The type will be Canvas.
The ID (and all following ID’s) will be decomposed into a specific way. The first part of the ID is the path to the manifest’s data on a server, then we give the key term canvas, and then the index of the canvas (starting from 1, think if this as the page number). We can also give the canvas a label.
{
“id” : “www.my-server.com/link-to-my-manifest/canvas/1”,
“type” : “Canvas”,
“label” : {“en” : [“Page One"]},
"width" : 1080,
"height" : 720,
"duration" : 1000.5
}
Next, a canvas will have an items list which will be populated notably with the main media content that we wish to paint to the screen. It will also have other lists like annotations – a list of annotations on the page (note that this means that if you intend for your annotations to be persistent across several pages, you will have to copy the list of annotations for each canvas). Another useful list is thumbnail, where you can set an image that will be used as a preview for the canvas.
We can also add a width, height (in pixels) and duration (if we are going to show timed media, in seconds) to the canvas.
AnnotationPage
Hold tight, this bit can seem a bit confusing at first. The items and annotations lists are populated with an IIIF Resource called an AnnotationPage, within which we place items called Annotations which pertain either to the main media resource we wish to show, or an annotation. Did you follow that? I’ll explain…
There are two confusing points – the first, why place our content within another item called an AnnotationPage? This kind of structure will allow us to perform higher level organizations and hierarchies of collections of content. For now, just know that you must put all of your content into an AnnotationPage’s items list.
The second is – why is everything called an annotation? This is because IIIF follows the principles of Linked Data, and Web Architecture. It’s standard terminology that allows for interoperability. Just know that your actual annotations are the things that are stored in the Canvas’s annotations list.
Hopefully this will become clearer with the examples below. For now, lets add an annotation page to our Canvas’s items:
{
“id” : “www.my-server.com/link-to-my-manifest/canvas/1”,
“type” : “Canvas”,
“label” : {“en” : [“Page One"]}
"items" : [
{
"id" : “www.my-server.com/link-to-my-manifest/canvas/1/page/1”,
"type" : "AnnotationPage"
"items" : []
}
]
"annotations" : []
}
Note that the AnnotationPage's ID takes the Canvas's ID, and adds "page" and then the index of the annotation page to it. If this were an AnnotationPage in the annotations list, instead of page, we would put annotation (see below).
We shall add our media to the AnnotationPage's items.
Adding Media
As mentioned above, the type of IIIF resource that will contain the media item is called an Annotation. As always, we start by defining an ID and a type. For the ID, we take the ID of the Annotation’s AnnotationPage, and add the index of the Annotation. The type is Annotation.
{
"id" : “www.my-server.com/link-to-my-manifest/canvas/1/page/1/1”,
"type" : "Annotation"
}
Next, there are some specific keys we will need to give. The first is motivation – the value is either painting or supplementing. We use painting when we’re talking about a main media item that will be drawn to the Canvas’s screen, we use supplementing when talking about another resource (like for an annotation). Here, we use painting for our main media item.
Next is target. Here, we must give the ID of the Canvas we wish to paint to, and then give information about where and when on the canvas we wish it to appear. Before giving these values, we add a hashtag #. Then if we can to define the position on the canvas, we add xywh= and give the x position, y position, width and height. If we want to define the start and end time, we add t= and then the beginning and end. If we wish to inform both, we must separate the two inputs with a &:
{
"id" : “www.my-server.com/link-to-my-manifest/canvas/1/page/1/1”,
"type" : "Annotation",
"motivation" : "painting",
"target" : "www.my-server.com/link-to-my-manifest/canvas/1#xywh=0,0,1080,720&t=0,1000.5"
}
In this example, we say that the item will be drawn at xy coordinates (0,0) with a width of 1080 and a height of 720. We also state that it will play from the beginning (0) to 1000.5 seconds.
The final key to give is the body. This is another JSON structure that will inform us about where to find the actual media file. Here, the ID will be the absolute path to the media file, and the type will depend on the type of media file. We also give the file format as format, and any information about dimensions and duration. Here is an example of a full Annotation of a video file:
{
"id" : “www.my-server.com/link-to-my-manifest/canvas/1/page/1/1”,
"type" : "Annotation",
"motivation" : "painting",
"target" : "www.my-server.com/link-to-my-manifest/canvas/1#xywh=0,0,1080,720&t=0,1000.5"
"body" : {
"id" : "www.my-server.com/my-media-file.mp4",
"type" : "Video",
"format" : "video/mp4",
"width" : 1080,
"height" : 720,
"duration" : 1000.5,
}
}
Annotations
You now know how to create a simple manifest that draws a video file on the Canvas. However, in MemoRekall, a powerful aspect is the ability to ass annotations to this media that can be directly linked to another IIIF manifest.
As explained above, annotations will be placed in an AnnotationPage that is in the Canvas’s annotations list. Remember, instead of using page in the AnnotationPage’s ID, you must use annotation.
{
"id" : “www.my-server.com/link-to-my-manifest/canvas/1/annotation/1”,
"type" : "AnnotationPage"
}
In the MemoRekall-IIIF environment, there are different kinds of annotations that can be added, we shall go through them now.
Basic Annotation
Let’s first create a basic annotation. This won’t paint anything to the screen. In the Mirador viewer, this would simply appear in the list of annotation. Like when we add a media item, we create an Annotation resource that will be added to the AnnotationPage’s items list.
As before, the ID is the AnnotationPage’s ID with the index of the annotation, and the type is Annotation. The motivation here will be supplementing. The target will just be the Canvas’s ID without any information about painting to the screen. We don’t need to inform the body of the annotation.
{
"id" : “www.my-server.com/link-to-my-manifest/canvas/1/annotation/1/1”,
"type" : "Annotation",
"motivation" : "supplementing",
"target" : "www.my-server.com/link-to-my-manifest/canvas/1"
}