diff servlet/src/digilib/image/ImageJobDescription.java @ 557:0885f5ca5b24 digilibPDF

more refactoring and rearranging pdf and image generation works now
author robcast
date Thu, 16 Dec 2010 21:19:11 +0100
parents servlet/src/digilib/servlet/ImageJobDescription.java@88ed97d08b97
children baaa5bab5e16
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/image/ImageJobDescription.java	Thu Dec 16 21:19:11 2010 +0100
@@ -0,0 +1,503 @@
+package digilib.image;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.io.IOException;
+
+import org.apache.log4j.Logger;
+
+import digilib.io.DocuDirCache;
+import digilib.io.DocuDirectory;
+import digilib.io.FileOpException;
+import digilib.io.FileOps;
+import digilib.io.ImageFile;
+import digilib.io.ImageFileset;
+import digilib.servlet.DigilibConfiguration;
+import digilib.util.OptionsSet;
+import digilib.util.Parameter;
+import digilib.util.ParameterMap;
+
+
+/** 
+ * A container class for storing a set of instructional parameters 
+ * used for content generating classes like MakePDF.  
+ * 
+ * This contains the functionality formerly found in Scaler, processRequest, only factorized.
+ * 
+ * TODO clean up...
+ * 
+ * @author cmielack, casties
+ *
+ */
+
+public class ImageJobDescription extends ParameterMap {
+	
+	DigilibConfiguration dlConfig = null;
+	protected static Logger logger = Logger.getLogger("digilib.servlet");
+
+	ImageFile fileToLoad = null;
+	ImageFileset fileset = null;
+	DocuDirectory fileDir = null;
+	String filePath = null;
+	ImageSize expectedSourceSize = null;
+	Float scaleXY = null;
+	Rectangle2D userImgArea = null;
+	Rectangle2D outerUserImgArea= null;
+	Boolean imageSendable = null;
+	String mimeType;
+	Integer paramDW;
+	Integer paramDH;
+
+	/** create empty ImageJobDescription.
+	 * @param dlcfg
+	 */
+	public ImageJobDescription(DigilibConfiguration dlcfg) {
+		super(30);
+		dlConfig = dlcfg;
+	}
+
+
+	/** set up Parameters
+	 * @see digilib.util.ParameterMap#initParams()
+	 */
+	@Override
+	protected void initParams() {
+		// url of the page/document (second part)
+		newParameter("fn", "", null, 's');
+		// page number
+		newParameter("pn", new Integer(1), null, 's');
+		// width of client in pixels
+		newParameter("dw", new Integer(0), null, 's');
+		// height of client in pixels
+		newParameter("dh", new Integer(0), null, 's');
+		// left edge of image (float from 0 to 1)
+		newParameter("wx", new Float(0), null, 's');
+		// top edge in image (float from 0 to 1)
+		newParameter("wy", new Float(0), null, 's');
+		// width of image (float from 0 to 1)
+		newParameter("ww", new Float(1), null, 's');
+		// height of image (float from 0 to 1)
+		newParameter("wh", new Float(1), null, 's');
+		// scale factor
+		newParameter("ws", new Float(1), null, 's');
+		// special options like 'fit' for gifs
+		newParameter("mo", this.options, null, 's');
+		// rotation angle (degree)
+		newParameter("rot", new Float(0), null, 's');
+		// contrast enhancement factor
+		newParameter("cont", new Float(0), null, 's');
+		// brightness enhancement factor
+		newParameter("brgt", new Float(0), null, 's');
+		// color multiplicative factors
+		newParameter("rgbm", "0/0/0", null, 's');
+		// color additive factors
+		newParameter("rgba", "0/0/0", null, 's');
+		// display dpi resolution (total)
+		newParameter("ddpi", new Float(0), null, 's');
+		// display dpi X resolution
+		newParameter("ddpix", new Float(0), null, 's');
+		// display dpi Y resolution
+		newParameter("ddpiy", new Float(0), null, 's');
+		// scale factor for mo=ascale
+		newParameter("scale", new Float(1), null, 's');
+	}
+
+
+	/* (non-Javadoc)
+	 * @see digilib.servlet.ParameterMap#initOptions()
+	 */
+	@Override
+	protected void initOptions() {
+		if (options == null) {
+			String s = this.getAsString("mo");
+			options = new OptionsSet(s);
+		}
+	}
+
+
+	/** Creates new ImageJobDescription by merging Parameters from another ParameterMap.
+	 * @param pm
+	 * @param dlcfg
+	 * @return
+	 */
+	public static ImageJobDescription getInstance(ParameterMap pm, DigilibConfiguration dlcfg) {
+		ImageJobDescription newMap = new ImageJobDescription(dlcfg);
+		// add all params to this map
+		newMap.params.putAll(pm.getParams());
+		newMap.initOptions();
+		return newMap;
+	}
+
+	
+	public String getMimeType() throws IOException {
+		if (mimeType == null) {
+			fileToLoad = getFileToLoad();
+			if(! fileToLoad.isChecked()){
+				ImageOps.checkFile(fileToLoad);
+			}
+			mimeType = fileToLoad.getMimetype();
+		}
+		return mimeType;
+	}
+	
+	public ImageFile getFileToLoad() throws IOException {
+		
+		if(fileToLoad == null){
+			fileset = getFileset();
+			
+			/* select a resolution */
+			if (getHiresOnly()) {
+				// get first element (= highest resolution)
+				fileToLoad = fileset.getBiggest();
+			} else if (getLoresOnly()) {
+				// enforced lores uses next smaller resolution
+				fileToLoad = fileset.getNextSmaller(getExpectedSourceSize());
+				if (fileToLoad == null) {
+					// this is the smallest we have
+					fileToLoad = fileset.getSmallest();
+				}
+			} else {
+				// autores: use next higher resolution
+				fileToLoad = fileset.getNextBigger(getExpectedSourceSize());
+				if (fileToLoad == null) {
+					// this is the highest we have
+					fileToLoad = fileset.getBiggest();
+				}
+			}
+			logger.info("Planning to load: " + fileToLoad.getFile());
+		}
+		
+		return fileToLoad;
+
+	}
+	
+	public DocuDirectory getFileDirectory() throws FileOpException {
+		if(fileDir == null){
+			DocuDirCache dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache");
+			String fp = getFilePath();
+			fileDir = dirCache.getDirectory(fp);
+			if (fileDir == null) {
+				throw new FileOpException("Directory " + getFilePath() + " not found.");
+			}
+		}
+		return fileDir;
+	}
+	
+    public ImageFileset getFileset() throws FileOpException {
+        if(fileset==null){
+            DocuDirCache dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache");
+    
+            fileset = (ImageFileset) dirCache.getFile(getFilePath(), getAsInt("pn"), FileOps.CLASS_IMAGE);
+            if (fileset == null) {
+                throw new FileOpException("File " + getFilePath() + "("
+                        + getAsInt("pn") + ") not found.");
+            }
+        }
+        return fileset;
+    }
+    
+	public String getFilePath() {
+		if(filePath == null){
+			String s = this.getAsString("request.path");
+			s += this.getAsString("fn");
+			filePath = FileOps.normalName(s);
+		}
+		return filePath;
+	}
+
+	public boolean getHiresOnly(){
+		return hasOption("clip") || hasOption("hires");
+	}
+	
+	public boolean getLoresOnly(){
+		return hasOption("lores");
+	}
+
+	public boolean getScaleToFit() {
+		return !(hasOption("clip") || hasOption("osize") || hasOption("ascale"));
+	}
+
+	public boolean getAbsoluteScale(){
+		return hasOption("osize") || hasOption("ascale");
+	}
+	
+	
+	public ImageSize getExpectedSourceSize() throws IOException {
+		if (expectedSourceSize == null){
+			expectedSourceSize = new ImageSize();
+			if (getScaleToFit()) {
+				// scale to fit -- calculate minimum source size
+				float scale = (1 / Math.min(getAsFloat("ww"), getAsFloat("wh"))) * getAsFloat("ws");
+				expectedSourceSize.setSize((int) (getDw() * scale),
+						(int) (getDh() * scale));
+			} else if (getAbsoluteScale() && hasOption("ascale")) {
+				// absolute scale -- apply scale to hires size
+				expectedSourceSize = getHiresSize().getScaled(getAsFloat("scale"));
+			} else {
+				// clip to fit -- source = destination size
+				expectedSourceSize.setSize((int) (getDw() * getAsFloat("ws")),
+						(int) (getDh() * getAsFloat("ws")));
+			}
+		}
+		return expectedSourceSize;
+	}
+	
+	public ImageSize getHiresSize() throws IOException {
+		logger.debug("get_hiresSize()");
+
+		ImageSize hiresSize = null;
+		ImageFileset fileset = getFileset();
+		if (getAbsoluteScale()) {
+			ImageFile hiresFile = fileset.getBiggest();
+			if (!hiresFile.isChecked()) {
+				ImageOps.checkFile(hiresFile);
+			}
+			hiresSize = hiresFile.getSize();
+		}
+		return hiresSize;
+		
+	}
+	
+	/** Returns image scaling factor.
+	 * Uses image size and user parameters.
+	 * Modifies scaleXY, userImgArea. 
+	 * @return
+	 * @throws IOException
+	 * @throws ImageOpException
+	 */
+	public float getScaleXY() throws IOException, ImageOpException {
+		//logger.debug("get_scaleXY()");
+		if(scaleXY == null){
+			// coordinates and scaling
+			float areaWidth;
+			float areaHeight;
+			float ws = getAsFloat("ws");
+			ImageSize imgSize = getFileToLoad().getSize();
+			// user window area in [0,1] coordinates
+			Rectangle2D relUserArea = new Rectangle2D.Float(getAsFloat("wx"), getAsFloat("wy"),
+					getAsFloat("ww"), getAsFloat("wh"));
+			// 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();
+	
+			if (getScaleToFit()) {
+				// calculate scaling factors based on inner user area
+				areaWidth = (float) userImgArea.getWidth();
+				areaHeight = (float) userImgArea.getHeight();
+				float scaleX = getDw() / areaWidth * ws;
+				float scaleY = getDh() / areaHeight * ws;
+				scaleXY = (scaleX > scaleY) ? scaleY : scaleX;
+			} else if (getAbsoluteScale()) {
+				// absolute scaling factor
+				if (hasOption("osize")) {
+					// get original resolution from metadata
+					fileset.checkMeta();
+					float origResX = fileset.getResX();
+					float origResY = fileset.getResY();
+					if ((origResX == 0) || (origResY == 0)) {
+						throw new ImageOpException("Missing image DPI information!");
+					}
+					if ((getAsFloat("ddpix") == 0) || (getAsFloat("ddpiy") == 0)) {
+						throw new ImageOpException("Missing display DPI information!");
+					}
+					// calculate absolute scale factor
+					float sx = getAsFloat("ddpix") / origResX;
+					float sy = getAsFloat("ddpiy") / origResY;
+					// currently only same scale -- mean value
+					scaleXY = (sx + sy) / 2f;
+				} else {
+					scaleXY = getAsFloat("scale");
+				}
+				// we need to correct the factor if we use a pre-scaled image
+				ImageSize hiresSize = getHiresSize();
+				if (imgSize.getWidth() != hiresSize.getWidth()) {
+					scaleXY *= (float)hiresSize.getWidth() / (float)imgSize.getWidth();
+				}
+				areaWidth = getDw() / scaleXY * ws;
+				areaHeight = 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;
+				// reset user area size
+				userImgArea.setRect(userImgArea.getX(), userImgArea.getY(),
+						areaWidth, areaHeight);
+				scaleXY = 1f;
+			}
+		}
+		return (float) scaleXY;
+	}
+	
+	public int getDw() throws IOException {
+		logger.debug("get_paramDW()");
+		if (paramDW == null) {
+
+			paramDW = getAsInt("dw");
+			paramDH = getAsInt("dh");
+
+			float imgAspect = getFileToLoad().getAspect();
+			if (paramDW == 0) {
+				// calculate dw
+				paramDW = Math.round(paramDH * imgAspect);
+				setValue("dw", paramDW);
+			} else if (paramDH == 0) {
+				// calculate dh
+				paramDH = Math.round(paramDW / imgAspect);
+				setValue("dh", paramDH);
+			}
+		}
+		return paramDW;
+	}
+	
+	public int getDh() throws IOException {
+		logger.debug("get_paramDH()");
+		if (paramDH == null) {
+			
+			paramDW = getAsInt("dw");
+			paramDH = getAsInt("dh");
+
+			float imgAspect = getFileToLoad().getAspect();
+			if (paramDW == 0) {
+				// calculate dw
+				paramDW = Math.round(paramDH * imgAspect);
+				setValue("dw", paramDW);
+			} else if (paramDH == 0) {
+				// calculate dh
+				paramDH = Math.round(paramDW / imgAspect);
+				setValue("dh", paramDH);
+			}
+		}
+		return paramDH;
+	}
+	
+	public Integer get_scaleQual(){
+		logger.debug("get_scaleQual()");
+		Integer qual = dlConfig.getAsInt("default-quality");
+		if(hasOption("q0"))
+			qual = 0;
+		else if(hasOption("q1"))
+			qual = 1;
+		else if(hasOption("q2"))
+			qual = 2;
+		return qual;
+	}
+
+	
+	public Rectangle2D getUserImgArea() throws IOException, ImageOpException{
+		if(userImgArea == null) {
+			// getScaleXY sets userImgArea
+			getScaleXY();
+		}
+		return userImgArea;		
+		
+	}
+	
+	public Rectangle2D getOuterUserImgArea() throws IOException, ImageOpException {
+		if(outerUserImgArea == null){
+			outerUserImgArea = getUserImgArea();
+			
+			// image size in pixels
+			ImageSize imgSize = getFileToLoad().getSize();
+			Rectangle2D imgBounds = new Rectangle2D.Float(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!");
+				throw new ImageOpException("Invalid scale parameter set!");
+			}
+		}
+		return outerUserImgArea;
+	}
+	
+	
+	public int getForceType(){
+		if(hasOption("jpg"))
+			return ImageOps.TYPE_JPEG;
+		if(hasOption("png"))
+			return ImageOps.TYPE_PNG;
+		
+		return ImageOps.TYPE_AUTO;
+	}
+	
+	public float[] getRGBM(){
+		float[] paramRGBM = null;//{0f,0f,0f};
+		Parameter p = params.get("rgbm");
+		if (p.hasValue() && (!p.getAsString().equals("0/0/0"))) {
+			return p.parseAsFloatArray("/");
+		}	
+		return paramRGBM;
+	}
+	
+	public float[] getRGBA(){
+		float[] paramRGBA =  null;//{0f,0f,0f};
+		Parameter p = params.get("rgba");
+		if (p.hasValue() && (!p.getAsString().equals("0/0/0"))) {
+			paramRGBA = p.parseAsFloatArray("/");
+		}
+		return paramRGBA;
+	}
+	
+	/** Has send-as-file been requested?
+	 * @return
+	 */
+	public boolean getSendAsFile(){
+		return hasOption("file")
+		|| hasOption("rawfile");
+	}
+	
+	/** Could the image be sent without processing?
+	 * Takes image type and additional image operations into account. 
+	 * Does not check requested size transformation.
+	 * @return
+	 * @throws IOException 
+	 */
+	public boolean isImageSendable() throws IOException {
+		// cached result?
+		if (imageSendable == null) {
+			String mimeType = getMimeType();
+			imageSendable = ( (mimeType.equals("image/jpeg")
+				        	|| mimeType.equals("image/png")
+				        	|| mimeType.equals("image/gif") )
+				        	&& 
+				        	!(hasOption("hmir")
+							|| hasOption("vmir") 
+							|| (getAsFloat("rot") != 0.0)
+							|| (getRGBM() != null) 
+							|| (getRGBA() != null)
+							|| (getAsFloat("cont") != 0.0) 
+							|| (getAsFloat("brgt") != 0.0)));
+		}
+		
+		return imageSendable;
+	}
+	
+	
+	public boolean isTransformRequired() throws IOException {
+		ImageSize is = getFileToLoad().getSize();
+		ImageSize ess = getExpectedSourceSize();
+		// nt = no transform required
+		boolean nt = isImageSendable() && (
+			// lores: send if smaller
+			(getLoresOnly() && is.isSmallerThan(ess))
+			// else send if it fits
+			|| (!(getLoresOnly() || getHiresOnly()) && is.fitsIn(ess)));
+		return ! nt;
+	}
+}
\ No newline at end of file