Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

0485 contentstate canvas region #529

Merged
merged 18 commits into from
Sep 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
07e1df4
First draft
giacomomarchioro Aug 2, 2024
89fee1c
Merge pull request #526 from giacomomarchioro/0485-contentstate-canva…
giacomomarchioro Aug 2, 2024
5387df8
post-cookbook meeting comments
giacomomarchioro Aug 9, 2024
17c7ee6
Merge pull request #527 from giacomomarchioro/0485-contentstate-canva…
giacomomarchioro Aug 9, 2024
5be9532
change viewers compatibility system
giacomomarchioro Aug 9, 2024
c0b74ca
Merge pull request #528 from giacomomarchioro/0485-contentstate-canva…
giacomomarchioro Aug 9, 2024
fa98c93
Merge branch 'master' into 0485-contentstate-canvas-region
glenrobson Aug 9, 2024
bcc3575
Merge branch 'master' into 0485-contentstate-canvas-region
glenrobson Aug 13, 2024
7732cee
Adding Content State encode
glenrobson Aug 13, 2024
748220d
Adding clover removing UV and Curation Viewer
glenrobson Aug 13, 2024
e913f4b
Merge pull request #530 from IIIF/add_content_state_links
glenrobson Aug 13, 2024
82077a0
Addressing editor comments
glenrobson Aug 19, 2024
e377ffd
Merge pull request #532 from IIIF/0485-editor-updates
glenrobson Aug 19, 2024
d4044ba
Merge branch 'master' into 0485-contentstate-canvas-region
glenrobson Aug 19, 2024
82ee43b
Merge branch 'master' into 0485-contentstate-canvas-region
glenrobson Aug 21, 2024
8650db6
Post TRC corrections
giacomomarchioro Sep 27, 2024
f8ca9c2
Merge pull request #543 from giacomomarchioro/0485-contentstate-canva…
giacomomarchioro Sep 27, 2024
52a877a
Merge branch 'master' into 0485-contentstate-canvas-region
glenrobson Sep 27, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions _includes/content-state-viewers.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{% if include.viewers %}
{% assign viewers = include.viewers | split: "," %}
{% else %}
{% assign viewers = page.viewers %}
{% endif %}
[JSON-LD]({{ include.iiif-content }}) {% for viewerTxt in viewers %}{% assign viewer = viewerTxt | strip %}| {% include viewer_link.html type=viewer manifest=include.iiif-content class="content-state" %}{% endfor %}

{% if page.code %}
{% include code_links.html %}
{% endif %}

<script>
function encodeContentState(plainContentState) {
let uriEncoded = encodeURIComponent(plainContentState); // using built in function
let base64 = btoa(uriEncoded); // using built in function
let base64url = base64.replace(/\+/g, "-").replace(/\//g, "_");
let base64urlNoPadding = base64url.replace(/=/g, "");
return base64urlNoPadding;
}

const links = document.getElementsByClassName("content-state");

Array.from(links).forEach(link => {
link.title = "Generating iiif-content link...."
fetch(link.dataset.iiifContent).then(response=> {
response.json().then (anno => {
const encoded = encodeContentState(JSON.stringify(anno));

if (/iiif-content=.*&/.test(link.href)){
link.href = link.href.replace(/iiif-content=.*&/, "iiif-content=" + encoded + '&');
} else {
link.href = link.href.replace(/iiif-content=.*$/, "iiif-content=" + encoded);
}
link.title = "";
})

});
});
</script>
2 changes: 2 additions & 0 deletions _includes/links.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@

[0466]: {{ site.cookbook_url | absolute_url }}/recipe/0466-link-for-loading-manifest/ "Loading a manifest with a viewer using a link"

[0485]: {{ site.cookbook_url | absolute_url }}/recipe/0485-contentstate-canvas-region/ "Open a specific region of a canvas in a viewer"

[0434]: {{ site.cookbook_url | absolute_url }}/recipe/0434-choice-av/ "Multiple Choice of Audio Formats in a Single View (Canvas)"

[cookbook-process]: {{site.cookbook_url | absolute_url }}/recipe
Expand Down
2 changes: 1 addition & 1 deletion _includes/viewer_link.html
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,4 @@
{% else %}
{% capture default_text %}Unknown Viewer type '{{ include.type}}'{% endcapture %}
{% capture viewer_url %}{{manifest_url |strip}}{% endcapture %}
{% endif %}<a href="{{ viewer_url | strip }}" target="_blank">{{ include.text | default: default_text }}</a>
{% endif %}<a href="{{ viewer_url | strip }}" class="{{ include.class }}" data-iiif-content="{{manifest_url |strip}}" target="_blank">{{ include.text | default: default_text }}</a>
1 change: 1 addition & 0 deletions index.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ _(leading on to segmentation examples later)_
Recipes using [Content State API](https://iiif.io/api/content-state/1.0/)

* [Loading a manifest with a viewer using a link][0466]
* [Open a specific region of a canvas in a viewer][0485]


## Technical
Expand Down
14 changes: 14 additions & 0 deletions recipe/0485-contentstate-canvas-region/annotation.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"@context": "http://iiif.io/api/presentation/3/context.json",
"id": "https://example.org/import/1",
"type": "Annotation",
"motivation": ["contentState"],
"target": {
"id": "https://iiif.io/api/cookbook/recipe/0009-book-1/canvas/p2#xywh=1528,3024,344,408",
"type": "Canvas",
"partOf": [{
"id": "https://iiif.io/api/cookbook/recipe/0009-book-1/manifest.json",
"type": "Manifest"
}]
}
}
95 changes: 95 additions & 0 deletions recipe/0485-contentstate-canvas-region/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
---
title: Open a specific region of a Canvas in a viewer
id: 485
layout: recipe
tags: [annotation, content-state]
summary: "Allows users to use Content State API to open a specific region of a Canvas by means of supported viewers."
viewers:
topic:
- content-state
---

## Use Case

I want to share a link to highlight a detail in a specific region of an image to share a portion of a digitized manuscript text, allowing the user easy access to the rest of the manuscript.

Institutions might want to use this recipe to share portions of their object through social media, allowing a direct link to the viewer to improve the user's interaction with the digitized content. A scholar who finds a relevant passage in a manuscript might want to share the precise location with other colleagues, allowing them to check the original source.

## Implementation Notes

This request can be implemented in a standardized manner using the [IIIF Content State API](https://iiif.io/api/content-state), providing the data as values of the `iiif-content` query string parameter as explained in the [API section](https://iiif.io/api/content-state/1.0/#initialization-mechanisms-link).

We can use the [Web Annotation Data Model](https://www.w3.org/TR/annotation-model/) to encode the information necessary, as shown in ["A Region of a Canvas in a Manifest"](https://iiif.io/api/content-state/1.0/#51-a-region-of-a-canvas-in-a-manifest) section of the standard.

However, before passing the data as a query parameter, we must encode it as explained in the [Content State encoding guidelines](https://iiif.io/api/content-state/1.0/#6-content-state-encoding).

In this example, we want to highlight a portion of an image contained in a book. We will use the following manifest shown in the Simple Manifest Book recipe, which is available at the following link: [https://iiif.io/api/cookbook/recipe/0009-book-1/manifest.json](https://iiif.io/api/cookbook/recipe/0009-book-1/manifest.json)

We want to open the viewport to a specific Canvas region using a viewer available on the following page `https://example.org/viewer`.

First, we create an Annotation:

```json
{
"@context": "http://iiif.io/api/presentation/3/context.json",
"id": "https://example.org/import/1",
"type": "Annotation",
"motivation": ["contentState"],
"target": {
"id": "https://iiif.io/api/cookbook/recipe/0009-book-1/canvas/p2#xywh=1528,3024,344,408",
"type": "Canvas",
"partOf": [{
"id": "https://iiif.io/api/cookbook/recipe/0009-book-1/manifest.json",
"type": "Manifest"
}]
}
}
```

We can create an Annotation with `motivation` set to `contentState` and a target `type` set to Canvas. The `id` of the target will contain a fragment selector (`#xywh=1528,3024,344,408`) with the coordinates of the Canvas we want to share, while the `partOf` element has the `id` of the Manifest containing the Canvas.

We can now use one of the methods listed in the [examples of Content State encoding section](https://iiif.io/api/content-state/1.0/#63-examples-of-content-state-encoding) to generate a base64url string (**note: for brevity, we removed new line characters and white space before computing the base64url**).

We can pass the encoded value, using the `iiif-content` query parameter of the viewer landing page:
[https://example.org/viewer?iiif-content=JTdCJTIyJTQwY29udGV4dCUyMiUzQSUyMmh0dHAlM0ElMkYlMkZpaWlmLmlvJTJGYXBpJTJGcHJlc2VudGF0aW9uJTJGMyUyRmNvbnRleHQuanNvbiUyMiUyQyUyMmlkJTIyJTNBJTIyaHR0cHMlM0ElMkYlMkZleGFtcGxlLm9yZyUyRmltcG9ydCUyRjElMjIlMkMlMjJ0eXBlJTIyJTNBJTIyQW5ub3RhdGlvbiUyMiUyQyUyMm1vdGl2YXRpb24lMjIlM0ElNUIlMjJjb250ZW50U3RhdGUlMjIlNUQlMkMlMjJ0YXJnZXQlMjIlM0ElN0IlMjJpZCUyMiUzQSUyMmh0dHBzJTNBJTJGJTJGaWlpZi5pbyUyRmFwaSUyRmNvb2tib29rJTJGcmVjaXBlJTJGMDAwOS1ib29rLTElMkZjYW52YXMlMkZwMiUyM3h5d2glM0QxNTI4JTJDMzAyNCUyQzM0NCUyQzQwOCUyMiUyQyUyMnR5cGUlMjIlM0ElMjJDYW52YXMlMjIlMkMlMjJwYXJ0T2YlMjIlM0ElNUIlN0IlMjJpZCUyMiUzQSUyMmh0dHBzJTNBJTJGJTJGaWlpZi5pbyUyRmFwaSUyRmNvb2tib29rJTJGcmVjaXBlJTJGMDAwOS1ib29rLTElMkZtYW5pZmVzdC5qc29uJTIyJTJDJTIydHlwZSUyMiUzQSUyMk1hbmlmZXN0JTIyJTdEJTVEJTdEJTdE](https://example.org/)

We can also create an anchor tag with the link as the `href` attribute for use in a web page:

```html
<a href="https://example.org/viewer?iiif-content=JTdCJTIyJTQwY29udGV4dCUyMiUzQSUyMmh0dHAlM0ElMkYlMkZpaWlmLmlvJTJGYXBpJTJGcHJlc2VudGF0aW9uJTJGMyUyRmNvbnRleHQuanNvbiUyMiUyQyUyMmlkJTIyJTNBJTIyaHR0cHMlM0ElMkYlMkZleGFtcGxlLm9yZyUyRmltcG9ydCUyRjElMjIlMkMlMjJ0eXBlJTIyJTNBJTIyQW5ub3RhdGlvbiUyMiUyQyUyMm1vdGl2YXRpb24lMjIlM0ElNUIlMjJjb250ZW50U3RhdGUlMjIlNUQlMkMlMjJ0YXJnZXQlMjIlM0ElN0IlMjJpZCUyMiUzQSUyMmh0dHBzJTNBJTJGJTJGaWlpZi5pbyUyRmFwaSUyRmNvb2tib29rJTJGcmVjaXBlJTJGMDAwOS1ib29rLTElMkZjYW52YXMlMkZwMiUyM3h5d2glM0QxNTI4JTJDMzAyNCUyQzM0NCUyQzQwOCUyMiUyQyUyMnR5cGUlMjIlM0ElMjJDYW52YXMlMjIlMkMlMjJwYXJ0T2YlMjIlM0ElNUIlN0IlMjJpZCUyMiUzQSUyMmh0dHBzJTNBJTJGJTJGaWlpZi5pbyUyRmFwaSUyRmNvb2tib29rJTJGcmVjaXBlJTJGMDAwOS1ib29rLTElMkZtYW5pZmVzdC5qc29uJTIyJTJDJTIydHlwZSUyMiUzQSUyMk1hbmlmZXN0JTIyJTdEJTVEJTdEJTdE">Link for visualizing the region of a Canvas using a viewer.</a>
```

An alternative way of sharing a region of an image is to use the [Image API](https://iiif.io/api/image/3.0/#41-region). However, the context from which the region is extracted is not easily accessible. Instead, sharing a link to open the specific region with a viewer allows the users to explore another part of the image or related content and metadata in the Manifest.

## Restrictions

Note Content State does not define how the viewer should bring the regions of the Canvas to the attention of the user. It only mentions:

"This data structure can be used by clients to load the resource required, present a particular part of the resource to the user." https://iiif.io/api/content-state/1.0/#content-state

Viewers may set the viewport to the region or highlight the region with an annotation.

## Example

In this example we are aiming to highlight the bug that is on the second page of the [Book in recipe][0009]. The part of the image we are highlighting is as follows:

![Image of a bug](https://iiif.io/api/image/3.0/example/reference/59d09e6773341f28ea166e9f3c1e674f-gallica_ark_12148_bpt6k1526005v_f19/1528,3024,344,408/pct:50/0/default.jpg)

and this is located in the following region of the second image:

![Location of the region to be highlighted.](page.jpg)

{% include content-state-viewers.html iiif-content="annotation.json" viewers="" %}

{% include jsonviewer.html src="annotation.json" %}

## Related Recipes

* [Simplest Manifest - Image][0001] shows the basic structure of a IIIF Manifest using Presentation API 3.0.
* [A simple book][0009] shows the manifest structure.
* [Link for loading a manifest][0466] another example of Content State API.
* [Addressing a Spatial Region][0299] an example of sharing a region of a Canvas creating a new Manifest.

{% include acronyms.md %}
{% include links.md %}

Binary file added recipe/0485-contentstate-canvas-region/page.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading