# HG changeset patch # User robcast # Date 1055364688 -7200 # Node ID a32e8c80e2f2229c7049b43a0fc9d217aba32143 # Parent 1ac2c5c6ec0e15ef703a312029389c23c920d4c1 Servlet Version 1.10b1 - more intelligent handling of resolutions - different handling of mo=lores diff -r 1ac2c5c6ec0e -r a32e8c80e2f2 servlet/src/digilib/image/DocuImage.java --- 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 mt and sent to the output diff -r 1ac2c5c6ec0e -r a32e8c80e2f2 servlet/src/digilib/image/DocuImageImpl.java --- 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 DocuImage 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; } diff -r 1ac2c5c6ec0e -r a32e8c80e2f2 servlet/src/digilib/image/DocuInfo.java --- /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; + +} diff -r 1ac2c5c6ec0e -r a32e8c80e2f2 servlet/src/digilib/image/ImageLoaderDocuImage.java --- 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; - } - } diff -r 1ac2c5c6ec0e -r a32e8c80e2f2 servlet/src/digilib/image/ImageLoaderDocuInfo.java --- /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; + } + +} diff -r 1ac2c5c6ec0e -r a32e8c80e2f2 servlet/src/digilib/io/DocuDirectory.java --- 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. diff -r 1ac2c5c6ec0e -r a32e8c80e2f2 servlet/src/digilib/io/DocuFile.java --- 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 */ diff -r 1ac2c5c6ec0e -r a32e8c80e2f2 servlet/src/digilib/io/DocuFileset.java --- 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 */ diff -r 1ac2c5c6ec0e -r a32e8c80e2f2 servlet/src/digilib/servlet/Scaler.java --- 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.");