Venice Centre for Digital and Public Humanities
It stands for International Image Interoperability Framework
It is a model for presenting and annotating digital representations of objects
It is a set of application programming interfaces (APIs) based on open web standards and defined in specifications derived from shared real world use cases.
It is also a community that implements those APIs and specifications in software, both server and client. Additionally it exposes interoperable content!
The International Image Interoperability Framework is a set of shared application programming interface (API) specifications for interoperable functionality in digital image repositories.
IIIF has the following goals:
Many libraries, archives, organizations, and museums store and provide access to images. Images transmit scholarship, culture, and understanding. There are a lot of great reasons to adopt IIIF, first and foremost, you don't need to keep solving common problems
We have done a really good job digitising our cultural heritage and put it online.
However, images are:
These things should not have to be invented each time.
Otherwise it would be a word of silos and dupliation
IIIF frees up your images to be creatively reused. Because scaling, cropping and zooming become trivial operations, you’re free to concentrate on the important task of providing a great user experience.
You also benefit from great image viewing software written and maintained by other people, so no need to reinvent the wheel.
Using JSON-LD, linked data, and standard W3C web protocols such as Web Annotation, IIIF makes it easy to parse and share digital image data, migrate across technology systems, and provide enhanced image access for scholars and researchers. In short, IIIF enables better, faster and cheaper image delivery.
The IIIF technical specifications are the glue that holds things together for image interoperability.
IIIF provides two core APIs:
There are several more APIs that IIIF supports including Search and Authentication. This workshop will focus on the Image and Presentation APIs.
The Image API provides for a standardized way to request and deliver images. This can be as simple as, give me the original image to give me an upside down tiled version of the image in gif format. The IIIF Image API is restful and allows for images to be served dynamically or from a static cache (implementation details).
https://iiif.io/api/image/2.1/compliance/#status-of-this-document
Images are requested using URI templates that have the following
syntax:
https://example.org/{id}/{region}/{size}/{rotation}/{quality}.{fmt}
https://example.org/{id}/info.json
International Image Interoperability Framework
This solution allows a client to "point" to an image available on the Web by requesting, at the same time, the supply of the same by the server with specific formal parameters explicitly expressed in the formulation of the same URI according to this syntax:
{scheme}://{server}{/prefix}/{identifier}/{region}/{size}/{rotation}/{quality}.{format}
The first API developed within the IIIF project concerns the identification of an image and its specifications through a URI conveyed through the HTTP or HTTPS protocols.
{scheme}://{server}{/prefix}/{identifier}/{region}/{size}/{rotation}/{quality}.{format}
{scheme}://{server}{/prefix}/{identifier}/{region}/{size}/{rotation}/{quality}.{format}
https://stacks.stanford.edu/image/iiif/hd288rd1737%252F0090_496-34/full/full/0/default.jpg
https:// | {scheme}:// |
---|---|
stacks.stanford.edu/ | {server} |
image/iiif/ | {/prefix}/ |
hd288rd1737%252F0090_496-34/ | {identifier}/ |
full/ | {region}/ |
full/ | {size}/ |
0/ | {rotation}/ |
default | {quality} |
.jpg | .{format} |
{scheme}://{server}{/prefix}/{identifier}/{region}/{size}/{rotation}/{quality}.{format}
https://images.lib.cam.ac.uk/iiif/MS-ORCS-00001-00002-000-00001.jp2/full/full/0/default.jpg
https:// | {scheme}:// |
---|---|
images.lib.cam.ac.uk | {server} |
/iiif/ | {/prefix}/ |
MS-ORCS-00001-00002-000-00001.jp2 | {identifier}/ |
full/ | {region}/ |
full/ | {size}/ |
0/ | {rotation}/ |
default | {quality} |
.jpg | .{format} |
{scheme}://{server}{/prefix}/{identifier}/{region}/{size}/{rotation}/{quality}.{format}
https://images.lib.cam.ac.uk/iiif/MS-ORCS-00001-00002-000-00001.jp2/full/full/0/default.jpg
{scheme}://{server}{/prefix}/{identifier}/{region}/{size}/{rotation}/{quality}.{format}
https://images.lib.cam.ac.uk/iiif/MS-ORCS-00001-00002-000-00001.jp2/full/full/0/default.jpg
https:// | {scheme}:// |
---|---|
images.lib.cam.ac.uk | {server} |
/iiif/ | {/prefix}/ |
MS-ORCS-00001-00002-000-00001.jp2 | {identifier}/ |
full/ | {region}/ |
full/ | {size}/ |
0/ | {rotation}/ |
default | {quality} |
.jpg | .{format} |
{scheme}://{server}{/prefix}/{identifier}/{region}/{size}/{rotation}/{quality}.{format}
https://images.lib.cam.ac.uk/iiif/MS-ORCS-00001-00002-000-00001.jp2/full/full/0/default.jpg
{scheme}://{server}{/prefix}/{identifier}/{region}/{size}/{rotation}/{quality}.{format}
https://images.lib.cam.ac.uk/iiif/MS-ORCS-00001-00002-000-00001.jp2/full/full/0/default.jpg
https:// | {scheme}:// |
---|---|
images.lib.cam.ac.uk | {server} |
/iiif/ | {/prefix}/ |
MS-ORCS-00001-00002-000-00001.jp2 | {identifier}/ |
full/ | {region}/ |
full/ | {size}/ |
0/ | {rotation}/ |
default | {quality} |
.jpg | .{format} |
{scheme}://{server}{/prefix}/{identifier}/{region}/{size}/{rotation}/{quality}.{format}
https://images.lib.cam.ac.uk/iiif/MS-ORCS-00001-00002-000-00001.jp2/full/full/0/default.jpg
{scheme}://{server}{/prefix}/{identifier}/{region}/{size}/{rotation}/{quality}.{format}
https://images.lib.cam.ac.uk/iiif/MS-ORCS-00001-00002-000-00001.jp2/full/full/0/default.jpg
https:// | {scheme}:// |
---|---|
images.lib.cam.ac.uk | {server} |
/iiif/ | {/prefix}/ |
MS-ORCS-00001-00002-000-00001.jp2 | {identifier}/ |
full/ | {region}/ |
full/ | {size}/ |
0/ | {rotation}/ |
default | {quality} |
.jpg | .{format} |
{scheme}://{server}{/prefix}/{identifier}/{region}/{size}/{rotation}/{quality}.{format}
https://images.lib.cam.ac.uk/iiif/MS-ORCS-00001-00002-000-00001.jp2/full/full/0/default.jpg
JSON-LD is a lightweight Linked Data format. It is easy for humans to read and write. It is based on the already successful JSON format and provides a way to help JSON data interoperate at Web-scale. JSON-LD is an ideal data format for programming environments, REST Web services, and unstructured databases such as CouchDB and MongoDB.
{
"@context" : "http://iiif.io/api/image/2/context.json",
"@id" : "http://iiif.thembi.me/10r/",
"protocol" : "http://iiif.io/api/image",
"width" : 1944,
"height" : 2592,
"sizes" : [
{ "width" : 121, "height" : 162 },
{ "width" : 243, "height" : 324 },
{ "width" : 486, "height" : 648 }
],
"tiles" : [
{ "width" : 256, "height" : 256, "scaleFactors" : [ 1, 2, 4, 8, 16 ] }
],
"profile" : [
"http://iiif.io/api/image/2/level1.json",
{ "formats" : [ "jpg" ],
"qualities" : [ "native","color","gray" ],
"supports" : ["regionByPct","regionSquare","sizeByForcedWh","sizeByWh","sizeAboveFull","rotationBy90s","mirroring"] }
]
Exercise:
From this image:
https://images.lib.cam.ac.uk/iiif/MS-ORCS-00001-00002-000-00001.jp2/full/full/0/default.jpg
https://iiif.bodleian.ox.ac.uk/iiif/image/5359a811-63e4-49d7-8cc1-e6b4308a7969
The primary requirements for the Presentation API are to provide an order for these views, the resources needed to display a representation of the view, and the descriptive information needed to allow the user to understand what is being seen.
The principles of Linked Data and the Architecture of the Web are adopted in order to provide a distributed and interoperable system. The Shared Canvas data model and JSON-LD are leveraged to create an easy-to-implement, JSON-based format.
http://iiif.io/api/presentation/2.1/#introduction
http://iiif.io/model/shared-canvas/1.0/
A canvas is a coordinate space on which images can be painted. Images are painted onto a canvas through annotation. In the simple case we're only painting a single image annotation so that it fills the whole canvas.
We call it a shared canvas because it allows for painting multiple images onto the same canvas as well as overlaying additional annotations.
http://iiif.io/model/shared-canvas/1.0/
Think of a canvas as an empty presentation slide. You can put a page image on the canvas via annotation:
http://iiif.io/model/shared-canvas/1.0/
Once you have a base image painted onto the canvas you can then apply further annotations like transcriptions, translations, scholarly commentary.
/info.json
Where is in the image you have just worked with?
The presentation API links the info.json
Just add: info.json
The objective of the IIIF Presentation API is to provide the information necessary to allow a rich, online viewing environment for primarily image-based objects to be presented to a human user [...]. (Yu 2011, 467).
This is the sole purpose of the API and therefore the descriptive information is given in a way that is intended for humans to read, but not semantically available to machines (Yu 2011, 467).
[... It] explicitly does not aim to provide metadata that would drive discovery of the digitized objects reated for a specific development domain and normally contains a set of common and reusable building blocks so that developers can use, extend, or customize for their specific business logic (Yu 2011, 467)
The overall description of the structure and properties of the digital representation of an object. It carries information needed for the viewer to present the digitized content to the user, such as a title and other descriptive information about the object or the intellectual work that it conveys. Each manifest describes how to present a single object such as a book, a photograph, or a statue.
The order of the views of the object. Multiple sequences are allowed to cover situations when there are multiple equally valid orders through the content, such as when a manuscript’s pages are rebound or archival collections are reordered.
A virtual container that represents a page or view and has content resources associated with it or with parts of it. The canvas provides a frame of reference for the layout of the content. The concept of a canvas is borrowed from standards like PDF and HTML, or applications like Photoshop and Powerpoint, where the display starts from a blank canvas and images, text and other resources are “painted” on to it.
Content resources such as images or texts that are associated with a canvas.
Essentially, a manifest is just a JSON-LD file that consists of several main sections, most of which are optional depending on your use-case.
Text
In this section we'll create a manifest by hand step by step.
In most cases in production you won't actually be creating manifests by hand. You will probably have different systems and workflows from other institutions so will need to determine the best way for you to create manifests.
Web server for Chrome
Navigate to the editor. If any of your info.json URLs begin with HTTP, use the HTTP version. See the Note on Mixed Content section at the bottom of this page for more information.
Add at least two Canvases to your Manifest. The option to add a Canvas is below the main image preview, to the left.
View the Manifest JSON at http://127.0.0.1:8887/manifest.json in your browser:
Copy the downloaded Manifest to the folder you created when setting up the Web Server for Chrome. Name the file manifest.json
Visit the URL http://127.0.0.1:8887/manifest.json You should see the Manifest's JSON.
There are some important elements of the Manifest that we did not add or edit using theonline editor. The goal of this exercise will be to edit or add them manually. Each task is linked to the specification for the property that you will need to edit or add to the Manifest.
There are some important elements of the Manifest that we did not add or edit using theonline editor. The goal of this exercise will be to edit or add them manually. Each task is linked to the specification for the property that you will need to edit or add to the Manifest.
It is possible to provide information about the structure of the content within the Manifest. For instance, you might want to group Canvases depicting pages of a book by chapter, or of a play by act and scene. The Range is the Presentation API mechanism for describing this type of structure. In this exercise we will add Range-based navigation to your Manifest.
Find the @id of each Canvas you created in your Manifest. Your structural mapping will reference the Canvases by their @ids.
"structures": [
{
"@id": "http://example.org/iiif/book1/range/r0",
"@type": "sc:Range",
"label": "Table of Contents",
"members": [
{
"@id": "http://example.org/iiif/book1/range/r1",
"@type": "sc:Range",
"label": "Introduction"
}
]
},
{
"@id": "http://example.org/iiif/book1/range/r1",
"@type": "sc:Range",
"label": "Introduction",
"canvases": ["$YOUR_CANVAS_ID"]
}
]
International Image Interoperability Framework
At this point, the parameters expressly defined by IIIF for the supply of images come into play, which must be listed in the order required
The parameters of the Image Request URI include region, size, rotation, quality and format, which define the characteristics of the returned image. These are described in detail in Image Request Parameters
{scheme}://{server}{/prefix}/{identifier}/{region}/{size}/{rotation}/{quality}.{format}
It is a viewer that supports only API Image
Download from my GitHub:
https://github.com/tmancinelli/digitaltext2022
API documentation: https://openseadragon.github.io/docs/
List of some Libraries
Exercise
Take one of them - go to the manifest and get an URL of an image and paste it on the index.html
Rotation
Take one of them - go to the manifest and get an URL of an image and paste it on the index.html
Can you add the rotation?
degrees: 90, showRotationControl: true,
Mirador home page: http://projectmirador.org/
Open the Mirador site and click on the "try a live demo" button.
You'll see some sample content. Click the "x" to close one of the windows. Click the upper-lefthand dropdown to "Replace Object".
Download the file on my GitHub:
https://github.com/tmancinelli/tutorial_Bologna_2020/tree/master/mirador1
Expose this file through a local web server
python -m SimpleHTTPServer 8000
Or
python -m http.server [<portNo>]
Exercise
On our Frankstein XML:
<facsimile>
<graphic xml:id="p21r"
url="https://iiif.bodleian.ox.ac.uk/iiif/image/5359a811-63e4-49d7-8cc1-e6b4308a7969/full/full/0/default.jpg">
</facsimile>
Let's going to see Paolo Monella's example:
http://www1.unipa.it/paolo.monella/romualdus/xml/chronicon.xml
Paolo Monella (http://www1.unipa.it/paolo.monella/reires2019/)
Perhaps on the MsDesc?
https://tei-c.org/release/doc/tei-p5-doc/en/html/ref-msDesc.html
OpenSeaDragon:
<graphic xml:id="p21r" url="https:canvas"></graphic>
</facsimile>
Mirador:
<facsimile facs="manifest.json">
<graphic xml:id="p21r" url="https:canvas"></graphic>
</facsimile>
Do you remember your XSLT?
Let's get it back!
Let's also get our OpenSeaDragon file.
How can we put them together?
1. Let's look at the value of the URL attribute. Is that right?
1. Let's look at the value of the URL attribute. Is that right?
Go to the manifest: https://iiif.bodleian.ox.ac.uk/iiif/manifest/53fd0f29-d482-46e1-aa9d-37829b49987d.json
1. download the file:
https://github.com/tmancinelli/tutorial_Bologna_2020/tree/master/xquery/exercise1
declare function prefix:function_name($parameter as datatype) as returnDatatype
{
...function code here...
};
(: Yeah! :)
declare function prefix:function_name($parameter as datatype) as returnDatatype
{
...function code here...
};
If you cannot find the XQuery function you need, you can write your own.
(: Yeah! :)
declare function prefix:function_name($parameter as datatype) as returnDatatype
{
...function code here...
};
(: Yeah! :)
declare function prefix:function_name($parameter as datatype) as returnDatatype
{
...function code here...
};
(: Yeah! :)
declare function prefix:function_name($parameter as datatype) as returnDatatype
{
...function code here...
};
An example with Python:
a = 123
type(a) # this will print 'int'
a = "hello world"
type(a) # this will print 'str'
An example with Javascript:
let a = 123;
console.log(typeof a); // this will show 'number'
a = "hello world";
console.log(typeof a); // this will show 'string'
declare function prefix:function_name($parameter as datatype) as returnDatatype
{
...function code here...
};
If a variable is a string you cannot set as interger and viceversa.
Why is it better to define a type?
1. To write better your code
2. make it understandable for the other will read it
declare function local:sumvalues($a as xs:integer, $b as xs:integer) as xs:integer {
let $sum := $a + $b
return $sum
};
let $foo := local:sumvalues(1, 2)
return $foo
The return datatype means:
what the function return value is in that datatype
declare function local:maybeSumValues($a as xs:integer, $b as xs:integer) as xs:integer {
let $sum := $a + $b
return if ($sum > 10)
then -1
else $sum
};
let $foo := local:maybeSumValues(1, 2)
return $foo
declare function local:countHands($node as node()) {
count($node//*[@hand])
};
let $root := doc("Frankenstein-v1c5-transcription.xml")
return <p>Corrections: {local:countHands($root)}</p>
declare function local:showMyType($a) {
typeswitch ($a)
case xs:string
return "This is a STRING!"
case xs:integer
return "This is a NUMBER!"
default
return "I don't know"
};
let $foo := local:showMyType("hi")
return $foo
Exercise:
Exercise:
declare function local:applyTemplateP($nodes as node()*) as node()* {
for $node in $nodes
return
<p>{local:applyTemplates($node/node())}</p>
};
Exercise:
3. add the typeswitch
case element(tei:p)
return local:applyTemplateP($node)
Exercise:
4. Recall it in the HTML tag
let $teiP := $root//tei:div//tei:p
return local:applyTemplateP($teiP)
Exercise 2
1. Make a function to transform <lb> to <br/>
You can download the entire Xquery script!
Exercise 3 and add it OpenSeaDragon
Let's work with your XSLT:
1. Add this script:
<script src="https://unpkg.com/mirador@beta/dist/mirador.min.js"></script>
Where?
2. Add the manifest in your TEI:
<facsimile facs="https://iiif.bodleian.ox.ac.uk/iiif/manifest/53fd0f29-d482-46e1-aa9d-37829b49987d.json">
<graphic xml:id="p21r" url="https://iiif.bodleian.ox.ac.uk/iiif/canvas/ac06667a-e105-4781-ad5d-209cad1c2ba8.json"></graphic>
</facsimile>
3. Add a bit of javacript to run Mirador
[...]
<div id="mirador" style="width: 400px; height: 600px;"></div>
<script type="text/javascript">
var mirador = Mirador.viewer({
"id": "mirador",
"windows": [
{
"manifestId": "<xsl:value-of select="//tei:facsimile/@facs"/>",
"canvasId": "<xsl:value-of select="//tei:facsimile/tei:graphic/@url"/>",
"thumbnailNavigationPosition": 'far-bottom'
}
]
});
</script>
[...]
tiziana.mancinelli@unive.it
@tizmancinelli