Skip to content

Instantly share code, notes, and snippets.

@terrywbrady
Last active December 13, 2023 09:46
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save terrywbrady/29006fadfd94fb0e47ba29b9d29cd738 to your computer and use it in GitHub Desktop.
Save terrywbrady/29006fadfd94fb0e47ba29b9d29cd738 to your computer and use it in GitHub Desktop.
DSpace / IIIF Integration for DigitalGeorgetown

DSpace/IIIF Example URL

https://repository.library.georgetown.edu/handle/10822/1044538#?m=7

This image gallery makes use of the IIIF (Internation Image Interoperability Framework) API's

Viewer Software

The UniversalViewer 2.0.2 is hosted within the same web server as our DSpace Instance

IIIF Image Server

Loris is used as the IIIF image server

Digital Assets

The source images used by the image server differ from the item bitstreams that we have historically provided in DSpace. They are a higher-resolution copy.

Currently, neither these image files nor the manifest files are stored within DSpace.

The metadata withing the manifest file is derived from DSpace metadata. Each object in the IIIF manifest links to the full descriptive metadata stored within DSpace.

Manifest Generation

The tool used to generate IIIF Manifest Files from DSpace metadata is described here: https://github.com/Georgetown-University-Libraries/File-Analyzer-Test-Data/blob/master/iiif/README.md

<!-- Generate the info about the collection from the metadata section -->
<xsl:template match="dim:dim" mode="collectionDetailView-DIM">
<!-- GUCODE[[twb27: SD-817, show short description since it appears in editor]] -->
<xsl:if test="string-length(dim:field[@element='description'][@qualifier='abstract'])&gt;0">
<p class="intro-text">
<xsl:copy-of select="dim:field[@element='description'][@qualifier='abstract']/node()"/>
</p>
</xsl:if>
<xsl:if test="string-length(dim:field[@element='description'][not(@qualifier)])&gt;0">
<p class="intro-text">
<xsl:copy-of select="dim:field[@element='description'][not(@qualifier)]/node()"/>
</p>
</xsl:if>
<xsl:variable name="toc" select="dim:field[@element='description'][@qualifier='tableofcontents']"/>
<xsl:if test="string-length($toc)&gt;0">
<xsl:choose>
<xsl:when test="starts-with($toc,'IIIF:')">
<xsl:call-template name="createIIIFManifest">
<xsl:with-param name="manifest" select="$toc"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="starts-with($toc,'IIIF-ND:')">
<xsl:call-template name="createIIIFManifest">
<xsl:with-param name="manifest" select="$toc"/>
<xsl:with-param name="config">config.no-download.json</xsl:with-param>
</xsl:call-template>
</xsl:when>
<xsl:otherwise>
<div class="detail-view-news">
<h3><i18n:text>xmlui.dri2xhtml.METS-1.0.news</i18n:text></h3>
<p class="news-text">
<xsl:copy-of select="$toc"/>
</p>
</div>
</xsl:otherwise>
</xsl:choose>
</xsl:if>
<xsl:if test="string-length(dim:field[@element='rights'][not(@qualifier)])&gt;0">
<div class="detail-view-rights-and-license">
<xsl:if test="string-length(dim:field[@element='rights'][not(@qualifier)])&gt;0">
<p class="copyright-text">
<xsl:copy-of select="dim:field[@element='rights'][not(@qualifier)]/node()"/>
</p>
</xsl:if>
</div>
</xsl:if>
</xsl:template>
<xsl:template match="dim:dim" mode="itemSummaryView-DIM">
<div class="item-summary-view-metadata">
<xsl:call-template name="itemSummaryView-DIM-title"/>
<xsl:call-template name="microtag-special-summary"/>
<!--GUCODE[[twb27:Show Sharestream Player, Finding Aid Image, Markdown]]-->
<!--GUCODE[[twb27:Show Bitstreams at the Top, Suppress if needed]]-->
<xsl:call-template name="summaryHeader"/>
<xsl:choose>
<xsl:when test="//mets:fileSec/mets:fileGrp[@USE='METADATA']/mets:file/mets:FLocat[@xlink:label='IIIF Manifest']"/>
<xsl:when test="//mets:fileSec/mets:fileGrp[mets:file[mets:FLocat[@LOCTYPE='URL'][@xlink:label='HTML Finding Aid']]]"/>
<xsl:when test="dim:field[@element='relation' and @qualifier='uri'][starts-with(.,'IIIF:')]"/>
<xsl:when test="dim:field[@element='relation' and @qualifier='uri'][starts-with(.,'IIIF-ND:')]"/>
<xsl:otherwise>
<xsl:call-template name="itemSummaryView-DIM-Files"/>
</xsl:otherwise>
</xsl:choose>
...
</div>
</xsl:template>
<!--
The following XSL lives in a top-level theme xsl file.
This block of code controls all of loose integrations that we have embedded in our custom themes.
Since our work with IIIF is still evolving, we offer a number of mechanisms for linking a IIIF manifest into DSpace
- Add the manifest file as a specially named item bitstream ("IIIF Manifest")
- Link a manifest to an item in dc.relation.uri
- Link a manifest file to a collection page with special markup in dc.description.tableofcontents
We expect to eventually standardize the integration on a smaller set of options.
-->
<xsl:template name="summaryHeaderDetail">
<xsl:choose>
<xsl:when test="dim:field[@element='relation' and @qualifier='uri'][contains(.,'findingaids.library.georgetown.edu')]">
<xsl:call-template name="summaryHeaderFindingAid"/>
</xsl:when>
<xsl:when test="dim:field[@element='relation' and @qualifier='uri'][contains(.,'//archive.org/')]">
<xsl:call-template name="summaryHeaderInternetArchive"/>
</xsl:when>
<xsl:when test="dim:field[@element='relation' and @qualifier='uri'] and dim:field[@element='type'][contains(.,'external resource')]">
<xsl:call-template name="summaryExternalFindingAid"/>
</xsl:when>
<xsl:when test="dim:field[@element='relation' and @qualifier='uri'][contains(.,'mediapilot')]">
<xsl:call-template name="summaryHeaderSharestream"/>
</xsl:when>
<xsl:when test="dim:field[@element='relation' and @qualifier='uri'][starts-with(.,'IIIF:')]">
<xsl:call-template name="createIIIFManifest">
<xsl:with-param name="manifest" select="dim:field[@element='relation' and @qualifier='uri']"/>
</xsl:call-template>
</xsl:when>
<xsl:when test="dim:field[@element='relation' and @qualifier='uri'][starts-with(.,'IIIF-ND:')]">
<xsl:call-template name="createIIIFManifest">
<xsl:with-param name="manifest" select="dim:field[@element='relation' and @qualifier='uri']"/>
<xsl:with-param name="config">config.no-download.json</xsl:with-param>
</xsl:call-template>
</xsl:when>
<xsl:when test="//mets:fileSec/mets:fileGrp[@USE='METADATA']/mets:file/mets:FLocat[@xlink:label='IIIF Manifest']">
<xsl:call-template name="createIIIFManifest">
<xsl:with-param name="manifest" select="$EXTMETS//mets:fileSec/mets:fileGrp[@USE='METADATA']/mets:file/mets:FLocat[@xlink:label='IIIF Manifest']/@xlink:href"/>
</xsl:call-template>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template name="createIIIFManifest">
<xsl:param name="manifest"/>
<xsl:param name="config">config.json</xsl:param>
<xsl:variable name="manifesturl">
<xsl:choose>
<xsl:when test="starts-with($manifest,'IIIF:http')">
<xsl:value-of select="substring($manifest, 6, string-length($manifest) - 5)"/>
</xsl:when>
<xsl:when test="starts-with($manifest,'IIIF-ND:http')">
<xsl:value-of select="substring($manifest, 9, string-length($manifest) - 8)"/>
</xsl:when>
<xsl:otherwise>
<xsl:value-of select="$manifest"/>
</xsl:otherwise>
</xsl:choose>
</xsl:variable>
<xsl:if test="$manifesturl!=''">
<div class="row">
<div class="col-sm-12">
<div class="uvgu">
<div
class="uv"
data-locale="en-GB:English (GB),cy-GB:Cymraeg"
data-collectionindex="0"
data-manifestindex="0"
data-sequenceindex="0"
data-canvasindex="0"
data-rotation="0"
style="height:520px;background-color: #000">
<xsl:attribute name="data-uri">
<xsl:value-of select="$manifesturl"/>
</xsl:attribute>
<xsl:attribute name="data-config">
<xsl:value-of select="concat('/uv/config/',$config)"/>
</xsl:attribute>
</div>
<script type="text/javascript" id="embedUV" src="/uv/lib/embed.js">
</script>
<script type="text/javascript">/* wordpress fix */</script>
</div>
<div class="iiiflogo">
<xsl:variable name="manifestfile" select="substring-after($manifesturl,'/manifests/')"/>
<a title="You may drag this icon into any IIIF compliant viewer">
<xsl:attribute name="href">
<xsl:value-of select="concat('?manifest=', $manifesturl)"/>
</xsl:attribute>
<img class="iiiflogo" src="/static/images/iiif.png" alt="IIIF Drag-n-drop"/>
</a>
</div>
</div>
</div>
</xsl:if>
</xsl:template>
{
options: {
pagingEnabled: false
},
modules: {
contentLeftPanel: {
options: {
defaultToTreeEnabled: true
}
}
}
}
{
options: {
pagingEnabled: false
},
modules: {
footerPanel: {
options: {
downloadEnabled: false
}
},
contentLeftPanel: {
options: {
defaultToTreeEnabled: true
}
}
}
}
@alawvt
Copy link

alawvt commented Mar 8, 2018

Thanks for sharing this. The link in, "This image gallery makes use of the IIIF (Internation Image Interoperability Framework) API's" doesn't work.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment