changeset 296:0a212bc468ad

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 90bab835fc25
children b74c914b48a9
files servlet/src/digilib/servlet/DigilibImageWorker.java
diffstat 1 files changed, 263 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/servlet/DigilibImageWorker.java	Sun Oct 24 20:23:50 2004 +0200
@@ -0,0 +1,263 @@
+/* DigilibImageWorker.java -- worker for image operations
+ * 
+ * Digital Image Library servlet components
+ * 
+ * Copyright (C) 2004 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 Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ * 
+ * Please read license.txt for the full details. A copy of the GPL may be found
+ * at http://www.gnu.org/copyleft/lgpl.html
+ * 
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ *  
+ * Created on 19.10.2004
+ */
+
+package digilib.servlet;
+
+import java.awt.geom.Rectangle2D;
+import java.io.IOException;
+
+import javax.servlet.http.HttpServletResponse;
+
+import digilib.image.DocuImage;
+import digilib.image.ImageOpException;
+import digilib.io.FileOpException;
+import digilib.io.ImageFile;
+
+/**
+ * worker for image operations.
+ * 
+ * @author casties
+ *  
+ */
+public class DigilibImageWorker extends DigilibWorker {
+	
+	private DigilibConfiguration dlConfig;
+
+	HttpServletResponse response;
+
+	long startTime;
+
+	String mimeType;
+
+	int scaleQual;
+
+	DigilibRequest dlRequest;
+
+	float paramROT;
+
+	float paramCONT;
+
+	float paramBRGT;
+
+	float[] paramRGBM;
+
+	float[] paramRGBA;
+
+	ImageFile fileToLoad;
+
+	float areaXoff;
+
+	float areaYoff;
+
+	float areaWidth;
+
+	float areaHeight;
+
+	float scaleXY;
+
+	Rectangle2D outerUserImgArea;
+
+	Rectangle2D innerUserImgArea;
+
+	float minSubsample;
+
+	boolean wholeRotArea;
+
+	/**
+	 * @param dlConfig
+	 * @param response
+	 * @param mimeType
+	 * @param scaleQual
+	 * @param dlRequest
+	 * @param paramROT
+	 * @param paramCONT
+	 * @param paramBRGT
+	 * @param paramRGBM
+	 * @param paramRGBA
+	 * @param fileToLoad
+	 * @param areaXoff
+	 * @param outerUserImgArea
+	 * @param innerUserImgArea
+	 * @param minSubsample
+	 * @param wholeRotArea
+	 */
+	public DigilibImageWorker(DigilibConfiguration dlConfig,
+			HttpServletResponse response, String mimeType, int scaleQual,
+			DigilibRequest dlRequest, float paramROT, float paramCONT,
+			float paramBRGT, float[] paramRGBM, float[] paramRGBA,
+			ImageFile fileToLoad, float scaleXY, Rectangle2D outerUserImgArea,
+			Rectangle2D innerUserImgArea, float minSubsample,
+			boolean wholeRotArea) {
+		super();
+		this.dlConfig = dlConfig;
+		this.response = response;
+		this.mimeType = mimeType;
+		this.scaleQual = scaleQual;
+		this.dlRequest = dlRequest;
+		this.paramROT = paramROT;
+		this.paramCONT = paramCONT;
+		this.paramBRGT = paramBRGT;
+		this.paramRGBM = paramRGBM;
+		this.paramRGBA = paramRGBA;
+		this.fileToLoad = fileToLoad;
+		this.scaleXY = scaleXY;
+		this.outerUserImgArea = outerUserImgArea;
+		this.innerUserImgArea = innerUserImgArea;
+		this.minSubsample = minSubsample;
+		this.wholeRotArea = wholeRotArea;
+	}
+
+	/*
+	 * do the work
+	 */
+	public void work() throws FileOpException, IOException, ImageOpException {
+		;
+		logger.debug("image worker " + this.getName() + " working");
+		startTime = System.currentTimeMillis();
+
+		/* crop and scale image */
+
+		// new DocuImage instance
+		DocuImage docuImage = dlConfig.getDocuImageInstance();
+		if (docuImage == null) {
+			throw new ImageOpException("Unable to load DocuImage class!");
+		}
+
+		// set interpolation quality
+		docuImage.setQuality(scaleQual);
+
+		// use subimage loading if possible
+		if (docuImage.isSubimageSupported()) {
+			logger.debug("Subimage: scale " + scaleXY + " = " + (1 / scaleXY));
+			float subf = 1f;
+			float subsamp = 1f;
+			if (scaleXY < 1) {
+				subf = 1 / scaleXY;
+				// for higher quality reduce subsample factor by
+				// minSubsample
+				if (scaleQual > 0) {
+					subsamp = (float) Math.max(Math.floor(subf / minSubsample),
+							1d);
+				} else {
+					subsamp = (float) Math.floor(subf);
+				}
+				scaleXY = subsamp / subf;
+				logger.debug("Using subsampling: " + subsamp + " rest "
+						+ scaleXY);
+			}
+
+			docuImage.loadSubimage(fileToLoad, outerUserImgArea.getBounds(),
+					(int) subsamp);
+
+			logger.debug("SUBSAMP: " + subsamp + " -> " + docuImage.getWidth()
+					+ "x" + docuImage.getHeight());
+
+			docuImage.scale(scaleXY, scaleXY);
+
+		} 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);
+		}
+
+		// rotate image
+		if (paramROT != 0d) {
+			docuImage.rotate(paramROT);
+			if (wholeRotArea) {
+				// crop to the inner bounding box
+				float xcrop = (float) (docuImage.getWidth() - innerUserImgArea
+						.getWidth()
+						* scaleXY);
+				float ycrop = (float) (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, (float) paramRGBM[i]);
+			}
+			docuImage.enhanceRGB(mult, paramRGBA);
+		}
+
+		// contrast and brightness enhancement
+		if ((paramCONT != 0f) || (paramBRGT != 0f)) {
+			float mult = (float) Math.pow(2, paramCONT);
+			docuImage.enhance(mult, 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());
+		response.flushBuffer();
+		
+		logger.info("image worker " + this.getName() + " done in "
+				+ (System.currentTimeMillis() - startTime));
+
+		docuImage.dispose();
+	}
+}