changeset 1451:f0947c6190e6

IIIF Image API 2.0 support.
author robcast
date Thu, 12 Nov 2015 15:00:16 +0100
parents fa63f437d5c5
children 9429bb9c3a42
files common/src/main/java/digilib/conf/DigilibConfiguration.java common/src/main/java/digilib/conf/DigilibRequest.java servlet/src/main/java/digilib/servlet/ServletOps.java servlet3/src/main/java/digilib/servlet/Scaler.java
diffstat 4 files changed, 92 insertions(+), 32 deletions(-) [+]
line wrap: on
line diff
--- a/common/src/main/java/digilib/conf/DigilibConfiguration.java	Thu Nov 12 12:02:14 2015 +0100
+++ b/common/src/main/java/digilib/conf/DigilibConfiguration.java	Thu Nov 12 15:00:16 2015 +0100
@@ -57,7 +57,7 @@
 
     /** digilib version */
     public static String getClassVersion() {
-        return "2.3.5a";
+        return "2.3.6a";
     }
 
     /* non-static getVersion for Java inheritance */
@@ -94,6 +94,8 @@
         newParameter("default-errmsg-type", "image", null, 'f');
         // prefix for IIIF image API paths (used by DigilibRequest)
         newParameter("iiif-prefix", "IIIF", null, 'f');
+        // IIIF Image API version to support (mostly relevant for info.json)
+        newParameter("iiif-api-version", "2.0", null, 'f');        
         // character to use as slash-replacement in IIIF identifier part
         newParameter("iiif-slash-replacement", "!", null, 'f');        
     }
--- a/common/src/main/java/digilib/conf/DigilibRequest.java	Thu Nov 12 12:02:14 2015 +0100
+++ b/common/src/main/java/digilib/conf/DigilibRequest.java	Thu Nov 12 15:00:16 2015 +0100
@@ -278,11 +278,13 @@
      * 
      * path should be non-URL-decoded and have no leading slash.
      * 
+     * URI template:
+     * {scheme}://{server}{/prefix}/{identifier}/{region}/{size}/{rotation}/{quality}.{format}
+     * 
      * @param path
      *            String with IIIF Image API path.
      * 
-     * @see <a href="http://www-sul.stanford.edu/iiif/image-api/1.1/">IIIF Image
-     *      API</a>
+     * @see <a href="http://iiif.io/api/image/2.0/">IIIF Image API</a>
      */
     public boolean setWithIiifPath(String path) {
         if (path == null) {
@@ -315,7 +317,7 @@
             }
         }
         /*
-         * second parameter FN (encoded)
+         * second parameter identifier (encoded)
          */
         if (query.hasMoreTokens()) {
             token = getNextDecodedToken(query);
@@ -404,11 +406,16 @@
 
 	/**
 	 * Populate a request from IIIF image API parameters.
-	 * 
-	 * {scheme}://{server}{/prefix}/{identifier}/{region}/{size}/{rotation}/{quality}{.format}
+	 *
+	 * @see <a href="http://iiif.io/api/image/2.0/">IIIF Image API</a>
 	 * 
-	 * @see <a href="http://www-sul.stanford.edu/iiif/image-api/1.1/">IIIF Image
-	 *      API</a>
+	 * @param identifier
+	 * @param region
+	 * @param size
+	 * @param rotation
+	 * @param quality
+	 * @param format
+	 * @return
 	 */
 	public boolean setWithIiifParams(String identifier, String region, String size, 
 			String rotation, String quality, String format) {
@@ -449,7 +456,7 @@
                 options.setOption("info");
                 return true;
             } else if (region.equals("full")) {
-                // full region -- default
+                // full image -- default
             } else if (region.startsWith("pct:")) {
                 // pct:x,y,w,h -- region in % of original image
                 String[] parms = region.substring(4).split(",");
@@ -483,8 +490,8 @@
                 }
             }
         } else {
-            // region omitted -- assume info request
-            options.setOption("info");
+            // region omitted -- redirect to info request
+            options.setOption("redirect-info");
             return true;
         }
         
@@ -493,11 +500,16 @@
          */
         if (size != null) {
             if (size.equals("full")) {
-                // full -- size of original
+                /*
+                 * full -- size of original
+                 */
                 options.setOption("ascale");
                 setValue("scale", 1f);
+                
             } else if (size.startsWith("pct:")) {
-                // pct:n -- n% size of original
+                /*
+                 * pct:n -- n% size of original
+                 */
                 try {
                     float pct = Float.parseFloat(size.substring(4));
                     options.setOption("ascale");
@@ -507,17 +519,20 @@
                     logger.error(errorMessage+e);
                     return false;
                 }
+                
             } else {
-                // w,h -- pixel size
+                /*
+                 * w,h -- pixel size
+                 */
                 try {
                     String[] parms = size.split(",", 2);
                     if (parms[0].length() > 0) {
                         // width param
                         if (parms[0].startsWith("!")) {
-                            // width (in digilib-like bounding box)
+                            // !w,h width (in digilib-like bounding box)
                             setValueFromString("dw", parms[0].substring(1));
                         } else if (parms[1].length() == 0) {
-                            // width only
+                            // w, width only
                             setValueFromString("dw", parms[0]);
                         } else {
                             // w,h -- according to spec, we should distort the image to match ;-(
@@ -546,6 +561,11 @@
          * parameter rotation
          */
         if (rotation != null) {
+            if (rotation.startsWith("!")) {
+                // !n -- mirror and rotate
+                options.setOption("hmir");
+                rotation = rotation.substring(1);
+            }
             try {
                 float rot = Float.parseFloat(rotation);
                 setValue("rot", rot);
@@ -561,9 +581,9 @@
          */
         if (quality != null) {
             // quality param
-            if (quality.equals("native") || quality.equals("color")) {
-                // native is default anyway
-            } else if (quality.equals("grey")) {
+            if (quality.equals("default") || quality.equals("native") || quality.equals("color")) {
+                // color is default anyway
+            } else if (quality.equals("gray") || quality.equals("grey")) {
                 setValueFromString("colop", "grayscale");
             } else {
                 errorMessage = "Invalid quality parameter in IIIF path!";
--- a/servlet/src/main/java/digilib/servlet/ServletOps.java	Thu Nov 12 12:02:14 2015 +0100
+++ b/servlet/src/main/java/digilib/servlet/ServletOps.java	Thu Nov 12 15:00:16 2015 +0100
@@ -412,20 +412,53 @@
          * send response
          */
         response.setCharacterEncoding("UTF-8");
-        response.setContentType("application/json,application/ld+json");
-        PrintWriter writer;
         logger.debug("sending info.json");
         try {
-            writer = response.getWriter();
-            writer.println("{");
-            writer.println("\"@context\" : \"http://library.stanford.edu/iiif/image-api/1.1/context.json\",");
-            writer.println("\"@id\" : \"" + url + "\",");
-            writer.println("\"width\" : " + size.width + ",");
-            writer.println("\"height\" : " + size.height + ",");
-            writer.println("\"formats\" : [\"jpg\", \"png\"],");
-            writer.println("\"qualities\" : [\"native\", \"color\", \"grey\"],");
-            writer.println("\"profile\" : \"http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level2\"");
-            writer.println("}");
+            PrintWriter writer;
+            if (dlReq.getDigilibConfig().getAsString("iiif-api-version").startsWith("2.")) {
+                /*
+                 * IIIF Image API version 2 image information
+                 */
+                // use JSON-LD content type only when asked
+                String accept = dlReq.getServletRequest().getHeader("Accept");
+                if (accept != null && accept.contains("application/ld+json")) {
+                    response.setContentType("application/ld+json");
+                } else {
+                    response.setContentType("application/json");
+                    response.setHeader("Link", "<http://iiif.io/api/image/2/context.json>"
+                            +"; rel=\"http://www.w3.org/ns/json-ld#context\""
+                            +"; type=\"application/ld+json\"");
+                }
+                writer = response.getWriter();
+                writer.println("{");
+                writer.println("\"@context\" : \"http://iiif.io/api/image/2/context.json\",");
+                writer.println("\"@id\" : \"" + url + "\",");
+                writer.println("\"@protocol\" : \"http://iiif.io/api/image\",");
+                writer.println("\"width\" : " + size.width + ",");
+                writer.println("\"height\" : " + size.height + ",");
+                writer.println("\"profile\" : [");
+                writer.println("\"http://iiif.io/api/image/2/level2.json\",");
+                writer.println("{");
+                writer.println("\"formats\" : [\"jpg\", \"png\"],");
+                writer.println("\"qualities\" : [\"color\", \"grey\"],");
+                writer.println("\"supports\" : [\"mirroring\", \"rotationArbitrary\", \"sizeAboveFull\"],");
+                writer.println("}]");
+            } else {
+                /*
+                 * IIIF Image API version 1 image information
+                 */
+                response.setContentType("application/json,application/ld+json");
+                writer = response.getWriter();
+                writer.println("{");
+                writer.println("\"@context\" : \"http://library.stanford.edu/iiif/image-api/1.1/context.json\",");
+                writer.println("\"@id\" : \"" + url + "\",");
+                writer.println("\"width\" : " + size.width + ",");
+                writer.println("\"height\" : " + size.height + ",");
+                writer.println("\"formats\" : [\"jpg\", \"png\"],");
+                writer.println("\"qualities\" : [\"native\", \"color\", \"grey\"],");
+                writer.println("\"profile\" : \"http://library.stanford.edu/iiif/image-api/1.1/compliance.html#level2\"");
+                writer.println("}");
+            }
         } catch (IOException e) {
             throw new ServletException("Unable to write response!", e);
         }
--- a/servlet3/src/main/java/digilib/servlet/Scaler.java	Thu Nov 12 12:02:14 2015 +0100
+++ b/servlet3/src/main/java/digilib/servlet/Scaler.java	Thu Nov 12 15:00:16 2015 +0100
@@ -252,11 +252,16 @@
             // extract the job information
             final ImageJobDescription jobTicket = ImageJobDescription.getInstance(dlRequest, dlConfig);
 
-            // handle the info-request
+            // handle the IIIF info-request
             if (dlRequest.hasOption("info")) {
                 ServletOps.sendIiifInfo(dlRequest, response, logger);
                 return;
             }
+            if (dlRequest.hasOption("redirect-info")) {
+                // TODO: the redirect should have code 303
+                response.sendRedirect("info.json");
+                return;
+            }
 
             // error out if request was bad
             if (dlRequest.errorMessage != null) {