Mercurial > hg > digilib
changeset 1412:52d0730b1f32
Merge from new_scaling branch
67134a81061b31656ea6cea322d64243625f2717
author | robcast |
---|---|
date | Tue, 20 Oct 2015 19:37:54 +0200 |
parents | 51587d36fd44 (current diff) 67134a81061b (diff) |
children | 48db87972281 |
files | |
diffstat | 6 files changed, 219 insertions(+), 120 deletions(-) [+] |
line wrap: on
line diff
--- a/common/pom.xml Mon Oct 19 12:44:26 2015 +0200 +++ b/common/pom.xml Tue Oct 20 19:37:54 2015 +0200 @@ -27,24 +27,17 @@ </pluginManagement> </build> - <repositories> - <!-- This provides Stian Soiland-Reyes re-packaged version of JAI-ImageIO --> - <repository> - <releases /> - <snapshots> - <enabled>false</enabled> - </snapshots> - <id>mygrid-repository</id> - <name>myGrid Repository</name> - <url>http://www.mygrid.org.uk/maven/repository</url> - </repository> - </repositories> <dependencies> - <dependency> - <groupId>net.java.dev.jai-imageio</groupId> - <artifactId>jai-imageio-core-standalone</artifactId> - <version>1.2-pre-dr-b04-2011-07-04</version> - </dependency> + <dependency> + <groupId>com.github.jai-imageio</groupId> + <artifactId>jai-imageio-core</artifactId> + <version>1.3.0</version> + </dependency> + <!-- <dependency> + <groupId>com.github.jai-imageio</groupId> + <artifactId>jai-imageio-jpeg2000</artifactId> + <version>1.3.0</version> + </dependency> --> <dependency> <groupId>org.devlib.schmidt</groupId> <artifactId>imageinfo</artifactId>
--- a/common/src/main/java/digilib/conf/DigilibConfiguration.java Mon Oct 19 12:44:26 2015 +0200 +++ b/common/src/main/java/digilib/conf/DigilibConfiguration.java Tue Oct 20 19:37:54 2015 +0200 @@ -57,7 +57,7 @@ /** digilib version */ public static String getClassVersion() { - return "2.3.1"; + return "2.3.2"; } /* non-static getVersion for Java inheritance */
--- a/common/src/main/java/digilib/image/ImageJobDescription.java Mon Oct 19 12:44:26 2015 +0200 +++ b/common/src/main/java/digilib/image/ImageJobDescription.java Tue Oct 20 19:37:54 2015 +0200 @@ -1,31 +1,5 @@ package digilib.image; -/* - * #%L - * A class for storing the set of parameters necessary for scaling images - * with an ImageWorker. - * - * %% - * Copyright (C) 2001 - 2013 MPIWG Berlin - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/lgpl-3.0.html>. - * #L% - * Author: Robert Casties (robcast@berlios.de) - */ - -import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.io.IOException; @@ -401,7 +375,6 @@ /** * Returns image scaling factor. * Uses image size and user parameters. - * Modifies scaleXY, userImgArea. * * @return * @throws IOException @@ -416,29 +389,21 @@ /* * calculate region of interest */ - double areaWidth; - double areaHeight; - // size of the currently selected input image - ImageSize imgSize = getInput().getSize(); - // user area is in [0,1] coordinates - Rectangle2D relUserArea = new Rectangle2D.Float(getWx(), getWy(), getWw(), getWh()); - // transform from relative [0,1] to image coordinates. - AffineTransform imgTrafo = AffineTransform.getScaleInstance(imgSize.getWidth(), imgSize.getHeight()); - // transform user coordinate area to image coordinate area - userImgArea = imgTrafo.createTransformedShape(relUserArea).getBounds2D(); - + userImgArea = getUserImgArea(); + double areaWidth = userImgArea.getWidth(); + double areaHeight = userImgArea.getHeight(); + /* * calculate scaling factor */ float ws = getAsFloat("ws"); - if (isScaleToFit()) { + if (isScaleToFit()) { /* * scale to fit -- scaling factor based on destination size and user area */ - areaWidth = (double) userImgArea.getWidth(); - areaHeight = (double) userImgArea.getHeight(); double scaleX = getDw() / areaWidth * ws; double scaleY = getDh() / areaHeight * ws; + // use the smaller factor to get fit-in-box scaleXY = (scaleX > scaleY) ? scaleY : scaleX; } else if (isAbsoluteScale()) { /* @@ -473,25 +438,26 @@ scaleXY = (double) getAsFloat("scale"); // use original size if no destination size given if (getDw() == 0 && getDh() == 0) { - paramDW = (int) userImgArea.getWidth(); - paramDH = (int) userImgArea.getHeight(); + paramDW = (int) areaWidth; + paramDH = (int) areaHeight; } } // we need to correct the factor if we use a pre-scaled image + ImageSize imgSize = getInput().getSize(); ImageSize hiresSize = getHiresSize(); if (imgSize.getWidth() != hiresSize.getWidth()) { scaleXY *= (double) hiresSize.getWidth() / (double) imgSize.getWidth(); } - areaWidth = getDw() / scaleXY * ws; - areaHeight = getDh() / scaleXY * ws; + areaWidth = (int) Math.round(getDw() / scaleXY * ws); + areaHeight = (int) Math.round(getDh() / scaleXY * ws); // reset user area size userImgArea.setRect(userImgArea.getX(), userImgArea.getY(), areaWidth, areaHeight); } else { /* * crop to fit -- don't scale */ - areaWidth = getDw() * ws; - areaHeight = getDh() * ws; + areaWidth = Math.round(getDw() * ws); + areaHeight = Math.round(getDh() * ws); // reset user area size userImgArea.setRect(userImgArea.getX(), userImgArea.getY(), areaWidth, areaHeight); scaleXY = 1d; @@ -507,20 +473,29 @@ * @throws IOException */ public int getDw() throws IOException { - logger.debug("get_paramDW()"); + //logger.debug("get_paramDW()"); if (paramDW == null) { paramDW = getAsInt("dw"); paramDH = getAsInt("dh"); - float imgAspect = getInput().getAspect(); if (paramDW == 0) { - // calculate dw - paramDW = Math.round(paramDH * imgAspect); + /* + * calculate dw using aspect ratio of image area + */ + userImgArea = getUserImgArea(); + double imgAspect = userImgArea.getWidth() / userImgArea.getHeight(); + // round up to make sure we don't squeeze dh + paramDW = (int) Math.ceil(paramDH * imgAspect); setValue("dw", paramDW); } else if (paramDH == 0) { - // calculate dh - paramDH = Math.round(paramDW / imgAspect); + /* + * calculate dh using aspect ratio of image area + */ + userImgArea = getUserImgArea(); + double imgAspect = userImgArea.getWidth() / userImgArea.getHeight(); + // round up to make sure we don't squeeze dw + paramDH = (int) Math.ceil(paramDW / imgAspect); setValue("dh", paramDH); } } @@ -535,20 +510,29 @@ * @throws IOException */ public int getDh() throws IOException { - logger.debug("get_paramDH()"); + //logger.debug("get_paramDH()"); if (paramDH == null) { paramDW = getAsInt("dw"); paramDH = getAsInt("dh"); - float imgAspect = getInput().getAspect(); if (paramDW == 0) { - // calculate dw - paramDW = Math.round(paramDH * imgAspect); + /* + * calculate dw using aspect ratio of image area + */ + userImgArea = getUserImgArea(); + double imgAspect = userImgArea.getWidth() / userImgArea.getHeight(); + // round up to make sure we don't squeeze dh + paramDW = (int) Math.ceil(paramDH * imgAspect); setValue("dw", paramDW); } else if (paramDH == 0) { - // calculate dh - paramDH = Math.round(paramDW / imgAspect); + /* + * calculate dh using aspect ratio of image area + */ + userImgArea = getUserImgArea(); + double imgAspect = userImgArea.getWidth() / userImgArea.getHeight(); + // round up to make sure we don't squeeze dw + paramDH = (int) Math.ceil(paramDW / imgAspect); setValue("dh", paramDH); } } @@ -563,7 +547,7 @@ * @throws IOException */ public Float getWw() throws IOException { - logger.debug("get_paramWW()"); + //logger.debug("get_paramWW()"); if (paramWW == null) { paramWW = getAsFloat("ww"); if (hasOption("pxarea")) { @@ -583,7 +567,7 @@ * @throws IOException */ public Float getWh() throws IOException { - logger.debug("get_paramWH()"); + //logger.debug("get_paramWH()"); if (paramWH == null) { paramWH = getAsFloat("wh"); if (hasOption("pxarea")) { @@ -603,7 +587,7 @@ * @throws IOException */ public Float getWx() throws IOException { - logger.debug("get_paramWX()"); + //logger.debug("get_paramWX()"); if (paramWX == null) { paramWX = getAsFloat("wx"); if (hasOption("pxarea")) { @@ -623,7 +607,7 @@ * @throws IOException */ public Float getWy() throws IOException { - logger.debug("get_paramWY()"); + //logger.debug("get_paramWY()"); if (paramWY == null) { paramWY = getAsFloat("wy"); if (hasOption("pxarea")) { @@ -641,7 +625,7 @@ * @return */ public int getScaleQual() { - logger.debug("get_scaleQual()"); + //logger.debug("get_scaleQual()"); int qual = dlConfig.getAsInt("default-quality"); if (hasOption("q0")) qual = 0; @@ -676,12 +660,22 @@ * * @return * @throws IOException - * @throws ImageOpException */ - public Rectangle2D getUserImgArea() throws IOException, ImageOpException { + public Rectangle2D getUserImgArea() throws IOException { if (userImgArea == null) { - // getScaleXY sets userImgArea - getScaleXY(); + // size of the currently selected input image + ImageSize imgSize = getInput().getSize(); + // 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); + userImgArea = new Rectangle2D.Double(areaX, areaY, areaWidth, areaHeight); } return userImgArea; } @@ -689,6 +683,10 @@ /** * Returns the maximal area of the source image that will be used. * + * This was meant to correct for missing pixels outside the + * userImgArea when rotating oblique angles but is not yet implemented. + * Currently returns userImgArea. + * * @return * @throws IOException * @throws ImageOpException @@ -699,25 +697,28 @@ // image size in pixels ImageSize imgSize = getInput().getSize(); - Rectangle2D imgBounds = new Rectangle2D.Float(0, 0, imgSize.getWidth(), imgSize.getHeight()); + Rectangle2D imgBounds = new Rectangle2D.Double(0, 0, imgSize.getWidth(), imgSize.getHeight()); // clip area at the image border outerUserImgArea = outerUserImgArea.createIntersection(imgBounds); // check image parameters sanity scaleXY = getScaleXY(); - logger.debug("outerUserImgArea.getWidth()=" + outerUserImgArea.getWidth()); - logger.debug("get_scaleXY() * outerUserImgArea.getWidth() = " + (scaleXY * outerUserImgArea.getWidth())); - if ((outerUserImgArea.getWidth() < 1) || (outerUserImgArea.getHeight() < 1) || (scaleXY * outerUserImgArea.getWidth() < 2) || (scaleXY * outerUserImgArea.getHeight() < 2)) { logger.error("ERROR: invalid scale parameter set!"); + logger.debug("scaleXY="+scaleXY+" outerUserImgArea="+outerUserImgArea); throw new ImageOpException("Invalid scale parameter set!"); } } return outerUserImgArea; } + /** + * Get the RGBM parameter set. + * + * @return + */ public float[] getRGBM() { float[] paramRGBM = null;// {0f,0f,0f}; Parameter p = params.get("rgbm"); @@ -727,6 +728,11 @@ return paramRGBM; } + /** + * Get the RGBA parameter set. + * + * @return + */ public float[] getRGBA() { float[] paramRGBA = null;// {0f,0f,0f}; Parameter p = params.get("rgba");
--- a/common/src/main/java/digilib/image/ImageLoaderDocuImage.java Mon Oct 19 12:44:26 2015 +0200 +++ b/common/src/main/java/digilib/image/ImageLoaderDocuImage.java Tue Oct 20 19:37:54 2015 +0200 @@ -72,7 +72,7 @@ public class ImageLoaderDocuImage extends ImageInfoDocuImage { /** DocuImage version */ - public static final String version = "ImageLoaderDocuImage 2.1.6a"; + public static final String version = "ImageLoaderDocuImage 2.1.7"; /** image object */ protected BufferedImage img; @@ -167,18 +167,24 @@ /** the size of the current image */ protected ImageSize imageSize; - /** - * @return the version + /* (non-Javadoc) + * @see digilib.image.DocuImageImpl#getVersion() */ public String getVersion() { return version; } - /* loadSubimage is supported. */ + /* + * loadSubimage is supported. + * @see digilib.image.DocuImageImpl#isSubimageSupported() + */ public boolean isSubimageSupported() { return true; } + /* (non-Javadoc) + * @see digilib.image.DocuImageImpl#setQuality(int) + */ public void setQuality(int qual) { quality = qual; renderHint = new RenderingHints(null); @@ -194,7 +200,10 @@ } } - /* returns the size of the current image */ + /* + * returns the size of the current image + * @see digilib.image.DocuImageImpl#getSize() + */ public ImageSize getSize() { if (imageSize == null) { int h = 0; @@ -218,13 +227,19 @@ return imageSize; } - /* returns a list of supported image formats */ + /* + * returns a list of supported image formats + * @see digilib.image.DocuImageImpl#getSupportedFormats() + */ public Iterator<String> getSupportedFormats() { String[] formats = ImageIO.getReaderFormatNames(); return Arrays.asList(formats).iterator(); } - /* Check image size and type and store in ImageInput */ + /* + * Check image size and type and store in ImageInput + * @see digilib.image.ImageInfoDocuImage#identify(digilib.io.ImageInput) + */ public ImageInput identify(ImageInput input) throws IOException { ImageInput ii = null; if (!reuseReader) { @@ -266,7 +281,10 @@ } } - /* load image file */ + /* + * load image file + * @see digilib.image.DocuImageImpl#loadImage(digilib.io.ImageInput) + */ public void loadImage(ImageInput ii) throws FileOpException { logger.debug("loadImage: " + ii); this.input = ii; @@ -335,7 +353,11 @@ return reader; } - /* Load an image file into the Object. */ + /* + * Load an image file into the Object. + * + * @see digilib.image.DocuImageImpl#loadSubimage(digilib.io.ImageInput, java.awt.Rectangle, int) + */ public void loadSubimage(ImageInput ii, Rectangle region, int prescale) throws FileOpException { logger.debug("loadSubimage"); this.input = ii; @@ -391,7 +413,10 @@ } } - /* write image of type mt to Stream */ + /* + * (non-Javadoc) + * @see digilib.image.DocuImageImpl#writeImage(java.lang.String, java.io.OutputStream) + */ public void writeImage(String mt, OutputStream ostream) throws ImageOpException, FileOpException { logger.debug("writeImage"); // setup output @@ -446,14 +471,43 @@ // TODO: should we: finally { writer.dispose(); } } + /* + * (non-Javadoc) + * @see digilib.image.DocuImageImpl#scale(double, double) + */ public void scale(double scaleX, double scaleY) throws ImageOpException { logger.debug("scale: " + scaleX); - /* for downscaling in high quality the image is blurred first */ + /* + * for downscaling in high quality the image is blurred first ... + */ if ((scaleX <= 0.5) && (quality > 1)) { int bl = (int) Math.floor(1 / scaleX); blur(bl); } - /* then scaled */ + /* + * ... then scaled. + * + * We need to correct the scale factors to round to whole pixels + * or else we get a 1px black (or transparent) border. + */ + int imgW = img.getWidth(); + int imgH = img.getHeight(); + double targetW = imgW * scaleX; + double targetH = imgH * scaleY; + double deltaX = targetW - Math.floor(targetW); + double deltaY = targetH - Math.floor(targetH); + if (deltaX > epsilon) { + // round up + logger.debug("rounding up x scale factor"); + scaleX += (1 - deltaX) / imgW; + } + if (deltaY > epsilon) { + // round up + logger.debug("rounding up y scale factor"); + scaleY += (1 - deltaY) / imgH; + } + // scale with AffineTransformOp + logger.debug("scaled from " + imgW + "x" + imgH + " img=" + img); AffineTransformOp scaleOp = new AffineTransformOp(AffineTransform.getScaleInstance(scaleX, scaleY), renderHint); img = scaleOp.filter(img, null); logger.debug("scaled to " + img.getWidth() + "x" + img.getHeight() + " img=" + img); @@ -461,6 +515,12 @@ imageSize = null; } + /** + * Blur the image with a convolution using the given radius. + * + * @param radius + * @throws ImageOpException + */ public void blur(int radius) throws ImageOpException { logger.debug("blur: " + radius); // minimum radius is 2 @@ -492,6 +552,10 @@ logger.debug("blurred: " + img); } + /* + * (non-Javadoc) + * @see digilib.image.DocuImageImpl#crop(int, int, int, int) + */ public void crop(int x_off, int y_off, int width, int height) throws ImageOpException { // setup Crop img = img.getSubimage(x_off, y_off, width, height); @@ -500,6 +564,10 @@ imageSize = null; } + /* + * (non-Javadoc) + * @see digilib.image.DocuImageImpl#rotate(double) + */ public void rotate(double angle) throws ImageOpException { logger.debug("rotate: " + angle); // setup rotation @@ -528,6 +596,10 @@ imageSize = null; } + /* + * (non-Javadoc) + * @see digilib.image.DocuImageImpl#mirror(double) + */ public void mirror(double angle) throws ImageOpException { logger.debug("mirror: " + angle); // setup mirror @@ -560,6 +632,10 @@ imageSize = null; } + /* + * (non-Javadoc) + * @see digilib.image.DocuImageImpl#enhance(float, float) + */ public void enhance(float mult, float add) throws ImageOpException { RescaleOp op = null; logger.debug("enhance: img=" + img); @@ -591,6 +667,11 @@ op.filter(img, img); } + /* + * (non-Javadoc) + * + * @see digilib.image.DocuImageImpl#enhanceRGB(float[], float[]) + */ public void enhanceRGB(float[] rgbm, float[] rgba) throws ImageOpException { logger.debug("enhanceRGB: rgbm=" + rgbm + " rgba=" + rgba); /* @@ -702,6 +783,10 @@ } } + /* + * (non-Javadoc) + * @see digilib.image.DocuImageImpl#dispose() + */ public void dispose() { if (reader != null) { reader.dispose(); @@ -710,6 +795,10 @@ img = null; } + /* + * (non-Javadoc) + * @see digilib.image.DocuImageImpl#getAwtImage() + */ public Image getAwtImage() { return (Image) img; }
--- a/common/src/main/java/digilib/image/ImageWorker.java Mon Oct 19 12:44:26 2015 +0200 +++ b/common/src/main/java/digilib/image/ImageWorker.java Tue Oct 20 19:37:54 2015 +0200 @@ -57,8 +57,7 @@ /** * render and return the image */ - public DocuImage call() throws FileOpException, IOException, - ImageOpException { + public DocuImage call() throws FileOpException, IOException, ImageOpException { logger.debug("ImageWorker starting"); long startTime = System.currentTimeMillis(); @@ -78,6 +77,7 @@ // set interpolation quality docuImage.setQuality(jobinfo.getScaleQual()); + // get area of interest and scale factor Rectangle loadRect = jobinfo.getOuterUserImgArea().getBounds(); double scaleXY = jobinfo.getScaleXY(); @@ -85,8 +85,11 @@ logger.debug("ImageWorker stopping (after setup)"); return null; } - // use subimage loading if possible + /* + * load, crop and scale the image + */ if (docuImage.isSubimageSupported()) { + // use subimage loading if possible logger.debug("Subimage: scale " + scaleXY + " = " + (1 / scaleXY)); double subf = 1d; double subsamp = 1d; @@ -126,26 +129,29 @@ } docuImage.scale(scaleXY, scaleXY); } - if (stopNow) { logger.debug("ImageWorker stopping (after scaling)"); return null; } - // mirror image - // operation mode: "hmir": mirror horizontally, "vmir": mirror - // vertically + + /* + * mirror image + * operation mode: "hmir": mirror horizontally, "vmir": mirror vertically + */ if (jobinfo.hasOption("hmir")) { docuImage.mirror(0); } if (jobinfo.hasOption("vmir")) { docuImage.mirror(90); } - if (stopNow) { logger.debug("ImageWorker stopping (after mirroring)"); return null; } - // rotate image + + /* + * rotate image + */ if (jobinfo.getAsFloat("rot") != 0d) { docuImage.rotate(jobinfo.getAsFloat("rot")); /* @@ -162,12 +168,14 @@ */ } - if (stopNow) { logger.debug("ImageWorker stopping (after rotating)"); return null; } - // color modification + + /* + * color modification + */ float[] paramRGBM = jobinfo.getRGBM(); float[] paramRGBA = jobinfo.getRGBA(); if ((paramRGBM != null) || (paramRGBA != null)) { @@ -185,31 +193,34 @@ } docuImage.enhanceRGB(mult, paramRGBA); } - if (stopNow) { logger.debug("ImageWorker stopping (after enhanceRGB)"); return null; } - // contrast and brightness enhancement + + /* + * contrast and brightness enhancement + */ float paramCONT = jobinfo.getAsFloat("cont"); float paramBRGT = jobinfo.getAsFloat("brgt"); if ((paramCONT != 0f) || (paramBRGT != 0f)) { float mult = (float) Math.pow(2, paramCONT); docuImage.enhance(mult, paramBRGT); } - if (stopNow) { logger.debug("ImageWorker stopping (after enhance)"); return null; } - // color operation + + /* + * color operation + */ DocuImage.ColorOp colop = jobinfo.getColOp(); if (colop != null) { docuImage.colorOp(colop); } - logger.debug("rendered in " + (System.currentTimeMillis() - startTime) - + "ms"); + logger.debug("rendered in " + (System.currentTimeMillis() - startTime) + "ms"); return docuImage; }
--- a/servlet3/src/main/java/digilib/conf/DigilibServlet3Configuration.java Mon Oct 19 12:44:26 2015 +0200 +++ b/servlet3/src/main/java/digilib/conf/DigilibServlet3Configuration.java Tue Oct 20 19:37:54 2015 +0200 @@ -42,7 +42,7 @@ public class DigilibServlet3Configuration extends DigilibServletConfiguration { public static String getClassVersion() { - return "2.3.0 async"; + return "2.3.2 async"; } /* non-static getVersion for Java inheritance */