Giter Site home page Giter Site logo

iiif-apis's Introduction

iiif-apis

Image API 2.1.1 compliant Presentation API 2.1.1 compliant Authentication API 1.0 compliant Search API 1.0 compliant

Javadocs License GitHub release Maven Central

This module contains model classes for all currently available IIIF API entities, namely for the Presentation, Image, Content Search and Authentication APIs, as well as the additional services defined in the Service Annex. It also includes all the necessary components to parse and create valid JSON-LD representations of these entities, using Jackson.

The library contains a comprehensive test suite for all entities, based on all of the examples provided in the IIIF specifications. Therefore, it should be able to parse and create any IIIF documents that are compliant with the official specifications. If you find that you cannot parse a IIIF entity that you believe to be correct, please submit an issue including a link to the JSON-LD representation of the entity. Likewise, if you find that you cannot express a certain IIIF construct with the Java API, let us know.

It is intended to replace both iiif-presentation-api and iiif-image-api once it is stable enough, with the non-model parts of these libraries being moved into hymir.

Usage

To use the module, first add it to your project's Maven or Gradle configuration:

<dependency>
  <groupId>de.digitalcollections.iiif</groupId>
  <artifactId>iiif-apis</artifactId>
  <version>0.3.10</version>
</dependency>
dependencies {
    compile 'de.digitalcollections.iiif.iiif-apis:0.3.10'
}

For both reading and writing IIIF JSON-LD documents, it is neccessary to instantiate the Jackson object mapper:

import de.digitalcollections.iiif.model.jackson.IiifObjectMapper;

ObjectMapper iiifMapper = new IiifObjectMapper();

The mapper can then be used to read IIIF JSON-LD documents into their corresponding Java object:

import de.digitalcollections.iiif.model.sharedcanvas.Manifest;

// Reading a manifest
Manifest manifest = iiifMapper.readValue(
    "http://iiif.biblissima.fr/manifests/ark:/12148/btv1b8304502m/manifest.json",
    Manifest.class);

// Reading an annotation list
AnnotationList annoList = iiifMapper.readValue(
    "http://dams.llgc.org.uk/iiif/4342443/annotation/list/ART8.json",
    AnnotationList.class);

To create your own IIIF entities, just model them using the available classes and use the object mapper to obtain their JSON-LD representation:

import de.digitalcollections.iiif.model.sharedcanvas.Canvas;
import de.digitalcollections.iiif.model.ImageContent;
import de.digitalcollections.iiif.model.image.ImageApiProfile;
import de.digitalcollections.iiif.model.image.ImageService;
import de.digitalcollections.iiif.model.OtherContent;
import de.digitalcollections.iiif.model.search.ContentSearchService;
import de.digitalcollections.iiif.model.PropertyValue;

import java.util.Locale;


Canvas canvas = new Canvas("http://some.uri");
canvas.addLabel("A label");
canvas.addDescription("This is a slightly longer text about this canvas.");
canvas.setWidth(800);
canvas.setHeight(600);

// Image
canvas.addIIIFImage("http://some.uri/iiif/foo", ImageApiProfile.LEVEL_ONE);

// Thumbnail
ImageContent thumbnail = new ImageContent("http://some.uri/iiif/foo/full/250,/0/default.jpg");
thumbnail.addService(new ImageService("http://some.uri/iiif/foo", ImageApiProfile.LEVEL_ONE));
canvas.addThumbnail(thumbnail);

// Other Content
canvas.addSeeAlso(new OtherContent("http://some.uri/ocr/foo.hocr", "text/html"));

// Search Service
ContentSearchService searchService = new ContentSearchService("http://some.uri/search/foo");
searchService.addAutocompleteService("http://some.uri/autocomplete/foo");
canvas.addService(searchService);

// Metadata
canvas.addMetadata("Author", "Ignatius Jacques Reilly");
canvas.addMetadata("Location", "New Orleans");
PropertyValue key = new PropertyValue();
key.addValue(Locale.ENGLISH, "Key");
key.addValue(Locale.GERMAN, "Schlüssel");
key.addValue(Locale.CHINESE, "钥");
PropertyValue value = new PropertyValue();
value.addValue(Locale.ENGLISH, "A value", "Another value");
value.addValue(Locale.GERMAN, "Ein Wert", "Noch ein Wert");
value.addValue(Locale.CHINESE, "值", "另值");
canvas.addMetadata(new MetadataEntry(key, value));

// Other stuff
canvas.addViewingHint(ViewingHint.NON_PAGED);

// Licensing/Attribution
canvas.addLicense("http://rightsstatements.org/vocab/NoC-NC/1.0/");
canvas.addAttribution("Some fictional institution");
canvas.addLogo("http://some.uri/logo.jpg");
canvas.addLogo(new ImageContent(new ImageService(
    "http://some.uri/iiif/logo", ImageApiProfile.LEVEL_ONE)));

String json = iiifMapper.writerWithDefaultPrettyPrinter().writeValueAsString(canvas);

For more information on how to use the API, consult the API documentation and the comprehensive test suite. Since the large majority of the tests are based on the examples from the specifications, they should be very easy to follow along.

iiif-apis's People

Contributors

bitzl avatar datazuul avatar dependabot-preview[bot] avatar dependabot-support avatar dependabot[bot] avatar jbaiter avatar morpheus-87 avatar stefan-it avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

iiif-apis's Issues

Add support for IIIF Image and Presentation API version 3

Both IIIF Image and IIIF Presentation APIs have their BETA 3.0 versions published (currently November 2019) and the only thing holding them back from being officially released are open source implementations of each version as per their editorial standards. As version 3 opens up the ability to create manifests for audio and video we are eager to start implementing new manifests

https://iiif.io/api/image/3.0/
https://iiif.io/api/presentation/3.0/

Manifests created should pass the official IIIF v3.0 manifest validators:

https://iiif.io/api/image/validator/
https://iiif.io/api/presentation/validator/service/

Edited to add link to change logs

https://iiif.io/api/presentation/3.0/change-log/
https://iiif.io/api/image/3.0/change-log/

missing ability to add annotation as image in canvas

I'm trying to add a rotated image to a canvas in my manifests, using this example from the spec, so that in the end I get a canvas like

{
          "@id": "https://iiifpres-dev.bdrc.io/v:bdr:I4CZ75258/canvas/I4CZ752580003.jpg",
          "@type": "sc:Canvas",
          "label": "1a",
          "images": [
            {
              "@type": "oa:Annotation",
              "motivation": "sc:painting",
              "resource": {
                "@id": "https://iiif-dev.bdrc.io/bdr:I4CZ75258::I4CZ752580003.jpg/full/max/180/default.jpg",
                "@type": "oa:SpecificResource",
                "full": {
                  "@id": "https://iiif-dev.bdrc.io/bdr:I4CZ75258::I4CZ752580003.jpg/full/max/0/default.jpg",
                  "@type": "dctypes:Image",
                  "service": {
                    "@context": "http://iiif.io/api/image/2/context.json",
                    "@id": "https://iiif-dev.bdrc.io/bdr:I4CZ75258::I4CZ752580003.jpg",
                    "width": 2550,
                    "height": 879,
                    "profile": "http://iiif.io/api/image/2/level0.json",
                    "protocol": "http://iiif.io/api/image"
                  },
                  "format": "image/jpeg",
                  "width": 2550,
                  "height": 879
                },
                "selector": {
                  "@context": "http://iiif.io/api/annex/openannotation/context.json",
                  "@type": "iiif:ImageApiSelector",
                  "rotation": "180"
                }
             },
              "on": "https://iiifpres-dev.bdrc.io/v:bdr:I4CZ75258/canvas/I4CZ752580003.jpg"
            }
          ],
          "width": 2550,
          "height": 879
        }

(see this manifest). WIth the current API, I can build the whole annotation (using this example), but then I'm stuck as I can't add it in the canvas object, because my Annotation is not an ImageContent.

Is it possible to tweak things a bit in the object model so that the annotation can be added in the canvas?

related: ProjectMirador/mirador#2962

The mime.types file is a root-level resource and may cause unexpected behaviors in the class loader

Problem
The mime.types file is placed at the root level of the resources.
So, to load it we will use the class loader passing the file name (without any package) - as you can see here https://github.com/dbmdz/iif-apis/blob/main/src/main/java/de/digitalcollections/iif/model/MimeType.java#L45.
This means that, depending on the class loader implementation, if you have multiple jars containing the same mime.type file at the root level, you may load the wrong file from another library.

Resolution
A simple solution could be to move the mime.types to a specific package.
Then, to load the resource, we can specify the package (for example de/digitalcollections/iiif/utils/mime.types).

infinite loop in serialization

What I'm trying to do boils down to:

    public void testInfiniteLoop() throws JsonGenerationException, JsonMappingException, IOException {
        String uribase = "http://example.com/";
        final Canvas canvas = new Canvas(uribase+"-canvas");
        Annotation annotation = new Annotation(uribase+"-ann0", Motivation.PAINTING);
        annotation.setOn(canvas);
        AnnotationList all = new AnnotationList(uribase+"-anlist0");
        all.addResource(annotation);
        canvas.addOtherContent(all);
        new IiifObjectMapper().writerWithDefaultPrettyPrinter().writeValue(System.out, canvas);
    }

which creates an infinite look in the serialization, because the annotation refers to the canvas in the .setOn() and the canvas refers to the annotation in the .addOtherContent(). There are probably better ways to avoid that, but one easy way out of this kind of issue would be to add a .setOn() function that takes a String as an argument instead of a resource

Format and MimeType issue

Hi,
According to http://iiif.io/api/presentation/2.1/#image-resources, "format" for the image resource should be something like "image/jpeg", however, it is currently printing out MimeType in its entirety:

"format": {"primaryType": "image","subType": "jpeg","extensions": ["jpg","jpeg","jpe"],"typeName": "image/jpeg"}

Would it still be compliant if it prints more than just the value of "typeName"?

Add API to validate image requests

A common issue are requests that either request a generally invalid image region (e.g. height or width of 0) or would result in a in a invalid image region after scaling. This could be checked within the ImageApiSelector to handle most of the cases at a central place.

Bug in method `getCompleteness` of `ModelUtilities`

Method addCanvas of class Range fails with message:

Exception in thread "main" java.lang.IllegalArgumentException: Member resource must only have an identifier and no other field. Use add<Resource>(URI first, URI... rest) for convenience.
	at de.digitalcollections.iiif.model.sharedcanvas.Range.checkIdOnly(Range.java:98)
	at de.digitalcollections.iiif.model.sharedcanvas.Range.addCanvas(Range.java:113)

It can be reproduced with:

import de.digitalcollections.iiif.model.sharedcanvas.Range;
class Test {
  public static void main(String[] args) {
    Range range = new Range("http://test/foo");
    range.addCanvas("http://test/baz");
  }
}

The cause is in method getCompleteness of ModelUtilities: the method getClass of Object is not filtered.
It could be replaced by:

  public static Completeness getCompleteness(Object res, Class<?> type) {
    Set<Method> getters =
        ReflectionUtils.getAllMethods(
            type, ReflectionUtils.withModifier(Modifier.PUBLIC), ReflectionUtils.withPrefix("get"));
    Set<String> gettersWithValues =
        getters.stream()
            .filter(g -> !g.getName().equals("getClass"))
            .filter(g -> g.getAnnotation(JsonIgnore.class) == null) // Only JSON-serializable fields
            .filter(g -> returnsValue(g, res))
            .map(Method::getName)
            .collect(Collectors.toSet());

    if (gettersWithValues.isEmpty()) {
      return Completeness.EMPTY;
    } else if (containsOnly(gettersWithValues, "getType", "getIdentifier")) {
      return Completeness.ID_AND_TYPE;
    } else if (containsOnly(gettersWithValues, "getType", "getIdentifier", "getLabels")) {
      return Completeness.ID_AND_TYPE_AND_LABEL;
    } else if (containsOnly(gettersWithValues, "getIdentifier")) {
      return Completeness.ID_ONLY;
    } else {
      return Completeness.COMPLEX;
    }
  }

"on" property incorrectly defined as a resource

In the Annotation.java class the "on" variable is defined as a Resource. This renders an invalid presentation manifest. This is a correct manifest:
"on": "https://some.url/iiif/dcterms/672/canvas/c0"
whereas this code deserializes to
"on": { "@id": "https://some.url/iiif/vads-demo2/2/canvas/c0", "@type": "sc:Canvas" }
If you view the IIIF presentation specs, all the examples use the first example.

Deserialisation doesn't work with translated `attribution`

See this manifest:

"attribution" : {
        "de" : [
            "Georg-August Universität Göttingen"
        ],
        "en" : [
            "Goobi viewer"
        ]
    }

The IiifObjectMapper fails with:

com.fasterxml.jackson.databind.JsonMappingException: (was java.lang.NullPointerException) (through reference chain: de.digitalcollections.iiif.model.sharedcanvas.Manifest["attribution"])

This certainly related to different minor versions of the IIIF Presentation API 2.x.

Performance hog class ResourceSerializer needs refactoring

When producing moderately small IIIF manfests (monograph with about 35 pages/images) using REST controller in Spring, added latency about 15ms can be noticed in process of serializing using Jackson. At first I thought that this was Jackson being slow... but slowdown can be traced down to custom serializer ResourceSerializer namely line 110 where replacing gen.writeObject with gen.writeString fixes most of the latency. This can be blatantly seen in Chrome response view as blue tail of time to download content.


Rest of processing in this class namely ModelUtilities.getCompleteness and following decoding/if statements also should be rethinked. Because you are calling this code (reflection!) on every processed element in JSON serialization again and again - it is not cached anywhere. What is the purpose of this code? I reckon that you try to determine if elements should be unwrapped to list or not, but for example "on" #25 , do you ever want it written out in exploded form? Does it have to be defined as (anonymous?) resource in contrast to context represented as simple string (no resource) #36 ? So the whole model approach should be reanalyzed and these flags to unwrap element or not - set it in form or some static flags in Resource instance itself, do not reverse engineer it at runtime!
Perhaps even authors of Jackson can look into/share some opinion on this: @cowtowncoder

Build issues on openjdk11

The repository is currently not ready for compilation with openjdk11:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-javadoc-plugin:3.0.1:jar (attach-javadocs) on project iiif-apis: MavenReportException: Error while generating Javadoc: 
[ERROR] Exit code: 1 - javadoc: warning - The old Doclet and Taglet APIs in the packages
[ERROR] com.sun.javadoc, com.sun.tools.doclets and their implementations
[ERROR] are planned to be removed in a future JDK release. These
[ERROR] components have been superseded by the new APIs in jdk.javadoc.doclet.
[ERROR] Users are strongly recommended to migrate to the new APIs.
[ERROR] javadoc: error - invalid flag: -author

The ch.raffael.mddoclet.MarkdownDoclet needs a fix, see also this issue.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.