# HG changeset patch # User robcast # Date 1046354849 -3600 # Node ID 4e6757e8ccd402864492d80159a37e04af5019f3 # Parent ed1b698b4f0ae783ddf6bcc96e3c276671011f7b New enhanced ImageLoader stuff. Now uses Subsampling and image regions on read. Now implements enhance, rotate and mirror for ImageLoader/Java2D diff -r ed1b698b4f0a -r 4e6757e8ccd4 servlet/src/digilib/image/DocuImage.java --- a/servlet/src/digilib/image/DocuImage.java Mon Feb 10 17:09:28 2003 +0100 +++ b/servlet/src/digilib/image/DocuImage.java Thu Feb 27 15:07:29 2003 +0100 @@ -2,7 +2,7 @@ Digital Image Library servlet components - Copyright (C) 2001, 2002 Robert Casties (robcast@mail.berlios.de) + Copyright (C) 2001, 2002, 2003 Robert Casties (robcast@mail.berlios.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -20,6 +20,7 @@ package digilib.image; +import java.awt.Rectangle; import java.io.File; import java.io.OutputStream; @@ -47,6 +48,35 @@ */ public void loadImage(File f) throws FileOpException; + /** This DocuImage support the loadSubImage operation. + * + * @return boolean + */ + public boolean isSubimageSupported(); + + /** Load only a subsampled region of the image file. + * + * @param f + * @param region + * @param subsample + * @throws FileOpException + */ + public void loadSubimage(File f, Rectangle region, int subsample) + throws FileOpException; + + /** This DocuImage support the preloadImage operation for getWidth/getHeight. + * + * @return boolean + */ + public boolean isPreloadSupported(); + + /** Preload image file into a state to use getWidth/getHeight. + * + * @param f + * @throws FileOpException + */ + public void preloadImage(File f) throws FileOpException; + /** Writes the current image to a ServletResponse. * * The image is encoded to the mime-type mt and sent to the output @@ -121,17 +151,18 @@ double scale, int qual) throws ImageOpException; - + /** Rotates the current image. * * Replaces the current image with a rotated image. The image is rotated - * around the center by angle given in degrees [0, 360] - * clockwise. Image size and aspect ratio are likely to change. + * around the point x,y by angle + * given in degrees [0, 360] clockwise. + * Image size and aspect ratio are likely to change. * * @param angle rotation angle in degree */ public void rotate(double angle) throws ImageOpException; - + /** Mirrors the current image. * * Replaces the current image with a mirrored image. The mirror axis goes @@ -143,7 +174,7 @@ * @throws ImageOpException */ public void mirror(double angle) throws ImageOpException; - + /** Enhaces brightness and contrast of the current image. * * Replaces the current image with a brightness and contrast enhanced image. diff -r ed1b698b4f0a -r 4e6757e8ccd4 servlet/src/digilib/image/DocuImageImpl.java --- a/servlet/src/digilib/image/DocuImageImpl.java Mon Feb 10 17:09:28 2003 +0100 +++ b/servlet/src/digilib/image/DocuImageImpl.java Thu Feb 27 15:07:29 2003 +0100 @@ -2,7 +2,7 @@ Digital Image Library servlet components - Copyright (C) 2001, 2002 Robert Casties (robcast@mail.berlios.de) + Copyright (C) 2001, 2002, 2003 Robert Casties (robcast@mail.berlios.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -20,7 +20,11 @@ package digilib.image; +import java.awt.Rectangle; +import java.io.File; + import digilib.Utils; +import digilib.io.FileOpException; /** Simple abstract implementation of the DocuImage interface. * @@ -37,6 +41,9 @@ /** Interpolation quality. */ protected int quality = 0; + + // epsilon for float comparisons + public final double epsilon = 1e-5; /** Default constructor. */ public DocuImageImpl() { @@ -121,4 +128,23 @@ // just a do-nothing implementation } + public void preloadImage(File f) throws FileOpException { + // just a do-nothing implementation + } + + public boolean isPreloadSupported() { + // preload per default not supported + return false; + } + + public boolean isSubimageSupported() { + // partial loading per default not supported + return false; + } + + public void loadSubimage(File f, Rectangle region, int subsample) + throws FileOpException { + // empty implementation + } + } diff -r ed1b698b4f0a -r 4e6757e8ccd4 servlet/src/digilib/image/ImageLoaderDocuImage.java --- a/servlet/src/digilib/image/ImageLoaderDocuImage.java Mon Feb 10 17:09:28 2003 +0100 +++ b/servlet/src/digilib/image/ImageLoaderDocuImage.java Thu Feb 27 15:07:29 2003 +0100 @@ -2,7 +2,7 @@ Digital Image Library servlet components - Copyright (C) 2001, 2002 Robert Casties (robcast@mail.berlios.de) + Copyright (C) 2002, 2003 Robert Casties (robcast@mail.berlios.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -20,16 +20,21 @@ package digilib.image; +import java.awt.Rectangle; import java.awt.geom.AffineTransform; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; +import java.awt.image.RescaleOp; import java.io.File; import java.io.IOException; import java.io.OutputStream; +import java.util.Iterator; import javax.imageio.ImageIO; +import javax.imageio.ImageReadParam; +import javax.imageio.ImageReader; +import javax.imageio.stream.ImageInputStream; -import digilib.Utils; import digilib.io.FileOpException; /** Implementation of DocuImage using the ImageLoader API of Java 1.4 and Java2D. */ @@ -37,13 +42,59 @@ private BufferedImage img; - private int scaleInt; + private int interpol; + + // ImageIO image reader + ImageReader reader; - public ImageLoaderDocuImage() { + /* preload is supported. */ + public boolean isPreloadSupported() { + return true; + } + + /* loadSubimage is supported. */ + public boolean isSubimageSupported() { + return true; } - public ImageLoaderDocuImage(Utils u) { - util = u; + public void setQuality(int qual) { + quality = qual; + // setup interpolation quality + if (qual > 0) { + util.dprintln(4, "quality q1"); + interpol = AffineTransformOp.TYPE_BILINEAR; + } else { + util.dprintln(4, "quality q0"); + interpol = AffineTransformOp.TYPE_NEAREST_NEIGHBOR; + } + } + + public int getHeight() { + int h = 0; + try { + if (img == null) { + h = reader.getHeight(0); + } else { + h = img.getHeight(); + } + } catch (IOException e) { + e.printStackTrace(); + } + return h; + } + + public int getWidth() { + int w = 0; + try { + if (img == null) { + w = reader.getWidth(0); + } else { + w = img.getWidth(); + } + } catch (IOException e) { + e.printStackTrace(); + } + return w; } /** @@ -63,6 +114,48 @@ } } + /* Get an ImageReader for the image file. */ + public void preloadImage(File f) throws FileOpException { + System.gc(); + try { + ImageInputStream istream = ImageIO.createImageInputStream(f); + Iterator readers = ImageIO.getImageReaders(istream); + reader = (ImageReader) readers.next(); + reader.setInput(istream); + } catch (IOException e) { + util.dprintln(3, "ERROR(loadImage): unable to load file"); + throw new FileOpException("Unable to load File!" + e); + } + if (reader == null) { + util.dprintln(3, "ERROR(loadImage): unable to load file"); + throw new FileOpException("Unable to load File!"); + } + } + + /* Load an image file into the Object. */ + public void loadSubimage(File f, Rectangle region, int prescale) + throws FileOpException { + System.gc(); + try { + if (reader == null) { + preloadImage(f); + } + // set up reader parameters + ImageReadParam readParam = reader.getDefaultReadParam(); + readParam.setSourceRegion(region); + readParam.setSourceSubsampling(prescale, prescale, 0, 0); + // read image + img = reader.read(0, readParam); + } catch (IOException e) { + util.dprintln(3, "ERROR(loadImage): unable to load file"); + throw new FileOpException("Unable to load File!"); + } + if (img == null) { + util.dprintln(3, "ERROR(loadImage): unable to load file"); + throw new FileOpException("Unable to load File!"); + } + } + /** * write image of type mt to Stream */ @@ -94,26 +187,12 @@ } } - public int getWidth() { - if (img != null) { - return img.getWidth(); - } - return 0; - } - - public int getHeight() { - if (img != null) { - return img.getHeight(); - } - return 0; - } - public void scale(double scale) throws ImageOpException { // setup scale AffineTransformOp scaleOp = new AffineTransformOp( AffineTransform.getScaleInstance(scale, scale), - scaleInt); + interpol); BufferedImage scaledImg = scaleOp.filter(img, null); if (scaledImg == null) { @@ -141,16 +220,102 @@ img = croppedImg; } - public void setQuality(int qual) { - quality = qual; - // setup interpolation quality - if (qual > 0) { - util.dprintln(4, "quality q1"); - scaleInt = AffineTransformOp.TYPE_BILINEAR; + public void enhance(double mult, double add) throws ImageOpException { + /* The number of constants must match the number of bands in the image. + * We only handle 1 (greyscale) or 3 (RGB) bands. + */ + float[] dm; + float[] da; + int ncol = img.getColorModel().getNumColorComponents(); + if (ncol == 3) { + float[] f1 = {(float)mult, (float)mult, (float)mult}; + dm = f1; + float[] f2 = {(float)add, (float)add, (float)add}; + da = f2; + } else if (ncol == 1) { + float[] f1 = {(float)mult}; + dm = f1; + float[] f2 = {(float)add}; + da = f2; } else { - util.dprintln(4, "quality q0"); - scaleInt = AffineTransformOp.TYPE_NEAREST_NEIGHBOR; + util.dprintln(2, "ERROR(enhance): unknown number of color bands ("+ncol+")"); + return; + } + RescaleOp scaleOp = + new RescaleOp( + dm, da, + null); + scaleOp.filter(img, img); + + /* Operation with only one constant should work regardless of the number of bands + * according to the JDK spec. + * Doesn't work on JDK 1.4 for OSX PR10 (at least). + */ + /* + RescaleOp scaleOp = + new RescaleOp( + (float)mult, (float)add, + null); + scaleOp.filter(img, img); + */ + } + + public void rotate(double angle) throws ImageOpException { + // setup rotation + double rangle = Math.toRadians(angle); + double x = getWidth()/2; + double y = getHeight()/2; + AffineTransformOp rotOp = + new AffineTransformOp( + AffineTransform.getRotateInstance(rangle, x, y), + interpol); + BufferedImage rotImg = rotOp.filter(img, null); + + if (rotImg == null) { + util.dprintln(2, "ERROR: error in rotate"); + throw new ImageOpException("Unable to rotate"); } + img = rotImg; + } + + public void mirror(double angle) throws ImageOpException { + // setup mirror + double mx = 1; + double my = 1; + double tx = 0; + double ty = 0; + if (Math.abs(angle - 0) < epsilon) { + // 0 degree + mx = -1; + tx = getWidth(); + } else if (Math.abs(angle - 90) < epsilon) { + // 90 degree + my = -1; + ty = getHeight(); + } else if (Math.abs(angle - 180) < epsilon) { + // 180 degree + mx = -1; + tx = getWidth(); + } else if (Math.abs(angle - 270) < epsilon) { + // 270 degree + my = -1; + ty = getHeight(); + } else if (Math.abs(angle - 360) < epsilon) { + // 360 degree + mx = -1; + tx = getWidth(); + } + AffineTransformOp mirOp = + new AffineTransformOp( + new AffineTransform(mx, 0 , 0, my, tx, ty), + interpol); + BufferedImage mirImg = mirOp.filter(img, null); + + if (mirImg == null) { + util.dprintln(2, "ERROR: error in mirror"); + throw new ImageOpException("Unable to mirror"); + } + img = mirImg; } } diff -r ed1b698b4f0a -r 4e6757e8ccd4 servlet/src/digilib/image/JAIDocuImage.java --- a/servlet/src/digilib/image/JAIDocuImage.java Mon Feb 10 17:09:28 2003 +0100 +++ b/servlet/src/digilib/image/JAIDocuImage.java Thu Feb 27 15:07:29 2003 +0100 @@ -2,7 +2,7 @@ Digital Image Library servlet components - Copyright (C) 2001, 2002 Robert Casties (robcast@mail.berlios.de) + Copyright (C) 2001, 2002, 2003 Robert Casties (robcast@mail.berlios.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -40,9 +40,6 @@ protected RenderedImage img; protected Interpolation interpol = null; - // epsilon for float comparisons - public final double epsilon = 1e-5; - /** Default constructor. */ public JAIDocuImage() { } @@ -203,9 +200,8 @@ RenderedImage rotImg; // convert degrees to radians double rangle = Math.toRadians(angle); - // rotate about the image center - double xoff = img.getWidth() / 2; - double yoff = img.getHeight() / 2; + float x = getWidth()/2; + float y = getHeight()/2; // optimize rotation by right angles TransposeType rotOp = null; @@ -235,8 +231,8 @@ // setup "normal" rotation ParameterBlock param = new ParameterBlock(); param.addSource(img); - param.add((float) xoff); - param.add((float) yoff); + param.add(x); + param.add(y); param.add((float) rangle); param.add(interpol); // hint with border extender @@ -251,9 +247,9 @@ util.dprintln( 3, "ROTATE: " - + xoff + + x + "," - + yoff + + y + ", " + angle + " (" diff -r ed1b698b4f0a -r 4e6757e8ccd4 servlet/src/digilib/image/JAIImageLoaderDocuImage.java --- a/servlet/src/digilib/image/JAIImageLoaderDocuImage.java Mon Feb 10 17:09:28 2003 +0100 +++ b/servlet/src/digilib/image/JAIImageLoaderDocuImage.java Thu Feb 27 15:07:29 2003 +0100 @@ -2,7 +2,7 @@ Digital Image Library servlet components - Copyright (C) 2001, 2002 Robert Casties (robcast@mail.berlios.de) + Copyright (C) 2002, 2003 Robert Casties (robcast@mail.berlios.de) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the @@ -20,13 +20,21 @@ package digilib.image; +import java.awt.Rectangle; import java.awt.image.renderable.ParameterBlock; import java.io.File; import java.io.IOException; import java.io.OutputStream; +import java.util.Iterator; +import javax.imageio.ImageIO; +import javax.imageio.ImageReadParam; +import javax.imageio.ImageReader; +import javax.imageio.stream.ImageInputStream; import javax.media.jai.JAI; +import com.sun.media.jai.operator.ImageReadDescriptor; + import digilib.io.FileOpException; /** DocuImage implementation using the Java Advanced Imaging API and the ImageLoader @@ -34,6 +42,46 @@ */ public class JAIImageLoaderDocuImage extends JAIDocuImage { + // ImageIO image reader + ImageReader reader; + + /* preload is supported. */ + public boolean isPreloadSupported() { + return true; + } + + /* loadSubimage is supported. */ + public boolean isSubimageSupported() { + return true; + } + + public int getHeight() { + int h = 0; + try { + if (img == null) { + h = reader.getHeight(0); + } else { + h = img.getHeight(); + } + } catch (IOException e) { + e.printStackTrace(); + } + return h; + } + + public int getWidth() { + int w = 0; + try { + if (img == null) { + w = reader.getWidth(0); + } else { + w = img.getWidth(); + } + } catch (IOException e) { + e.printStackTrace(); + } + return w; + } /* Load an image file into the Object. */ public void loadImage(File f) throws FileOpException { @@ -45,6 +93,62 @@ } } + /* Load an image file into the Object. */ + public void loadSubimage(File f, Rectangle region, int prescale) + throws FileOpException { + System.gc(); + try { + if (reader == null) { + preloadImage(f); + } + ImageInputStream istream = (ImageInputStream) reader.getInput(); + ImageReadParam readParam = reader.getDefaultReadParam(); + readParam.setSourceRegion(region); + readParam.setSourceSubsampling(prescale, prescale, 0, 0); + /* Parameter for ImageRead operation: + Input, ImageChoice, ReadMetadata, ReadThumbnails, VerifyInput, + Listeners, Locale, ReadParam, Reader, RenderingHints + */ + img = + ImageReadDescriptor.create( + istream, + new Integer(0), + Boolean.TRUE, + Boolean.FALSE, + Boolean.FALSE, + null, + null, + readParam, + reader, + null); + } catch (IOException e) { + util.dprintln(3, "ERROR(loadImage): unable to load file"); + throw new FileOpException("Unable to load File!"); + } + if (img == null) { + util.dprintln(3, "ERROR(loadImage): unable to load file"); + throw new FileOpException("Unable to load File!"); + } + } + + /* Get an ImageReader for the image file. */ + public void preloadImage(File f) throws FileOpException { + System.gc(); + try { + ImageInputStream istream = ImageIO.createImageInputStream(f); + Iterator readers = ImageIO.getImageReaders(istream); + reader = (ImageReader) readers.next(); + reader.setInput(istream); + } catch (IOException e) { + util.dprintln(3, "ERROR(loadImage): unable to load file"); + throw new FileOpException("Unable to load File!" + e); + } + if (reader == null) { + util.dprintln(3, "ERROR(loadImage): unable to load file"); + throw new FileOpException("Unable to load File!"); + } + } + /* Write the current image to an OutputStream. */ public void writeImage(String mt, OutputStream ostream) throws FileOpException { diff -r ed1b698b4f0a -r 4e6757e8ccd4 servlet/src/digilib/io/FileOps.java --- a/servlet/src/digilib/io/FileOps.java Mon Feb 10 17:09:28 2003 +0100 +++ b/servlet/src/digilib/io/FileOps.java Thu Feb 27 15:07:29 2003 +0100 @@ -1,4 +1,4 @@ -/* FileOps -- Utility class for file operations +/* FileOps -- Utility class for file operations Digital Image Library servlet components diff -r ed1b698b4f0a -r 4e6757e8ccd4 servlet/src/digilib/servlet/DigilibConfiguration.java --- a/servlet/src/digilib/servlet/DigilibConfiguration.java Mon Feb 10 17:09:28 2003 +0100 +++ b/servlet/src/digilib/servlet/DigilibConfiguration.java Thu Feb 27 15:07:29 2003 +0100 @@ -77,7 +77,7 @@ private int debugLevel = 5; private String debugLevelParam = "debug-level"; // Utils instance - private Utils util = new Utils(); + private Utils util = new Utils(debugLevel); // HashTable for parameters private Hashtable confTable = null; // Type of DocuImage instance @@ -86,6 +86,9 @@ // part of URL used to indicate authorized access private String authURLPath = "authenticated/"; private String AuthURLPathParam = "auth-url-path"; + // degree of subsampling on image load + private float subsampleDistance = 0; + private String subsampleDistanceParam = "subsample-distance"; /** Constructor taking a ServletConfig. * Reads the config file location from an init parameter and loads the @@ -117,7 +120,7 @@ XMLListLoader lilo = new XMLListLoader("digilib-config", "parameter", "name", "value"); confTable = lilo.loadURL(f.toURL().toString()); - dlConfPath = fn; + dlConfPath = f.getCanonicalPath(); /* * read parameters @@ -125,6 +128,7 @@ // debugLevel debugLevel = tryToGetInitParam(debugLevelParam, debugLevel); + util.setDebugLevel(debugLevel); // errorImgFileName errorImgFileName = tryToGetInitParam(errorImgParam, errorImgFileName); // denyImgFileName @@ -151,6 +155,8 @@ authConfPath = tryToGetInitParam(authConfParam, authConfPath); authOp = new XMLAuthOps(util, authConfPath); } + // subsampleDistance + subsampleDistance = tryToGetInitParam(subsampleDistanceParam, subsampleDistance); } /** @@ -455,4 +461,19 @@ return dlConfPath; } + /** + * @return float + */ + public float getSubsampleDistance() { + return subsampleDistance; + } + + /** + * Sets the subsampleDistance. + * @param subsampleDistance The subsampleDistance to set + */ + public void setSubsampleDistance(float subsampleDistance) { + this.subsampleDistance = subsampleDistance; + } + } diff -r ed1b698b4f0a -r 4e6757e8ccd4 servlet/src/digilib/servlet/Scaler.java --- a/servlet/src/digilib/servlet/Scaler.java Mon Feb 10 17:09:28 2003 +0100 +++ b/servlet/src/digilib/servlet/Scaler.java Thu Feb 27 15:07:29 2003 +0100 @@ -52,7 +52,7 @@ public class Scaler extends HttpServlet { // digilib servlet version (for all components) - public static final String dlVersion = "1.6b"; + public static final String dlVersion = "1.6b3"; // Utils instance with debuglevel Utils util; @@ -331,7 +331,12 @@ } // finally load the file - docuImage.loadImage(fileToLoad); + if (docuImage.isPreloadSupported()) { + // only preload if supported + docuImage.preloadImage(fileToLoad); + } else { + docuImage.loadImage(fileToLoad); + } /* * crop and scale the image @@ -348,20 +353,21 @@ // coordinates using Java2D // image size - Rectangle2D imgBounds = new Rectangle2D.Double(0, 0, imgWidth, imgHeight); + Rectangle2D imgBounds = + new Rectangle2D.Double(0, 0, imgWidth, imgHeight); // user window area in 4-point form (ul, ur, ll, lr) - Point2D[] userAreaC = { - new Point2D.Double(paramWX, paramWY), - new Point2D.Double(paramWX + paramWW, paramWY), - new Point2D.Double(paramWX, paramWY + paramWH), - new Point2D.Double(paramWX + paramWW, paramWY + paramWH) - }; + Point2D[] userAreaC = + { + new Point2D.Double(paramWX, paramWY), + new Point2D.Double(paramWX + paramWW, paramWY), + new Point2D.Double(paramWX, paramWY + paramWH), + new Point2D.Double(paramWX + paramWW, paramWY + paramWH)}; // transformation from relative [0,1] to image coordinates. AffineTransform imgTrafo = new AffineTransform(); imgTrafo.scale(imgWidth, imgHeight); // rotate coordinates //imgTrafo.rotate(Math.toRadians(-paramROT)); - + // coordinates and scaling double areaXoff; double areaYoff; @@ -371,27 +377,68 @@ double scaleY; double scaleXY; + /* if (scaleToFit) { + // calculate absolute from relative coordinates + areaXoff = paramWX * imgWidth; + areaYoff = paramWY * imgHeight; + areaWidth = paramWW * imgWidth; + areaHeight = paramWH * imgHeight; + // calculate scaling factors + scaleX = paramDW / areaWidth * paramWS; + scaleY = paramDH / areaHeight * paramWS; + scaleXY = (scaleX > scaleY) ? scaleY : scaleX; + } else { + // crop to fit + // calculate absolute from relative coordinates + areaXoff = paramWX * imgWidth; + areaYoff = paramWY * imgHeight; + areaWidth = paramDW; + areaHeight = paramDH; + // calculate scaling factors + scaleX = 1f; + scaleY = 1f; + scaleXY = 1f; + } + + util.dprintln( + 1, + "Scale " + + scaleXY + + "(" + + scaleX + + "," + + scaleY + + ") on " + + areaXoff + + "," + + areaYoff + + " " + + areaWidth + + "x" + + areaHeight); + */ + // Java2D + // area in image pixel coordinates + Point2D[] imgAreaC = { null, null, null, null }; + // transform user coordinate area to image coordinate area + imgTrafo.transform(userAreaC, 0, imgAreaC, 0, 4); + areaXoff = imgAreaC[0].getX(); + areaYoff = imgAreaC[0].getY(); + // calculate scaling factors if (scaleToFit) { - // calculate absolute from relative coordinates - areaXoff = paramWX * imgWidth; - areaYoff = paramWY * imgHeight; - areaWidth = paramWW * imgWidth; - areaHeight = paramWH * imgHeight; - // calculate scaling factors + areaWidth = imgAreaC[0].distance(imgAreaC[1]); + areaHeight = imgAreaC[0].distance(imgAreaC[2]); scaleX = paramDW / areaWidth * paramWS; scaleY = paramDH / areaHeight * paramWS; scaleXY = (scaleX > scaleY) ? scaleY : scaleX; } else { // crop to fit - // calculate absolute from relative coordinates - areaXoff = paramWX * imgWidth; - areaYoff = paramWY * imgHeight; - areaWidth = paramDW; - areaHeight = paramDH; - // calculate scaling factors + areaWidth = paramDW * paramWS; + areaHeight = paramDH * paramWS; scaleX = 1f; scaleY = 1f; scaleXY = 1f; + } util.dprintln( @@ -411,42 +458,6 @@ + "x" + areaHeight); - // Java2D - Point2D[] imgAreaC = { null, null, null, null }; - - imgTrafo.transform(userAreaC, 0, imgAreaC, 0, 4); - areaXoff = imgAreaC[0].getX(); - areaYoff = imgAreaC[0].getY(); - areaWidth = imgAreaC[0].distance(imgAreaC[1]); - areaHeight = imgAreaC[0].distance(imgAreaC[2]); - Rectangle2D imgArea = - new Rectangle2D.Double( - areaXoff, - areaYoff, - areaWidth, - areaHeight); - // calculate scaling factors - scaleX = paramDW / areaWidth * paramWS; - scaleY = paramDH / areaHeight * paramWS; - scaleXY = (scaleX > scaleY) ? scaleY : scaleX; - - util.dprintln( - 1, - "Scale " - + scaleXY - + "(" - + scaleX - + "," - + scaleY - + ") on " - + areaXoff - + "," - + areaYoff - + " " - + areaWidth - + "x" - + areaHeight); - // clip area at the image border /* areaWidth = (areaXoff + areaWidth > imgWidth) @@ -457,13 +468,22 @@ ? imgHeight - areaYoff : areaHeight; */ + + // create new rectangle from coordinates + Rectangle2D imgArea = + new Rectangle2D.Double( + areaXoff, + areaYoff, + areaWidth, + areaHeight); + // clip area at the image border imgArea = imgArea.createIntersection(imgBounds); areaWidth = imgArea.getWidth(); areaHeight = imgArea.getHeight(); util.dprintln( 2, - "cropped: " + "crop: " + areaXoff + "," + areaYoff @@ -481,14 +501,48 @@ throw new ImageOpException("Invalid scale parameter set!"); } - // crop and scale image - docuImage.crop( - (int) areaXoff, - (int) areaYoff, - (int) areaWidth, - (int) areaHeight); + /* + * crop and scale image + */ + + // use subimage loading if possible + if (docuImage.isSubimageSupported()) { + System.out.println( + "Subimage: scale " + scaleXY + " = " + (1 / scaleXY)); + double subf = 1d; + double subsamp = 1d; + if (scaleXY < 1) { + subf = 1 / scaleXY; + subsamp = Math.floor(subf); + scaleXY = subsamp / subf; + System.out.println( + "Using subsampling: " + subsamp + " rest " + scaleXY); + } - docuImage.scale(scaleXY); + docuImage.loadSubimage( + fileToLoad, + imgArea.getBounds(), + (int) subsamp); + + System.out.println( + "SUBSAMP: " + + subsamp + + " -> " + + docuImage.getWidth() + + "x" + + docuImage.getHeight()); + + docuImage.scale(scaleXY); + + } else { + docuImage.crop( + (int) areaXoff, + (int) areaYoff, + (int) areaWidth, + (int) areaHeight); + + docuImage.scale(scaleXY); + } // mirror image if (doMirror) { @@ -497,12 +551,13 @@ // rotate image (first shot :-) if (paramROT != 0) { - docuImage.rotate(paramROT); + docuImage.rotate( + paramROT); } // contrast and brightness enhancement if ((paramCONT != 0) || (paramBRGT != 0)) { - double mult = Math.pow(2, paramCONT); + double mult = Math.pow(2, paramCONT); docuImage.enhance(mult, paramBRGT); }