changeset 1444:02df383e0a85 new_scaling

reshuffled ImageJobDescription again. all case-dependent logic is now in prepareScaleParams which gets called automatically by getInstance.
author robcast
date Tue, 10 Nov 2015 18:36:46 +0100
parents e321607eb36e
children 49ba776b9004
files common/src/main/java/digilib/conf/DigilibConfiguration.java common/src/main/java/digilib/image/ImageJobDescription.java common/src/main/java/digilib/image/ImageWorker.java servlet/src/main/java/digilib/servlet/ServletOps.java servlet2/src/main/java/digilib/servlet/Scaler.java servlet2/src/main/java/digilib/servlet/ScalerNoThread.java servlet3/src/main/java/digilib/servlet/Scaler.java
diffstat 7 files changed, 297 insertions(+), 179 deletions(-) [+]
line wrap: on
line diff
--- a/common/src/main/java/digilib/conf/DigilibConfiguration.java	Tue Nov 10 16:15:52 2015 +0100
+++ b/common/src/main/java/digilib/conf/DigilibConfiguration.java	Tue Nov 10 18:36:46 2015 +0100
@@ -57,7 +57,7 @@
 
     /** digilib version */
     public static String getClassVersion() {
-        return "2.3.4a";
+        return "2.3.4b";
     }
 
     /* non-static getVersion for Java inheritance */
--- a/common/src/main/java/digilib/image/ImageJobDescription.java	Tue Nov 10 16:15:52 2015 +0100
+++ b/common/src/main/java/digilib/image/ImageJobDescription.java	Tue Nov 10 18:36:46 2015 +0100
@@ -23,7 +23,8 @@
  * License along with this program.  If not, see
  * <http://www.gnu.org/licenses/lgpl-3.0.html>.
  * #L%
- * Author: Robert Casties (robcast@berlios.de)
+ * Author: Robert Casties (robcast@users.sourceforge.de),
+ *   Christopher Mielack (cmielack@mpiwg-berlin.mpg.de)
  */
 
 import java.awt.geom.Rectangle2D;
@@ -93,6 +94,7 @@
      */
     public ImageJobDescription(DigilibConfiguration dlcfg) {
         super(30);
+        initParams();
         dlConfig = dlcfg;
         dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache");
     }
@@ -164,13 +166,15 @@
      * @param dlReq
      * @param dlcfg
      * @return
+     * @throws ImageOpException 
+     * @throws IOException 
      */
-    public static ImageJobDescription getInstance(DigilibRequest dlReq, DigilibConfiguration dlcfg) {
+    public static ImageJobDescription getInstance(DigilibRequest dlReq, DigilibConfiguration dlcfg) throws IOException, ImageOpException {
         ImageJobDescription newMap = new ImageJobDescription(dlcfg);
-        newMap.initParams();
         // add all params to this map
         newMap.params.putAll(dlReq.getParams());
         newMap.initOptions();
+        newMap.prepareScaleParams();
         // add ImageJobDescription back into DigilibRequest
         dlReq.setJobDescription(newMap);
         return newMap;
@@ -186,7 +190,6 @@
      */
     public static ImageJobDescription getInstance(ParameterMap pm, DigilibConfiguration dlcfg) {
         ImageJobDescription newMap = new ImageJobDescription(dlcfg);
-        newMap.initParams();
         // add all params to this map
         newMap.params.putAll(pm.getParams());
         newMap.initOptions();
@@ -208,10 +211,65 @@
     public void prepareScaleParams() throws IOException, ImageOpException {
         // logger.debug("get_scaleXY()");
 
-    	/*
+        /*
+         * calculate scaling factors
+         */
+		if (isScaleToFit()) {
+		    /* 
+		     * scale to fit -- scale factor based on destination size dw/dh and user area 
+		     * using a uniform scale factor for x and y.
+		     */
+		    imgArea = prepareScaleToFit();
+		    
+        } else if (isSqueezeToFit()) {
+            /*
+             * squeeze to fit -- scale factor based on destination size and user area
+             * 
+             * uses separate scale factors for x and y
+             */
+            imgArea = prepareSqueezeToFit();
+            
+        } else if (isCropToFit()){
+            /*
+             * crop to fit -- don't scale
+             */
+            imgArea = prepareCropToFit();
+
+        } else if (isAbsoluteScale()) {
+            /*
+             * absolute scaling factor -- either original size, based on dpi, or absolute 
+             */
+            imgArea = prepareAbsoluteScale();
+            
+        } else {
+            throw new ImageOpException("Unknown scaling mode!");
+        }
+    
+    }
+
+    /**
+     * Scale to fit: scale factor based on destination size dw/dh and user area.
+     * 
+     * Uses a uniform scale factor for x and y.
+     * Sets ScaleX and ScaleY.
+     */
+    protected Rectangle2D prepareScaleToFit() throws IOException {
+        /*
+         * prepare minimum source image size
+         * 
+         * minSourceSize: w_min = dw * 1/ww
+         * 
+         * Note: dw or dh can be empty (=0) 
+         */
+        float scale = (1 / Math.min(getWw(), getWh()));
+        minSourceSize = new ImageSize(
+                Math.round(getAsInt("dw") * scale), 
+                Math.round(getAsInt("dh") * scale));
+        
+        /*
          * get image region of interest
          */
-        // size of the currently selected input image
+        // size of the currently selected input image (uses minSourceSize)
         imgSize  = getImgSize();
         // transform from relative [0,1] to image coordinates.
         double areaXf = getWx() * imgSize.getWidth();
@@ -225,125 +283,201 @@
         long areaWidth = Math.round(areaWidthF);
 
         /*
-         * calculate scaling factors
+         * calculate scale factors
          */
-		if (isScaleToFit()) {
-            /*
-             * scale to fit -- scale factor based on destination size dw/dh and user area
-             * 
-             * uses a uniform scale factor for x and y
-             */
-            scaleX = getDw() / (double) areaWidth;
-            scaleY = getDh() / (double) areaHeight;
-            if (scaleX == 0) {
-            	// dw undefined
-            	scaleX = scaleY;
-            } else if (scaleY == 0) {
-            	// dh undefined
-            	scaleY = scaleX;
+        scaleX = getDw() / (double) areaWidth;
+        scaleY = getDh() / (double) areaHeight;
+        if (scaleX == 0) {
+            // dw undefined
+            scaleX = scaleY;
+        } else if (scaleY == 0) {
+            // dh undefined
+            scaleY = scaleX;
+        } else {
+            // use the smaller factor to get fit-in-box
+            if (scaleX > scaleY) {
+                scaleX = scaleY;
+                if (hasOption("fill")) {
+                    // fill mode uses whole destination rect
+                    // TODO: should we center, clip or shift the area?
+                    areaWidth = (long) (getDw() / scaleX);
+                }
             } else {
-                // use the smaller factor to get fit-in-box
-            	if (scaleX > scaleY) {
-            		scaleX = scaleY;
-            		if (hasOption("fill")) {
-            			// fill mode uses whole destination rect
-            			// TODO: should we center, clip or shift the area?
-            			areaWidth = (long) (getDw() / scaleX);
-            		}
-            	} else {
-            		scaleY = scaleX;
-            		if (hasOption("fill")) {
-            			// fill mode uses whole destination rect
-            			// TODO: should we center, clip or shift the area?
-            			areaHeight = (long) (getDh() / scaleY);
-            		}
-            	}
-            }
-            
-        } else if (isSqueezeToFit()) {
-            /*
-             * squeeze to fit -- scale factor based on destination size and user area
-             * 
-             * uses separate scale factors for x and y
-             */
-            scaleX = getDw() / (double) areaWidth;
-            scaleY = getDh() / (double) areaHeight;
-            
-        } else if (isCropToFit()){
-            /*
-             * crop to fit -- don't scale
-             */
-            areaWidth = getDw();
-            areaHeight = getDh();
-            scaleX = 1d;
-            scaleY = 1d;
-
-        } else if (isAbsoluteScale()) {
-            /*
-             * absolute scaling factor -- either original size, based on dpi, or absolute 
-             */
-            if (hasOption("osize")) {
-                /*
-                 * get original resolution from metadata
-                 */
-                imageSet.checkMeta();
-                double origResX = imageSet.getResX();
-                double origResY = imageSet.getResY();
-                if ((origResX == 0) || (origResY == 0)) {
-                    throw new ImageOpException("Missing image DPI information!");
-                }
-                double ddpix = getAsFloat("ddpix");
-                double ddpiy = getAsFloat("ddpiy");
-                if (ddpix == 0 || ddpiy == 0) {
-                    double ddpi = getAsFloat("ddpi");
-                    if (ddpi == 0) {
-                        throw new ImageOpException("Missing display DPI information!");
-                    } else {
-                        ddpix = ddpi;
-                        ddpiy = ddpi;
-                    }
-                }
-                // calculate absolute scale factor
-                scaleX = ddpix / origResX;
-                scaleY = ddpiy / origResY;
-                
-            } else {
-                /*
-                 * explicit absolute scale factor
-                 */
-                double scaleXY = (double) getAsFloat("scale");
-                scaleX = scaleXY;
-                scaleY = scaleXY;
-                // use original size if no destination size given
-                if (getDw() == 0 && getDh() == 0) {
-                    paramDW = (int) areaWidth;
-                    paramDH = (int) areaHeight;
+                scaleY = scaleX;
+                if (hasOption("fill")) {
+                    // fill mode uses whole destination rect
+                    // TODO: should we center, clip or shift the area?
+                    areaHeight = (long) (getDh() / scaleY);
                 }
             }
+        }
+        
+        return new Rectangle2D.Double(areaX, areaY, areaWidth, areaHeight);
+    }
+
+    /**
+     * Squeeze to fit: scale factor based on destination size and user area.
+     * 
+     * Uses separate scale factors for x and y
+     * Sets ScaleX and ScaleY.
+     */
+    protected Rectangle2D prepareSqueezeToFit() throws IOException {
+        /*
+         * calculate minimum source size
+         * 
+         * w_min = dw * 1/ww
+         */
+        minSourceSize = new ImageSize(
+                Math.round(getAsInt("dw") / getWw()), 
+                Math.round(getAsInt("dh") / getWh()));
+        
+        /*
+         * get image region of interest
+         */
+        // size of the currently selected input image (uses minSourceSize)
+        imgSize  = getImgSize();
+        // transform from relative [0,1] to image coordinates.
+        double areaXf = getWx() * imgSize.getWidth();
+        double areaYf = getWy() * imgSize.getHeight();
+        double areaWidthF = getWw() * imgSize.getWidth();
+        double areaHeightF = getWh() * imgSize.getHeight();
+        // round to pixels
+        long areaX = Math.round(areaXf);
+        long areaY = Math.round(areaYf);
+        long areaHeight = Math.round(areaHeightF);
+        long areaWidth = Math.round(areaWidthF);
+
+        /*
+         * calculate scale factors
+         */
+        scaleX = getDw() / (double) areaWidth;
+        scaleY = getDh() / (double) areaHeight;
+        
+        return new Rectangle2D.Double(areaX, areaY, areaWidth, areaHeight);
+    }
+
+    
+    /**
+     * Absolute scale factor: either original size, based on dpi, or absolute. 
+     * 
+     * Uses a uniform scale factor for x and y.
+     * Sets ScaleX and ScaleY.
+     * @throws ImageOpException 
+     */
+    protected Rectangle2D prepareAbsoluteScale() throws IOException, ImageOpException {
+        /*
+         * minimum source size -- apply scale to hires size
+         */
+        minSourceSize = getHiresSize().getScaled(getAsFloat("scale"));
+        
+        /*
+         * get image region of interest
+         */
+        // size of the currently selected input image (uses minSourceSize)
+        imgSize  = getImgSize();
+        // transform from relative [0,1] to image coordinates.
+        double areaXf = getWx() * imgSize.getWidth();
+        double areaYf = getWy() * imgSize.getHeight();
+        double areaWidthF = getWw() * imgSize.getWidth();
+        double areaHeightF = getWh() * imgSize.getHeight();
+        // round to pixels
+        long areaX = Math.round(areaXf);
+        long areaY = Math.round(areaYf);
+        long areaHeight = Math.round(areaHeightF);
+        long areaWidth = Math.round(areaWidthF);
+
+        /*
+         * absolute scale factor -- either original size, based on dpi, or absolute 
+         */
+        if (hasOption("osize")) {
             /*
-             * correct absolute scale factor if we use a pre-scaled image
+             * get original resolution from metadata
              */
-            hiresSize = getHiresSize();
-            if (imgSize.getWidth() != hiresSize.getWidth()) {
-                double preScale = (double) hiresSize.getWidth() / (double) imgSize.getWidth();
-				scaleX *= preScale;
-				scaleY *= preScale;
+            imageSet.checkMeta();
+            double origResX = imageSet.getResX();
+            double origResY = imageSet.getResY();
+            if ((origResX == 0) || (origResY == 0)) {
+                throw new ImageOpException("Missing image DPI information!");
             }
-            areaWidth = Math.round(getDw() / scaleX);
-            areaHeight = Math.round(getDh() / scaleY);
+            double ddpix = getAsFloat("ddpix");
+            double ddpiy = getAsFloat("ddpiy");
+            if (ddpix == 0 || ddpiy == 0) {
+                double ddpi = getAsFloat("ddpi");
+                if (ddpi == 0) {
+                    throw new ImageOpException("Missing display DPI information!");
+                } else {
+                    ddpix = ddpi;
+                    ddpiy = ddpi;
+                }
+            }
+            // calculate absolute scale factor
+            scaleX = ddpix / origResX;
+            scaleY = ddpiy / origResY;
             
         } else {
-            throw new ImageOpException("Unknown scaling mode!");
+            /*
+             * explicit absolute scale factor
+             */
+            double scaleXY = (double) getAsFloat("scale");
+            scaleX = scaleXY;
+            scaleY = scaleXY;
+            // use original size if no destination size given
+            if (getDw() == 0 && getDh() == 0) {
+                paramDW = (int) areaWidth;
+                paramDH = (int) areaHeight;
+            }
         }
+        /*
+         * correct absolute scale factor if we use a pre-scaled image
+         */
+        hiresSize = getHiresSize();
+        if (imgSize.getWidth() != hiresSize.getWidth()) {
+            double preScale = (double) hiresSize.getWidth() / (double) imgSize.getWidth();
+            scaleX *= preScale;
+            scaleY *= preScale;
+        }
+        areaWidth = Math.round(getDw() / scaleX);
+        areaHeight = Math.round(getDh() / scaleY);
+        
+        return new Rectangle2D.Double(areaX, areaY, areaWidth, areaHeight);
+    }
+
 
-		/*
-		 * set image area
-		 */
-		imgArea = new Rectangle2D.Double(areaX, areaY, areaWidth, areaHeight);
+    /**
+     * Crop to fit: don't scale.
+     * 
+     * Sets ScaleX and ScaleY.
+     */
+    protected Rectangle2D prepareCropToFit() throws IOException {
+        /*
+         * minimum source size = hires size
+         */
+        minSourceSize = getHiresSize();
+        
+        /*
+         * get image region of interest
+         */
+        // size of the currently selected input image (uses minSourceSize)
+        imgSize  = getImgSize();
+        // transform from relative [0,1] to image coordinates.
+        double areaXf = getWx() * imgSize.getWidth();
+        double areaYf = getWy() * imgSize.getHeight();
+        // round to pixels
+        long areaX = Math.round(areaXf);
+        long areaY = Math.round(areaYf);
+
+        /*
+         * crop to fit -- don't scale
+         */
+        int areaWidth = getDw();
+        int areaHeight = getDh();
+        scaleX = 1d;
+        scaleY = 1d;
+        
+        return new Rectangle2D.Double(areaX, areaY, areaWidth, areaHeight);
+    }
+
     
-    }
-    
-
     /**
      * Returns the mime-type of the input.
      * 
@@ -403,6 +537,8 @@
     /**
      * Returns the ImageInput to use.
      * 
+     * uses getMinSourceSize().
+     * 
      * @return
      * @throws IOException
      */
@@ -562,45 +698,13 @@
      */
     public ImageSize getMinSourceSize() throws IOException {
         //logger.debug("getMinSourceSize()");
-        if (minSourceSize != null) {
-        	return minSourceSize;
-        }
-        
-        minSourceSize = new ImageSize();
-        if (isScaleToFit()) {
-        	/*
-        	 * scale to fit -- calculate minimum source size
-        	 * 
-        	 * roughly: w_min = dw * 1/ww
-        	 * 
-        	 * Note: dw or dh can be empty (=0) 
-        	 */
-        	float scale = (1 / Math.min(getWw(), getWh()));
-        	minSourceSize.setSize(
-        			Math.round(getAsInt("dw") * scale), 
-        			Math.round(getAsInt("dh") * scale));
-        	
-        } else if (isSqueezeToFit()) {
-        	/*
-        	 * squeeze to fit -- calculate minimum source size
-        	 * 
-        	 * w_min = dw * 1/ww
-        	 */
-        	minSourceSize.setSize(
-        			Math.round(getAsInt("dw") / getWw()), 
-        			Math.round(getAsInt("dh") / getWh()));
-        	
-        } else if (isAbsoluteScale() && hasOption("ascale")) {
-        	/*
-        	 * absolute scale -- apply scale to hires size
-        	 */
-        	minSourceSize = getHiresSize().getScaled(getAsFloat("scale"));
-        	
-        } else {
-        	/*
-        	 * clip or other -- source = hires size
-        	 */
-        	minSourceSize = getHiresSize();
+        if (minSourceSize == null) {
+            // this should not happen, it may lead to a loop!
+            logger.warn("MinSourceSize is not set! Calling prepareScaleParams again.");
+            try {
+                prepareScaleParams();
+            } catch (ImageOpException e) {
+            }
         }
         return minSourceSize;
     }
--- a/common/src/main/java/digilib/image/ImageWorker.java	Tue Nov 10 16:15:52 2015 +0100
+++ b/common/src/main/java/digilib/image/ImageWorker.java	Tue Nov 10 18:36:46 2015 +0100
@@ -78,7 +78,6 @@
         docuImage.setQuality(jobinfo.getScaleQual());
 
         // get area of interest and scale factor
-        jobinfo.prepareScaleParams();
         Rectangle loadRect = jobinfo.getOuterImgArea().getBounds();
         double scaleX = jobinfo.getScaleX();
         double scaleY = jobinfo.getScaleY();
--- a/servlet/src/main/java/digilib/servlet/ServletOps.java	Tue Nov 10 16:15:52 2015 +0100
+++ b/servlet/src/main/java/digilib/servlet/ServletOps.java	Tue Nov 10 18:36:46 2015 +0100
@@ -379,6 +379,10 @@
             logger.error("No response!");
             return;
         }
+        
+        /*
+         * get image size
+         */
         ImageSize size = null;
         try {
             // get original image size
@@ -393,15 +397,24 @@
                 throw new ServletException("Unable to write error response!", e);
             }
         }
+        
+        /*
+         * get resource URL
+         */
         String url = dlReq.getServletRequest().getRequestURL().toString();
         if (url.endsWith("/info.json")) {
             url = url.substring(0, url.lastIndexOf("/info.json"));
         } else if (url.endsWith("/")) {
             url = url.substring(0, url.lastIndexOf("/"));
         }
+        
+        /*
+         * 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("{");
--- a/servlet2/src/main/java/digilib/servlet/Scaler.java	Tue Nov 10 16:15:52 2015 +0100
+++ b/servlet2/src/main/java/digilib/servlet/Scaler.java	Tue Nov 10 18:36:46 2015 +0100
@@ -224,9 +224,7 @@
 
         // parse request
         DigilibServletRequest dlRequest = new DigilibServletRequest(request, dlConfig);
-        // extract the job information
-        ImageJobDescription jobTicket = ImageJobDescription.getInstance(dlRequest, dlConfig);
-
+        
         // type of error reporting
         ErrMsg errMsgType = ErrMsg.IMAGE;
         if (dlRequest.hasOption("errtxt")) {
@@ -236,10 +234,13 @@
         }
 
         try {
+            // extract the job information
+            ImageJobDescription jobTicket = ImageJobDescription.getInstance(dlRequest, dlConfig);
+
             /*
              * check if we can fast-track without scaling
              */
-            ImageInput fileToLoad = (ImageInput) jobTicket.getInput();
+            ImageInput fileToLoad = jobTicket.getInput();
 
             // check permissions
             if (useAuthorization) {
--- a/servlet2/src/main/java/digilib/servlet/ScalerNoThread.java	Tue Nov 10 16:15:52 2015 +0100
+++ b/servlet2/src/main/java/digilib/servlet/ScalerNoThread.java	Tue Nov 10 18:36:46 2015 +0100
@@ -55,7 +55,7 @@
     private static final long serialVersionUID = 1450947819851623306L;
 
     /** digilib servlet version (for all components) */
-    public static final String version = "2.3.1 nothread";
+    public static final String version = DigilibServletConfiguration.getClassVersion() + " nothread";
 
     /** servlet error codes */
     public static enum Error {
@@ -207,8 +207,6 @@
 
         // parse request
         DigilibServletRequest dlRequest = new DigilibServletRequest(request, dlConfig);
-        // extract the job information
-        ImageJobDescription jobTicket = ImageJobDescription.getInstance(dlRequest, dlConfig);
 
         // type of error reporting
         ErrMsg errMsgType = ErrMsg.IMAGE;
@@ -219,6 +217,8 @@
         }
 
         try {
+            // extract the job information
+            ImageJobDescription jobTicket = ImageJobDescription.getInstance(dlRequest, dlConfig);
             /*
              * check if we can fast-track without scaling
              */
--- a/servlet3/src/main/java/digilib/servlet/Scaler.java	Tue Nov 10 16:15:52 2015 +0100
+++ b/servlet3/src/main/java/digilib/servlet/Scaler.java	Tue Nov 10 18:36:46 2015 +0100
@@ -237,14 +237,6 @@
 
         // parse request
         DigilibServletRequest dlRequest = new DigilibServletRequest(request, dlConfig);
-        // extract the job information
-        final ImageJobDescription jobTicket = ImageJobDescription.getInstance(dlRequest, dlConfig);
-        
-        // handle the info-request
-        if (dlRequest.hasOption("info")) {
-            ServletOps.sendIiifInfo(dlRequest, response, logger);
-            return;
-        }
 
         // type of error reporting
         ErrMsg errMsgType = defaultErrMsgType;
@@ -256,17 +248,21 @@
             errMsgType = ErrMsg.CODE;
         }
 
-        // error out if request was bad
-        if (dlRequest.errorMessage != null) {
-            digilibError(errMsgType, Error.UNKNOWN, dlRequest.errorMessage, response);
-            return;
-        }
-        
         try {
-            /*
-             * get the input file
-             */
-            ImageInput fileToLoad = (ImageInput) jobTicket.getInput();
+            // extract the job information
+            final ImageJobDescription jobTicket = ImageJobDescription.getInstance(dlRequest, dlConfig);
+
+            // handle the info-request
+            if (dlRequest.hasOption("info")) {
+                ServletOps.sendIiifInfo(dlRequest, response, logger);
+                return;
+            }
+
+            // error out if request was bad
+            if (dlRequest.errorMessage != null) {
+                digilibError(errMsgType, Error.UNKNOWN, dlRequest.errorMessage, response);
+                return;
+            }
 
             /*
              * check permissions
@@ -280,6 +276,11 @@
             }
 
             /*
+             * get the input file
+             */
+            ImageInput fileToLoad = jobTicket.getInput();
+
+            /*
              * if requested, send image as a file
              */
             if (sendFileAllowed && jobTicket.getSendAsFile()) {