changeset 298:1ecaf9c1fd8a

Servlet version 1.5.0b -- the beginning of the next generation :-) - code restructuring to improve scaleability - new Initialiser servlet that must be run first - image transformation work moved to DigilibImageWorker class - Maximum number of concurrent threads limited by Semaphore - old JIMI toolkit implementation removed
author robcast
date Sun, 24 Oct 2004 20:23:50 +0200
parents b74c914b48a9
children 0ddfc57a79af
files servlet/src/digilib/servlet/Scaler.java
diffstat 1 files changed, 205 insertions(+), 373 deletions(-) [+]
line wrap: on
line diff
--- a/servlet/src/digilib/servlet/Scaler.java	Sun Oct 24 20:23:50 2004 +0200
+++ b/servlet/src/digilib/servlet/Scaler.java	Sun Oct 24 20:23:50 2004 +0200
@@ -39,7 +39,6 @@
 
 import digilib.auth.AuthOpException;
 import digilib.auth.AuthOps;
-import digilib.image.DocuImage;
 import digilib.image.ImageOpException;
 import digilib.image.ImageOps;
 import digilib.image.ImageSize;
@@ -59,41 +58,59 @@
 
 	private static final long serialVersionUID = -325080527268912852L;
 
-	// digilib servlet version (for all components)
-	public static final String dlVersion = "1.22b2";
+	/** digilib servlet version (for all components) */
+	public static final String dlVersion = "1.5.0b";
+
+	/** logger for accounting requests */
+	private static Logger accountlog = Logger.getLogger("account.request");
+	
+	/** gengeral logger for this class */
+	private static Logger logger = Logger.getLogger("digilib.servlet");
+	
+	/** logger for authentication related */
+	private static Logger authlog = Logger.getLogger("digilib.auth");
 
-	// logger for accounting requests
-	Logger accountlog = Logger.getLogger("account.request");
-	// gengeral logger for this class
-	Logger logger = Logger.getLogger("digilib.servlet");
-	// logger for authentication related
-	Logger authlog = Logger.getLogger("digilib.auth");
-	
-	
-	// AuthOps instance
-	AuthOps authOp;
-	// DocuDirCache instance
+	/** general error code */
+	public static final int ERROR_UNKNOWN = 0;
+
+	/** error code for authentication error */
+	public static final int ERROR_AUTH = 1;
+
+	/** error code for file operation error */
+	public static final int ERROR_FILE = 2;
+
+	/** error code for image operation error */
+	public static final int ERROR_IMAGE = 3;
+
+	/** DocuDirCache instance */
 	DocuDirCache dirCache;
 
-	// deny image file
+	/** authentication error image file */
 	File denyImgFile;
-	// error image file
+
+	/** image error image file */
 	File errorImgFile;
-	// subsampling before scaling
+
+	/** subsampling before scaling */
 	float minSubsample = 2f;
-	// send files as is?
+
+	/** send files as is? */
 	boolean sendFileAllowed = true;
-	// default scaling quality
+
+	/** default scaling quality */
 	int defaultQuality = 1;
 
-	// DigilibConfiguration instance
+	/** DigilibConfiguration instance */
 	DigilibConfiguration dlConfig;
 
-	// use authorization database
-	boolean useAuthentication = true;
+	/** use authorization database */
+	boolean useAuthorization = true;
+
+	/** AuthOps instance */
+	AuthOps authOp;
 
 	// EXPRIMENTAL
-	// try to enlarge cropping area for "oblique" angles
+	/** try to enlarge cropping area for "oblique" angles */
 	boolean wholeRotArea = false;
 
 	/**
@@ -104,42 +121,31 @@
 	public void init(ServletConfig config) throws ServletException {
 		super.init(config);
 
-		// Debuggin!
-		//TCTool tctool = new TCTool();
-
-		System.out.println(
-			"***** Digital Image Library Image Scaler Servlet (version "
-				+ dlVersion
-				+ ") *****");
+		System.out
+				.println("***** Digital Image Library Image Scaler Servlet (version "
+						+ dlVersion + ") *****");
+		// say hello in the log file
+		logger
+				.info("***** Digital Image Library Image Scaler Servlet (version "
+						+ dlVersion + ") *****");
 
 		// get our ServletContext
 		ServletContext context = config.getServletContext();
 		// see if there is a Configuration instance
-		dlConfig =
-			(DigilibConfiguration) context.getAttribute(
-				"digilib.servlet.configuration");
+		dlConfig = (DigilibConfiguration) context
+				.getAttribute("digilib.servlet.configuration");
 		if (dlConfig == null) {
-			// create new Configuration
-			try {
-				dlConfig = new DigilibConfiguration(config);
-				context.setAttribute("digilib.servlet.configuration", dlConfig);
-			} catch (Exception e) {
-				throw new ServletException(e);
+			// no Configuration
+			throw new ServletException("No Configuration!");
 			}
-		}
-		// say hello in the log file
-		logger.info("***** Digital Image Library Image Scaler Servlet (version "
-				+ dlVersion
-				+ ") *****");
 		// set our AuthOps
-		useAuthentication = dlConfig.getAsBoolean("use-authorization");
-		// AuthOps instance
+		useAuthorization = dlConfig.getAsBoolean("use-authorization");
 		authOp = (AuthOps) dlConfig.getValue("servlet.auth.op");
 
 		// DocuDirCache instance
 		dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache");
-		denyImgFile = new File(dlConfig.getAsString("denied-image"));
-		errorImgFile = new File(dlConfig.getAsString("error-image"));
+		denyImgFile = (File) dlConfig.getValue("denied-image");
+		errorImgFile = (File) dlConfig.getValue("error-image");
 		sendFileAllowed = dlConfig.getAsBoolean("sendfile-allowed");
 		minSubsample = dlConfig.getAsFloat("subsample-minimum");
 		defaultQuality = dlConfig.getAsInt("default-quality");
@@ -160,9 +166,7 @@
 	}
 
 	/** Process the HTTP Post request */
-	public void doPost(
-		HttpServletRequest request,
-		HttpServletResponse response)
+	public void doPost(HttpServletRequest request, HttpServletResponse response)
 		throws ServletException, IOException {
 		accountlog.info("POST from "+request.getRemoteAddr());
 		// create new request with defaults
@@ -176,10 +180,12 @@
 	}
 
 	/** main request handler. */
-	void processRequest(
-		HttpServletRequest request,
-		HttpServletResponse response)
-		throws ServletException, IOException {
+	void processRequest(HttpServletRequest request, HttpServletResponse response)
+			throws ServletException {
+
+		if (dlConfig == null) {
+			throw new ServletException("ERROR: No Configuration!");
+		}
 
 		accountlog.debug("request: "+request.getQueryString());
 		logger.debug("request: "+request.getQueryString());
@@ -210,32 +216,32 @@
 		// mirror the image
 		boolean doMirror = false;
 		// angle of mirror axis
-		double mirrorAngle = 0;
+		float mirrorAngle = 0;
 		// original (hires) image resolution
-		double origResX = 0;
-		double origResY = 0;
+		float origResX = 0;
+		float origResY = 0;
 
 		/* request parameters */
 
-		DigilibRequest dlRequest =
-			(DigilibRequest) request.getAttribute("digilib.servlet.request");
+		DigilibRequest dlRequest = (DigilibRequest) request
+				.getAttribute("digilib.servlet.request");
 
 		// destination image width
 		int paramDW = dlRequest.getAsInt("dw");
 		// destination image height
 		int paramDH = dlRequest.getAsInt("dh");
 		// relative area x_offset (0..1)
-		double paramWX = dlRequest.getAsFloat("wx");
+		float paramWX = dlRequest.getAsFloat("wx");
 		// relative area y_offset
-		double paramWY = dlRequest.getAsFloat("wy");
+		float paramWY = dlRequest.getAsFloat("wy");
 		// relative area width (0..1)
-		double paramWW = dlRequest.getAsFloat("ww");
+		float paramWW = dlRequest.getAsFloat("ww");
 		// relative area height
-		double paramWH = dlRequest.getAsFloat("wh");
+		float paramWH = dlRequest.getAsFloat("wh");
 		// scale factor (additional to dw/width, dh/height)
-		double paramWS = dlRequest.getAsFloat("ws");
+		float paramWS = dlRequest.getAsFloat("ws");
 		// rotation angle
-		double paramROT = dlRequest.getAsFloat("rot");
+		float paramROT = dlRequest.getAsFloat("rot");
 		// contrast enhancement
 		float paramCONT = dlRequest.getAsFloat("cont");
 		// brightness enhancement
@@ -315,8 +321,10 @@
 		// check with the maximum allowed size (if set)
 		int maxImgSize = dlConfig.getAsInt("max-image-size");
 		if (maxImgSize > 0) {
-			paramDW = (paramDW * paramWS > maxImgSize) ? (int)(maxImgSize / paramWS) : paramDW;
-			paramDH = (paramDH * paramWS > maxImgSize) ? (int)(maxImgSize / paramWS) : paramDH;
+			paramDW = (paramDW * paramWS > maxImgSize) ? (int) (maxImgSize / paramWS)
+					: paramDW;
+			paramDH = (paramDH * paramWS > maxImgSize) ? (int) (maxImgSize / paramWS)
+					: paramDH;
 		}
 		
 		//"big" try for all file/image actions
@@ -331,54 +339,37 @@
 			String loadPathName = dlRequest.getFilePath();
 
 			/* check permissions */
-			if (useAuthentication) {
+			if (useAuthorization) {
 				// get a list of required roles (empty if no restrictions)
 				List rolesRequired = authOp.rolesForPath(loadPathName, request);
 				if (rolesRequired != null) {
-					authlog.info("Role required: " + rolesRequired);
-					authlog.info("User: " + request.getRemoteUser());
+					authlog.debug("Role required: " + rolesRequired);
+					authlog.debug("User: " + request.getRemoteUser());
 					// is the current request/user authorized?
 					if (!authOp.isRoleAuthorized(rolesRequired, request)) {
 						// send deny answer and abort
-						authlog.error("ERROR: access denied!");
-						if (errorMsgHtml) {
-							ServletOps.htmlMessage(
-								"ERROR: Unauthorized access!",
-								response);
-						} else {
-							ServletOps.sendFile(denyImgFile, null, response);
+						throw new AuthOpException();
 						}
-						return;
 					}
 				}
-			}
 
 			// find the file(set)
 			ImageFile fileToLoad;
-			fileset =
-				(ImageFileset) dirCache.getFile(
-					loadPathName,
-					dlRequest.getAsInt("pn"),
-					FileOps.CLASS_IMAGE);
+			fileset = (ImageFileset) dirCache.getFile(loadPathName, dlRequest
+					.getAsInt("pn"), FileOps.CLASS_IMAGE);
 			if (fileset == null) {
-				throw new FileOpException(
-					"File "
-						+ loadPathName
-						+ "("
-						+ dlRequest.getAsInt("pn")
-						+ ") not found.");
+				throw new FileOpException("File " + loadPathName + "("
+						+ dlRequest.getAsInt("pn") + ") not found.");
 			}
 
 			/* calculate expected source image size */
 			ImageSize expectedSourceSize = new ImageSize();
 			if (scaleToFit) {
-				double scale = (1 / Math.min(paramWW, paramWH)) * paramWS;
-				expectedSourceSize.setSize(
-					(int) (paramDW * scale),
+				float scale = (1 / Math.min(paramWW, paramWH)) * paramWS;
+				expectedSourceSize.setSize((int) (paramDW * scale),
 					(int) (paramDH * scale));
 			} else {
-				expectedSourceSize.setSize(
-					(int) (paramDW * paramWS),
+				expectedSourceSize.setSize((int) (paramDW * paramWS),
 					(int) (paramDH * paramWS));
 			}
 
@@ -388,22 +379,20 @@
 				fileToLoad = fileset.getBiggest();
 			} else if (loresOnly) {
 				// enforced lores uses next smaller resolution
-				fileToLoad =
-					fileset.getNextSmaller(expectedSourceSize);
+				fileToLoad = fileset.getNextSmaller(expectedSourceSize);
 				if (fileToLoad == null) {
 					// this is the smallest we have
 					fileToLoad = fileset.getSmallest();
 				}
 			} else {
 				// autores: use next higher resolution
-				fileToLoad =
-					fileset.getNextBigger(expectedSourceSize);
+				fileToLoad = fileset.getNextBigger(expectedSourceSize);
 				if (fileToLoad == null) {
 					// this is the highest we have
 					fileToLoad = fileset.getBiggest();
 				}
 			}
-			logger.info("Loading: " + fileToLoad.getFile());
+			logger.info("Planning to load: " + fileToLoad.getFile());
 
 			/*
 			 * send the image if its mo=(raw)file
@@ -418,8 +407,7 @@
 					logger.debug("Sending RAW File as is.");
 					ServletOps.sendFile(fileToLoad.getFile(), mt, response);
 					logger.info("Done in "
-							+ (System.currentTimeMillis() - startTime)
-							+ "ms");
+							+ (System.currentTimeMillis() - startTime) + "ms");
 					return;
 				}
 			}
@@ -437,7 +425,8 @@
 				}
 
 				if ((paramDDPIX == 0) || (paramDDPIY == 0)) {
-					throw new ImageOpException("Missing display DPI information!");
+					throw new ImageOpException(
+							"Missing display DPI information!");
 				}
 			}
 
@@ -451,53 +440,37 @@
 			ImageSize imgSize = fileToLoad.getSize();
 
 			// decide if the image can be sent as is
-			boolean mimetypeSendable =
-				mimeType.equals("image/jpeg")
+			boolean mimetypeSendable = mimeType.equals("image/jpeg")
 					|| mimeType.equals("image/png")
 					|| mimeType.equals("image/gif");
-			boolean imagoOptions =
-				dlRequest.hasOption("mo", "hmir")
-					|| dlRequest.hasOption("mo", "vmir")
-					|| (paramROT != 0)
-					|| (paramRGBM != null)
-					|| (paramRGBA != null)
-					|| (paramCONT != 0)
-					|| (paramBRGT != 0);
+			boolean imagoOptions = dlRequest.hasOption("mo", "hmir")
+					|| dlRequest.hasOption("mo", "vmir") || (paramROT != 0)
+					|| (paramRGBM != null) || (paramRGBA != null)
+					|| (paramCONT != 0) || (paramBRGT != 0);
 			boolean imageSendable = mimetypeSendable && !imagoOptions;
 
 			/*
-			 * if not autoRes and image smaller than requested size then send
-			 * as is. if autoRes and image has requested size then send as is.
-			 * if not autoScale and not scaleToFit nor cropToFit then send as
-			 * is (mo=file)
+			 * if not autoRes and image smaller than requested size then send as
+			 * is. if autoRes and image has requested size then send as is. if
+			 * not autoScale and not scaleToFit nor cropToFit then send as is
+			 * (mo=file)
 			 */
 			if (imageSendable
-				&& ((loresOnly
-					&& fileToLoad.getSize().isSmallerThan(expectedSourceSize))
-					|| (!(loresOnly || hiresOnly)
-						&& fileToLoad.getSize().fitsIn(expectedSourceSize)))) {
+					&& ((loresOnly && fileToLoad.getSize().isSmallerThan(
+							expectedSourceSize)) || (!(loresOnly || hiresOnly) && fileToLoad
+							.getSize().fitsIn(expectedSourceSize)))) {
 
 				logger.debug("Sending File as is.");
 
 				ServletOps.sendFile(fileToLoad.getFile(), null, response);
 
 				logger.info("Done in "
-						+ (System.currentTimeMillis() - startTime)
-						+ "ms");
+						+ (System.currentTimeMillis() - startTime) + "ms");
 				return;
 			}
 
-			// new DocuImage instance
-			DocuImage docuImage = dlConfig.getDocuImageInstance();
-			if (docuImage == null) {
-				throw new ImageOpException("Unable to load DocuImage class!");
-			}
-
-			// set interpolation quality
-			docuImage.setQuality(scaleQual);
-
 			// set missing dw or dh from aspect ratio
-			double imgAspect = fileToLoad.getAspect();
+			float imgAspect = fileToLoad.getAspect();
 			if (paramDW == 0) {
 				paramDW = (int) Math.round(paramDH * imgAspect);
 			} else if (paramDH == 0) {
@@ -506,42 +479,38 @@
 
 			/* crop and scale the image */
 
-			logger.debug("IMG: " + imgSize.getWidth() + "x" + imgSize.getHeight());
-			logger.debug("time " + (System.currentTimeMillis() - startTime) + "ms");
+			logger.debug("IMG: " + imgSize.getWidth() + "x"
+					+ imgSize.getHeight());
+			logger.debug("time " + (System.currentTimeMillis() - startTime)
+					+ "ms");
 
 			// coordinates and scaling
-			double areaXoff;
-			double areaYoff;
-			double areaWidth;
-			double areaHeight;
-			double scaleX;
-			double scaleY;
-			double scaleXY;
+			float areaXoff;
+			float areaYoff;
+			float areaWidth;
+			float areaHeight;
+			float scaleX;
+			float scaleY;
+			float scaleXY;
 
 			// coordinates using Java2D
 			// image size in pixels
-			Rectangle2D imgBounds =
-				new Rectangle2D.Double(
-					0,
-					0,
-					imgSize.getWidth(),
-					imgSize.getHeight());
+			Rectangle2D imgBounds = new Rectangle2D.Float(0, 0, imgSize
+					.getWidth(), imgSize.getHeight());
 			// user window area in [0,1] coordinates
-			Rectangle2D relUserArea =
-				new Rectangle2D.Double(paramWX, paramWY, paramWW, paramWH);
+			Rectangle2D relUserArea = new Rectangle2D.Float(paramWX, paramWY,
+					paramWW, paramWH);
 			// transform from relative [0,1] to image coordinates.
-			AffineTransform imgTrafo =
-				AffineTransform.getScaleInstance(
-					imgSize.getWidth(),
-					imgSize.getHeight());
+			AffineTransform imgTrafo = AffineTransform.getScaleInstance(imgSize
+					.getWidth(), imgSize.getHeight());
 			// transform user coordinate area to image coordinate area
-			Rectangle2D userImgArea =
-				imgTrafo.createTransformedShape(relUserArea).getBounds2D();
+			Rectangle2D userImgArea = imgTrafo.createTransformedShape(
+					relUserArea).getBounds2D();
 
 			// calculate scaling factors based on inner user area
 			if (scaleToFit) {
-				areaWidth = userImgArea.getWidth();
-				areaHeight = userImgArea.getHeight();
+				areaWidth = (float) userImgArea.getWidth();
+				areaHeight = (float) userImgArea.getHeight();
 				scaleX = paramDW / areaWidth * paramWS;
 				scaleY = paramDH / areaHeight * paramWS;
 				scaleXY = (scaleX > scaleY) ? scaleY : scaleX;
@@ -554,21 +523,15 @@
 				areaWidth = paramDW / scaleXY * paramWS;
 				areaHeight = paramDH / scaleXY * paramWS;
 				// reset user area size
-				userImgArea.setRect(
-					userImgArea.getX(),
-					userImgArea.getY(),
-					areaWidth,
-					areaHeight);
+				userImgArea.setRect(userImgArea.getX(), userImgArea.getY(),
+						areaWidth, areaHeight);
 			} else {
 				// crop to fit
 				areaWidth = paramDW * paramWS;
 				areaHeight = paramDH * paramWS;
 				// reset user area size
-				userImgArea.setRect(
-					userImgArea.getX(),
-					userImgArea.getY(),
-					areaWidth,
-					areaHeight);
+				userImgArea.setRect(userImgArea.getX(), userImgArea.getY(),
+						areaWidth, areaHeight);
 				scaleX = 1f;
 				scaleY = 1f;
 				scaleXY = 1f;
@@ -582,243 +545,112 @@
 					try {
 						// rotate user area coordinates around center of user
 						// area
-						AffineTransform rotTrafo =
-							AffineTransform.getRotateInstance(
-								Math.toRadians(paramROT),
-								userImgArea.getCenterX(),
-								userImgArea.getCenterY());
+						AffineTransform rotTrafo = AffineTransform
+								.getRotateInstance(Math.toRadians(paramROT),
+										userImgArea.getCenterX(), userImgArea
+												.getCenterY());
 						// get bounds from rotated end position
-						innerUserImgArea =
-							rotTrafo
-								.createTransformedShape(userImgArea)
-								.getBounds2D();
+						innerUserImgArea = rotTrafo.createTransformedShape(
+								userImgArea).getBounds2D();
 						// get bounds from back-rotated bounds
-						outerUserImgArea =
-							rotTrafo
-								.createInverse()
+						outerUserImgArea = rotTrafo.createInverse()
 								.createTransformedShape(innerUserImgArea)
 								.getBounds2D();
 					} catch (NoninvertibleTransformException e1) {
 						// this shouldn't happen anyway
-						e1.printStackTrace();
+						logger.error(e1);
 					}
 				}
 			}
 
-			logger.debug("Scale "
-					+ scaleXY
-					+ "("
-					+ scaleX
-					+ ","
-					+ scaleY
-					+ ") on "
-					+ outerUserImgArea);
+			logger.debug("Scale " + scaleXY + "(" + scaleX + "," + scaleY
+					+ ") on " + outerUserImgArea);
 
 			// clip area at the image border
 			outerUserImgArea = outerUserImgArea.createIntersection(imgBounds);
 
-			areaWidth = outerUserImgArea.getWidth();
-			areaHeight = outerUserImgArea.getHeight();
-			areaXoff = outerUserImgArea.getX();
-			areaYoff = outerUserImgArea.getY();
-
-			logger.debug("crop: "
-					+ areaXoff
-					+ ","
-					+ areaYoff
-					+ " "
-					+ areaWidth
-					+ "x"
-					+ areaHeight);
-
 			// check image parameters sanity
-			if ((areaWidth < 1)
-				|| (areaHeight < 1)
-				|| (scaleXY * areaWidth < 2)
-				|| (scaleXY * areaHeight < 2)) {
+			if ((outerUserImgArea.getWidth() < 1)
+					|| (outerUserImgArea.getHeight() < 1)
+					|| (scaleXY * outerUserImgArea.getWidth() < 2)
+					|| (scaleXY * outerUserImgArea.getHeight() < 2)) {
 				logger.error("ERROR: invalid scale parameter set!");
 				throw new ImageOpException("Invalid scale parameter set!");
 			}
 
-			/* crop and scale image */
-
-			// use subimage loading if possible
-			if (docuImage.isSubimageSupported()) {
-				logger.debug("Subimage: scale " + scaleXY + " = " + (1 / scaleXY));
-				double subf = 1d;
-				double subsamp = 1d;
-				if (scaleXY < 1) {
-					subf = 1 / scaleXY;
-					// for higher quality reduce subsample factor by
-					// minSubsample
-					if (scaleQual > 0) {
-						subsamp = Math.max(Math.floor(subf / minSubsample), 1d);
-					} else {
-						subsamp = Math.floor(subf);
-					}
-					scaleXY = subsamp / subf;
-					logger.debug("Using subsampling: " + subsamp + " rest " + scaleXY);
-				}
-
-				docuImage.loadSubimage(
-					fileToLoad,
-					outerUserImgArea.getBounds(),
-					(int) subsamp);
+			/*
+			 * submit the image worker job
+			 */
 
-				logger.debug("SUBSAMP: "
-						+ subsamp
-						+ " -> "
-						+ docuImage.getWidth()
-						+ "x"
-						+ docuImage.getHeight());
-
-				docuImage.scale(scaleXY, scaleXY);
+			DigilibWorker job = new DigilibImageWorker(dlConfig, response,
+					mimeType, scaleQual, dlRequest, paramROT, paramCONT,
+					paramBRGT, paramRGBM, paramRGBA, fileToLoad, scaleXY,
+					outerUserImgArea, innerUserImgArea, minSubsample,
+					wholeRotArea);
 
-			} else {
-				// else load and crop the whole file
-				docuImage.loadImage(fileToLoad);
-				docuImage.crop(
-					(int) areaXoff,
-					(int) areaYoff,
-					(int) areaWidth,
-					(int) areaHeight);
-
-				docuImage.scale(scaleXY, scaleXY);
-			}
-
-			// mirror image
-			// operation mode: "hmir": mirror horizontally, "vmir": mirror
-			// vertically
-			if (dlRequest.hasOption("mo", "hmir")) {
-				docuImage.mirror(0);
-			}
-			if (dlRequest.hasOption("mo", "vmir")) {
-				docuImage.mirror(90);
+			job.run();
+			if (job.hasError()) {
+				throw new ImageOpException(job.getError().toString());
 			}
 
-			// rotate image
-			if (paramROT != 0d) {
-				docuImage.rotate(paramROT);
-				if (wholeRotArea) {
-					// crop to the inner bounding box
-					double xcrop =
-						docuImage.getWidth()
-							- innerUserImgArea.getWidth() * scaleXY;
-					double ycrop =
-						docuImage.getHeight()
-							- innerUserImgArea.getHeight() * scaleXY;
-					if ((xcrop > 0) || (ycrop > 0)) {
-						// only crop smaller
-						xcrop = (xcrop > 0) ? xcrop : 0;
-						ycrop = (ycrop > 0) ? ycrop : 0;
-						// crop image
-						docuImage.crop(
-							(int) (xcrop / 2),
-							(int) (ycrop / 2),
-							(int) (docuImage.getWidth() - xcrop),
-							(int) (docuImage.getHeight() - ycrop));
-					}
-				}
-
-			}
-
-			// color modification
-			if ((paramRGBM != null) || (paramRGBA != null)) {
-				// make shure we actually have two arrays
-				if (paramRGBM == null) {
-					paramRGBM = new float[3];
-				}
-				if (paramRGBA == null) {
-					paramRGBA = new float[3];
-				}
-				// calculate "contrast" values (c=2^x)
-				float[] mult = new float[3];
-				for (int i = 0; i < 3; i++) {
-					mult[i] = (float) Math.pow(2, (double) paramRGBM[i]);
-				}
-				docuImage.enhanceRGB(mult, paramRGBA);
-			}
-
-			// contrast and brightness enhancement
-			if ((paramCONT != 0f) || (paramBRGT != 0f)) {
-				double mult = Math.pow(2, paramCONT);
-				docuImage.enhance((float) mult, (float) paramBRGT);
-			}
-
-			logger.debug("time " + (System.currentTimeMillis() - startTime) + "ms");
-
-			/* write the resulting image */
-
-			// setup output -- if source is JPG then dest will be JPG else it's
-			// PNG
-			if (mimeType.equals("image/jpeg")
-				|| mimeType.equals("image/jp2")) {
-				mimeType = "image/jpeg";
-			} else {
-				mimeType = "image/png";
-			}
-			response.setContentType(mimeType);
-
-			// write the image
-			docuImage.writeImage(mimeType, response.getOutputStream());
-
-			logger.info("Done in " + (System.currentTimeMillis() - startTime) + "ms");
-			
-			docuImage.dispose();
+			logger.debug("servlet done in "
+					+ (System.currentTimeMillis() - startTime));
 
 			/* error handling */
 
 		} // end of "big" try
 		catch (IOException e) {
-			logger.fatal("ERROR: File IO Error: "+e);
-			try {
-				if (errorMsgHtml) {
-					ServletOps.htmlMessage(
-						"ERROR: File IO Error: " + e,
-						response);
-				} else {
-					ServletOps.sendFile(errorImgFile, null, response);
-				}
-			} catch (FileOpException ex) {
-			} // so we don't get a loop
+			logger.error("ERROR: File IO Error: " + e);
+			digilibError(errorMsgHtml, ERROR_FILE,
+					"ERROR: File IO Error: " + e, response);
 		} catch (AuthOpException e) {
-			logger.fatal("ERROR: Authorization error: "+e);
-			try {
-				if (errorMsgHtml) {
-					ServletOps.htmlMessage(
-						"ERROR: Authorization error: " + e,
-						response);
-				} else {
-					ServletOps.sendFile(errorImgFile, null, response);
-				}
-			} catch (FileOpException ex) {
-			} // so we don't get a loop
+			logger.error("ERROR: Authorization error: " + e);
+			digilibError(errorMsgHtml, ERROR_AUTH,
+					"ERROR: Authorization error: " + e, response);
 		} catch (ImageOpException e) {
-			logger.fatal("ERROR: Image Error: "+e);
-			try {
-				if (errorMsgHtml) {
-					ServletOps.htmlMessage(
-						"ERROR: Image Operation Error: " + e,
-						response);
-				} else {
-					ServletOps.sendFile(errorImgFile, null, response);
-				}
-			} catch (FileOpException ex) {
-			} // so we don't get a loop
+			logger.error("ERROR: Image Error: " + e);
+			digilibError(errorMsgHtml, ERROR_IMAGE,
+					"ERROR: Image Operation Error: " + e, response);
 		} catch (RuntimeException e) {
 			// JAI likes to throw RuntimeExceptions ;-(
-			logger.fatal("ERROR: Other Image Error: "+e);
-			try {
-				if (errorMsgHtml) {
-					ServletOps.htmlMessage(
-						"ERROR: Other Image Operation Error: " + e,
-						response);
-				} else {
-					ServletOps.sendFile(errorImgFile, null, response);
-				}
-			} catch (FileOpException ex) {
-			} // so we don't get a loop
+			logger.error("ERROR: Other Image Error: " + e);
+			digilibError(errorMsgHtml, ERROR_IMAGE,
+					"ERROR: Other Image Operation Error: " + e, response);
 		}
 	}
 
+	/**
+	 * Sends an error to the client as text or image.
+	 * 
+	 * @param asHTML
+	 * @param type
+	 * @param msg
+	 * @param response
+	 */
+	public void digilibError(boolean asHTML, int type, String msg,
+			HttpServletResponse response) {
+			try {
+			File img = null;
+			if (type == ERROR_AUTH) {
+				if (msg == null) {
+					msg = "ERROR: Unauthorized access!";
+				}
+				img = denyImgFile;
+				} else {
+				if (msg == null) {
+					msg = "ERROR: Other image error!";
+				}
+				img = this.errorImgFile;
+		}
+			if (asHTML && (img != null)) {
+				ServletOps.htmlMessage(msg, response);
+			} else {
+				ServletOps.sendFile(img, null, response);
+	}
+		} catch (IOException e) {
+			logger.error("Error sending error!", e);
+		}
+
+	}
+
 } //Scaler class