# HG changeset patch # User robcast # Date 1447177006 -3600 # Node ID 02df383e0a8508e97e6c94bb261c551746b49fdc # Parent e321607eb36e89cde7d6881facb324fadff3d597 reshuffled ImageJobDescription again. all case-dependent logic is now in prepareScaleParams which gets called automatically by getInstance. diff -r e321607eb36e -r 02df383e0a85 common/src/main/java/digilib/conf/DigilibConfiguration.java --- 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 */ diff -r e321607eb36e -r 02df383e0a85 common/src/main/java/digilib/image/ImageJobDescription.java --- 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 * . * #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; } diff -r e321607eb36e -r 02df383e0a85 common/src/main/java/digilib/image/ImageWorker.java --- 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(); diff -r e321607eb36e -r 02df383e0a85 servlet/src/main/java/digilib/servlet/ServletOps.java --- 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("{"); diff -r e321607eb36e -r 02df383e0a85 servlet2/src/main/java/digilib/servlet/Scaler.java --- 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) { diff -r e321607eb36e -r 02df383e0a85 servlet2/src/main/java/digilib/servlet/ScalerNoThread.java --- 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 */ diff -r e321607eb36e -r 02df383e0a85 servlet3/src/main/java/digilib/servlet/Scaler.java --- 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()) {