Skip to content

dbmdz/iiif-server-hymir

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Hymir IIIF Server

Javadocs License GitHub release Maven Central

Hymir is a Java based IIIF Server. It is based on our IIIF API Java Libraries (Java implementations of the IIIF specifications). It can be used to serve images, presentation manifests, presentation collections and presentation annotation lists.

Features

  • IIIF Image API 2.1 compliant (see http://iiif.io/api/image/2.1/).
  • IIIF Presentation API 2.1 compliant (see http://iiif.io/api/presentation/2.1/).
  • On the fly image processing. No additional pregenerated (pyramid zoom) images are needed. No additional storage consumption.
  • Can simply be run as a standalone IIIF server from the JAR, no application server necessary
  • Spring based modular, extendable, easy to maintain enterprise architecture.
  • Highly customizable image storage and identifier resolving: Access to images over project specific Resolver-plugin mechanism.
  • Support for Filesystem- and HTTP-Image-Repositories (own protocols can be added by providing specific resolver)
  • Pluggable Manifest generation: implement your own mapping from project specific structure metadata to a standard Manifest object.
  • Embedded IIIF Image Viewer (for out of the box viewing of served images): OpenSeadragon 2.4.0 (see "Usage" below)
  • Embedded IIIF Presentation Viewer: Mirador 2.7.0 (see "Usage" below)
  • Direct Manifest access (see "Usage" below)

Supported image formats

Format Reading Writing Dependencies Comment
JPEG [x] [x] libturbojpeg (optional, but recommended)
JPEG2000 [x] [ ] libopenjp2 (>= 2.3 recommended)
TIFF [x] [x]
PNG [x] [x] Due to possible transparency (alpha channel) in PNG it is not possible to use a PNG source file and deliver it as JPG. PNG delivered as PNG is possible.
GIF [x] [x]

Prerequisites

  • Server with minimum 4GB RAM.
  • Java 11

Installation

Download hymir-<version>-exec.jar from the GitHub releases page.

Using the TurboJPEG backend for JPEG files

By default, a Java-based image processing backend is used. If you want better performance, it is recommended to use the native image processing backend that is based on TurboJPEG. For this, you will have to install the TurboJPEG native library, on Ubuntu libturbojpeg.

Debian:

$ sudo apt-get install libturbojpeg

Adding JPEG2000 support

By default, a Java-based image processing backend is used which has no support for JPEG2000. For adding JPEG2000 support, you will have to install the libopenjp2 native library.

Debian:

$ sudo apt-cache search libopenjp2
libopenjp2-7 - Kompressions-/Dekompressions-Bibliothek fĂĽr das Bildformat JPEG 2000
libopenjp2-tools - Kommandozeilenwerkzeuge zur Verwendung der JPEG 2000-Bibliothek
libopenjp2-7-dev - development files for OpenJPEG, a JPEG 2000 image library
$ sudo apt-get install libopenjp2-7

Creating logging directories

Create directories for

  • hymir application logging (configured in logback-spring.xml), e.g. /var/log/hymir
  • hymir access logs (default: /var/log/digitalcollections)

Example (use more restricted access rights than in this example):

$ sudo mkdir /var/log/hymir
$ sudo chmod 777 /var/log/hymir
$ sudo mkdir /var/log/digitalcollections
$ sudo chmod 777 /var/log/digitalcollections

Usage

Run the downloaded application:

  • locally for testing (default active configuration profile is "local"):
$ java -jar hymir-<version>-exec.jar

Logging: to console

Image, manifest, collection and annotation list file resolving: see here (using directories under /var/local/iiif)

Application configuration: see here (local profile section at beginning of file)

  • in production
$ java -jar hymir-<version>-exec.jar --spring.profiles.active=PROD

Logging: to file ./hymir.log in Logstash-JSON format

Image, manifest, collection and annotation list file resolving: see here (using directories under /var/local/iiif)

Application configuration: see here (PROD profile section overriding some values at bottom of file)

  • in production with custom logging configuration file:
$ java -jar hymir-<version>-exec.jar --logging.config=file:/etc/hymir/logback-spring.xml  --spring.profiles.active=PROD

Read https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-logging.html and https://logback.qos.ch/manual/configuration.html.

  • in production with custom configuration file application.yml:

(Custom application.yml placed beside jar-file. No explicit command line option needed.)

$ java -jar hymir-<version>-exec.jar --spring.profiles.active=PROD
  • in production with a custom server port (e.g. port 8080):
$ java -jar hymir-<version>-exec.jar --server.port=8080 --spring.profiles.active=PROD

Complete parametrized example:

$ java -jar hymir-<version>-exec.jar --logging.config=file:/etc/hymir/logback-spring.xml --server.port=8080 --spring.profiles.active=PROD

(and application.yml beside jar file).

Access Hymir GUI (e.g. http://localhost:9000/).

Configuration

Running Hymir behind a proxy server

If you are running Hymir behind a proxy server, it is important to configure the proxy server to set the X-Forwarded-For and X-Forwarded-Proto headers, because they are used e.g. in rendering absolute URLs in info.json response content.

For NGinx this can be configured like this:

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;

Image and presentation manifest resolving

Based on unique resource identifiers the server tries to resolve identifiers to a file: or http: path. The resolving rules (one rule per line) are configurable with regular expressions in YML-files.

You can pass the path to your custom resolving rules with the --spring.config.additional-location=/path/to/rules.yml option.

Example:

$ java -jar hymir-<version>-exec.jar --spring.config.additional-location=file:/etc/hymir/rules.yml

Example file /etc/hymir/rules.yml:

resourceRepository:
  resolved:
    patterns:
      # This configuration file defines a list of patterns with one ore more substitutions.
      # These are used for resolving IDs to a concrete URI, e.g. on the file system, the
      # classpath or even a remote HTTP endpoint.
      # You can specify multiple substitutions, the resolver will try to match them against
      # the desired MIME type and return all that matches
      # The repository will then verify which of these URIs are actually readable and return
      # the first matching substitution.
      # In the example below, we have two MIME types (tiff/jpeg) and for JPEG two resolutions
      # in decreasing order of quality, so that the higher-resolution image will be chosen
      # if it is available.
      # An image pattern resolving example:
      - pattern: ^(\d{8})_(\d{5})$
        substitutions:
          - 'file:/var/local/iiif/images/$1/original/image_$1_$2.tif'
          - 'file:/var/local/iiif/images/$1/300/image_$1_$2.jpg'
          - 'file:/var/local/iiif/images/$1/150/image_$1_$2.jpg'

      # An manifest pattern resolving example:
      - pattern: ^(\d{8})$
        substitutions:
          - 'file:/var/local/iiif/presentation/manifests/manifest_$1.json'

      # For the official IIIF Image API Validator
      - pattern: 67352ccc-d1b0-11e1-89ae-279075081939
        substitutions:
          - 'classpath:validation.jp2'
          - 'classpath:validation.png'

      # Collection manifests ('collection-' pattern-prefix is statically added to requested collection name to disambigued from other patterns)
      - pattern: ^collection-(.*)$
        substitutions:
          - 'file:/var/local/iiif/presentation/collections/$1.json'

Serve images

See https://iiif.io/api/image/2.1/

In the simplest case you just want to serve images of a directory.

Example:

Let's assume you have a bunch of jpg-files residing in the directory "/var/local/iiif/images" for objects with identifiers 00000001, 00000002 and so on. The images-directory contains a directory for each object in which in turn all images of an object reside.

The files are named "image_00000001_00001.jpg", "image_00000001_00002.jpg", ... thus containing the object id and the image number in the filename.

An example for an entry in the rules.yml (including matching just for identifiers and numbered images with digits) then just could look like this:

- pattern: ^(\d{8})_(\d{5})$
  substitutions:
    - 'file:/var/local/iiif/images/$1/image_$1_$2.jpg'

An IIIF Image API url example for this pattern: http://localhost:9000/image/v2/00000005_00012/full/full/0/default.jpg

Change Image API URL prefix

By default the url prefix of the IIIF Image API endpoint is /image/v2/.

You can configure another url prefix on server startup using system property custom.iiif.image.urlPrefix.

Example:

$ java -jar target/hymir-<version>-exec.jar --custom.iiif.image.urlPrefix='/iiifImage/' --spring.config.additional-location=file:/etc/hymir/rules.yml --spring.profiles.active=local

Resulting URL: http://localhost:9000/iiifImage/00113391_00001/full/300,/0/default.jpg

Serve IIIF Presentation manifests

See https://iiif.io/api/presentation/2.1/#manifest

In the simplest case you just want to serve static (pregenerated) IIIF Presentation manifest json-files of a directory.

Example:

Let's assume you have a bunch of json-files residing in the directory "/var/local/iiif/presentation/manifests" for the objects with identifiers 00000001, 00000002 and so on.

The files are named "manifest_00000001.json", "manifest_00000002.json", ... containing the object id in the filename.

An example for an entry in the rules.yml (including matching just for identifiers with digits) then could look like this:

- pattern: ^(\d{8})$
  substitutions:
    - 'file:/var/local/iiif/presentation/manifests/manifest_$1.json'

An IIIF Presentation API url for a manifest example: http://localhost:9000/presentation/v2/00000002/manifest

Change Presentation API URL prefix

By default the url prefix of the IIIF Presentation API endpoint is /presentation/v2/.

You can configure another url prefix on server startup using system property custom.iiif.presentation.urlPrefix.

Example:

$ java -jar hymir-<version>-exec.jar --custom.iiif.presentation.urlPrefix='/iiifPresentation/' --spring.config.additional-location=file:/etc/hymir/rules.yml --spring.profiles.active=local

Resulting URL: http://localhost:9000/iiifPresentation/00113391/manifest

Serve IIIF Presentation collections

See https://iiif.io/api/presentation/2.1/#collection

In the simplest case you just want to serve static (pregenerated) IIIF Presentation collection json-files of a directory.

Example:

Let's assume you have a bunch of json-files residing in the directory "/var/local/iiif/presentation/collections" for collections with a specific name, e.g. newspapers.

The files are named e.g. newspapers.json, medieval_manuscripts.json, ... containing the collection name in the filename.

An example for an entry in the rules.yml then just could look like this:

- pattern: ^collection-(.*)$
  substitutions:
    - 'file:/var/local/iiif/presentation/collections/$1.json'

An IIIF Presentation API url for a collection example: http://localhost:9000/presentation/v2/collection/newspapers

Implementation background: To get a regex resolvable pattern that can be differentiated from patterns for manifest json-files (same mimetype), Hymir adds the static prefix collection- to the given identifier for collections. (This does not appear in the identifier in the url, just in the rules.yml regex)

Logging

Default logging configuration is specified in the file logback-spring.xml packaged in the exectable Hymir JAR-file. The default logging file is configured as ./hymir.log in Logstash-JSON-format.

If you want human readable logging to console use --spring.profiles.active=local on start command line or define a custom logback-spring.xml config location (see "Usage" section above).

Example: Custom config file with human readable logging

$ java -jar hymir-<version>-exec.jar --logging.config=file:/etc/hymir/logback-spring.xml

Example file /etc/hymir/logback-spring.xml:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
  <!-- see https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-logging.html#_profile_specific_configuration -->
  <springProfile name="PROD">
    <appender name="default" class="ch.qos.logback.core.rolling.RollingFileAppender">
      <file>/var/log/hymir/hymir.log</file>
      <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
        <fileNamePattern>/var/log/hymir/hymir.%d{yyyy-MM-dd}.log</fileNamePattern>
      </rollingPolicy>
      <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
        <fileNamePattern>/var/log/hymir/hymir.%d{yyyy-MM}.%i.log.gz</fileNamePattern>
        <maxFileSize>100MB</maxFileSize>
        <maxHistory>90</maxHistory>
        <totalSizeCap>5GB</totalSizeCap>
      </rollingPolicy>
      <encoder>
        <pattern>[%d{ISO8601} %5p] %40.40c:%4L [%-8t] - %m%n</pattern>
      </encoder>
      <!--
      <encoder class="net.logstash.logback.encoder.LogstashEncoder">
        <customFields>{"service":"hymir-server", "group":"rest", "instance":"${instance.name:-default}"}</customFields>
      </encoder>
      -->
    </appender>
  </springProfile>

  <springProfile name="local">
    <appender name="default" class="ch.qos.logback.core.ConsoleAppender">
      <encoder>
        <pattern>[%d{ISO8601} %5p] %40.40c:%4L [%-8t] - %m%n</pattern>
      </encoder>
    </appender>
  </springProfile>

  <logger name="de.digitalcollections.iiif.hymir.presentation.backend" level="error" />
  <logger name="de.digitalcollections.iiif.hymir.presentation.business" level="error" />
  <logger name="de.digitalcollections.commons" level="error" />

  <root level="info">
    <appender-ref ref="default" />
  </root>

</configuration>

Custom configuration file application.yml

The default configuration of the server comes packaged in the executable JAR-file of Hymir. To customize (override) the default configuration parameters, simply put your custom application.yml file beside (in the same directory of) the Hymir JAR-file.

Your custom application.yml does not have to replace all default properties. It can contain only the properties you want to change.

To get the default configuration file, you should download the hymir-<release-version>.jar file (NOT containing -exec in filename) from https://github.com/dbmdz/iiif-server-hymir/releases and unpack the contained application.yml with:

$ jar xfv hymir-<version>.jar application.yml

Now put the file beside the executable Hymir jar and edit it according to your requirements.

Configure custom HTTP-Response-Header

If you already put your custom application.yml file in place (see above), it is possible to set custom HTTP response headers in responses for

  • all requests to Image and Presentation API urls
  • Image API: image requests
  • Image API: info.json requests
  • Presentation API: manifest requests (includes canvas and range requests)
  • Presentation API: collection requests
  • Presentation API: Annotation list requests

Customized response headers are placed in the custom.iiif.headers-section of your application.yml configuration file, e.g.:

custom:
  iiif:
    headers:
      all:
        - name: 'served by'
          value: 'hymir'
      image:
        image:
          - name: 'cache-control'
            value: 'max-age=86400'
        info:
          - name: 'header1'
            value: 'value1'
      presentation:
        manifest:
          - name: 'mani1'
            value: 'mani-value1'
          - name: 'mani2'
            value: 'mani-value2'
        collection: null
        annotationList: null

If you want to override a header that is set by default (e.g. Access-Control-Allow-Origin=*), you just have to configure it with another value, e.g.:

custom:
  iiif:
    headers:
      image:
        info:
          - name: 'Access-Control-Allow-Origin'
            value: 'https://yourdomain.org'

(Given example is a bad practice in the IIIF context, as it contradicts the "interoperability" idea of IIIF...)

Administration

Monitoring

Monitoring endpoints under http://localhost:9001/monitoring, authentication by default: admin/secret (configurable in application.yml)

To change monitoring port, e.g. to 8081 use management.server.port option:

$ java -jar hymir-<version>-exec.jar --management.server.port=8081

Out Of Memory handling

In case the IIIF server runs out of memory it should quit - use java options for this. (To be restarted automatically install it as systemd service, see below.)

$ java -jar hymir-<version>-exec.jar -XX:+ExitOnOutOfMemoryError -XX:+CrashOnOutOfMemoryError

Configure IIIF service as systemd service

In Linux production environments it is a best practice to install the IIIF server as a systemd service / daemon.

Therefore create a user iiif, a service file, add it as service and enable it:

$ sudo nano /etc/systemd/system/iiif-hymir.service
[Unit]
Description=IIIF Hymir Server
After=syslog.target

[Service]
User=iiif
ExecStart=/usr/bin/java -jar /opt/hymir-<version>-exec.jar \
    -XX:+ExitOnOutOfMemoryError -XX:+CrashOnOutOfMemoryError \
    --spring.config.additional-location=file:/etc/hymir/rules.yml \
    --spring.profiles.active=PROD \
    --logging.config=file:/etc/hymir/logback-spring.xml \
    --server.port=8080 \
    --management.server.port=8081
SuccessExitStatus=143

[Install]
WantedBy=multi-user.target

$ sudo systemctl daemon-reload
$ sudo systemctl enable iiif-hymir.service
$ sudo systemctl start iiif-hymir.service

Users

Development

  • Install git client
  • Install Java JDK 11 or above
  • Install Apache Maven buildttool
$ cd ~/development
$ git clone git@github.com:dbmdz/iiif-server-hymir.git
$ cd iiif-server-hymir
$ mvn clean install

Executable JAR-file is in target directory.

On systems without installed libturbojpeg test fail. To build without tests, execute:

$ mvn clean install -DskipTests=true

To install libturbojpeg on Debian based systems:

$ sudo apt install libturbojpeg