changeset 122:a32e8c80e2f2

Servlet Version 1.10b1 - more intelligent handling of resolutions - different handling of mo=lores
author robcast
date Wed, 11 Jun 2003 22:51:28 +0200
parents 1ac2c5c6ec0e
children 8564a437843d
files servlet/src/digilib/image/DocuImage.java servlet/src/digilib/image/DocuImageImpl.java servlet/src/digilib/image/DocuInfo.java servlet/src/digilib/image/ImageLoaderDocuImage.java servlet/src/digilib/image/ImageLoaderDocuInfo.java servlet/src/digilib/io/DocuDirectory.java servlet/src/digilib/io/DocuFile.java servlet/src/digilib/io/DocuFileset.java servlet/src/digilib/servlet/Scaler.java
diffstat 9 files changed, 264 insertions(+), 97 deletions(-) [+]
line wrap: on
line diff
--- a/servlet/src/digilib/image/DocuImage.java	Wed Jun 11 22:50:13 2003 +0200
+++ b/servlet/src/digilib/image/DocuImage.java	Wed Jun 11 22:51:28 2003 +0200
@@ -14,7 +14,7 @@
 
   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
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 
 */
 
@@ -22,10 +22,8 @@
 
 import java.awt.Rectangle;
 import java.io.File;
-import java.io.IOException;
 import java.io.OutputStream;
 
-import digilib.io.DocuFile;
 import digilib.io.FileOpException;
 
 /** The basic class for the representation of a digilib image.
@@ -66,17 +64,6 @@
 	public void loadSubimage(File f, Rectangle region, int subsample)
 		throws FileOpException;
 
-	/** Checks the size and type of the DocuFile f.
-	 * 
-	 * The image size and type of the DocuFile f is determined and stored in
-	 * the DocuFile object. Returns true if successfull.
-	 * 
-	 * @param f DocuFile to be checked.
-	 * @return boolean true if check was successfull.
-	 * @throws FileOpException Exception thrown on error.
-	 */
-	public boolean checkFile(DocuFile f) throws IOException;
-
 	/** Writes the current image to a ServletResponse.
 	 *
 	 * The image is encoded to the mime-type <code>mt</code> and sent to the output
--- a/servlet/src/digilib/image/DocuImageImpl.java	Wed Jun 11 22:50:13 2003 +0200
+++ b/servlet/src/digilib/image/DocuImageImpl.java	Wed Jun 11 22:51:28 2003 +0200
@@ -20,15 +20,11 @@
 
 package digilib.image;
 
-import java.awt.Dimension;
 import java.awt.Rectangle;
 import java.io.File;
-import java.io.IOException;
 
 import digilib.Utils;
-import digilib.io.DocuFile;
 import digilib.io.FileOpException;
-import digilib.io.FileOps;
 
 /** Simple abstract implementation of the <code>DocuImage</code> interface.
  *
@@ -123,19 +119,6 @@
 		scale(scale);
 	}
 	
-	/* this is a rather stupid implementation, eventually loading the whole file. */
-	public boolean checkFile(DocuFile f) throws IOException {
-		loadImage(f.getFile());
-		int w = getWidth();
-		int h = getHeight();
-		Dimension s = new Dimension(w, h);
-		f.setSize(s);
-		String m = FileOps.mimeForFile(f.getFile());
-		mimeType = m;
-		f.setMimetype(m);
-		return true;
-	}
-
 	public String getMimetype() {
 		return mimeType;
 	}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/image/DocuInfo.java	Wed Jun 11 22:51:28 2003 +0200
@@ -0,0 +1,44 @@
+/* DocuInfo -- General image information interface
+
+  Digital Image Library servlet components
+
+  Copyright (C) 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
+  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
+
+*/
+
+package digilib.image;
+
+import java.io.IOException;
+
+import digilib.io.DocuFile;
+
+/**
+ * @author casties
+ *
+ */
+public interface DocuInfo {
+
+	/** Checks the size and type of the DocuFile f.
+	 * 
+	 * The image size and type of the DocuFile f is determined and stored in
+	 * the DocuFile object. Returns true if successfull.
+	 * 
+	 * @param f DocuFile to be checked.
+	 * @return boolean true if check was successfull.
+	 * @throws FileOpException Exception thrown on error.
+	 */
+	public boolean checkFile(DocuFile f) throws IOException;
+
+}
--- a/servlet/src/digilib/image/ImageLoaderDocuImage.java	Wed Jun 11 22:50:13 2003 +0200
+++ b/servlet/src/digilib/image/ImageLoaderDocuImage.java	Wed Jun 11 22:51:28 2003 +0200
@@ -20,7 +20,6 @@
 
 package digilib.image;
 
-import java.awt.Dimension;
 import java.awt.Rectangle;
 import java.awt.geom.AffineTransform;
 import java.awt.geom.Rectangle2D;
@@ -38,9 +37,7 @@
 import javax.imageio.ImageReader;
 import javax.imageio.stream.ImageInputStream;
 
-import digilib.io.DocuFile;
 import digilib.io.FileOpException;
-import digilib.io.FileOps;
 
 /** Implementation of DocuImage using the ImageLoader API of Java 1.4 and Java2D. */
 public class ImageLoaderDocuImage extends DocuImageImpl {
@@ -359,20 +356,4 @@
 		img = mirImg;
 	}
 
-	/* check image size and type and store in DocuFile f */
-	public boolean checkFile(DocuFile f) throws IOException {
-		// see if f is already loaded
-		if ((reader == null) || (imgFile != f.getFile())) {
-			preloadImage(f.getFile());
-		}
-		Dimension d = new Dimension();
-		d.setSize(reader.getWidth(0), reader.getHeight(0));
-		f.setSize(d);
-		String t = reader.getFormatName();
-		t = FileOps.mimeForFile(f.getFile());
-		f.setMimetype(t);
-		f.setChecked(true);
-		return true;
-	}
-
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/image/ImageLoaderDocuInfo.java	Wed Jun 11 22:51:28 2003 +0200
@@ -0,0 +1,54 @@
+/* ImageLoaderDocuInfo -- DocuInfo implementation using ImageLoader API
+
+  Digital Image Library servlet components
+
+  Copyright (C) 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
+  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 11.06.2003
+ *
+ */
+package digilib.image;
+
+import java.awt.Dimension;
+import java.io.IOException;
+
+import digilib.io.DocuFile;
+import digilib.io.FileOps;
+
+/**
+ * @author casties
+ *
+ */
+public class ImageLoaderDocuInfo implements DocuInfo {
+
+	private ImageLoaderDocuImage img = new ImageLoaderDocuImage();
+
+	/* check image size and type and store in DocuFile f */
+	public boolean checkFile(DocuFile f) throws IOException {
+		// see if f is already loaded
+		if ((img.reader == null) || (img.imgFile != f.getFile())) {
+			img.preloadImage(f.getFile());
+		}
+		Dimension d =
+			new Dimension(img.reader.getWidth(0), img.reader.getHeight(0));
+		f.setSize(d);
+		String t = img.reader.getFormatName();
+		t = FileOps.mimeForFile(f.getFile());
+		f.setMimetype(t);
+		f.setChecked(true);
+		return true;
+	}
+
+}
--- a/servlet/src/digilib/io/DocuDirectory.java	Wed Jun 11 22:50:13 2003 +0200
+++ b/servlet/src/digilib/io/DocuDirectory.java	Wed Jun 11 22:51:28 2003 +0200
@@ -77,7 +77,10 @@
 	}
 
 	public DocuFileset get(int index) {
-		return (list != null) ? (DocuFileset) list.get(index) : null;
+		if ((list == null)||(index >= list.size())) {
+			return null;
+		} 
+		return (DocuFileset)list.get(index);
 	}
 
 	/** Read the directory and fill this object.
--- a/servlet/src/digilib/io/DocuFile.java	Wed Jun 11 22:50:13 2003 +0200
+++ b/servlet/src/digilib/io/DocuFile.java	Wed Jun 11 22:51:28 2003 +0200
@@ -23,6 +23,9 @@
 
 import java.awt.Dimension;
 import java.io.File;
+import java.io.IOException;
+
+import digilib.image.DocuInfo;
 
 /**
  * @author casties
@@ -51,6 +54,15 @@
 		return null;
 	}
 
+
+	public void check(DocuInfo info) {
+		try {
+			info.checkFile(this);
+		} catch (IOException e) {
+			checked = false;
+		}
+	}
+
 	/**
 	 * @return File
 	 */
--- a/servlet/src/digilib/io/DocuFileset.java	Wed Jun 11 22:50:13 2003 +0200
+++ b/servlet/src/digilib/io/DocuFileset.java	Wed Jun 11 22:51:28 2003 +0200
@@ -19,10 +19,14 @@
  */
 package digilib.io;
 
+import java.awt.Dimension;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.ListIterator;
 
+import digilib.image.DocuInfo;
+
 /**
  * @author casties
  */
@@ -49,8 +53,8 @@
 
 	/** Adds a DocuFile to this Fileset.
 	 * 
-	 * The files should be added in the order of lower resolutions. The first
-	 * file is considered the hires "original". 
+	 * The files should be added in the order of higher to lower resolutions. 
+	 * The first file is considered the hires "original". 
 	 * 
 	 * @param f file to add
 	 * @return true (always)
@@ -59,7 +63,7 @@
 		f.setParent(this);
 		return list.add(f);
 	}
-	
+
 	/** The number of image files in this Fileset.
 	 * 
 	 * @return number of image files
@@ -67,7 +71,7 @@
 	public int size() {
 		return (list != null) ? list.size() : 0;
 	}
-	
+
 	/** Get the DocuFile at the index.
 	 * 
 	 * @param index
@@ -76,8 +80,57 @@
 	public DocuFile get(int index) {
 		return (DocuFile) list.get(index);
 	}
-	
-	
+
+	/** Get the next smaller DocuFile than the given size.
+	 * 
+	 * Returns the DocuFile from the set that has a width and height 
+	 * smaller or equal the given size. 
+	 * Returns null if there isn't any smaller image.
+	 * Needs DocuInfo instance to checkFile().
+	 * 
+	 * @param size
+	 * @param info
+	 * @return
+	 */
+	public DocuFile getNextSmaller(Dimension size, DocuInfo info) {
+		for (Iterator i = getHiresIterator(); i.hasNext();) {
+			DocuFile f = (DocuFile) i.next();
+			if (!f.isChecked()) {
+				f.check(info);
+			}
+			if ((f.getSize().getHeight() <= size.getHeight())
+				&& (f.getSize().getWidth() <= size.getWidth())) {
+				return f;
+			}
+		}
+		return null;
+	}
+
+	/** Get the next bigger DocuFile than the given size.
+	 * 
+	 * Returns the DocuFile from the set that has a width and height 
+	 * bigger or equal the given size. 
+	 * Returns null if there isn't any bigger image.
+	 * Needs DocuInfo instance to checkFile().
+	 * 
+	 * @param size
+	 * @param info
+	 * @return
+	 */
+	public DocuFile getNextBigger(Dimension size, DocuInfo info) {
+		for (ListIterator i = getLoresIterator(); i.hasPrevious();) {
+			DocuFile f = (DocuFile) i.previous();
+			if (!f.isChecked()) {
+				f.check(info);
+			}
+			if ((f.getSize().getHeight() >= size.getHeight())
+				&& (f.getSize().getWidth() >= size.getWidth())) {
+				return f;
+			}
+		}
+		return null;
+	}
+
 	/** Get an Iterator for this Fileset starting at the highest resolution 
 	 * images.
 	 * 
@@ -86,7 +139,7 @@
 	public ListIterator getHiresIterator() {
 		return list.listIterator();
 	}
-	
+
 	/** Get an Iterator for this Fileset starting at the lowest resolution 
 	 * images.
 	 * 
@@ -98,7 +151,7 @@
 	public ListIterator getLoresIterator() {
 		return list.listIterator(list.size());
 	}
-	
+
 	/** Reads meta-data for this Fileset if there is any.
 	 * (not yet implemented)
 	 */
@@ -116,7 +169,7 @@
 		}
 		return null;
 	}
-	
+
 	/** Returns the parent DocuDirectory.
 	 * @return DocuDirectory
 	 */
--- a/servlet/src/digilib/servlet/Scaler.java	Wed Jun 11 22:50:13 2003 +0200
+++ b/servlet/src/digilib/servlet/Scaler.java	Wed Jun 11 22:51:28 2003 +0200
@@ -39,6 +39,8 @@
 import digilib.auth.AuthOpException;
 import digilib.auth.AuthOps;
 import digilib.image.DocuImage;
+import digilib.image.DocuInfo;
+import digilib.image.ImageLoaderDocuInfo;
 import digilib.image.ImageOpException;
 import digilib.io.DocuDirCache;
 import digilib.io.DocuFile;
@@ -56,7 +58,7 @@
 public class Scaler extends HttpServlet {
 
 	// digilib servlet version (for all components)
-	public static final String dlVersion = "1.9b3";
+	public static final String dlVersion = "1.10b1";
 
 	// Utils instance with debuglevel
 	Utils util;
@@ -168,12 +170,12 @@
 		boolean scaleToFit = true;
 		// scale the image by a fixed factor only
 		boolean absoluteScale = false;
-		// crop the image if needed
-		boolean cropToFit = true;
-		// use heuristics (GIF?) to scale or send as is
-		boolean autoScale = true;
-		// try prescaled images first
-		boolean preScaledFirst = true;
+		// only crop the image to fit
+		boolean cropToFit = false;
+		// try different resolution images automatically 
+		boolean autoRes = true;
+		// use hires images (if autoRes == false) 
+		boolean hiresOnly = false;
 		// interpolation to use for scaling
 		int scaleQual = 0;
 		// send html error message (or image file)
@@ -194,6 +196,13 @@
 		int paramDW = dlRequest.getDw();
 		// destination image height
 		int paramDH = dlRequest.getDh();
+		// dw and dh shouldn't be empty, if they are, set dw=dh
+		if (paramDW <= 0) {
+			paramDW = paramDH;
+		}
+		if (paramDH <= 0) {
+			paramDH = paramDW;
+		}
 		// relative area x_offset (0..1)
 		double paramWX = dlRequest.getWx();
 		// relative area y_offset
@@ -222,29 +231,29 @@
 			scaleToFit = false;
 			absoluteScale = false;
 			cropToFit = true;
-			autoScale = false;
-			preScaledFirst = false;
+			autoRes = true;
 		} else if (dlRequest.isOption("fit")) {
 			scaleToFit = true;
 			absoluteScale = false;
-			cropToFit = true;
-			autoScale = false;
+			cropToFit = false;
+			autoRes = true;
 		} else if (dlRequest.isOption("scale")) {
 			scaleToFit = false;
 			absoluteScale = true;
-			cropToFit = true;
-			autoScale = false;
-			preScaledFirst = false;
+			cropToFit = false;
+			autoRes = false;
+			hiresOnly = true;
 		} else if (dlRequest.isOption("file")) {
 			scaleToFit = false;
 			absoluteScale = false;
 			if (dlConfig.isSendFileAllowed()) {
 				cropToFit = false;
 			} else {
+				// crop to fit if send file not allowed
 				cropToFit = true;
 			}
-			autoScale = false;
-			preScaledFirst = false;
+			autoRes = false;
+			hiresOnly = true;
 		}
 		// operation mode: "errtxt": error message in html, "errimg": error image
 		if (dlRequest.isOption("errtxt")) {
@@ -261,10 +270,15 @@
 			scaleQual = 2;
 		}
 		// operation mode: "lores": try to use scaled image, "hires": use unscaled image
+		//   "autores": try best fitting resolution
 		if (dlRequest.isOption("lores")) {
-			preScaledFirst = true;
+			autoRes = false;
+			hiresOnly = false;
 		} else if (dlRequest.isOption("hires")) {
-			preScaledFirst = false;
+			autoRes = false;
+			hiresOnly = true;
+		} else if (dlRequest.isOption("autores")) {
+			autoRes = true;
 		}
 
 		//"big" try for all file/image actions
@@ -276,6 +290,9 @@
 				throw new ImageOpException("Unable to load DocuImage class!");
 			}
 
+			// new DocuInfo instance
+			DocuInfo docuInfo = new ImageLoaderDocuInfo();
+
 			// set interpolation quality
 			docuImage.setQuality(scaleQual);
 
@@ -313,7 +330,7 @@
 				}
 			}
 
-			// find the file
+			// find the file(set)
 			DocuFile fileToLoad;
 			DocuFileset fileset =
 				dirCache.getFileset(loadPathName, dlRequest.getPn());
@@ -326,36 +343,69 @@
 						+ ") not found.");
 			}
 
-			// if it's zoomed, try hires version (to be optimized...)
-			if ((paramWW < 1f) || (paramWH < 1f)) {
-				preScaledFirst = false;
+			/*
+			 * calculate expected source image size
+			 * 
+			 */
+			Dimension expectedSourceSize = new Dimension();
+			if (scaleToFit) {
+				double scale = (1 / Math.min(paramWW, paramWH)) * paramWS;
+				expectedSourceSize.setSize(paramDW * scale, paramDH * scale);
+			} else {
+				expectedSourceSize.setSize(
+					paramDW * paramWS,
+					paramDH * paramWS);
 			}
 
-			// simplistic selection of resolution
-			if (preScaledFirst) {
-				// get last element
-				fileToLoad = fileset.get(fileset.size() - 1);
+			/* 
+			 * select a resolution
+			 */
+			if (autoRes) {
+				// autores: use next bigger resolution
+				fileToLoad =
+					fileset.getNextBigger(expectedSourceSize, docuInfo);
+				if (fileToLoad == null) {
+					// this is the biggest we have
+					fileToLoad = fileset.get(0);
+				}
 			} else {
-				// get first element
-				fileToLoad = fileset.get(0);
+				// enforced hires or lores
+				if (hiresOnly) {
+					// get first element
+					fileToLoad = fileset.get(0);
+				} else {
+					// enforced lores uses next smaller resolution
+					fileToLoad =
+						fileset.getNextSmaller(expectedSourceSize, docuInfo);
+					if (fileToLoad == null) {
+						// this is the smallest we have
+						fileToLoad = fileset.get(fileset.size() - 1);
+					}
+				}
 			}
 			util.dprintln(1, "Loading: " + fileToLoad.getFile());
 
 			// check the source image
-			docuImage.checkFile(fileToLoad);
+			if (!fileToLoad.isChecked()) {
+				fileToLoad.check(docuInfo);
+			}
 			// get the source image type
 			mimeType = fileToLoad.getMimetype();
+			boolean imageSendable =
+				mimeType.equals("image/jpeg")
+					|| mimeType.equals("image/png")
+					|| mimeType.equals("image/gif");
 
-			/* if autoScale and not zoomed and source is GIF/PNG 
-			 * then send as is.
+			/* if not autoRes and image smaller than requested 
+			 * size then send as is. 
 			 * if not autoScale and not scaleToFit nor cropToFit 
-			 * then send as is
+			 * then send as is (mo=file)
 			 */
-			if ((autoScale
-				&& (mimeType == "image/gif" || mimeType == "image/png")
-				&& (paramWW == 1f)
-				&& (paramWH == 1f))
-				|| (!autoScale && !scaleToFit && !cropToFit)) {
+			if ((!autoRes
+				&& imageSendable
+				&& (fileToLoad.getSize().width <= expectedSourceSize.width)
+				&& (fileToLoad.getSize().height <= expectedSourceSize.height))
+				|| (!autoRes && !scaleToFit && !cropToFit)) {
 
 				util.dprintln(1, "Sending File as is.");