Mercurial > hg > digilib-old
changeset 840:a7e157d258e8 jquery
merge
author | hertzhaft |
---|---|
date | Tue, 01 Mar 2011 22:00:50 +0100 |
parents | 9fa078dcb493 (current diff) ea6c8f92c929 (diff) |
children | 73dd59b48c5e dad6a171bc52 |
files | servlet/src/digilib/auth/HashTree.java servlet/src/digilib/image/ImageSize.java servlet/src/digilib/io/DigilibInfoReader.java servlet/src/digilib/io/DocuDirent.java servlet/src/digilib/io/ImageFileset.java servlet/src/digilib/io/MetadataMap.java servlet/src/digilib/io/XMLListLoader.java servlet/src/digilib/io/XMLMetaLoader.java |
diffstat | 57 files changed, 3861 insertions(+), 2221 deletions(-) [+] |
line wrap: on
line diff
--- a/client/digitallibrary/ImgInfo-json.jsp Tue Mar 01 17:12:25 2011 +0100 +++ b/client/digitallibrary/ImgInfo-json.jsp Tue Mar 01 22:00:50 2011 +0100 @@ -1,6 +1,6 @@ <%@page language="java" - import="digilib.io.FileOps, digilib.io.ImageFileset, digilib.io.ImageFile, - digilib.image.ImageSize, digilib.servlet.DigilibConfiguration" + import="digilib.io.FileOps, digilib.io.ImageFileSet, digilib.io.ImageFile, + digilib.util.ImageSize, digilib.servlet.DigilibConfiguration" contentType="application/json"%><%! // create DocumentBean instance for all JSP requests digilib.servlet.DocumentBean docBean = new digilib.servlet.DocumentBean(); @@ -23,14 +23,11 @@ digilib.io.DocuDirCache dirCache = (digilib.io.DocuDirCache) dlConfig.getValue("servlet.dir.cache"); // get file FileOps.FileClass fc = FileOps.FileClass.IMAGE; -ImageFileset imgFile = (ImageFileset) dirCache.getFile(dlRequest.getFilePath(), dlRequest.getAsInt("pn"), fc); +ImageFileSet imgFile = (ImageFileSet) dirCache.getFile(dlRequest.getFilePath(), dlRequest.getAsInt("pn"), fc); %>{ <% if (imgFile != null) { - ImageFile img = imgFile.getBiggest(); - if (!img.isChecked()) { - DigilibConfiguration.docuImageIdentify(img); - } + ImageFile img = (ImageFile) imgFile.getBiggest(); ImageSize imgSize = img.getSize(); %> "filename" : "<%= imgFile.getName() %>",
--- a/client/digitallibrary/WEB-INF/digilib-config.xml Tue Mar 01 17:12:25 2011 +0100 +++ b/client/digitallibrary/WEB-INF/digilib-config.xml Tue Mar 01 22:00:50 2011 +0100 @@ -23,7 +23,7 @@ <parameter name="subsample-minimum" value="2"/> <!-- default interpolation quality (0=worst) --> - <parameter name="default-quality" value="1"/> + <parameter name="default-quality" value="2"/> <!-- is sending whole image files with mo=file allowed? --> <parameter name="sendfile-allowed" value="true" /> @@ -68,5 +68,7 @@ <!-- logo for PDFs --> <parameter name="pdf-logo" value="http://www.mpiwg-berlin.mpg.de/de/images/logo.png" /> + <!-- is the image toolkit allowed to use a disk cache --> + <parameter name="img-diskcache-allowed" value="false"/> </digilib-config>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/digitallibrary/WEB-INF/web-2.3.xml Tue Mar 01 22:00:50 2011 +0100 @@ -0,0 +1,142 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd"> + +<web-app> + <!-- General description of your web application --> + <display-name> + digilib + </display-name> + <description> + This is the web frontend of the Digital Document Library. + </description> + <!-- The Intialisation Listener --> + <listener> + <listener-class> + digilib.servlet.Initialiser + </listener-class> + </listener> + <!-- The Scaler servlet --> + <servlet> + <servlet-name> + Scaler + </servlet-name> + <servlet-class> + digilib.servlet.ScalerNoAsync + </servlet-class> + <!-- Load this servlet at server startup time --> + <load-on-startup> + 5 + </load-on-startup> + </servlet> + <!-- The Texter servlet --> + <servlet> + <servlet-name> + Texter + </servlet-name> + <servlet-class> + digilib.servlet.Texter + </servlet-class> + </servlet> + <!-- The PDFCache servlet --> + <servlet> + <servlet-name> + PDFCache + </servlet-name> + <servlet-class> + digilib.servlet.PDFCache + </servlet-class> + </servlet> + <!-- The mapping for the Scaler servlet --> + <servlet-mapping> + <servlet-name> + Scaler + </servlet-name> + <url-pattern> + /servlet/Scaler/* + </url-pattern> + </servlet-mapping> + <servlet-mapping> + <servlet-name> + Scaler + </servlet-name> + <url-pattern> + /Scaler + </url-pattern> + </servlet-mapping> + <servlet-mapping> + <servlet-name> + Scaler + </servlet-name> + <url-pattern> + /authenticated/servlet/Scaler/* + </url-pattern> + </servlet-mapping> + <!-- The mapping for the Texter servlet --> + <servlet-mapping> + <servlet-name> + Texter + </servlet-name> + <url-pattern> + /servlet/Texter/* + </url-pattern> + </servlet-mapping> + <servlet-mapping> + <servlet-name> + Texter + </servlet-name> + <url-pattern> + /authenticated/servlet/Texter/* + </url-pattern> + </servlet-mapping> + <!-- The mapping for the Texter servlet --> + <servlet-mapping> + <servlet-name> + PDFCache + </servlet-name> + <url-pattern> + /servlet/PDFCache/* + </url-pattern> + </servlet-mapping> + <servlet-mapping> + <servlet-name> + PDFCache + </servlet-name> + <url-pattern> + /authenticated/servlet/PDFCache/* + </url-pattern> + </servlet-mapping> + <!-- region for authenticated access --> + <security-constraint> + <web-resource-collection> + <web-resource-name> + Authenticated Digilib + </web-resource-name> + <url-pattern> + /authenticated/* + </url-pattern> + </web-resource-collection> + <!-- we need a default user --> +<!-- <auth-constraint> + <role-name> + user + </role-name> + </auth-constraint> --> + </security-constraint> + <login-config> + <!-- + <auth-method>BASIC</auth-method> + <realm-name>digilib</realm-name> + --> + <auth-method> + FORM + </auth-method> + <form-login-config> + <form-login-page> + /digilib-login.html + </form-login-page> + <form-error-page> + /digilib-fail.html + </form-error-page> + </form-login-config> + </login-config> +</web-app>
--- a/client/digitallibrary/WEB-INF/web.xml Tue Mar 01 17:12:25 2011 +0100 +++ b/client/digitallibrary/WEB-INF/web.xml Tue Mar 01 22:00:50 2011 +0100 @@ -1,8 +1,10 @@ -<!DOCTYPE web-app - PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" - "http://java.sun.com/dtd/web-app_2_3.dtd"> - -<web-app> +<?xml version="1.0" encoding="UTF-8"?> +<web-app + version="3.0" + xmlns="http://java.sun.com/xml/ns/javaee" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> + <!-- General description of your web application --> <display-name> digilib @@ -10,30 +12,17 @@ <description> This is the web frontend of the Digital Document Library. </description> - <!-- The Initaliser servlet --> - <servlet> - <servlet-name> - Initialiser - </servlet-name> - <description> - The inialisation servlet (must run first). - </description> - <servlet-class> + <!-- The Intialisation Listener (also configured by annotation) --> + <listener> + <listener-class> digilib.servlet.Initialiser - </servlet-class> - <!-- Load this servlet at server startup time --> - <load-on-startup> - 1 - </load-on-startup> - </servlet> - <!-- The Scaler servlet --> + </listener-class> + </listener> + <!-- The Scaler servlet (also configured by annotation) --> <servlet> <servlet-name> Scaler </servlet-name> - <description> - The servlet to scale the digilib images. - </description> <servlet-class> digilib.servlet.Scaler </servlet-class> @@ -47,9 +36,6 @@ <servlet-name> Texter </servlet-name> - <description> - The servlet for text. - </description> <servlet-class> digilib.servlet.Texter </servlet-class> @@ -59,9 +45,6 @@ <servlet-name> PDFCache </servlet-name> - <description> - The servlet for PDF. - </description> <servlet-class> digilib.servlet.PDFCache </servlet-class> @@ -80,6 +63,14 @@ Scaler </servlet-name> <url-pattern> + /Scaler + </url-pattern> + </servlet-mapping> + <servlet-mapping> + <servlet-name> + Scaler + </servlet-name> + <url-pattern> /authenticated/servlet/Scaler/* </url-pattern> </servlet-mapping>
--- a/client/digitallibrary/digimage_tbl_inc.jsp Tue Mar 01 17:12:25 2011 +0100 +++ b/client/digitallibrary/digimage_tbl_inc.jsp Tue Mar 01 22:00:50 2011 +0100 @@ -1,6 +1,6 @@ <%@ page language="java" %><% // retrieve objects from context -digilib.servlet.DocumentBean docBean = (digilib.servlet.DocumentBean) pageContext.getAttribute("docBean", pageContext.REQUEST_SCOPE); +digilib.servlet.DocumentBean docBean = (digilib.servlet.DocumentBean) pageContext.getAttribute("docBean", PageContext.REQUEST_SCOPE); digilib.servlet.DigilibRequest dlRequest = docBean.getRequest(); String ua = request.getHeader("User-Agent"); boolean isN4 = ((ua.indexOf("Mozilla/4.") > -1)&&(ua.indexOf("MSIE") == -1));
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/client/digitallibrary/jquery/digilib.html Tue Mar 01 22:00:50 2011 +0100 @@ -0,0 +1,42 @@ +<?xml version="1.0" ?> +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title>Digilib jQuery: fullscreen</title> + + <style type="text/css"> + body { + background: silver; + } + </style> + + <script type="text/javascript" src="jquery-1.4.4.js"></script> + <script type="text/javascript" src="jquery.cookie.js"></script> + <script type="text/javascript" src="jquery.digilib.js"></script> + <script type="text/javascript" src="jquery.digilib.geometry.js"></script> + <script type="text/javascript" src="jquery.digilib.birdseye.js"></script> + <script type="text/javascript" src="jquery.digilib.regions.js"></script> +<!-- <script type="text/javascript" src="jquery.digilib.pluginstub.js"></script> --> + <link rel="stylesheet" type="text/css" href="jquery.digilib.css" /> + + + <script type="text/javascript"> + $(document).ready(function(){ + var opts = { + interactionMode : 'fullscreen' + }; + var $div = $('div.digilib'); + $div.digilib(opts); + }); + + </script> + </head> + + <body> + <div id="digilib" class="digilib"> + <p>digilib doesn't work! Please switch on Javascript or notify the server administrator!</p> + <img src="http://digilib.berlios.de/images/digilib-logo-big.png" /> + </div> + </body> +</html> +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/servlet/DigilibServlet.jardesc Tue Mar 01 22:00:50 2011 +0100 @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="MacRoman" standalone="no"?> +<jardesc> + <jar path="digilib-servlet/DigilibServlet.jar"/> + <options buildIfNeeded="true" compress="true" descriptionLocation="/digilib-servlet/DigilibServlet.jardesc" exportErrors="false" exportWarnings="true" includeDirectoryEntries="false" overwrite="true" saveDescription="true" storeRefactorings="false" useSourceFolders="false"/> + <storedRefactorings deprecationInfo="true" structuralOnly="false"/> + <selectedProjects/> + <manifest generateManifest="true" manifestLocation="" manifestVersion="1.0" reuseManifest="false" saveManifest="false" usesManifest="true"> + <sealing sealJar="false"> + <packagesToSeal/> + <packagesToUnSeal/> + </sealing> + </manifest> + <selectedElements exportClassFiles="true" exportJavaFiles="false" exportOutputFolder="false"> + <javaElement handleIdentifier="=digilib-servlet/src<digilib.util"/> + <javaElement handleIdentifier="=digilib-servlet/src<digilib.auth"/> + <file path="/digilib-servlet/license.txt"/> + <javaElement handleIdentifier="=digilib-servlet/src<digilib.meta"/> + <javaElement handleIdentifier="=digilib-servlet/src<digilib.pdf"/> + <javaElement handleIdentifier="=digilib-servlet/src<digilib.io"/> + <file path="/digilib-servlet/DigilibServlet.jardesc"/> + <javaElement handleIdentifier="=digilib-servlet/src<digilib.servlet"/> + <javaElement handleIdentifier="=digilib-servlet/src<digilib.image"/> + </selectedElements> +</jardesc>
--- a/servlet/src/digilib/auth/HashTree.java Tue Mar 01 17:12:25 2011 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,113 +0,0 @@ -/* HashTree -- Tree in a Hashtable - - Digital Image Library servlet components - - Copyright (C) 2001, 2002 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.auth; - -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.StringTokenizer; - -/** - * Tree representation wrapper for a HashMap. - * - * The HashTree is constructed from a HashMap filled with 'branches' with - * 'leaves'. The branches are stored as String keys in the HashMap. The String - * values are leaves. - * - * Branches are matched in 'twigs' separated by 'twig separator' Strings. The - * return values for a match are leaf values separated by 'leaf separator' - * Strings. - * - * @author casties - */ -public class HashTree { - - private Map<String, String> table; - - private String twigSep = "/"; - - private String leafSep = ","; - - /** - * Constructor of a HashTree. - * - * Creates a HashTree wrapper around a given HashMap, using the given twig - * separator and leaf separator. - * - * @param t - * @param twig_separator - * @param leaf_separator - */ - public HashTree(Map<String, String> t, String twig_separator, String leaf_separator) { - table = t; - twigSep = twig_separator; - leafSep = leaf_separator; - optimizeTable(); - } - - void optimizeTable() { - } - - /** - * Matches the given branch against the HashTree. - * - * Returns a LinkedList of all leaves on all matching branches in the tree. - * Branches in the tree match if they are substrings starting at the same - * root. - * - * @param branch - * @return - */ - List<String> match(String branch) { - String b = ""; - String m; - LinkedList<String> matches = new LinkedList<String>(); - - // split branch - StringTokenizer twig = new StringTokenizer(branch, twigSep); - // walk branch and check with tree - while (twig.hasMoreTokens()) { - if (b.length() == 0) { - b = twig.nextToken(); - } else { - b += twigSep + twig.nextToken(); - } - m = table.get(b); - if (m != null) { - if (m.indexOf(leafSep) < 0) { - // single leaf - matches.add(m); - } else { - // split leaves - StringTokenizer leaf = new StringTokenizer(m, leafSep); - while (leaf.hasMoreTokens()) { - matches.add(leaf.nextToken()); - } - } - } - } - if (matches.size() > 0) { - return matches; - } else { - return null; - } - } -}
--- a/servlet/src/digilib/auth/XMLAuthOps.java Tue Mar 01 17:12:25 2011 +0100 +++ b/servlet/src/digilib/auth/XMLAuthOps.java Tue Mar 01 22:00:50 2011 +0100 @@ -26,8 +26,9 @@ import javax.servlet.http.HttpServletRequest; -import digilib.io.XMLListLoader; import digilib.servlet.DigilibRequest; +import digilib.util.HashTree; +import digilib.util.XMLListLoader; /** Implementation of AuthOps using XML files. *
--- a/servlet/src/digilib/image/DocuImage.java Tue Mar 01 17:12:25 2011 +0100 +++ b/servlet/src/digilib/image/DocuImage.java Tue Mar 01 22:00:50 2011 +0100 @@ -27,8 +27,9 @@ import javax.servlet.ServletException; -import digilib.io.ImageFile; import digilib.io.FileOpException; +import digilib.io.ImageInput; +import digilib.util.ImageSize; /** The basic class for the representation of a digilib image. * @@ -41,12 +42,12 @@ /** Loads an image file into the Object. * - * @param f Image File. + * @param ii Image File. * @throws FileOpException Exception thrown if any error occurs. */ - public void loadImage(ImageFile f) throws FileOpException; + public void loadImage(ImageInput ii) throws FileOpException; - /** This DocuImage support the loadSubImage operation. + /** This DocuImage supports the loadSubImage operation. * * @return boolean */ @@ -54,23 +55,23 @@ /** Load only a subsampled region of the image file. * - * @param f + * @param ii * @param region * @param subsample * @throws FileOpException */ - public void loadSubimage(ImageFile f, Rectangle region, int subsample) + public void loadSubimage(ImageInput ii, Rectangle region, int subsample) throws FileOpException; - /** Writes the current image to a ServletResponse. + /** Writes the current image to an OutputStream. * * The image is encoded to the mime-type <code>mt</code> and sent to the output - * stream of the <code>ServletResponse</code> <code>res</code>. + * stream <code>ostream</code>. * * Currently only mime-types "image/jpeg" and "image/png" are supported. * * @param mt mime-type of the image to be sent. - * @param res ServletResponse where the image is sent. + * @param ostream OutputStream where the image is sent. * @throws ServletException Exception thrown on sending data. * @throws ImageOpException Exception in other cases. */ @@ -95,7 +96,7 @@ */ public ImageSize getSize(); - /** The mime-type of the current image. + /** The mime-type of the image, i.e. the mime-type of the input that was read. * * @return String the mime-type of this image. */ @@ -201,6 +202,22 @@ public void enhanceRGB(float[] rgbm, float[] rgba) throws ImageOpException; + + /** Operations for colorOps. + * + * + */ + public enum ColorOp {GRAYSCALE, INVERT}; + + /** Changes the colors of the current image. + * + * Changes the colors of the current image. Operations are e.g. + * reduction to grayscale or false-color palettes. + * + * @throws ImageOpException + */ + public void colorOp(ColorOp op) throws ImageOpException; + /** * Returns the interpolation quality. * @return int @@ -221,9 +238,9 @@ public void dispose(); /** - * Check image size and type and store in ImageFile f + * Check image size and type and store in ImageInput ii */ - public ImageFile identify(ImageFile imgf) throws IOException; + public ImageInput identify(ImageInput ii) throws IOException; /** * Returns a list of supported image formats
--- a/servlet/src/digilib/image/DocuImageImpl.java Tue Mar 01 17:12:25 2011 +0100 +++ b/servlet/src/digilib/image/DocuImageImpl.java Tue Mar 01 22:00:50 2011 +0100 @@ -33,7 +33,8 @@ import org.apache.log4j.Logger; import digilib.io.FileOpException; -import digilib.io.ImageFile; +import digilib.io.ImageInput; +import digilib.util.ImageSize; /** Simple abstract implementation of the <code>DocuImage</code> interface. * @@ -53,13 +54,13 @@ /** epsilon for float comparisons. */ public final double epsilon = 1e-5; - - /** image mime-type */ - protected String mimeType = null; /** image size */ protected ImageSize imgSize = null; + /** ImageInput that was read */ + protected ImageInput input; + /** * Returns the quality. * @return int @@ -99,14 +100,20 @@ scale(scale, scale); } + /* (non-Javadoc) + * @see digilib.image.DocuImage#getMimetype() + */ public String getMimetype() { - return mimeType; + if (input != null) { + return input.getMimetype(); + } + return null; } /* (non-Javadoc) * @see digilib.image.DocuImage#identify(digilib.io.ImageFile) */ - public ImageFile identify(ImageFile imgf) throws IOException { + public ImageInput identify(ImageInput ii) throws IOException { // just a do-nothing implementation return null; } @@ -128,7 +135,7 @@ return false; } - public void loadSubimage(ImageFile f, Rectangle region, int subsample) + public void loadSubimage(ImageInput ii, Rectangle region, int subsample) throws FileOpException { // empty implementation } @@ -138,6 +145,10 @@ // emtpy implementation } + public void colorOp(ColorOp op) throws ImageOpException { + // emtpy implementation + } + public void dispose() { // emtpy implementation } @@ -149,11 +160,11 @@ public void crop(int xoff, int yoff, int width, int height) throws ImageOpException { - // TODO Auto-generated method stub + // emtpy implementation } public Image getAwtImage() { - // TODO Auto-generated method stub + // emtpy implementation return null; } @@ -177,19 +188,12 @@ return imgSize; } - public void loadImage(ImageFile f) throws FileOpException { - // TODO Auto-generated method stub - - } + public abstract void loadImage(ImageInput ii) throws FileOpException; + + public abstract void scale(double scaleX, double scaleY) throws ImageOpException; - public void scale(double scaleX, double scaleY) throws ImageOpException { - // TODO Auto-generated method stub - - } + public abstract void writeImage(String mt, OutputStream ostream) + throws ServletException, ImageOpException; - public void writeImage(String mt, OutputStream ostream) - throws ServletException, ImageOpException { - // TODO Auto-generated method stub - } }
--- a/servlet/src/digilib/image/ImageInfoDocuImage.java Tue Mar 01 17:12:25 2011 +0100 +++ b/servlet/src/digilib/image/ImageInfoDocuImage.java Tue Mar 01 22:00:50 2011 +0100 @@ -3,13 +3,13 @@ */ package digilib.image; -import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import org.marcoschmidt.image.ImageInfo; -import digilib.io.ImageFile; +import digilib.io.ImageInput; +import digilib.util.ImageSize; /** Simple abstract implementation of the <code>DocuImage</code> interface. * Implements only the identify method using the ImageInfo class. @@ -18,31 +18,38 @@ */ public abstract class ImageInfoDocuImage extends DocuImageImpl { - /** Check image size and type and store in ImageFile f */ - public ImageFile identify(ImageFile imgf) throws IOException { - // fileset to store the information - File f = imgf.getFile(); - if (f == null) { - throw new IOException("File not found!"); - } - RandomAccessFile raf = new RandomAccessFile(f, "r"); - // set up ImageInfo object - ImageInfo iif = new ImageInfo(); - iif.setInput(raf); - iif.setCollectComments(false); - iif.setDetermineImageNumber(false); - logger.debug("identifying (ImageInfo) " + f); - // try with ImageInfo first - if (iif.check()) { - ImageSize d = new ImageSize(iif.getWidth(), iif.getHeight()); - imgf.setSize(d); - imgf.setMimetype(iif.getMimeType()); - //logger.debug(" format:"+iif.getFormatName()); - raf.close(); - logger.debug("image size: " + imgf.getSize()); - return imgf; - } else { - raf.close(); + /* Check image size and type and store in ImageFile f */ + public ImageInput identify(ImageInput ii) throws IOException { + logger.debug("identifying (ImageInfo) " + ii); + RandomAccessFile raf = null; + try { + // set up ImageInfo object + ImageInfo iif = new ImageInfo(); + if (ii.hasImageInputStream()) { + iif.setInput(ii.getImageInputStream()); + } else if (ii.hasFile()) { + raf = new RandomAccessFile(ii.getFile(), "r"); + iif.setInput(raf); + } else { + return null; + } + iif.setCollectComments(false); + iif.setDetermineImageNumber(false); + // try with ImageInfo first + if (iif.check()) { + ImageSize d = new ImageSize(iif.getWidth(), iif.getHeight()); + ii.setSize(d); + ii.setMimetype(iif.getMimeType()); + logger.debug("image size: " + ii.getSize()); + return ii; + } + } catch (Exception e) { + logger.debug("ImageInfoDocuimage unable to identify.", e); + } finally { + // close file, don't close stream(?) + if (raf != null) { + raf.close(); + } } return null; }
--- a/servlet/src/digilib/image/ImageJobDescription.java Tue Mar 01 17:12:25 2011 +0100 +++ b/servlet/src/digilib/image/ImageJobDescription.java Tue Mar 01 22:00:50 2011 +0100 @@ -6,29 +6,29 @@ import org.apache.log4j.Logger; +import digilib.image.DocuImage.ColorOp; import digilib.io.DocuDirCache; import digilib.io.DocuDirectory; import digilib.io.FileOpException; import digilib.io.FileOps; import digilib.io.FileOps.FileClass; -import digilib.io.ImageFile; -import digilib.io.ImageFileset; +import digilib.io.ImageInput; +import digilib.io.ImageSet; import digilib.servlet.DigilibConfiguration; +import digilib.util.ImageSize; 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. +/** + * A class for storing the set of parameters necessary for scaling images + * with an ImageWorker. * - * This contains the functionality formerly found in Scaler, processRequest, only factorized. - * - * TODO clean up... + * This contains the functionality formerly found in Scaler.processRequest(), + * only factorized. * * @author cmielack, casties - * + * */ public class ImageJobDescription extends ParameterMap { @@ -36,18 +36,18 @@ DigilibConfiguration dlConfig = null; protected static Logger logger = Logger.getLogger("digilib.servlet"); - ImageFile fileToLoad = null; - ImageFileset fileset = null; + ImageInput input = null; + ImageSet imageSet = null; DocuDirectory fileDir = null; String filePath = null; ImageSize expectedSourceSize = null; Float scaleXY = null; Rectangle2D userImgArea = null; - Rectangle2D outerUserImgArea= null; + Rectangle2D outerUserImgArea = null; Boolean imageSendable = null; - String mimeType; - Integer paramDW; - Integer paramDH; + String mimeType = null; + Integer paramDW = null; + Integer paramDH = null; /** create empty ImageJobDescription. * @param dlcfg @@ -101,6 +101,8 @@ newParameter("ddpiy", new Float(0), null, 's'); // scale factor for mo=ascale newParameter("scale", new Float(1), null, 's'); + // color conversion operation + newParameter("colop", "", null, 's'); } @@ -128,48 +130,57 @@ } + /** Returns the mime-type (of the input). + * @return + * @throws IOException + */ public String getMimeType() throws IOException { if (mimeType == null) { - fileToLoad = getFileToLoad(); - if(! fileToLoad.isChecked()){ - DigilibConfiguration.docuImageIdentify(fileToLoad); - } - mimeType = fileToLoad.getMimetype(); + input = getInput(); + mimeType = input.getMimetype(); } return mimeType; } - public ImageFile getFileToLoad() throws IOException { - - if(fileToLoad == null){ - fileset = getFileset(); + /** Returns the ImageInput to use. + * @return + * @throws IOException + */ + public ImageInput getInput() throws IOException { + if(input == null){ + imageSet = getImageSet(); /* select a resolution */ - if (getHiresOnly()) { + if (isHiresOnly()) { // get first element (= highest resolution) - fileToLoad = fileset.getBiggest(); - } else if (getLoresOnly()) { + input = imageSet.getBiggest(); + } else if (isLoresOnly()) { // enforced lores uses next smaller resolution - fileToLoad = fileset.getNextSmaller(getExpectedSourceSize()); - if (fileToLoad == null) { + input = imageSet.getNextSmaller(getExpectedSourceSize()); + if (input == null) { // this is the smallest we have - fileToLoad = fileset.getSmallest(); + input = imageSet.getSmallest(); } } else { // autores: use next higher resolution - fileToLoad = fileset.getNextBigger(getExpectedSourceSize()); - if (fileToLoad == null) { + input = imageSet.getNextBigger(getExpectedSourceSize()); + if (input == null) { // this is the highest we have - fileToLoad = fileset.getBiggest(); + input = imageSet.getBiggest(); } } - logger.info("Planning to load: " + fileToLoad.getFile()); + if (input == null || input.getMimetype() == null) { + throw new FileOpException("Unable to load "+input); + } + logger.info("Planning to load: " + input); } - - return fileToLoad; - + return input; } + /** Returns the DocuDirectory for the input (file). + * @return + * @throws FileOpException + */ public DocuDirectory getFileDirectory() throws FileOpException { if(fileDir == null){ DocuDirCache dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache"); @@ -182,19 +193,26 @@ return fileDir; } - public ImageFileset getFileset() throws FileOpException { - if(fileset==null){ + /** Returns the ImageSet to load. + * @return + * @throws FileOpException + */ + public ImageSet getImageSet() throws FileOpException { + if(imageSet==null){ DocuDirCache dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache"); - fileset = (ImageFileset) dirCache.getFile(getFilePath(), getAsInt("pn"), FileClass.IMAGE); - if (fileset == null) { + imageSet = (ImageSet) dirCache.getFile(getFilePath(), getAsInt("pn"), FileClass.IMAGE); + if (imageSet == null) { throw new FileOpException("File " + getFilePath() + "(" + getAsInt("pn") + ") not found."); } } - return fileset; + return imageSet; } + /** Returns the file path name from the request. + * @return + */ public String getFilePath() { if(filePath == null){ String s = this.getAsString("request.path"); @@ -204,32 +222,36 @@ return filePath; } - public boolean getHiresOnly(){ + public boolean isHiresOnly(){ return hasOption("clip") || hasOption("hires"); } - public boolean getLoresOnly(){ + public boolean isLoresOnly(){ return hasOption("lores"); } - public boolean getScaleToFit() { + public boolean isScaleToFit() { return !(hasOption("clip") || hasOption("osize") || hasOption("ascale")); } - public boolean getAbsoluteScale(){ + public boolean isAbsoluteScale(){ return hasOption("osize") || hasOption("ascale"); } + /** Returns the minimum size the source image should have for scaling. + * @return + * @throws IOException + */ public ImageSize getExpectedSourceSize() throws IOException { if (expectedSourceSize == null){ expectedSourceSize = new ImageSize(); - if (getScaleToFit()) { + if (isScaleToFit()) { // 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")) { + } else if (isAbsoluteScale() && hasOption("ascale")) { // absolute scale -- apply scale to hires size expectedSourceSize = getHiresSize().getScaled(getAsFloat("scale")); } else { @@ -241,16 +263,17 @@ return expectedSourceSize; } + /** Returns the size of the highest resolution image. + * @return + * @throws IOException + */ public ImageSize getHiresSize() throws IOException { logger.debug("get_hiresSize()"); ImageSize hiresSize = null; - ImageFileset fileset = getFileset(); - if (getAbsoluteScale()) { - ImageFile hiresFile = fileset.getBiggest(); - if (!hiresFile.isChecked()) { - DigilibConfiguration.docuImageIdentify(hiresFile); - } + ImageSet fileset = getImageSet(); + if (isAbsoluteScale()) { + ImageInput hiresFile = fileset.getBiggest(); hiresSize = hiresFile.getSize(); } return hiresSize; @@ -270,7 +293,7 @@ float areaWidth; float areaHeight; float ws = getAsFloat("ws"); - ImageSize imgSize = getFileToLoad().getSize(); + ImageSize imgSize = getInput().getSize(); // user window area in [0,1] coordinates Rectangle2D relUserArea = new Rectangle2D.Float(getAsFloat("wx"), getAsFloat("wy"), getAsFloat("ww"), getAsFloat("wh")); @@ -281,20 +304,20 @@ userImgArea = imgTrafo.createTransformedShape( relUserArea).getBounds2D(); - if (getScaleToFit()) { + if (isScaleToFit()) { // 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()) { + } else if (isAbsoluteScale()) { // absolute scaling factor if (hasOption("osize")) { // get original resolution from metadata - fileset.checkMeta(); - float origResX = fileset.getResX(); - float origResY = fileset.getResY(); + imageSet.checkMeta(); + float origResX = imageSet.getResX(); + float origResY = imageSet.getResY(); if ((origResX == 0) || (origResY == 0)) { throw new ImageOpException("Missing image DPI information!"); } @@ -340,6 +363,11 @@ return (float) scaleXY; } + /** Returns the width of the destination image. + * Uses dh parameter and aspect ratio if dw parameter is empty. + * @return + * @throws IOException + */ public int getDw() throws IOException { logger.debug("get_paramDW()"); if (paramDW == null) { @@ -347,7 +375,7 @@ paramDW = getAsInt("dw"); paramDH = getAsInt("dh"); - float imgAspect = getFileToLoad().getAspect(); + float imgAspect = getInput().getAspect(); if (paramDW == 0) { // calculate dw paramDW = Math.round(paramDH * imgAspect); @@ -361,6 +389,11 @@ return paramDW; } + /** Returns the height of the destination image. + * Uses dw parameter and aspect ratio if dh parameter is empty. + * @return + * @throws IOException + */ public int getDh() throws IOException { logger.debug("get_paramDH()"); if (paramDH == null) { @@ -368,7 +401,7 @@ paramDW = getAsInt("dw"); paramDH = getAsInt("dh"); - float imgAspect = getFileToLoad().getAspect(); + float imgAspect = getInput().getAspect(); if (paramDW == 0) { // calculate dw paramDW = Math.round(paramDH * imgAspect); @@ -382,9 +415,12 @@ return paramDH; } - public Integer getScaleQual(){ + /** Returns image quality as an integer. + * @return + */ + public int getScaleQual(){ logger.debug("get_scaleQual()"); - Integer qual = dlConfig.getAsInt("default-quality"); + int qual = dlConfig.getAsInt("default-quality"); if(hasOption("q0")) qual = 0; else if(hasOption("q1")) @@ -394,22 +430,43 @@ return qual; } + public ColorOp getColOp() { + String op = getAsString("colop"); + try { + return ColorOp.valueOf(op.toUpperCase()); + } catch (Exception e) { + logger.error("Invalid color op: " + op); + } + return null; + } + /** + * Returns the area of the source image that will be transformed into the + * destination image. + * + * @return + * @throws IOException + * @throws ImageOpException + */ public Rectangle2D getUserImgArea() throws IOException, ImageOpException{ if(userImgArea == null) { // getScaleXY sets userImgArea getScaleXY(); } return userImgArea; - } + /** Returns the maximal area of the source image that will be used. + * @return + * @throws IOException + * @throws ImageOpException + */ public Rectangle2D getOuterUserImgArea() throws IOException, ImageOpException { if(outerUserImgArea == null){ outerUserImgArea = getUserImgArea(); // image size in pixels - ImageSize imgSize = getFileToLoad().getSize(); + ImageSize imgSize = getInput().getSize(); Rectangle2D imgBounds = new Rectangle2D.Float(0, 0, imgSize.getWidth(), imgSize.getHeight()); @@ -437,10 +494,7 @@ float[] paramRGBM = null;//{0f,0f,0f}; Parameter p = params.get("rgbm"); if (p.hasValue() && (!p.getAsString().equals("0/0/0"))) { - paramRGBM = p.parseAsFloatArray("/"); - if ((paramRGBM == null) || (paramRGBM.length != 3)) { - return null; - } + return p.parseAsFloatArray("/"); } return paramRGBM; } @@ -450,9 +504,6 @@ Parameter p = params.get("rgba"); if (p.hasValue() && (!p.getAsString().equals("0/0/0"))) { paramRGBA = p.parseAsFloatArray("/"); - if ((paramRGBA == null) || (paramRGBA.length != 3)) { - return null; - } } return paramRGBA; } @@ -465,42 +516,45 @@ || 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; - } + /** + * Returns if the image can 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 { + if (imageSendable == null) { + String mimeType = getMimeType(); + imageSendable = (mimeType != null + && (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; + } + /** + * Returns if any transformation of the source image (image manipulation or + * format conversion) is required. + * + * @return + * @throws IOException + */ public boolean isTransformRequired() throws IOException { - ImageSize is = getFileToLoad().getSize(); + ImageSize is = getInput().getSize(); ImageSize ess = getExpectedSourceSize(); // nt = no transform required boolean nt = isImageSendable() && ( // lores: send if smaller - (getLoresOnly() && is.isSmallerThan(ess)) + (isLoresOnly() && is.isSmallerThan(ess)) // else send if it fits - || (!(getLoresOnly() || getHiresOnly()) && is.fitsIn(ess))); + || (!(isLoresOnly() || isHiresOnly()) && is.fitsIn(ess))); return ! nt; } } \ No newline at end of file
--- a/servlet/src/digilib/image/ImageLoaderDocuImage.java Tue Mar 01 17:12:25 2011 +0100 +++ b/servlet/src/digilib/image/ImageLoaderDocuImage.java Tue Mar 01 22:00:50 2011 +0100 @@ -2,7 +2,7 @@ Digital Image Library servlet components - Copyright (C) 2002, 2003 Robert Casties (robcast@mail.berlios.de) + Copyright (C) 2002 - 2011 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 @@ -22,14 +22,19 @@ import java.awt.Image; import java.awt.Rectangle; import java.awt.RenderingHints; +import java.awt.color.ColorSpace; import java.awt.geom.AffineTransform; import java.awt.geom.Rectangle2D; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; +import java.awt.image.ByteLookupTable; +import java.awt.image.ColorConvertOp; +import java.awt.image.ColorModel; import java.awt.image.ConvolveOp; import java.awt.image.Kernel; +import java.awt.image.LookupOp; +import java.awt.image.LookupTable; import java.awt.image.RescaleOp; -import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.io.RandomAccessFile; @@ -49,24 +54,48 @@ import digilib.io.FileOpException; import digilib.io.FileOps; -import digilib.io.ImageFile; -import digilib.io.ImageFileset; +import digilib.io.ImageInput; +import digilib.util.ImageSize; /** Implementation of DocuImage using the ImageLoader API of Java 1.4 and Java2D. */ public class ImageLoaderDocuImage extends ImageInfoDocuImage { - + /** image object */ protected BufferedImage img; /** interpolation type */ - protected RenderingHints renderHint; + protected RenderingHints renderHint = null; + + /** convolution kernels for blur() */ + protected static Kernel[] convolutionKernels = { + null, + new Kernel(1, 1, new float[] {1f}), + new Kernel(2, 2, new float[] {0.25f, 0.25f, 0.25f, 0.25f}), + new Kernel(3, 3, new float[] {1f/9f, 1f/9f, 1f/9f, 1f/9f, 1f/9f, 1f/9f, 1f/9f, 1f/9f, 1f/9f}) + }; - /** ImageIO image reader */ - protected ImageReader reader; - - /** File that was read */ - protected File imgFile; - + /** lookup table for inverting images (byte) */ + protected static LookupTable invertByteTable; + protected static LookupTable invertRGBByteTable; + + static { + byte[] invertByte = new byte[256]; + byte[] orderedByte = new byte[256]; + for (int i = 0; i < 256; ++i) { + invertByte[i] = (byte) (256 - i); + orderedByte[i] = (byte) i; + } + // works for JPEG in q2 + invertRGBByteTable = new ByteLookupTable(0, new byte[][] { + orderedByte, invertByte, invertByte}); + // should work for all color models + invertByteTable = new ByteLookupTable(0, invertByte); + } + + /** the size of the current image */ + protected ImageSize imageSize; + + /* loadSubimage is supported. */ public boolean isSubimageSupported() { return true; @@ -91,25 +120,26 @@ /* returns the size of the current image */ public ImageSize getSize() { - ImageSize is = null; - // TODO: do we want to cache imageSize? - int h = 0; - int w = 0; - try { - if (img == null) { - // get size from ImageReader - h = reader.getHeight(0); - w = reader.getWidth(0); - } else { - // get size from image - h = img.getHeight(); - w = img.getWidth(); + if (imageSize == null) { + int h = 0; + int w = 0; + try { + if (img == null) { + ImageReader reader = getReader(input); + // get size from ImageReader + h = reader.getHeight(0); + w = reader.getWidth(0); + } else { + // get size from image + h = img.getHeight(); + w = img.getWidth(); + } + imageSize = new ImageSize(w, h); + } catch (IOException e) { + logger.debug("error in getSize:", e); } - is = new ImageSize(w, h); - } catch (IOException e) { - logger.debug("error in getSize:", e); } - return is; + return imageSize; } /* returns a list of supported image formats */ @@ -118,44 +148,56 @@ return Arrays.asList(formats).iterator(); } - /** Check image size and type and store in ImageFile f */ - public ImageFile identify(ImageFile imageFile) throws IOException { + /* Check image size and type and store in ImageInput */ + public ImageInput identify(ImageInput input) throws IOException { // try parent method first - ImageFile imf = super.identify(imageFile); - if (imf != null) { - return imf; - } - // fileset to store the information - ImageFileset imgfs = imageFile.getParent(); - File f = imageFile.getFile(); - if (f == null) { - throw new IOException("File not found!"); + ImageInput ii = super.identify(input); + if (ii != null) { + return ii; } - logger.debug("identifying (ImageIO) " + f); - /* - * try ImageReader - */ - if ((reader == null) || (imgFile != imageFile.getFile())) { - getReader(imageFile); + logger.debug("identifying (ImageIO) " + input); + ImageReader reader = null; + try { + /* + * try ImageReader + */ + reader = getReader(input); + // set size + ImageSize d = new ImageSize(reader.getWidth(0), reader.getHeight(0)); + input.setSize(d); + // set mime type + if (input.getMimetype() == null) { + if (input.hasFile()) { + String t = FileOps.mimeForFile(input.getFile()); + input.setMimetype(t); + } else { + // FIXME: is format name a mime type??? + String t = reader.getFormatName(); + input.setMimetype(t); + } + } + return input; + } catch (FileOpException e) { + // maybe just our class doesn't know what to do + logger.error("ImageLoaderDocuimage unable to identify:", e); + return null; + } finally { + if (reader != null) { + reader.dispose(); + } } - ImageSize d = new ImageSize(reader.getWidth(0), reader.getHeight(0)); - imageFile.setSize(d); - // String t = reader.getFormatName(); - String t = FileOps.mimeForFile(f); - imageFile.setMimetype(t); - // logger.debug(" format:"+t); - if (imgfs != null) { - imgfs.setAspect(d); - } - return imageFile; } /* load image file */ - public void loadImage(ImageFile f) throws FileOpException { - logger.debug("loadImage " + f.getFile()); + public void loadImage(ImageInput ii) throws FileOpException { + logger.debug("loadImage: " + ii); + this.input = ii; try { - img = ImageIO.read(f.getFile()); - mimeType = f.getMimetype(); + if (ii.hasImageInputStream()) { + img = ImageIO.read(ii.getImageInputStream()); + } else if (ii.hasFile()) { + img = ImageIO.read(ii.getFile()); + } } catch (IOException e) { throw new FileOpException("Error reading image."); } @@ -166,17 +208,28 @@ * * @return */ - public ImageReader getReader(ImageFile f) throws IOException { - logger.debug("preloadImage " + f.getFile()); - if (reader != null) { - logger.debug("Reader was not null!"); - // clean up old reader - dispose(); + public ImageReader getReader(ImageInput input) throws IOException { + logger.debug("get ImageReader for " + input); + ImageInputStream istream = null; + if (input.hasImageInputStream()) { + // stream input + istream = input.getImageInputStream(); + } else if (input.hasFile()) { + // file only input + RandomAccessFile rf = new RandomAccessFile(input.getFile(), "r"); + istream = new FileImageInputStream(rf); + } else { + throw new FileOpException("Unable to get data from ImageInput"); } - RandomAccessFile rf = new RandomAccessFile(f.getFile(), "r"); - ImageInputStream istream = new FileImageInputStream(rf); Iterator<ImageReader> readers; - String mt = f.getMimetype(); + String mt = null; + if (input.hasMimetype()) { + // check hasMimetype first or we might get into a loop + mt = input.getMimetype(); + } else { + // try file extension + mt = FileOps.mimeForFile(input.getFile()); + } if (mt == null) { logger.debug("No mime-type. Trying automagic."); readers = ImageIO.getImageReaders(istream); @@ -185,28 +238,26 @@ readers = ImageIO.getImageReadersByMIMEType(mt); } if (!readers.hasNext()) { - rf.close(); throw new FileOpException("Can't find Reader to load File!"); } - reader = readers.next(); + ImageReader reader = readers.next(); /* are there more readers? */ logger.debug("ImageIO: this reader: " + reader.getClass()); /* while (readers.hasNext()) { logger.debug("ImageIO: next reader: " + readers.next().getClass()); } */ reader.setInput(istream); - imgFile = f.getFile(); return reader; } /* Load an image file into the Object. */ - public void loadSubimage(ImageFile f, Rectangle region, int prescale) + public void loadSubimage(ImageInput ii, Rectangle region, int prescale) throws FileOpException { logger.debug("loadSubimage"); + this.input = ii; + ImageReader reader = null; try { - if ((reader == null) || (imgFile != f.getFile())) { - getReader(f); - } + reader = getReader(ii); // set up reader parameters ImageReadParam readParam = reader.getDefaultReadParam(); readParam.setSourceRegion(region); @@ -216,10 +267,13 @@ // read image logger.debug("loading.."); img = reader.read(0, readParam); - mimeType = f.getMimetype(); logger.debug("loaded"); } catch (IOException e) { throw new FileOpException("Unable to load File!"); + } finally { + if (reader != null) { + reader.dispose(); + } } } @@ -285,16 +339,12 @@ } catch (IOException e) { logger.error("Error writing image:", e); throw new ServletException("Error writing image:", e); - } finally { - // clean up - if (writer != null) { - writer.dispose(); - } } + // TODO: should we: finally { writer.dispose(); } } public void scale(double scale, double scaleY) throws ImageOpException { - logger.debug("scale"); + logger.debug("scale: " + scale); /* for downscaling in high quality the image is blurred first */ if ((scale <= 0.5) && (quality > 1)) { int bl = (int) Math.floor(1 / scale); @@ -325,19 +375,23 @@ } public void blur(int radius) throws ImageOpException { - // DEBUG logger.debug("blur: " + radius); // minimum radius is 2 int klen = Math.max(radius, 2); - // FIXME: use constant kernels for most common sizes - int ksize = klen * klen; - // kernel is constant 1/k - float f = 1f / ksize; - float[] kern = new float[ksize]; - for (int i = 0; i < ksize; i++) { - kern[i] = f; + Kernel blur = null; + if (klen < convolutionKernels.length) { + blur = convolutionKernels[klen]; + } else { + // calculate our own kernel + int ksize = klen * klen; + // kernel is constant 1/k + float f = 1f / ksize; + float[] kern = new float[ksize]; + for (int i = 0; i < ksize; ++i) { + kern[i] = f; + } + blur = new Kernel(klen, klen, kern); } - Kernel blur = new Kernel(klen, klen, kern); // blur with convolve operation ConvolveOp blurOp = new ConvolveOp(blur, ConvolveOp.EDGE_NO_OP, renderHint); @@ -391,8 +445,7 @@ */ int ncol = img.getColorModel().getNumColorComponents(); if ((ncol != 3) || (rgbm.length != 3) || (rgba.length != 3)) { - logger - .debug("ERROR(enhance): unknown number of color bands or coefficients (" + logger.debug("ERROR(enhance): unknown number of color bands or coefficients (" + ncol + ")"); return; } @@ -403,7 +456,7 @@ /** * Ensures that the array f is in the right order to map the images RGB - * components. (not shure what happens + * components. (not sure what happens otherwise) */ public float[] rgbOrdered(float[] fa) { /* @@ -443,6 +496,31 @@ return fb; } + /* + * (non-Javadoc) + * + * @see + * digilib.image.DocuImageImpl#colorOp(digilib.image.DocuImage.ColorOps) + */ + public void colorOp(ColorOp op) throws ImageOpException { + if (op == ColorOp.GRAYSCALE) { + // convert image to grayscale + logger.debug("Color op: grayscaling"); + ColorConvertOp colop = new ColorConvertOp( + ColorSpace.getInstance(ColorSpace.CS_GRAY), renderHint); + img = colop.filter(img, null); + } else if (op == ColorOp.INVERT) { + // invert colors i.e. invert every channel + logger.debug("Color op: inverting"); + // TODO: is this enough for all image types? + LookupOp colop = new LookupOp(invertByteTable, renderHint); + ColorModel cm = img.getColorModel(); + logger.debug("colop: image="+img+" colormodel="+cm); + img = colop.filter(img, null); + } + + } + public void rotate(double angle) throws ImageOpException { // setup rotation double rangle = Math.toRadians(angle); @@ -504,23 +582,8 @@ img = mirImg; } - /* - * (non-Javadoc) - * - * @see java.lang.Object#finalize() - */ - protected void finalize() throws Throwable { - dispose(); - super.finalize(); - } - public void dispose() { - // we must dispose the ImageReader because it keeps the filehandle - // open! - if (reader != null) { - reader.dispose(); - reader = null; - } + // is this necessary? img = null; }
--- a/servlet/src/digilib/image/ImageSize.java Tue Mar 01 17:12:25 2011 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,230 +0,0 @@ -/* - * ImageSize.java -- digilib image size class. - * 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 26.08.2003 - */ - -package digilib.image; - -/** Class for image size (width, height). - * - * A width or height of 0 is treated as a 'wildcard' that matches any size. - * - * @author casties - * - */ -public class ImageSize { - public int width; - public int height; - - public ImageSize() { - super(); - } - - public ImageSize(int width, int height) { - this.width = width; - this.height = height; - } - - public ImageSize(ImageSize i) { - this.width = i.width; - this.height = i.height; - } - - public void setSize(int width, int height) { - this.width = width; - this.height = height; - } - - /** - * Returns if the size of this image is smaller in every dimension than the - * other image. - * - * - * - * @param is - * @return - */ - public boolean isTotallySmallerThan(ImageSize is) { - if ((this.width == 0)||(is.width == 0)) { - // width wildcard - return (this.height <= is.height); - } - if ((this.height == 0)||(is.height == 0)) { - // height wildcard - return (this.width <= is.width); - } - return ((this.width <= is.width)&&(this.height <= is.height)); - } - - /** - * Returns if the size of this image is smaller in at least one dimension - * than the other image. - * - * @param is - * @return - */ - public boolean isSmallerThan(ImageSize is) { - if ((this.width == 0)||(is.width == 0)) { - // width wildcard - return (this.height <= is.height); - } - if ((this.height == 0)||(is.height == 0)) { - // height wildcard - return (this.width <= is.width); - } - return ((this.width <= is.width) || (this.height <= is.height)); - } - - /** - * Returns if the size of this image is bigger in every dimension than the - * other image. - * - * - * - * @param is - * @return - */ - public boolean isTotallyBiggerThan(ImageSize is) { - if ((this.width == 0)||(is.width == 0)) { - // width wildcard - return (this.height >= is.height); - } - if ((this.height == 0)||(is.height == 0)) { - // height wildcard - return (this.width >= is.width); - } - return ((this.width >= is.width) && (this.height >= is.height)); - } - - /** - * Returns if the size of this image is bigger in at least one dimension - * than the other image. - * - * - * - * @param is - * @return - */ - public boolean isBiggerThan(ImageSize is) { - if ((this.width == 0)||(is.width == 0)) { - // width wildcard - return (this.height >= is.height); - } - if ((this.height == 0)||(is.height == 0)) { - // height wildcard - return (this.width >= is.width); - } - return ((this.width >= is.width) || (this.height >= is.height)); - } - - /** - * Returns if this image has the same size or height as the other image. - * - * - * - * @param is - * @return - */ - public boolean fitsIn(ImageSize is) { - if ((this.width == 0)||(is.width == 0)) { - // width wildcard - return (this.height == is.height); - } - if ((this.height == 0)||(is.height == 0)) { - // height wildcard - return (this.width == is.width); - } - return ( - (this.width == is.width) - && (this.height <= is.height) - || (this.width <= is.width) - && (this.height == is.height)); - } - - /** - * Returns if the size of this image is the same as the other image. - * - * - * - * @param is - * @return - */ - public boolean equals(ImageSize is) { - if ((this.width == 0)||(is.width == 0)) { - // width wildcard - return (this.height == is.height); - } - if ((this.height == 0)||(is.height == 0)) { - // height wildcard - return (this.width == is.width); - } - return ((this.width == is.width) && (this.height == is.height)); - } - - /** - * @return - */ - public int getHeight() { - return height; - } - - /** - * @param height - */ - public void setHeight(int height) { - this.height = height; - } - - /** - * @return - */ - public int getWidth() { - return width; - } - - /** - * @param width - */ - public void setWidth(int width) { - this.width = width; - } - - /** - * Returns the aspect ratio. - * - * Aspect ratio is (width/height). So it's <1 for portrait and >1 for - * landscape. - * - * @return - */ - public float getAspect() { - return (height > 0) ? ((float) width / (float) height) : 0; - } - - /** - * Returns a scaled copy of this image size. - * - * @param scale - * @return - */ - public ImageSize getScaled(float scale) { - return new ImageSize((int) (width * scale), (int) (height * scale)); - } - - /* (non-Javadoc) - * @see java.lang.Object#toString() - */ - public String toString() { - String s = "[" + width + "x" + height + "]"; - return s; - } -}
--- a/servlet/src/digilib/image/ImageWorker.java Tue Mar 01 17:12:25 2011 +0100 +++ b/servlet/src/digilib/image/ImageWorker.java Tue Mar 01 22:00:50 2011 +0100 @@ -19,7 +19,6 @@ */ public class ImageWorker implements Callable<DocuImage> { - protected static Logger logger = Logger.getLogger(ImageWorker.class); private DigilibConfiguration dlConfig; private ImageJobDescription jobinfo; @@ -69,19 +68,14 @@ logger.debug("Using subsampling: " + subsamp + " rest " + scaleXY); } - - docuImage.loadSubimage(jobinfo.getFileToLoad(), loadRect, (int) subsamp); - + docuImage.loadSubimage(jobinfo.getInput(), loadRect, (int) subsamp); logger.debug("SUBSAMP: " + subsamp + " -> " + docuImage.getSize()); - docuImage.scale(scaleXY, scaleXY); - } else { // else load and crop the whole file - docuImage.loadImage(jobinfo.getFileToLoad()); + docuImage.loadImage(jobinfo.getInput()); docuImage.crop((int) loadRect.getX(), (int) loadRect.getY(), (int) loadRect.getWidth(), (int) loadRect.getHeight()); - docuImage.scale(scaleXY, scaleXY); } @@ -144,6 +138,12 @@ docuImage.enhance(mult, paramBRGT); } + // color operation + DocuImage.ColorOp colop = jobinfo.getColOp(); + if (colop != null) { + docuImage.colorOp(colop); + } + logger.debug("rendered in " + (System.currentTimeMillis() - startTime) + "ms"); return docuImage;
--- a/servlet/src/digilib/image/JAIDocuImage.java Tue Mar 01 17:12:25 2011 +0100 +++ b/servlet/src/digilib/image/JAIDocuImage.java Tue Mar 01 22:00:50 2011 +0100 @@ -24,7 +24,6 @@ import java.awt.RenderingHints; import java.awt.image.RenderedImage; import java.awt.image.renderable.ParameterBlock; -import java.io.File; import java.io.IOException; import java.io.OutputStream; import java.util.ArrayList; @@ -46,8 +45,8 @@ import digilib.io.FileOpException; import digilib.io.FileOps; -import digilib.io.ImageFile; -import digilib.io.ImageFileset; +import digilib.io.ImageInput; +import digilib.util.ImageSize; /** A DocuImage implementation using Java Advanced Imaging Library. */ /** @@ -104,53 +103,64 @@ } /* Check image size and type and store in ImageFile f */ - public ImageFile identify(ImageFile imageFile) throws IOException { + public ImageInput identify(ImageInput input) throws IOException { + this.input = input; // try parent method first - ImageFile imf = super.identify(imageFile); + ImageInput imf = super.identify(input); if (imf != null) { return imf; } - // fileset to store the information - ImageFileset imgfs = imageFile.getParent(); - File f = imageFile.getFile(); - if (f == null) { - throw new IOException("File not found!"); - } /* * try JAI */ - logger.debug("identifying (JAI) " + f); + logger.debug("identifying (JAI) " + input); try { - RenderedOp img = JAI.create("fileload", f.getAbsolutePath()); + RenderedOp img = null; + if (input.hasFile()) { + String t = FileOps.mimeForFile(input.getFile()); + input.setMimetype(t); + img = JAI.create("fileload", input.getFile().getAbsolutePath()); + } else if (input.hasInputStream()) { + img = JAI.create("stream", input.getInputStream()); + // FIXME: where do we get the mimetype? + } else { + throw new FileOpException("unable to get data for image!"); + } ImageSize d = new ImageSize(img.getWidth(), img.getHeight()); - imageFile.setSize(d); - String t = FileOps.mimeForFile(f); - imageFile.setMimetype(t); - // logger.debug(" format:"+t); - if (imgfs != null) { - imgfs.setAspect(d); - } - logger.debug("image size: " + imageFile.getSize()); - return imageFile; + input.setSize(d); + logger.debug("image size: " + d); + return input; } catch (Exception e) { - throw new FileOpException("ERROR: unknown image file format!"); + throw new FileOpException("ERROR: unable to identify image!"); } } /* Load an image file into the Object. */ - public void loadImage(ImageFile f) throws FileOpException { - img = JAI.create("fileload", f.getFile().getAbsolutePath()); + public void loadImage(ImageInput ii) throws FileOpException { + this.input = ii; + if (ii.hasFile()) { + img = JAI.create("fileload", ii.getFile().getAbsolutePath()); + } else if (ii.hasInputStream()) { + img = JAI.create("stream", ii.getInputStream()); + } else { + throw new FileOpException("unable to get data for image!"); + } if (img == null) { throw new FileOpException("Unable to load File!"); } - mimeType = f.getMimetype(); } /* Load an image file into the Object. */ - public void loadSubimage(ImageFile f, Rectangle region, int subsample) - throws FileOpException { + public void loadSubimage(ImageInput ii, Rectangle region, int subsample) throws FileOpException { logger.debug("loadSubimage"); - img = JAI.create("fileload", f.getFile().getAbsolutePath()); + this.input = ii; + if (ii.hasFile()) { + img = JAI.create("fileload", ii.getFile().getAbsolutePath()); + } else if (ii.hasInputStream()) { + img = JAI.create("stream", ii.getInputStream()); + } else { + throw new FileOpException("unable to get data for image!"); + } if ((region.width < img.getWidth()) || (region.height < img.getHeight())) { // setup Crop @@ -174,7 +184,6 @@ // scale logger.debug("loadSubimage: scale"); img = JAI.create("scale", sp); - mimeType = f.getMimetype(); } }
--- a/servlet/src/digilib/image/JAIImageLoaderDocuImage.java Tue Mar 01 17:12:25 2011 +0100 +++ b/servlet/src/digilib/image/JAIImageLoaderDocuImage.java Tue Mar 01 22:00:50 2011 +0100 @@ -38,7 +38,8 @@ import javax.servlet.ServletException; import digilib.io.FileOpException; -import digilib.io.ImageFile; +import digilib.io.ImageInput; +import digilib.util.ImageSize; /** DocuImage implementation using the Java Advanced Imaging API and the ImageLoader * API of Java 1.4. @@ -80,44 +81,73 @@ /* Load an image file into the Object. */ - public void loadImage(ImageFile f) throws FileOpException { - logger.debug("loadImage: "+f.getFile()); - //System.gc(); - img = JAI.create("ImageRead", f.getFile().getAbsolutePath()); + public void loadImage(ImageInput ii) throws FileOpException { + logger.debug("loadImage: "+ii); + if (ii.hasImageInputStream()) { + img = JAI.create("ImageRead", ii.getImageInputStream()); + } else if (ii.hasFile()) { + img = JAI.create("ImageRead", ii.getFile().getAbsolutePath()); + } if (img == null) { throw new FileOpException("Unable to load File!"); } - mimeType = f.getMimetype(); } /* Get an ImageReader for the image file. */ - public ImageReader getReader(ImageFile f) throws IOException { - logger.debug("preloadImage: "+f.getFile()); - //System.gc(); - RandomAccessFile rf = new RandomAccessFile(f.getFile(), "r"); - ImageInputStream istream = new FileImageInputStream(rf); - //Iterator readers = ImageIO.getImageReaders(istream); - Iterator<ImageReader> readers = ImageIO.getImageReadersByMIMEType(f.getMimetype()); - if (! readers.hasNext()) { - throw new FileOpException("Unable to load File!"); - } - reader = readers.next(); - logger.debug("JAIImageIO: this reader: " + reader.getClass()); - while (readers.hasNext()) { - logger.debug(" next reader: " + readers.next().getClass()); - } - reader.setInput(istream); - return reader; + public ImageReader getReader(ImageInput input) throws IOException { + logger.debug("get ImageReader for " + input); + if (this.reader != null) { + if (this.input == input) { + // it was the same input + logger.debug("reusing Reader"); + return reader; + } + // clean up old reader + logger.debug("cleaning Reader!"); + dispose(); + } + this.input = input; + ImageInputStream istream = null; + if (input.hasImageInputStream()) { + // stream input + istream = input.getImageInputStream(); + } else if (input.hasFile()) { + // file only input + RandomAccessFile rf = new RandomAccessFile(input.getFile(), "r"); + istream = new FileImageInputStream(rf); + } else { + throw new FileOpException("Unable to get data from ImageInput"); + } + Iterator<ImageReader> readers; + String mt = input.getMimetype(); + if (mt == null) { + logger.debug("No mime-type. Trying automagic."); + readers = ImageIO.getImageReaders(istream); + } else { + logger.debug("File type:" + mt); + readers = ImageIO.getImageReadersByMIMEType(mt); + } + if (!readers.hasNext()) { + throw new FileOpException("Can't find Reader to load File!"); + } + reader = readers.next(); + logger.debug("ImageIO: this reader: " + reader.getClass()); + /* are there more readers? */ + /* while (readers.hasNext()) { + logger.debug("ImageIO: next reader: " + readers.next().getClass()); + } */ + reader.setInput(istream); + return reader; } /* Load an image file into the Object. */ - public void loadSubimage(ImageFile f, Rectangle region, int prescale) + public void loadSubimage(ImageInput ii, Rectangle region, int prescale) throws FileOpException { - logger.debug("loadSubimage: "+f.getFile()); + logger.debug("loadSubimage: "+ii.getFile()); //System.gc(); try { - if ((reader == null) || (imgFile != f.getFile())) { - getReader(f); + if ((reader == null) || (imgFile != ii.getFile())) { + getReader(ii); } ImageReadParam readParam = reader.getDefaultReadParam(); readParam.setSourceRegion(region); @@ -137,8 +167,7 @@ if (img == null) { throw new FileOpException("Unable to load File!"); } - imgFile = f.getFile(); - mimeType = f.getMimetype(); + imgFile = ii.getFile(); }
--- a/servlet/src/digilib/io/AliasingDocuDirCache.java Tue Mar 01 17:12:25 2011 +0100 +++ b/servlet/src/digilib/io/AliasingDocuDirCache.java Tue Mar 01 22:00:50 2011 +0100 @@ -28,6 +28,7 @@ import digilib.io.FileOps.FileClass; import digilib.servlet.DigilibConfiguration; +import digilib.util.XMLListLoader; /** * @author casties
--- a/servlet/src/digilib/io/DigilibInfoReader.java Tue Mar 01 17:12:25 2011 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -package digilib.io; - -/** DigilibInfoReader - * A class for reading the information from info.xml files used in digilib image directories. - * - */ - -import java.io.File; -import java.util.List; - -import org.apache.log4j.Logger; -import org.jdom.Document; -import org.jdom.Element; -import org.jdom.input.SAXBuilder; - - - -public class DigilibInfoReader { - - /** gengeral logger for this class */ - protected static Logger logger = Logger.getLogger("digilib.servlet"); - - private String filename = null; - //private static String base_element = "info"; - - public DigilibInfoReader(String fn){ - filename = fn; - } - - /** - * Returns the attribute defined by 'attr' as a String. - * - * @param attr - * @return - */ - @SuppressWarnings("unchecked") // Element.getChildren() returns naked List - public String getAsString(String attr){ - try{ - SAXBuilder builder = new SAXBuilder(); - Document doc = builder.build(new File(filename)); - Element root = doc.getRootElement(); - List<Element> mainElements = root.getChildren(); - // logger.debug("XML mainElements:"+mainElements.toString()); - - for(int i=0; i<mainElements.size(); i++){ - Element elem = mainElements.get(i); - if(elem.getName()==attr){ - // logger.debug(attr+" == "+(String)elem.getTextTrim()); - return (String)elem.getTextTrim(); - } - } - - } - catch(Exception e){ - logger.error(e.getMessage()); - } - return null; - } - - - /** - * Find out if the info.xml exists - * @return - */ - public boolean hasInfo(){ - try { - SAXBuilder builder = new SAXBuilder(); - builder.build(new File(filename)); - return true; - } - catch(Exception e){ - return false; - } - } - -}
--- a/servlet/src/digilib/io/DocuDirCache.java Tue Mar 01 17:12:25 2011 +0100 +++ b/servlet/src/digilib/io/DocuDirCache.java Tue Mar 01 22:00:50 2011 +0100 @@ -23,10 +23,10 @@ package digilib.io; import java.io.File; -import java.util.HashMap; import java.util.LinkedList; import java.util.List; -import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; import org.apache.log4j.Logger; @@ -42,7 +42,7 @@ Logger logger = Logger.getLogger(this.getClass()); /** HashMap of directories */ - Map<String, DocuDirectory> map = null; + ConcurrentMap<String, DocuDirectory> map = new ConcurrentHashMap<String, DocuDirectory>(); /** names of base directories */ String[] baseDirNames = null; @@ -71,7 +71,6 @@ public DocuDirCache(String[] bd, FileClass[] fcs, DigilibConfiguration dlConfig) { baseDirNames = bd; - map = new HashMap<String, DocuDirectory>(); this.fileClasses = fcs; } @@ -83,7 +82,6 @@ */ public DocuDirCache(String[] bd) { baseDirNames = bd; - map = new HashMap<String, DocuDirectory>(); // default file class is CLASS_IMAGE fileClasses = new FileClass[] { FileClass.IMAGE }; } @@ -99,38 +97,49 @@ /** * Add a DocuDirectory to the cache. + * Always returns the correct Object from the cache, + * either newdir one or another one. * * @param newdir + * @return dir */ - public void put(DocuDirectory newdir) { + public DocuDirectory put(DocuDirectory newdir) { String s = newdir.getDirName(); logger.debug("DocuDirCache.put for "+s+" in "+this); - if (map.containsKey(s)) { + DocuDirectory olddir = map.putIfAbsent(s, newdir); + if (olddir != null) { logger.warn("Duplicate key in DocuDirCache.put -- ignoring!"); - } else { - map.put(s, newdir); - numFiles += newdir.size(); + return olddir; } + numFiles += newdir.size(); + return newdir; } /** * Add a directory to the cache and check its parents. - * + * Always returns the correct Object from the cache, + * either newDir one or another one. + * * @param newDir + * @return dir */ - public void putDir(DocuDirectory newDir) { - put(newDir); - String parent = FileOps.parent(newDir.getDirName()); - if (parent != "") { - // check the parent in the cache - DocuDirectory pd = map.get(parent); - if (pd == null) { - // the parent is unknown - pd = new DocuDirectory(parent, this); - putDir(pd); + public DocuDirectory putDir(DocuDirectory newDir) { + DocuDirectory dd = put(newDir); + if (dd.getParent() == null) { + // no parent link yet + String parent = FileOps.parent(newDir.getDirName()); + if (parent != "") { + // check the parent in the cache + DocuDirectory pd = map.get(parent); + if (pd == null) { + // the parent is unknown + pd = new DocuDirectory(parent, this); + pd = putDir(pd); + } + newDir.setParent(pd); } - newDir.setParent(pd); } + return dd; } /** @@ -182,8 +191,6 @@ int n = in - 1; // first, assume fn is a directory and look in the cache dd = map.get(fn); - // logger.debug("fn: " + fn); - // logger.debug("dd: " + dd); if (dd == null) { // cache miss misses++; @@ -196,7 +203,7 @@ dd = new DocuDirectory(fn, this); if (dd.isValid()) { // add to the cache - putDir(dd); + dd = putDir(dd); } } else { /* @@ -214,7 +221,7 @@ if (dd.isValid()) { // add to the cache // logger.debug(dd + " is valid"); - putDir(dd); + dd = putDir(dd); } else { // invalid path return null; @@ -225,17 +232,14 @@ } // get the file's index n = dd.indexOf(f.getName(), fc); - // logger.debug(f.getName() + ", index is " + n + ", fc = " + fc); } } else { // cache hit hits++; } dd.refresh(); - // logger.debug(dd + " refreshed"); if (dd.isValid()) { try { - // logger.debug(dd + " is valid"); return dd.get(n, fc); } catch (IndexOutOfBoundsException e) { // logger.debug(fn + " not found in directory"); @@ -266,7 +270,7 @@ dd = new DocuDirectory(fn, this); if (dd.isValid()) { // add to the cache - putDir(dd); + dd = putDir(dd); } } else { // maybe it's a file @@ -278,7 +282,7 @@ dd = new DocuDirectory(f.getParent(), this); if (dd.isValid()) { // add to the cache - putDir(dd); + dd = putDir(dd); } else { // invalid path return null;
--- a/servlet/src/digilib/io/DocuDirectory.java Tue Mar 01 17:12:25 2011 +0100 +++ b/servlet/src/digilib/io/DocuDirectory.java Tue Mar 01 22:00:50 2011 +0100 @@ -31,6 +31,8 @@ import org.xml.sax.SAXException; import digilib.io.FileOps.FileClass; +import digilib.meta.MetadataMap; +import digilib.meta.XMLMetaLoader; /** * @author casties @@ -40,9 +42,6 @@ /** list of files (DocuDirent) */ private List<List<DocuDirent>> list = null; - /** default FileClass for unspecified calls */ - public static FileClass defaultFileClass = FileClass.IMAGE; - /** directory object is valid (exists on disk) */ private boolean isValid = false; @@ -52,6 +51,9 @@ /** directory name (digilib canonical form) */ private String dirName = null; + /** array of parallel dirs for scaled images */ + private Directory[] dirs = null; + /** directory metadata */ private MetadataMap dirMeta = null; @@ -83,15 +85,6 @@ public DocuDirectory(String path, DocuDirCache cache) { this.dirName = path; this.cache = cache; - initDir(); - checkDir(); - } - - /** - * Sets and checks the dir object. - * - */ - protected void initDir() { String baseDirName = cache.getBaseDirNames()[0]; // clear directory list FileClass[] fcs = FileClass.values(); @@ -100,10 +93,10 @@ for (@SuppressWarnings("unused") FileClass fc: fcs) { list.add(null); } - isValid = false; dirMTime = 0; // the first directory has to exist - dir = new File(baseDirName, dirName); + dir = new File(baseDirName, path); + isValid = dir.isDirectory(); } /** @@ -111,7 +104,7 @@ * */ public int size() { - return size(defaultFileClass); + return ((list != null) && (list.get(0) != null)) ? list.get(0).size() : 0; } /** @@ -121,13 +114,7 @@ * fileClass */ public int size(FileClass fc) { - if (list != null) { - List<DocuDirent> l = list.get(fc.ordinal()); - if (l != null) { - return l.size(); - } - } - return 0; + return ((list != null) && (list.get(fc.ordinal()) != null)) ? list.get(fc.ordinal()).size() : 0; } /** @@ -136,8 +123,11 @@ * @param index * @return */ - public ImageFileset get(int index) { - return (ImageFileset) get(index, defaultFileClass); + public DocuDirent get(int index) { + if ((list == null) || (list.get(0) == null) || (index >= list.get(0).size())) { + return null; + } + return list.get(0).get(index); } /** @@ -156,102 +146,84 @@ } /** - * Checks if the directory exists on the filesystem. - * - * Sets isValid. - * - * @return - */ - public boolean checkDir() { - if (dir == null) { - initDir(); - } - isValid = dir.isDirectory(); - return isValid; - } - - /** * Read the filesystem directory and fill this object. * * Clears the List and (re)reads all files. * * @return boolean the directory exists */ - public boolean readDir() { + public synchronized boolean readDir() { // check directory first - checkDir(); if (!isValid) { return false; } - // first file extension to try for scaled directories - String scalext = null; + // re-check modification time because the thread may have slept + if (dir.lastModified() <= dirMTime) { + return true; + } // read all filenames - logger.debug("reading directory " + dir.getPath()); + logger.debug("reading directory "+this+" = "+dir.getPath()); + File[] allFiles = null; /* * using ReadableFileFilter is safer (we won't get directories with file * extensions) but slower. */ - File[] allFiles = null; - // allFiles = dir.listFiles(new FileOps.ReadableFileFilter()); + // allFiles = dir.listFiles(new FileOps.ReadableFileFilter()); allFiles = dir.listFiles(); - //logger.debug(" done"); if (allFiles == null) { // not a directory return false; } - // list of base dirs from the parent cache - String[] baseDirNames = cache.getBaseDirNames(); - // number of base dirs - int nb = baseDirNames.length; - // array of base dirs - Directory[] dirs = new Directory[nb]; - // first entry is this directory - dirs[0] = this; - // fill array with the remaining directories - for (int j = 1; j < nb; j++) { - File d = new File(baseDirNames[j], dirName); - if (d.isDirectory()) { - dirs[j] = new Directory(d); - logger.debug(" reading scaled directory " + d.getPath()); - dirs[j].readDir(); - //logger.debug(" done"); + // init parallel directories + if (dirs == null) { + // list of base dirs from the parent cache + String[] baseDirNames = cache.getBaseDirNames(); + // number of base dirs + int nb = baseDirNames.length; + // array of parallel dirs + dirs = new Directory[nb]; + // first entry is this directory + dirs[0] = this; + // fill array with the remaining directories + for (int j = 1; j < nb; j++) { + // add dirName to baseDirName + File d = new File(baseDirNames[j], dirName); + if (d.isDirectory()) { + dirs[j] = new Directory(d); + logger.debug(" reading scaled directory " + d.getPath()); + dirs[j].readDir(); + } } } // go through all file classes - //for (int classIdx = 0; classIdx < FileOps.NUM_CLASSES; classIdx++) { - for (FileClass fileClass: cache.getFileClasses()) { - //fileClass = cache.getFileClasses()[classIdx]; - File[] fileList = FileOps.listFiles(allFiles, FileOps - .filterForClass(fileClass)); - //logger.debug(" done"); + for (FileClass fileClass : cache.getFileClasses()) { + File[] fileList = FileOps.listFiles(allFiles, + FileOps.filterForClass(fileClass)); // number of files in the directory int numFiles = fileList.length; if (numFiles > 0) { // create new list - list.set(fileClass.ordinal(), new ArrayList<DocuDirent>(numFiles)); - // sort the file names alphabetically and iterate the list - // Arrays.sort(fileList); // not needed <hertzhaft> - Map<Integer, Object> hints = FileOps.newHints(FileOps.HINT_BASEDIRS, dirs); - hints.put(FileOps.HINT_FILEEXT, scalext); - for (int i = 0; i < numFiles; i++) { - DocuDirent f = FileOps.fileForClass(fileClass, fileList[i], - hints); + ArrayList<DocuDirent> dl = new ArrayList<DocuDirent>(numFiles); + list.set(fileClass.ordinal(), dl); + for (File f : fileList) { + DocuDirent df = FileOps.fileForClass(fileClass, f, dirs); + df.setParent(this); // add the file to our list - // logger.debug(f.getName()); - - list.get(fileClass.ordinal()).add(f); - f.setParent(this); + dl.add(df); } - // we sort the inner ArrayList (the list of files not the list of file types) - // for binarySearch to work (DocuDirent's natural sort order is by filename) - Collections.sort(list.get(fileClass.ordinal())); + /* + * we sort the inner ArrayList (the list of files not the list + * of file types) for binarySearch to work (DocuDirent's natural + * sort order is by filename) + */ + Collections.sort(dl); } } // clear the scaled directories - for (int j = 1; j < nb; j++) { - if (dirs[j] != null) { - dirs[j].clearFilenames(); + for (Directory d: dirs) { + if (d != null) { + d.clearFilenames(); } } // update number of cached files if this was the first time @@ -456,9 +428,8 @@ return -1; } - private boolean isBasenameInList(List<DocuDirent> fl, int idx, String fn) { - String dfn = FileOps.basename((fl.get(idx)) - .getName()); + private boolean isBasenameInList(List<DocuDirent> fileList, int idx, String fn) { + String dfn = FileOps.basename((fileList.get(idx)).getName()); return (dfn.equals(fn)||dfn.equals(FileOps.basename(fn))); } @@ -474,7 +445,12 @@ * @return DocuDirent */ public DocuDirent find(String fn) { - return find(fn, defaultFileClass); + FileClass fc = FileOps.classForFilename(fn); + int i = indexOf(fn, fc); + if (i >= 0) { + return list.get(0).get(i); + } + return null; } /** @@ -491,7 +467,7 @@ public DocuDirent find(String fn, FileClass fc) { int i = indexOf(fn, fc); if (i >= 0) { - return (DocuDirent) list.get(fc.ordinal()).get(i); + return list.get(fc.ordinal()).get(i); } return null; }
--- a/servlet/src/digilib/io/DocuDirent.java Tue Mar 01 17:12:25 2011 +0100 +++ b/servlet/src/digilib/io/DocuDirent.java Tue Mar 01 22:00:50 2011 +0100 @@ -1,169 +1,81 @@ -/* - * DocuDirent.java -- Abstract directory entry in a DocuDirectory - * - * 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 15.09.2003 by casties - * - */ package digilib.io; import java.io.File; -import java.util.Map; - -import org.apache.log4j.Logger; - -import digilib.io.FileOps.FileClass; -/** - * Abstract directory entry in a DocuDirectory. - * - * @author casties - * - */ -public abstract class DocuDirent implements Comparable<Object> { +import digilib.meta.MetadataMap; + +public interface DocuDirent extends Comparable<Object> { - /** the file class of this file */ - protected static FileClass fileClass = FileClass.NONE; - /** HashMap with metadata */ - protected MetadataMap fileMeta = null; - /** Is the Metadata valid */ - protected boolean metaChecked = false; - /** the parent directory */ - protected Directory parent = null; - - /** - * Checks metadata and does something with it. - * - */ - public abstract void checkMeta(); + /** + * Checks metadata and does something with it. + * + */ + public abstract void checkMeta(); - /** - * gets the (default) File - * - * @return - */ - public abstract File getFile(); + /** + * gets the (default) File + * + * @return + */ + public abstract File getFile(); - /** - * Reads meta-data for this Fileset if there is any. - * - */ - public void readMeta() { - if ((fileMeta != null) || (getFile() == null)) { - // there is already metadata or there is no file - return; - } - // metadata is in the file {filename}.meta - String fn = getFile().getAbsolutePath(); - File mf = new File(fn + ".meta"); - if (mf.canRead()) { - XMLMetaLoader ml = new XMLMetaLoader(); - try { - // read meta file - Map<String, MetadataMap> meta = ml.loadURL(mf.getAbsolutePath()); - if (meta == null) { - return; - } - fileMeta = meta.get(getName()); - } catch (Exception e) { - Logger.getLogger(this.getClass()).warn("error reading file .meta", e); - } - } - } + /** + * Reads meta-data for this Fileset if there is any. + * + */ + public abstract void readMeta(); + + /** + * The name of the file. + * + * If this is a Fileset, the method returns the name of the default file + * (for image filesets the highest resolution file). + * + * @return + */ + public abstract String getName(); - /** - * The name of the file. - * - * If this is a Fileset, the method returns the name of the default file - * (for image filesets the highest resolution file). - * - * @return - */ - public String getName() { - File f = getFile(); - return (f != null) ? f.getName() : null; - } - - /** - * Returns the parent Directory. - * - * @return DocuDirectory - */ - public Directory getParent() { - return parent; - } - - /** - * Sets the parent Directory. - * - * @param parent - * The parent to set - */ - public void setParent(Directory parent) { - this.parent = parent; - } - - /** - * Returns the meta-data for this file(set). - * - * @return HashMap - */ - public MetadataMap getFileMeta() { - return fileMeta; - } - - /** - * Sets the meta-data for this file(set) . - * - * @param fileMeta - * The fileMeta to set - */ - public void setFileMeta(MetadataMap fileMeta) { - this.fileMeta = fileMeta; - } - - /** - * @return - */ - public boolean isMetaChecked() { - return metaChecked; - } - - /** - * @return - */ - public static FileClass getFileClass() { - return fileClass; - } + /** + * Returns the parent Directory. + * + * @return DocuDirectory + */ + public abstract Directory getParent(); + + /** + * Sets the parent Directory. + * + * @param parent + * The parent to set + */ + public abstract void setParent(Directory parent); + + /** + * Returns the meta-data for this file(set). + * + * @return HashMap + */ + public abstract MetadataMap getFileMeta(); - /** Comparator using the file name. - * Compares to a String (for binarySearch) + /** + * Sets the meta-data for this file(set) . + * + * @param fileMeta + * The fileMeta to set + */ + public abstract void setFileMeta(MetadataMap fileMeta); + + /** + * @return + */ + public abstract boolean isMetaChecked(); + + /** Comparator using the file name. + * Compares to a String (for binarySearch) * or to another DocuDirent (for sort) - * - * @see java.lang.Comparable#compareTo(java.lang.Object) - */ - public int compareTo(Object arg0) { - if (arg0 instanceof DocuDirent) { - return getName().compareTo(((DocuDirent) arg0).getName()); - } else { - return getName().compareTo((String) arg0); - } - } + * + * @see java.lang.Comparable#compareTo(java.lang.Object) + */ + public abstract int compareTo(Object arg0); - -} +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/servlet/src/digilib/io/DocuDirentImpl.java Tue Mar 01 22:00:50 2011 +0100 @@ -0,0 +1,149 @@ +/* + * DocuDirent.java -- Abstract directory entry in a DocuDirectory + * + * 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 15.09.2003 by casties + * + */ +package digilib.io; + +import java.io.File; +import java.util.Map; + +import org.apache.log4j.Logger; + +import digilib.io.FileOps.FileClass; +import digilib.meta.MetadataMap; +import digilib.meta.XMLMetaLoader; + +/** + * Abstract directory entry in a DocuDirectory. + * + * @author casties + * + */ +public abstract class DocuDirentImpl implements DocuDirent { + + /** the file class of this file */ + protected static FileClass fileClass = FileClass.NONE; + /** HashMap with metadata */ + protected MetadataMap fileMeta = null; + /** Is the Metadata valid */ + protected boolean metaChecked = false; + /** the parent directory */ + protected Directory parent = null; + + /* (non-Javadoc) + * @see digilib.io.DocuDirent#checkMeta() + */ + public abstract void checkMeta(); + + /* (non-Javadoc) + * @see digilib.io.DocuDirent#getInput() + */ + public abstract File getFile(); + + /* (non-Javadoc) + * @see digilib.io.DocuDirent#readMeta() + */ + public void readMeta() { + if ((fileMeta != null) || (getFile() == null)) { + // there is already metadata or there is no file + return; + } + // metadata is in the file {filename}.meta + String fn = getFile().getAbsolutePath(); + File mf = new File(fn + ".meta"); + if (mf.canRead()) { + XMLMetaLoader ml = new XMLMetaLoader(); + try { + // read meta file + Map<String, MetadataMap> meta = ml.loadURL(mf.getAbsolutePath()); + if (meta == null) { + return; + } + fileMeta = meta.get(getName()); + } catch (Exception e) { + Logger.getLogger(this.getClass()).warn("error reading file .meta", e); + } + } + } + + /* (non-Javadoc) + * @see digilib.io.DocuDirent#getName() + */ + public String getName() { + File f = getFile(); + return (f != null) ? f.getName() : null; + } + + /* (non-Javadoc) + * @see digilib.io.DocuDirent#getParent() + */ + public Directory getParent() { + return parent; + } + + /* (non-Javadoc) + * @see digilib.io.DocuDirent#setParent(digilib.io.Directory) + */ + public void setParent(Directory parent) { + this.parent = parent; + } + + /* (non-Javadoc) + * @see digilib.io.DocuDirent#getFileMeta() + */ + public MetadataMap getFileMeta() { + return fileMeta; + } + + /* (non-Javadoc) + * @see digilib.io.DocuDirent#setFileMeta(digilib.io.MetadataMap) + */ + public void setFileMeta(MetadataMap fileMeta) { + this.fileMeta = fileMeta; + } + + /* (non-Javadoc) + * @see digilib.io.DocuDirent#isMetaChecked() + */ + public boolean isMetaChecked() { + return metaChecked; + } + + /** + * @return + */ + public static FileClass getFileClass() { + return fileClass; + } + + /* (non-Javadoc) + * @see digilib.io.DocuDirent#compareTo(java.lang.Object) + */ + public int compareTo(Object arg0) { + if (arg0 instanceof DocuDirentImpl) { + return getName().compareTo(((DocuDirent) arg0).getName()); + } else { + return getName().compareTo((String) arg0); + } + } + + +}
--- a/servlet/src/digilib/io/FileOps.java Tue Mar 01 17:12:25 2011 +0100 +++ b/servlet/src/digilib/io/FileOps.java Tue Mar 01 22:00:50 2011 +0100 @@ -107,7 +107,10 @@ * get the mime type for a file format (by extension) */ public static String mimeForFile(File f) { - return (String) fileTypes.get(extname(f.getName().toLowerCase())); + if (f == null) { + return null; + } + return fileTypes.get(extname(f.getName().toLowerCase())); } /** @@ -329,20 +332,20 @@ /** * Factory for DocuDirents based on file class. * - * Returns an ImageFileset, TextFile or SVGFile. baseDirs and scalext are + * Returns an ImageSet, TextFile or SVGFile. scaleDirs are * only for ImageFilesets. * * @param fileClass * @param file - * @param hints + * @param scaleDirs * optional additional parameters * @return */ - public static DocuDirent fileForClass(FileClass fileClass, File file, Map<Integer,Object> hints) { + public static DocuDirent fileForClass(FileClass fileClass, File file, Directory[] scaleDirs) { // what class of file do we have? if (fileClass == FileClass.IMAGE) { // image file - return new ImageFileset(file, hints); + return new ImageFileSet(file, scaleDirs); } else if (fileClass == FileClass.TEXT) { // text file return new TextFile(file);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/servlet/src/digilib/io/ImageCacheStream.java Tue Mar 01 22:00:50 2011 +0100 @@ -0,0 +1,49 @@ +/** + * + */ +package digilib.io; + +import java.io.InputStream; + +import javax.imageio.stream.ImageInputStream; +import javax.imageio.stream.MemoryCacheImageInputStream; + +/** + * @author casties + * + */ +public class ImageCacheStream extends ImageStream { + + public ImageCacheStream(InputStream stream, String mimeType) { + super(stream, mimeType); + } + + /* + * (non-Javadoc) + * + * @see digilib.io.ImageInput#hasImageInputStream() + */ + @Override + public boolean hasImageInputStream() { + return true; + } + + /* + * (non-Javadoc) + * + * @see digilib.io.ImageInput#getImageInputStream() + */ + @Override + public ImageInputStream getImageInputStream() { + /* + * TODO: which type of stream backing? + * In general, it is preferable to + * use a FileCacheImageInputStream when reading from a regular + * InputStream. This class is provided for cases where it is not + * possible to create a writable temporary file. + */ + ImageInputStream iis = new MemoryCacheImageInputStream(this.stream); + return iis; + } + +}
--- a/servlet/src/digilib/io/ImageFile.java Tue Mar 01 17:12:25 2011 +0100 +++ b/servlet/src/digilib/io/ImageFile.java Tue Mar 01 22:00:50 2011 +0100 @@ -22,74 +22,142 @@ package digilib.io; import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; -import digilib.image.ImageSize; +import javax.imageio.stream.FileImageInputStream; +import javax.imageio.stream.ImageInputStream; + +import digilib.servlet.DigilibConfiguration; +import digilib.util.ImageSize; /** * @author casties */ -public class ImageFile { +public class ImageFile extends ImageInput { + // file + private File file = null; // file name - private String filename = null; - // parent ImageFileset - private ImageFileset parent = null; + private String name = null; // parent directory private Directory dir = null; - // mime file type - private String mimetype = null; - // image size in pixels - private ImageSize pixelSize = null; - public ImageFile(String fn, ImageFileset parent, Directory dir) { - this.filename = fn; + /** Constructor with File. + * + * @param f + * @param parent + * @param dir + */ + public ImageFile(File f, ImageSet parent, Directory dir) { + this.file = f; + this.name = f.getName(); this.parent = parent; this.dir = dir; } - public ImageFile(String fn) { - File f = new File(fn); - this.dir = new Directory(f.getParentFile()); - this.filename = f.getName(); + /** Constructor with filename (without path). + * @param fn + * @param parent + * @param dir + */ + public ImageFile(String fn, ImageSet parent, Directory dir) { + this.name = fn; + this.dir = dir; + this.file = new File(this.dir.getDir(), fn); + this.parent = parent; + } + + + /** Checks the image and sets size and type. + * + */ + public void check() { + if (pixelSize == null) { + try { + // use the configured toolkit to identify the image + DigilibConfiguration.identifyDocuImage(this); + } catch (IOException e) { + // nothing much to do... + } + } } - /** Returns the file name (without path). + /* (non-Javadoc) + * @see digilib.io.ImageInput#getSize() + */ + @Override + public ImageSize getSize() { + check(); + return pixelSize; + } + + /* (non-Javadoc) + * @see digilib.io.ImageInput#getMimetype() + */ + @Override + public String getMimetype() { + check(); + return mimetype; + } + + /* (non-Javadoc) + * @see digilib.io.ImageInput#getAspect() + */ + @Override + public float getAspect() { + check(); + return (pixelSize != null) ? pixelSize.getAspect() : 0f; + } + + /** Returns the file name (without path). * * @return */ public String getName() { - return filename; - } - - - /** - * @return File - */ - public File getFile() { - if (dir == null) { - return null; - } - File f = new File(dir.getDir(), filename); - return f; + return name; } - /** - * @return ImageSize + + /* (non-Javadoc) + * @see digilib.io.ImageInput#hasImageInputStream() + */ + @Override + public boolean hasImageInputStream() { + return true; + } + + /* (non-Javadoc) + * @see digilib.io.ImageInput#getImageInputStream() + */ + @Override + public ImageInputStream getImageInputStream() { + try { + RandomAccessFile rf = new RandomAccessFile(file, "r"); + return new FileImageInputStream(rf); + } catch (IOException e) { + // what now? + } + return null; + } + + /* (non-Javadoc) + * @see digilib.io.ImageInput#hasFile() + */ + @Override + public boolean hasFile() { + return true; + } + + /* (non-Javadoc) + * @see digilib.io.ImageInput#getFile() */ - public ImageSize getSize() { - return pixelSize; + public File getFile() { + return file; } - /** - * @return String - */ - public String getMimetype() { - return mimetype; - } - - /** - * Sets the imageSize. - * @param imageSize The imageSize to set + /* (non-Javadoc) + * @see digilib.io.ImageInput#setSize(digilib.image.ImageSize) */ public void setSize(ImageSize imageSize) { this.pixelSize = imageSize; @@ -99,42 +167,17 @@ } } - /** - * Sets the mimetype. - * @param mimetype The mimetype to set - */ - public void setMimetype(String filetype) { - this.mimetype = filetype; - } - - /** - * @return ImageFileset - */ - public ImageFileset getParent() { - return parent; - } + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + @Override + public String toString() { + // try to use File.toString + if (file != null) { + return file.toString(); + } + return super.toString(); + } - /** - * Sets the parent. - * @param parent The parent to set - */ - public void setParent(ImageFileset parent) { - this.parent = parent; - } - - /** - * @return boolean - */ - public boolean isChecked() { - return (pixelSize != null); - } - /** Returns the aspect ratio of the image (width/height). - * - * @return - */ - public float getAspect() { - return (pixelSize != null) ? pixelSize.getAspect() : 0; - } - }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/servlet/src/digilib/io/ImageFileSet.java Tue Mar 01 22:00:50 2011 +0100 @@ -0,0 +1,307 @@ +/** + * + */ +package digilib.io; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Map; + +import org.apache.log4j.Logger; + +import digilib.io.FileOps.FileClass; +import digilib.meta.MetadataMap; +import digilib.meta.XMLMetaLoader; + +/** + * @author casties + * + */ +public class ImageFileSet extends ImageSet implements DocuDirent { + + /** this is an image file */ + protected static FileClass fileClass = FileClass.IMAGE; + /** the (main) file */ + protected File file = null; + /** the file name */ + protected String name = null; + /** HashMap with metadata */ + protected MetadataMap fileMeta = null; + /** Is the Metadata valid */ + protected boolean metaChecked = false; + /** the parent directory */ + protected Directory parentDir = null; + + /** + * Constructor with a File and Directories. + * + * @param file + * @param scaleDirs + */ + public ImageFileSet(File file, Directory[] scaleDirs) { + int nb = scaleDirs.length; + list = new ArrayList<ImageInput>(nb); + // first dir is our parent + parentDir = scaleDirs[0]; + this.file = file; + this.name = file.getName(); + fill(scaleDirs, file); + } + + /* (non-Javadoc) + * @see digilib.io.DocuDirent#getName() + */ + public String getName() { + return this.name; + } + + /* (non-Javadoc) + * @see digilib.io.DocuDirent#getParent() + */ + public Directory getParent() { + return this.parentDir; + } + + /* (non-Javadoc) + * @see digilib.io.DocuDirent#setParent(digilib.io.Directory) + */ + public void setParent(Directory parent) { + this.parentDir = parent; + } + + /* (non-Javadoc) + * @see digilib.io.DocuDirent#getFileMeta() + */ + public MetadataMap getFileMeta() { + return this.fileMeta; + } + + /* (non-Javadoc) + * @see digilib.io.DocuDirent#setFileMeta(digilib.io.MetadataMap) + */ + public void setFileMeta(MetadataMap fileMeta) { + this.fileMeta = fileMeta; + } + + /* (non-Javadoc) + * @see digilib.io.DocuDirent#isMetaChecked() + */ + public boolean isMetaChecked() { + return this.metaChecked; + } + + /* (non-Javadoc) + * @see digilib.io.DocuDirent#compareTo(java.lang.Object) + */ + public int compareTo(Object arg0) { + if (arg0 instanceof DocuDirent) { + return name.compareTo(((DocuDirent) arg0).getName()); + } else { + return getName().compareTo((String) arg0); + } + } + + /* (non-Javadoc) + * @see digilib.io.DocuDirent#getFile() + */ + public File getFile() { + return file; + } + + /** + * Adds an ImageFile to this Fileset. + * + * 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) + */ + public boolean add(ImageInput f) { + f.setParent(this); + return list.add(f); + } + + /** + * Fill the ImageSet with files from different base directories. + * + * + * @param dirs + * list of base directories + * @param fl + * file (from first base dir) + * @param hints + * + */ + void fill(Directory[] dirs, File fl) { + String fn = fl.getName(); + String baseFn = FileOps.basename(fn); + // add the first ImageFile to the ImageSet + add(new ImageFile(fl, this, parentDir)); + // iterate the remaining base directories + for (int i = 1; i < dirs.length; ++i) { + Directory dir = dirs[i]; + if (dir == null) { + continue; + } + // read the directory + if (dir.getFilenames() == null) { + dir.readDir(); + } + String[] dirFiles = dir.getFilenames(); + // try the same filename as the original + int fileIdx = Arrays.binarySearch(dirFiles, fn); + if (fileIdx < 0) { + // try closest matches without extension + fileIdx = -fileIdx - 1; + // try idx + if ((fileIdx < dirFiles.length) + && (FileOps.basename(dirFiles[fileIdx]).equals(baseFn))) { + // idx ok + } else if ((fileIdx > 0) + && (FileOps.basename(dirFiles[fileIdx - 1]) + .equals(baseFn))) { + // idx-1 ok + fileIdx = fileIdx - 1; + } else if ((fileIdx+1 < dirFiles.length) + && (FileOps.basename(dirFiles[fileIdx + 1]) + .equals(baseFn))) { + // idx+1 ok + fileIdx = fileIdx + 1; + } else { + // basename doesn't match + continue; + } + } + if (FileOps.classForFilename(dirFiles[fileIdx]) == fileClass) { + /* logger.debug("adding file " + dirFiles[fileIdx] + + " to Fileset " + this.getName()); */ + add(new ImageFile(dirFiles[fileIdx], this, dir)); + } + } + } + + /** + * Checks metadata and sets resolution in resX and resY. + * + */ + public void checkMeta() { + if (metaChecked) { + return; + } + if (fileMeta == null) { + // try to read metadata file + readMeta(); + if (fileMeta == null) { + // try directory metadata + ((DocuDirectory) parentDir).checkMeta(); + if (((DocuDirectory) parentDir).getDirMeta() != null) { + fileMeta = ((DocuDirectory) parentDir).getDirMeta(); + } else { + // try parent directory metadata + DocuDirectory gp = (DocuDirectory) parentDir.getParent(); + if (gp != null) { + gp.checkMeta(); + if (gp.getDirMeta() != null) { + fileMeta = gp.getDirMeta(); + } + } + } + } + } + if (fileMeta == null) { + // no metadata available + metaChecked = true; + return; + } + metaChecked = true; + float dpi = 0; + float dpix = 0; + float dpiy = 0; + float sizex = 0; + float sizey = 0; + float pixx = 0; + float pixy = 0; + // DPI is valid for X and Y + if (fileMeta.containsKey("original-dpi")) { + try { + dpi = Float.parseFloat((String) fileMeta.get("original-dpi")); + } catch (NumberFormatException e) { + } + if (dpi != 0) { + resX = dpi; + resY = dpi; + return; + } + } + // DPI-X and DPI-Y + if (fileMeta.containsKey("original-dpi-x") + && fileMeta.containsKey("original-dpi-y")) { + try { + dpix = Float.parseFloat((String) fileMeta + .get("original-dpi-x")); + dpiy = Float.parseFloat((String) fileMeta + .get("original-dpi-y")); + } catch (NumberFormatException e) { + } + if ((dpix != 0) && (dpiy != 0)) { + resX = dpix; + resY = dpiy; + return; + } + } + // SIZE-X and SIZE-Y and PIXEL-X and PIXEL-Y + if (fileMeta.containsKey("original-size-x") + && fileMeta.containsKey("original-size-y") + && fileMeta.containsKey("original-pixel-x") + && fileMeta.containsKey("original-pixel-y")) { + try { + sizex = Float.parseFloat((String) fileMeta + .get("original-size-x")); + sizey = Float.parseFloat((String) fileMeta + .get("original-size-y")); + pixx = Float.parseFloat((String) fileMeta + .get("original-pixel-x")); + pixy = Float.parseFloat((String) fileMeta + .get("original-pixel-y")); + } catch (NumberFormatException e) { + } + if ((sizex != 0) && (sizey != 0) && (pixx != 0) && (pixy != 0)) { + resX = pixx / (sizex * 100 / 2.54f); + resY = pixy / (sizey * 100 / 2.54f); + return; + } + } + } + + /* (non-Javadoc) + * @see digilib.io.DocuDirent#readMeta() + */ + public void readMeta() { + if ((fileMeta != null) || (file == null)) { + // there is already metadata or there is no file + return; + } + // metadata is in the file {filename}.meta + String fn = file.getAbsolutePath(); + File mf = new File(fn + ".meta"); + if (mf.canRead()) { + XMLMetaLoader ml = new XMLMetaLoader(); + try { + // read meta file + Map<String, MetadataMap> meta = ml.loadURL(mf.getAbsolutePath()); + if (meta == null) { + return; + } + fileMeta = meta.get(name); + } catch (Exception e) { + Logger.getLogger(this.getClass()).warn("error reading file .meta", e); + } + } + } + + +}
--- a/servlet/src/digilib/io/ImageFileset.java Tue Mar 01 17:12:25 2011 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,414 +0,0 @@ -/* ImageFileset -- digilib image file info class. - * 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.io; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; - -import digilib.image.ImageSize; -import digilib.io.FileOps.FileClass; -import digilib.servlet.DigilibConfiguration; - -/** - * @author casties - */ -public class ImageFileset extends DocuDirent { - - /** this is an image file */ - protected static FileClass fileClass = FileClass.IMAGE; - - /** list of files (ImageFile) */ - private List<ImageFile> list = null; - - /** aspect ratio (width/height) */ - private float aspect = 0; - - /** resolution of the biggest image (DPI) */ - private float resX = 0; - - /** resolution of the biggest image (DPI) */ - private float resY = 0; - - /** - * Creator for empty fileset. - * - * - * @param initialCapacity - */ - public ImageFileset() { - list = new ArrayList<ImageFile>(); - } - - /** - * Constructor with a file and hints. - * - * The hints are expected to contain 'basedirs' and 'scaledfilext' keys. - * - * @param file - * @param hints - */ - public ImageFileset(File file, Map<Integer,Object> hints) { - Directory[] dirs = (Directory[]) hints.get(FileOps.HINT_BASEDIRS); - int nb = dirs.length; - list = new ArrayList<ImageFile>(nb); - parent = dirs[0]; - fill(dirs, file, hints); - } - - /** - * Adds an ImageFile to this Fileset. - * - * 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) - */ - public boolean add(ImageFile f) { - f.setParent(this); - return list.add(f); - } - - /** - * The number of image files in this Fileset. - * - * - * @return number of image files - */ - public int size() { - return (list != null) ? list.size() : 0; - } - - /** - * Gets the default File. - * - */ - public File getFile() { - return (list != null) ? list.get(0).getFile() : null; - } - - /** - * Get the ImageFile at the index. - * - * - * @param index - * @return - */ - public ImageFile get(int index) { - return list.get(index); - } - - /** - * Get the next smaller ImageFile than the given size. - * - * Returns the ImageFile 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 ImageFile getNextSmaller(ImageSize size) { - for (Iterator<ImageFile> i = getHiresIterator(); i.hasNext();) { - ImageFile f = i.next(); - try { - if (!f.isChecked()) { - DigilibConfiguration.docuImageIdentify(f); - } - if (f.getSize().isTotallySmallerThan(size)) { - return f; - } - } catch (IOException e) { - } - } - return null; - } - - /** - * Get the next bigger ImageFile than the given size. - * - * Returns the ImageFile from the set that has a width or 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 ImageFile getNextBigger(ImageSize size) { - for (ListIterator<ImageFile> i = getLoresIterator(); i.hasPrevious();) { - ImageFile f = i.previous(); - try { - if (!f.isChecked()) { - DigilibConfiguration.docuImageIdentify(f); - } - if (f.getSize().isBiggerThan(size)) { - return f; - } - } catch (IOException e) { - } - } - return null; - } - - /** - * Returns the biggest ImageFile in the set. - * - * - * @return - */ - public ImageFile getBiggest() { - return this.get(0); - } - - /** - * Returns the biggest ImageFile in the set. - * - * - * @return - */ - public ImageFile getSmallest() { - return this.get(this.size() - 1); - } - - /** - * Get an Iterator for this Fileset starting at the highest resolution - * images. - * - * - * @return - */ - public ListIterator<ImageFile> getHiresIterator() { - return list.listIterator(); - } - - /** - * Get an Iterator for this Fileset starting at the lowest resolution - * images. - * - * The Iterator starts at the last element, so you have to use it backwards - * with hasPrevious() and previous(). - * - * - * @return - */ - public ListIterator<ImageFile> getLoresIterator() { - return list.listIterator(list.size()); - } - - /** - * Fill the ImageFileset with files from different base directories. - * - * - * @param dirs - * list of base directories - * @param fl - * file (from first base dir) - * @param hints - * - */ - void fill(Directory[] dirs, File fl, Map<Integer,Object> hints) { - int nb = dirs.length; - String fn = fl.getName(); - String baseFn = FileOps.basename(fn); - // add the first ImageFile to the ImageFileset - add(new ImageFile(fn, this, parent)); - // iterate the remaining base directories - for (int dirIdx = 1; dirIdx < nb; dirIdx++) { - if (dirs[dirIdx] == null) { - continue; - } - // read the directory - if (dirs[dirIdx].getFilenames() == null) { - dirs[dirIdx].readDir(); - } - String[] dirFiles = dirs[dirIdx].getFilenames(); - // try the same filename as the original - int fileIdx = Arrays.binarySearch(dirFiles, fn); - if (fileIdx < 0) { - // try closest matches without extension - fileIdx = -fileIdx - 1; - // try idx - if ((fileIdx < dirFiles.length) - && (FileOps.basename(dirFiles[fileIdx]).equals(baseFn))) { - // idx ok - } else if ((fileIdx > 0) - && (FileOps.basename(dirFiles[fileIdx - 1]) - .equals(baseFn))) { - // idx-1 ok - fileIdx = fileIdx - 1; - } else if ((fileIdx+1 < dirFiles.length) - && (FileOps.basename(dirFiles[fileIdx + 1]) - .equals(baseFn))) { - // idx+1 ok - fileIdx = fileIdx + 1; - } else { - // basename doesn't match - continue; - } - } - if (FileOps.classForFilename(dirFiles[fileIdx]) == fileClass) { - /* logger.debug("adding file " + dirFiles[fileIdx] - + " to Fileset " + this.getName()); */ - add(new ImageFile(dirFiles[fileIdx], this, dirs[dirIdx])); - } - } - } - - /** - * Checks metadata and sets resolution in resX and resY. - * - */ - public void checkMeta() { - if (metaChecked) { - return; - } - if (fileMeta == null) { - // try to read metadata file - readMeta(); - if (fileMeta == null) { - // try directory metadata - ((DocuDirectory) parent).checkMeta(); - if (((DocuDirectory) parent).getDirMeta() != null) { - fileMeta = ((DocuDirectory) parent).getDirMeta(); - } else { - // try parent directory metadata - DocuDirectory gp = (DocuDirectory) parent.getParent(); - if (gp != null) { - gp.checkMeta(); - if (gp.getDirMeta() != null) { - fileMeta = gp.getDirMeta(); - } - } - } - } - } - if (fileMeta == null) { - // no metadata available - metaChecked = true; - return; - } - metaChecked = true; - float dpi = 0; - float dpix = 0; - float dpiy = 0; - float sizex = 0; - float sizey = 0; - float pixx = 0; - float pixy = 0; - // DPI is valid for X and Y - if (fileMeta.containsKey("original-dpi")) { - try { - dpi = Float.parseFloat((String) fileMeta.get("original-dpi")); - } catch (NumberFormatException e) { - } - if (dpi != 0) { - resX = dpi; - resY = dpi; - return; - } - } - // DPI-X and DPI-Y - if (fileMeta.containsKey("original-dpi-x") - && fileMeta.containsKey("original-dpi-y")) { - try { - dpix = Float.parseFloat((String) fileMeta - .get("original-dpi-x")); - dpiy = Float.parseFloat((String) fileMeta - .get("original-dpi-y")); - } catch (NumberFormatException e) { - } - if ((dpix != 0) && (dpiy != 0)) { - resX = dpix; - resY = dpiy; - return; - } - } - // SIZE-X and SIZE-Y and PIXEL-X and PIXEL-Y - if (fileMeta.containsKey("original-size-x") - && fileMeta.containsKey("original-size-y") - && fileMeta.containsKey("original-pixel-x") - && fileMeta.containsKey("original-pixel-y")) { - try { - sizex = Float.parseFloat((String) fileMeta - .get("original-size-x")); - sizey = Float.parseFloat((String) fileMeta - .get("original-size-y")); - pixx = Float.parseFloat((String) fileMeta - .get("original-pixel-x")); - pixy = Float.parseFloat((String) fileMeta - .get("original-pixel-y")); - } catch (NumberFormatException e) { - } - if ((sizex != 0) && (sizey != 0) && (pixx != 0) && (pixy != 0)) { - resX = pixx / (sizex * 100 / 2.54f); - resY = pixy / (sizey * 100 / 2.54f); - return; - } - } - } - - /** - * @return - */ - public float getResX() { - return resX; - } - - /** - * @return - */ - public float getResY() { - return resY; - } - - /** - * Sets the aspect ratio from an ImageSize. - * - * - * @param f - */ - public void setAspect(ImageSize s) { - aspect = s.getAspect(); - } - - /** - * Returns the aspect ratio. - * - * Aspect ratio is (width/height). So it's <1 for portrait and >1 for - * landscape. - * - * - * @return - */ - public float getAspect() { - return aspect; - } - -} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/servlet/src/digilib/io/ImageInput.java Tue Mar 01 22:00:50 2011 +0100 @@ -0,0 +1,159 @@ +/* ImageInput-- digilib image input interface. + + Digital Image Library servlet components + + Copyright (C) 2010 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 20.12.2010 + */ + +package digilib.io; + +import java.io.File; +import java.io.InputStream; + +import javax.imageio.stream.ImageInputStream; + +import digilib.util.ImageSize; + +public abstract class ImageInput { + + // mime file type + protected String mimetype = null; + // image size in pixels + protected ImageSize pixelSize = null; + protected ImageSet parent = null; + + /** + * @return ImageSize + */ + public ImageSize getSize() { + return pixelSize; + } + + /** + * Sets the imageSize. + * @param imageSize The imageSize to set + */ + public void setSize(ImageSize imageSize) { + this.pixelSize = imageSize; + } + + /** returns if mimetype has been set. + * + * @return String + */ + public boolean hasMimetype() { + return (mimetype != null); + } + + /** + * @return String + */ + public String getMimetype() { + return mimetype; + } + + /** + * Sets the mimetype. + * @param mimetype The mimetype to set + */ + public void setMimetype(String filetype) { + this.mimetype = filetype; + } + + /** returns if this image has been checked + * (i.e. has size and mimetype) + * TODO: deprecated + * @return boolean + */ + public boolean isChecked() { + return (pixelSize != null); + } + + /** Returns the aspect ratio of the image (width/height). + * + * @return + */ + public float getAspect() { + return (pixelSize != null) ? pixelSize.getAspect() : 0f; + } + + /** + * @return ImageSet + */ + public ImageSet getParent() { + return parent; + } + + /** + * Sets the parent. + * @param parent The parent to set + */ + public void setParent(ImageSet parent) { + this.parent = parent; + } + + /** Returns if the input can be returned as ImageInputStream. + * + * @return + */ + public boolean hasImageInputStream() { + return false; + } + + /** Returns the input as ImageInputStream (if available) + * + * @return + */ + public ImageInputStream getImageInputStream() { + return null; + } + + /** Returns if the input can be returned as InputStream. + * + * @return + */ + public boolean hasInputStream() { + return false; + } + + /** Returns the input as InputStream (if available) + * + * @return + */ + public InputStream getInputStream() { + return null; + } + + /** Returns if the input can be returned as File. + * + * @return + */ + public boolean hasFile() { + return false; + } + + /** Returns the input as File (if available) + * + * @return + */ + public File getFile() { + return null; + } + + + +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/servlet/src/digilib/io/ImageSet.java Tue Mar 01 22:00:50 2011 +0100 @@ -0,0 +1,211 @@ +/* ImageSet -- digilib image file info class. + * 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.io; + +import java.util.ArrayList; +import java.util.List; +import java.util.ListIterator; + +import digilib.util.ImageSize; + +/** + * @author casties + */ +public class ImageSet { + + /** list of files (ImageFile) */ + protected List<ImageInput> list = null; + + /** aspect ratio (width/height) */ + protected float aspect = 0f; + + /** resolution of the biggest image (DPI) */ + protected float resX = 0f; + + /** resolution of the biggest image (DPI) */ + protected float resY = 0f; + + /** + * Creator for empty fileset. + * + * + * @param initialCapacity + */ + public ImageSet() { + list = new ArrayList<ImageInput>(); + } + + /** + * The number of image files in this Fileset. + * + * + * @return number of image files + */ + public int size() { + return (list != null) ? list.size() : 0; + } + + /** + * Gets the default Input. + * + */ + public ImageInput get() { + return (list != null) ? list.get(0) : null; + } + + /** + * Get the ImageFile at the index. + * + * + * @param index + * @return + */ + public ImageInput get(int index) { + return list.get(index); + } + + /** + * Get the next smaller ImageFile than the given size. + * + * Returns the ImageFile from the set that has a width and height smaller or + * equal the given size. Returns null if there isn't any smaller image. + * + * @param size + * @param info + * @return + */ + public ImageInput getNextSmaller(ImageSize size) { + for (ListIterator<ImageInput> i = getHiresIterator(); i.hasNext();) { + ImageInput f = i.next(); + ImageSize is = f.getSize(); + if (is != null && is.isTotallySmallerThan(size)) { + return f; + } + } + return null; + } + + /** + * Get the next bigger ImageFile than the given size. + * + * Returns the ImageFile from the set that has a width or height bigger or + * equal the given size. Returns null if there isn't any bigger image. + * + * @param size + * @param info + * @return + */ + public ImageInput getNextBigger(ImageSize size) { + for (ListIterator<ImageInput> i = getLoresIterator(); i.hasPrevious();) { + ImageInput f = i.previous(); + ImageSize is = f.getSize(); + if (is != null && is.isBiggerThan(size)) { + return f; + } + } + return null; + } + + /** + * Returns the biggest ImageFile in the set. + * + * + * @return + */ + public ImageInput getBiggest() { + return this.get(0); + } + + /** + * Returns the biggest ImageFile in the set. + * + * + * @return + */ + public ImageInput getSmallest() { + return this.get(this.size() - 1); + } + + /** + * Get an Iterator for this Fileset starting at the highest resolution + * images. + * + * + * @return + */ + public ListIterator<ImageInput> getHiresIterator() { + return list.listIterator(); + } + + /** + * Get an Iterator for this Fileset starting at the lowest resolution + * images. + * + * The Iterator starts at the last element, so you have to use it backwards + * with hasPrevious() and previous(). + * + * + * @return + */ + public ListIterator<ImageInput> getLoresIterator() { + return list.listIterator(list.size()); + } + + /** + * @return + */ + public float getResX() { + return resX; + } + + /** + * @return + */ + public float getResY() { + return resY; + } + + /** + * Sets the aspect ratio from an ImageSize. + * + * + * @param f + */ + public void setAspect(ImageSize s) { + aspect = s.getAspect(); + } + + /** + * Returns the aspect ratio. + * + * Aspect ratio is (width/height). So it's <1 for portrait and >1 for + * landscape. + * + * + * @return + */ + public float getAspect() { + return aspect; + } + + public void checkMeta() { + // TODO Auto-generated method stub + + } + +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/servlet/src/digilib/io/ImageStream.java Tue Mar 01 22:00:50 2011 +0100 @@ -0,0 +1,41 @@ +/** + * + */ +package digilib.io; + +import java.io.InputStream; + +/** + * @author casties + * + */ +public class ImageStream extends ImageInput { + + protected InputStream stream = null; + + public ImageStream(InputStream stream, String mimeType) { + this.stream = stream; + this.mimetype = mimeType; + } + + /* + * (non-Javadoc) + * + * @see digilib.io.ImageInput#hasInputStream() + */ + @Override + public boolean hasInputStream() { + return true; + } + + /* + * (non-Javadoc) + * + * @see digilib.io.ImageInput#getInputStream() + */ + @Override + public InputStream getInputStream() { + return stream; + } + +}
--- a/servlet/src/digilib/io/MetadataMap.java Tue Mar 01 17:12:25 2011 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -/** - * - */ -package digilib.io; - -import java.util.HashMap; - -/** Map for metadata related to files. - * @author casties - * - */ -public class MetadataMap extends HashMap<String, String> { - -}
--- a/servlet/src/digilib/io/SVGFile.java Tue Mar 01 17:12:25 2011 +0100 +++ b/servlet/src/digilib/io/SVGFile.java Tue Mar 01 22:00:50 2011 +0100 @@ -30,7 +30,7 @@ * @author casties * */ -public class SVGFile extends DocuDirent { +public class SVGFile extends DocuDirentImpl { /** this is a text file */ protected static FileClass fileClass = FileClass.SVG; /** our File instance */
--- a/servlet/src/digilib/io/TextFile.java Tue Mar 01 17:12:25 2011 +0100 +++ b/servlet/src/digilib/io/TextFile.java Tue Mar 01 22:00:50 2011 +0100 @@ -30,7 +30,7 @@ * @author casties * */ -public class TextFile extends DocuDirent { +public class TextFile extends DocuDirentImpl { /** this is a text file */ protected static FileClass fileClass = FileClass.TEXT; /** our File instance */
--- a/servlet/src/digilib/io/XMLListLoader.java Tue Mar 01 17:12:25 2011 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,178 +0,0 @@ -/* XMLListLoader -- Load an XML list into a Hashtable - - Digital Image Library servlet components - - Copyright (C) 2001, 2002 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.io; - -// JAXP packages -import java.io.IOException; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Map; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -import org.apache.log4j.Logger; -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; -import org.xml.sax.helpers.DefaultHandler; - -/** Loads a simple XML list into a HashMap. - * - * The XML file has an outer <code>list_tag</code>. Every entry is an - * <code>entry_tag</code> with two attributes: the <code>key_att</code> - * key and the <code>value_att</code> value. - * - * The file is read by the <code>loadURL</code> method, that returns a - * HashMap with the key-value pairs. - * - * @author casties - */ -public class XMLListLoader { - - private Logger logger = Logger.getLogger(this.getClass()); - private String listTag = "list"; - private String entryTag = "entry"; - private String keyAtt = "key"; - private String valueAtt = "value"; - - public XMLListLoader() { - } - - public XMLListLoader( - String list_tag, - String entry_tag, - String key_att, - String value_att) { - logger.debug("xmlListLoader("+list_tag+","+entry_tag+","+key_att+","+value_att+")"); - listTag = list_tag; - entryTag = entry_tag; - keyAtt = key_att; - valueAtt = value_att; - } - - /** - * inner class XMLListParser to be called by the parser - */ - private class XMLListParser extends DefaultHandler { - - private Map<String, String> listData; - private LinkedList<String> tagSpace; - - public Map<String, String> getData() { - return listData; - } - - // Parser calls this once at the beginning of a document - public void startDocument() throws SAXException { - listData = new HashMap<String, String>(); - tagSpace = new LinkedList<String>(); - } - - // Parser calls this for each element in a document - public void startElement( - String namespaceURI, - String localName, - String qName, - Attributes atts) - throws SAXException { - //System.out.println("<"+qName); - // open a new namespace - tagSpace.addLast(qName); - - // ist it an entry tag? - if (qName.equals(entryTag)) { - // is it inside a list tag? - if ((listTag.length() > 0) && (!tagSpace.contains(listTag))) { - logger.error("BOO: Entry " - + entryTag - + " not inside list " - + listTag); - throw new SAXParseException( - "Entry " + entryTag + " not inside list " + listTag, - null); - } - // get the attributes - String key = atts.getValue(keyAtt); - String val = atts.getValue(valueAtt); - if ((key == null) || (val == null)) { - logger.error("BOO: Entry " - + entryTag - + " does not have Attributes " - + keyAtt - + ", " - + valueAtt); - throw new SAXParseException( - "Entry " - + entryTag - + " does not have Attributes " - + keyAtt - + ", " - + valueAtt, - null); - } - // add the values - //System.out.println("DATA: "+key+" = "+val); - listData.put(key, val); - } - } - - public void endElement( - String namespaceURI, - String localName, - String qName) - throws SAXException { - // exit the namespace - tagSpace.removeLast(); - } - - } - - /** - * load and parse a file (as URL) - * returns HashMap with list data - */ - public Map<String, String> loadURL(String path) throws SAXException, IOException { - //System.out.println("loadurl ("+path+")"); - // Create a JAXP SAXParserFactory and configure it - SAXParserFactory spf = SAXParserFactory.newInstance(); - spf.setNamespaceAware(true); - - SAXParser parser = null; - try { - // Create a JAXP SAXParser - parser = spf.newSAXParser(); - - } catch (ParserConfigurationException e) { - throw new SAXException(e); - } - - // create a list parser (keeps the data!) - XMLListParser listParser = new XMLListParser(); - - // Tell the SAXParser to parse the XML document - parser.parse(path, listParser); - - return listParser.getData(); - } - -}
--- a/servlet/src/digilib/io/XMLMetaLoader.java Tue Mar 01 17:12:25 2011 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,287 +0,0 @@ -/* XMLMetaLoader -- Load an XML format metadata into a Hashtable - - 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.io; - -import java.io.IOException; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Map; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -import org.apache.log4j.Logger; -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; - -public class XMLMetaLoader { - - private Logger logger = Logger.getLogger(this.getClass()); - private String metaTag = "meta"; - private String fileTag = "file"; - private String fileNameTag = "name"; - private String filePathTag = "path"; - private String imgTag = "img"; - private String collectTag = "context"; - - public XMLMetaLoader() { - } - - /** - * inner class XMLMetaParser to be called by the parser - */ - private class XMLMetaParser extends DefaultHandler { - - private LinkedList<String> tags; - private Map<String, MetadataMap> files; - private MetadataMap meta; - private StringBuffer content; - private boolean collecting; - private StringBuffer collectedContent; - private String fileName; - private String filePath; - - /** - * extracts the elements name from either localName ln or qName qn. - * - * @param ln localName - * @param qn qName - * @return element name - */ - private String getName(String ln, String qn) { - if (ln != null) { - if (ln.length() > 0) { - return ln; - } - } - // else it's qName (or nothing) - return qn; - } - - /** - * returns all attributes as a String - * - * @param attrs - * @return - */ - private String getAttrString(Attributes attrs) { - StringBuffer s = new StringBuffer(); - for (int i = 0; i < attrs.getLength(); i++) { - String key = getName(attrs.getLocalName(i), attrs.getQName(i)); - s.append(" "+key+"=\""+attrs.getValue(i)+"\""); - } - return s.toString(); - } - - - // Parser calls this once at the beginning of a document - public void startDocument() throws SAXException { - tags = new LinkedList<String>(); - files = new HashMap<String, MetadataMap>(); - collecting = false; - collectedContent = null; - } - - // Parser calls this for each element in a document - public void startElement( - String namespaceURI, - String localName, - String qName, - Attributes atts) - throws SAXException { - - String name = getName(localName, qName); - // open a new tag - tags.addLast(name); - // start new content (no nesting of tags and content) - content = new StringBuffer(); - - if (name.equals(metaTag)) { - // new meta tag - meta = new MetadataMap(); - collectedContent = new StringBuffer(); - } else if (name.equals(fileTag)) { - // new file tag - fileName = null; - filePath = null; - meta = new MetadataMap(); - collectedContent = new StringBuffer(); - } else if (name.equals(collectTag)) { - // start collecting - collecting = true; - if (collectedContent == null) { - collectedContent = new StringBuffer(); - } - } - - // record mode - if (collecting) { - collectedContent.append("<"+name); - collectedContent.append(getAttrString(atts)); - collectedContent.append(">"); - } - } - - // parser calls this for all tag content (possibly more than once) - public void characters(char[] ch, int start, int length) - throws SAXException { - // append data to current string buffer - if (content == null) { - content = new StringBuffer(); - } - content.append(ch, start, length); - } - - // parser calls this at the end of each element - public void endElement( - String namespaceURI, - String localName, - String qName) - throws SAXException { - - String name = getName(localName, qName); - // exit the tag - tags.removeLast(); - String lastTag = (tags.isEmpty()) ? "" : tags.getLast(); - - // was it a file/name tag? - if (name.equals(fileNameTag) && lastTag.equals(fileTag)) { - // save name as filename - if ((content != null) && (content.length() > 0)) { - fileName = content.toString().trim(); - } - content = null; - return; - } - - // was it a file/path tag? - if (name.equals(filePathTag) && lastTag.equals(fileTag)) { - // save path as filepath - if ((content != null) && (content.length() > 0)) { - filePath = content.toString().trim(); - } - content = null; - return; - } - - // was it a file tag? - if (name.equals(fileTag)) { - // is there meta to save? - if ((meta != null) && (meta.size() > 0)) { - // file name is (optional file/path) / file/name - String fn = null; - - if (fileName != null) { - if (filePath != null) { - fn = filePath + "/" + fileName; - } else { - fn = fileName; - } - } else { - // no file name, no file - content = null; - return; - } - // save meta in file list - files.put(fn, meta); - } - content = null; - return; - } - - // was it a meta tag outside a file tag? - if (name.equals(metaTag) && !tags.contains(fileTag)) { - // save meta as dir meta - if ((meta != null) && (meta.size() > 0)) { - files.put("", meta); - } - content = null; - return; - } - - // is this inside an digilib info (=img) tag? - if (lastTag.equals(imgTag)) { - // then add whatever this is - if ((content != null) && (content.length() > 0)) { - meta.put(name, content.toString().trim()); - } - content = null; - return; - } - - // is this the end of collectTag? - if (name.equals(collectTag)) { - collecting = false; - collectedContent.append("</"+collectTag+">\n"); - // store collected stuff - meta.put(collectTag, collectedContent.toString()); - //logger.debug("collected: '"+collectedContent+"'"); - content = null; - return; - } - - // write collected content - if (collecting) { - String s = ""; - if ((content != null) && (content.length() > 0)) { - s = content.toString().trim(); - } - //logger.debug("collect:"+name+" = "+s); - collectedContent.append(s); - collectedContent.append("</"+name+">\n"); - content = null; - return; - } - } - - } - - /** - * load and parse a file (as URL) - * returns HashMap with list data - */ - public Map<String, MetadataMap> loadURL(String path) throws SAXException, IOException { - logger.debug("loading meta: "+path); - // Create a JAXP SAXParserFactory and configure it - SAXParserFactory spf = SAXParserFactory.newInstance(); - spf.setNamespaceAware(true); - - SAXParser parser = null; - try { - // Create a JAXP SAXParser - parser = spf.newSAXParser(); - - } catch (ParserConfigurationException e) { - throw new SAXException(e); - } - - // create a list parser (keeps the data!) - XMLMetaParser listParser = new XMLMetaParser(); - - // Tell the SAXParser to parse the XML document - parser.parse(path, listParser); - - return listParser.files; - } - -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/servlet/src/digilib/meta/MetadataMap.java Tue Mar 01 22:00:50 2011 +0100 @@ -0,0 +1,15 @@ +/** + * + */ +package digilib.meta; + +import java.util.HashMap; + +/** Map for metadata related to files. + * @author casties + * + */ +@SuppressWarnings("serial") +public class MetadataMap extends HashMap<String, String> { + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/servlet/src/digilib/meta/XMLMetaLoader.java Tue Mar 01 22:00:50 2011 +0100 @@ -0,0 +1,287 @@ +/* XMLMetaLoader -- Load an XML format metadata into a Hashtable + + 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.meta; + +import java.io.IOException; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.apache.log4j.Logger; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.helpers.DefaultHandler; + +public class XMLMetaLoader { + + private Logger logger = Logger.getLogger(this.getClass()); + private String metaTag = "meta"; + private String fileTag = "file"; + private String fileNameTag = "name"; + private String filePathTag = "path"; + private String imgTag = "img"; + private String collectTag = "context"; + + public XMLMetaLoader() { + } + + /** + * inner class XMLMetaParser to be called by the parser + */ + private class XMLMetaParser extends DefaultHandler { + + private LinkedList<String> tags; + private Map<String, MetadataMap> files; + private MetadataMap meta; + private StringBuffer content; + private boolean collecting; + private StringBuffer collectedContent; + private String fileName; + private String filePath; + + /** + * extracts the elements name from either localName ln or qName qn. + * + * @param ln localName + * @param qn qName + * @return element name + */ + private String getName(String ln, String qn) { + if (ln != null) { + if (ln.length() > 0) { + return ln; + } + } + // else it's qName (or nothing) + return qn; + } + + /** + * returns all attributes as a String + * + * @param attrs + * @return + */ + private String getAttrString(Attributes attrs) { + StringBuffer s = new StringBuffer(); + for (int i = 0; i < attrs.getLength(); i++) { + String key = getName(attrs.getLocalName(i), attrs.getQName(i)); + s.append(" "+key+"=\""+attrs.getValue(i)+"\""); + } + return s.toString(); + } + + + // Parser calls this once at the beginning of a document + public void startDocument() throws SAXException { + tags = new LinkedList<String>(); + files = new HashMap<String, MetadataMap>(); + collecting = false; + collectedContent = null; + } + + // Parser calls this for each element in a document + public void startElement( + String namespaceURI, + String localName, + String qName, + Attributes atts) + throws SAXException { + + String name = getName(localName, qName); + // open a new tag + tags.addLast(name); + // start new content (no nesting of tags and content) + content = new StringBuffer(); + + if (name.equals(metaTag)) { + // new meta tag + meta = new MetadataMap(); + collectedContent = new StringBuffer(); + } else if (name.equals(fileTag)) { + // new file tag + fileName = null; + filePath = null; + meta = new MetadataMap(); + collectedContent = new StringBuffer(); + } else if (name.equals(collectTag)) { + // start collecting + collecting = true; + if (collectedContent == null) { + collectedContent = new StringBuffer(); + } + } + + // record mode + if (collecting) { + collectedContent.append("<"+name); + collectedContent.append(getAttrString(atts)); + collectedContent.append(">"); + } + } + + // parser calls this for all tag content (possibly more than once) + public void characters(char[] ch, int start, int length) + throws SAXException { + // append data to current string buffer + if (content == null) { + content = new StringBuffer(); + } + content.append(ch, start, length); + } + + // parser calls this at the end of each element + public void endElement( + String namespaceURI, + String localName, + String qName) + throws SAXException { + + String name = getName(localName, qName); + // exit the tag + tags.removeLast(); + String lastTag = (tags.isEmpty()) ? "" : tags.getLast(); + + // was it a file/name tag? + if (name.equals(fileNameTag) && lastTag.equals(fileTag)) { + // save name as filename + if ((content != null) && (content.length() > 0)) { + fileName = content.toString().trim(); + } + content = null; + return; + } + + // was it a file/path tag? + if (name.equals(filePathTag) && lastTag.equals(fileTag)) { + // save path as filepath + if ((content != null) && (content.length() > 0)) { + filePath = content.toString().trim(); + } + content = null; + return; + } + + // was it a file tag? + if (name.equals(fileTag)) { + // is there meta to save? + if ((meta != null) && (meta.size() > 0)) { + // file name is (optional file/path) / file/name + String fn = null; + + if (fileName != null) { + if (filePath != null) { + fn = filePath + "/" + fileName; + } else { + fn = fileName; + } + } else { + // no file name, no file + content = null; + return; + } + // save meta in file list + files.put(fn, meta); + } + content = null; + return; + } + + // was it a meta tag outside a file tag? + if (name.equals(metaTag) && !tags.contains(fileTag)) { + // save meta as dir meta + if ((meta != null) && (meta.size() > 0)) { + files.put("", meta); + } + content = null; + return; + } + + // is this inside an digilib info (=img) tag? + if (lastTag.equals(imgTag)) { + // then add whatever this is + if ((content != null) && (content.length() > 0)) { + meta.put(name, content.toString().trim()); + } + content = null; + return; + } + + // is this the end of collectTag? + if (name.equals(collectTag)) { + collecting = false; + collectedContent.append("</"+collectTag+">\n"); + // store collected stuff + meta.put(collectTag, collectedContent.toString()); + //logger.debug("collected: '"+collectedContent+"'"); + content = null; + return; + } + + // write collected content + if (collecting) { + String s = ""; + if ((content != null) && (content.length() > 0)) { + s = content.toString().trim(); + } + //logger.debug("collect:"+name+" = "+s); + collectedContent.append(s); + collectedContent.append("</"+name+">\n"); + content = null; + return; + } + } + + } + + /** + * load and parse a file (as URL) + * returns HashMap with list data + */ + public Map<String, MetadataMap> loadURL(String path) throws SAXException, IOException { + logger.debug("loading meta: "+path); + // Create a JAXP SAXParserFactory and configure it + SAXParserFactory spf = SAXParserFactory.newInstance(); + spf.setNamespaceAware(true); + + SAXParser parser = null; + try { + // Create a JAXP SAXParser + parser = spf.newSAXParser(); + + } catch (ParserConfigurationException e) { + throw new SAXException(e); + } + + // create a list parser (keeps the data!) + XMLMetaParser listParser = new XMLMetaParser(); + + // Tell the SAXParser to parse the XML document + parser.parse(path, listParser); + + return listParser.files; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/servlet/src/digilib/pdf/DigilibInfoReader.java Tue Mar 01 22:00:50 2011 +0100 @@ -0,0 +1,76 @@ +package digilib.pdf; + +/** DigilibInfoReader + * A class for reading the information from info.xml files used in digilib image directories. + * + */ + +import java.io.File; +import java.util.List; + +import org.apache.log4j.Logger; +import org.jdom.Document; +import org.jdom.Element; +import org.jdom.input.SAXBuilder; + + + +public class DigilibInfoReader { + + /** gengeral logger for this class */ + protected static Logger logger = Logger.getLogger("digilib.servlet"); + + private String filename = null; + //private static String base_element = "info"; + + public DigilibInfoReader(String fn){ + filename = fn; + } + + /** + * Returns the attribute defined by 'attr' as a String. + * + * @param attr + * @return + */ + @SuppressWarnings("unchecked") // Element.getChildren() returns naked List + public String getAsString(String attr){ + try{ + SAXBuilder builder = new SAXBuilder(); + Document doc = builder.build(new File(filename)); + Element root = doc.getRootElement(); + List<Element> mainElements = root.getChildren(); + // logger.debug("XML mainElements:"+mainElements.toString()); + + for(int i=0; i<mainElements.size(); i++){ + Element elem = mainElements.get(i); + if(elem.getName()==attr){ + // logger.debug(attr+" == "+(String)elem.getTextTrim()); + return (String)elem.getTextTrim(); + } + } + + } + catch(Exception e){ + logger.error(e.getMessage()); + } + return null; + } + + + /** + * Find out if the info.xml exists + * @return + */ + public boolean hasInfo(){ + try { + SAXBuilder builder = new SAXBuilder(); + builder.build(new File(filename)); + return true; + } + catch(Exception e){ + return false; + } + } + +}
--- a/servlet/src/digilib/pdf/PDFFileWorker.java Tue Mar 01 17:12:25 2011 +0100 +++ b/servlet/src/digilib/pdf/PDFFileWorker.java Tue Mar 01 22:00:50 2011 +0100 @@ -46,10 +46,18 @@ } public File call() throws Exception { - OutputStream outstream = streamWorker.call(); - outstream.flush(); - // move temporary to final file - tempFile.renameTo(finalFile); + OutputStream outstream = null; + try { + outstream = streamWorker.call(); + outstream.flush(); + outstream.close(); + // move temporary to final file + tempFile.renameTo(finalFile); + } finally { + if (outstream != null) { + outstream.close(); + } + } return finalFile; }
--- a/servlet/src/digilib/pdf/PDFStreamWorker.java Tue Mar 01 17:12:25 2011 +0100 +++ b/servlet/src/digilib/pdf/PDFStreamWorker.java Tue Mar 01 22:00:50 2011 +0100 @@ -97,6 +97,7 @@ doc.close(); logger.debug("PDF: " + outstream + " doc.close() (" + (System.currentTimeMillis() - start_time) + "ms)"); + docwriter.flush(); docwriter.close(); return outstream; }
--- a/servlet/src/digilib/pdf/PDFTitlePage.java Tue Mar 01 17:12:25 2011 +0100 +++ b/servlet/src/digilib/pdf/PDFTitlePage.java Tue Mar 01 22:00:50 2011 +0100 @@ -15,7 +15,6 @@ import com.itextpdf.text.Image; import com.itextpdf.text.Paragraph; -import digilib.io.DigilibInfoReader; import digilib.io.FileOpException; import digilib.servlet.PDFCache; import digilib.servlet.PDFRequest;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/servlet/src/digilib/servlet/AsyncServletWorker.java Tue Mar 01 22:00:50 2011 +0100 @@ -0,0 +1,94 @@ +/** + * + */ +package digilib.servlet; + +import java.io.IOException; + +import javax.servlet.AsyncContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletResponse; + +import org.apache.log4j.Logger; + +import digilib.image.DocuImage; +import digilib.image.ImageJobDescription; +import digilib.image.ImageOpException; +import digilib.image.ImageWorker; +import digilib.servlet.Scaler.ErrMsg; +import digilib.servlet.Scaler.Error; + +/** + * @author casties + * + */ +public class AsyncServletWorker implements Runnable { + + /** the AsyncServlet context */ + private AsyncContext asyncContext; + + /** the ImageWorker we use */ + private ImageWorker imageWorker; + + protected static Logger logger = Logger.getLogger(AsyncServletWorker.class); + private long startTime; + private ErrMsg errMsgType = ErrMsg.IMAGE; + private ImageJobDescription jobinfo; + + /** + * @param dlConfig + * @param jobinfo + */ + public AsyncServletWorker(DigilibConfiguration dlConfig, + ImageJobDescription jobinfo, AsyncContext asyncContext, + ErrMsg errMsgType, long startTime) { + // set up image worker + imageWorker = new ImageWorker(dlConfig, jobinfo); + // save AsyncContext + this.asyncContext = asyncContext; + this.startTime = startTime; + this.errMsgType = errMsgType; + this.jobinfo = jobinfo; + } + + /** + * runs the ImageWorker and writes the image to the ServletResponse. + */ + public void run() { + // get fresh response + HttpServletResponse response = (HttpServletResponse) asyncContext.getResponse(); + logger.debug("working on response: (" + ServletOps.headersToString(response) + ")"); + try { + // render the image + DocuImage img = imageWorker.call(); + // forced destination image type + String mt = null; + if (jobinfo.hasOption("jpg")) { + mt = "image/jpeg"; + } else if (jobinfo.hasOption("png")) { + mt = "image/png"; + } + // send image + ServletOps.sendImage(img, mt, response, logger); + logger.debug("Job done in: " + + (System.currentTimeMillis() - startTime) + "ms"); + } catch (ImageOpException e) { + logger.error(e.getClass() + ": " + e.getMessage()); + Scaler.digilibError(errMsgType, Error.IMAGE, null, response); + } catch (IOException e) { + logger.error(e.getClass() + ": " + e.getMessage()); + Scaler.digilibError(errMsgType, Error.FILE, null, response); + } catch (ServletException e) { + logger.error("Servlet error: ", e); + } catch (Exception e) { + logger.error("Other error: ", e); + } finally { + // submit response + logger.debug("context complete."); + logger.debug("response: (" + ServletOps.headersToString(response) + ")"); + asyncContext.complete(); + } + + } + +}
--- a/servlet/src/digilib/servlet/DigilibConfiguration.java Tue Mar 01 17:12:25 2011 +0100 +++ b/servlet/src/digilib/servlet/DigilibConfiguration.java Tue Mar 01 22:00:50 2011 +0100 @@ -26,7 +26,7 @@ import java.util.Map; import java.util.Map.Entry; -import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; import javax.servlet.ServletException; import org.apache.log4j.BasicConfigurator; @@ -35,10 +35,10 @@ import digilib.image.DocuImage; import digilib.image.DocuImageImpl; import digilib.io.FileOps; -import digilib.io.ImageFile; -import digilib.io.XMLListLoader; +import digilib.io.ImageInput; import digilib.util.Parameter; import digilib.util.ParameterMap; +import digilib.util.XMLListLoader; /** * Class to hold the digilib servlet configuration parameters. The parameters @@ -172,8 +172,8 @@ newParameter("pdf-temp-dir", "pdf_temp", null, 'f'); // PDF generation cache directory newParameter("pdf-cache-dir", "pdf_cache", null, 'f'); - // PDF generation cache directory - newParameter("pdf-cache-dir", "pdf_cache", null, 'f'); + // allow image toolkit to use disk cache + newParameter("img-diskcache-allowed", Boolean.TRUE, null, 'f'); } /** @@ -182,7 +182,7 @@ * * @see readConfig() */ - public DigilibConfiguration(ServletConfig c) throws Exception { + public DigilibConfiguration(ServletContext c) throws Exception { this(); readConfig(c); } @@ -192,7 +192,7 @@ * or file digilib-config.xml */ @SuppressWarnings("unchecked") - public void readConfig(ServletConfig c) throws Exception { + public void readConfig(ServletContext c) throws Exception { /* * Get config file name. The file name is first looked for as an init @@ -215,7 +215,7 @@ XMLListLoader lilo = new XMLListLoader("digilib-config", "parameter", "name", "value"); // read config file into HashMap - Map<String,String> confTable = lilo.loadURL(f.toURL().toString()); + Map<String,String> confTable = lilo.loadURL(f.toString()); // set config file path parameter setValue("servlet.config.file", f.getCanonicalPath()); @@ -277,7 +277,7 @@ * @return * @throws IOException */ - public static ImageFile docuImageIdentify(ImageFile imgf) throws IOException { + public static ImageInput identifyDocuImage(ImageInput imgf) throws IOException { // use fresh DocuImage instance DocuImage di = getDocuImageInstance(); return di.identify(imgf);
--- a/servlet/src/digilib/servlet/DigilibRequest.java Tue Mar 01 17:12:25 2011 +0100 +++ b/servlet/src/digilib/servlet/DigilibRequest.java Tue Mar 01 22:00:50 2011 +0100 @@ -131,6 +131,8 @@ newParameter("ddpiy", new Float(0), null, 's'); // scale factor for mo=ascale newParameter("scale", new Float(1), null, 's'); + // color conversion operation + newParameter("colop", "", null, 's'); /* * Parameters of type 'i' are not exchanged between client and server,
--- a/servlet/src/digilib/servlet/DocumentBean.java Tue Mar 01 17:12:25 2011 +0100 +++ b/servlet/src/digilib/servlet/DocumentBean.java Tue Mar 01 22:00:50 2011 +0100 @@ -33,12 +33,12 @@ import digilib.auth.AuthOpException; import digilib.auth.AuthOps; -import digilib.image.ImageSize; import digilib.io.DocuDirCache; import digilib.io.DocuDirectory; import digilib.io.FileOps.FileClass; -import digilib.io.ImageFile; -import digilib.io.ImageFileset; +import digilib.io.ImageInput; +import digilib.io.ImageSet; +import digilib.util.ImageSize; public class DocumentBean { @@ -191,13 +191,13 @@ } String fn = dlRequest.getFilePath(); // get information about the file - ImageFileset fileset = (ImageFileset) dirCache.getFile(fn, dlRequest + ImageSet fileset = (ImageSet) dirCache.getFile(fn, dlRequest .getAsInt("pn"), FileClass.IMAGE); if (fileset == null) { return; } // add file name - dlRequest.setValue("img.fn", fileset.getName()); + dlRequest.setValue("img.fn", fileset); // add dpi dlRequest.setValue("img.dpix", new Double(fileset.getResX())); dlRequest.setValue("img.dpiy", new Double(fileset.getResY())); @@ -208,12 +208,8 @@ dlRequest.setValue("pt", dd.size()); } // get original pixel size - ImageFile origfile = fileset.getBiggest(); - // check image for size if mo=hires - if ((! origfile.isChecked())&&dlRequest.hasOption("hires")) { - logger.debug("pre-checking image!"); - DigilibConfiguration.docuImageIdentify(origfile); - } + ImageInput origfile = fileset.getBiggest(); + // check image for size (TODO: just if mo=hires?) ImageSize pixsize = origfile.getSize(); if (pixsize != null) { // add pixel size
--- a/servlet/src/digilib/servlet/Initialiser.java Tue Mar 01 17:12:25 2011 +0100 +++ b/servlet/src/digilib/servlet/Initialiser.java Tue Mar 01 22:00:50 2011 +0100 @@ -24,10 +24,11 @@ import java.io.OutputStream; import java.util.List; -import javax.servlet.ServletConfig; +import javax.imageio.ImageIO; import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; +import javax.servlet.annotation.WebListener; import org.apache.log4j.Logger; import org.apache.log4j.xml.DOMConfigurator; @@ -41,16 +42,17 @@ import digilib.util.DigilibJobCenter; /** - * Singleton initalisation servlet for setup tasks and resources. + * Singleton initalisation listener for setup tasks and resources. * * @author casties * */ -@SuppressWarnings("serial") -public class Initialiser extends HttpServlet { +@WebListener +public class Initialiser implements ServletContextListener { + /** servlet version */ - public static final String version = "0.2"; + public static final String version = "0.3"; /** gengeral logger for this class */ private static Logger logger = Logger.getLogger("digilib.init"); @@ -61,7 +63,7 @@ /** DigilibConfiguration instance */ DigilibConfiguration dlConfig; - /** Executor for digilib image jobs */ + /** Executor for digilib image jobs (AsyncServletWorker doesn't return anything) */ DigilibJobCenter<DocuImage> imageEx; /** Executor for PDF jobs */ @@ -72,24 +74,19 @@ /** * Initialisation on first run. - * - * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig) */ - public void init(ServletConfig config) throws ServletException { - super.init(config); + public void contextInitialized(ServletContextEvent cte) { + ServletContext context = cte.getServletContext(); - System.out - .println("***** Digital Image Library Initialisation Servlet (version " + System.out.println("***** Digital Image Library Initialiser (version " + version + ") *****"); - // get our ServletContext - ServletContext context = config.getServletContext(); // see if there is a Configuration instance dlConfig = (DigilibConfiguration) context.getAttribute("digilib.servlet.configuration"); if (dlConfig == null) { // create new Configuration try { - dlConfig = new DigilibConfiguration(config); + dlConfig = new DigilibConfiguration(context); /* * further initialization @@ -97,12 +94,12 @@ // set up the logger File logConf = ServletOps.getConfigFile((File) dlConfig - .getValue("log-config-file"), config); + .getValue("log-config-file"), context); DOMConfigurator.configure(logConf.getAbsolutePath()); dlConfig.setValue("log-config-file", logConf); // say hello in the log file logger - .info("***** Digital Image Library Initialisation Servlet (version " + .info("***** Digital Image Library Initialiser (version " + version + ") *****"); // directory cache String[] bd = (String[]) dlConfig.getValue("basedir-list"); @@ -110,7 +107,7 @@ if (dlConfig.getAsBoolean("use-mapping")) { // with mapping file File mapConf = ServletOps.getConfigFile((File) dlConfig - .getValue("mapping-file"), config); + .getValue("mapping-file"), context); dirCache = new AliasingDocuDirCache(bd, fcs, mapConf, dlConfig); dlConfig.setValue("mapping-file", mapConf); @@ -125,7 +122,7 @@ //authOp = new DBAuthOpsImpl(util); // XML version File authConf = ServletOps.getConfigFile((File) dlConfig - .getValue("auth-file"), config); + .getValue("auth-file"), context); AuthOps authOp = new XMLAuthOps(authConf); dlConfig.setValue("servlet.auth.op", authOp); dlConfig.setValue("auth-file", authConf); @@ -133,6 +130,10 @@ // DocuImage class DocuImage di = DigilibConfiguration.getDocuImageInstance(); dlConfig.setValue("servlet.docuimage.class", di.getClass().getName()); + // disk cache for image toolkit + boolean dc = dlConfig.getAsBoolean("img-diskcache-allowed"); + // TODO: methods for all toolkits? + ImageIO.setUseCache(dc); // digilib worker threads int nt = dlConfig.getAsInt("worker-threads"); int mt = dlConfig.getAsInt("max-waiting-threads"); @@ -152,22 +153,21 @@ context.setAttribute("digilib.servlet.configuration", dlConfig); } catch (Exception e) { - throw new ServletException(e); + logger.error("Error in initialisation: ", e); } } else { // say hello in the log file - logger - .info("***** Digital Image Library Initialisation Servlet (version " + logger.info("***** Digital Image Library Initialiser (version " + version + ") *****"); logger.warn("Already initialised!"); } } /** clean up local resources - * @see javax.servlet.GenericServlet#destroy() + * */ - @Override - public void destroy() { + public void contextDestroyed(ServletContextEvent arg0) { + logger.info("Initialiser shutting down."); if (dirCache != null) { // shut down dirCache? dirCache = null; @@ -196,7 +196,6 @@ logger.error("Still running threads when shutting down PDF-image job queue: "+nrj); } } - super.destroy(); } }
--- a/servlet/src/digilib/servlet/Scaler.java Tue Mar 01 17:12:25 2011 +0100 +++ b/servlet/src/digilib/servlet/Scaler.java Tue Mar 01 22:00:50 2011 +0100 @@ -3,12 +3,12 @@ import java.io.File; import java.io.IOException; import java.util.List; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; +import javax.servlet.AsyncContext; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.ServletException; +import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -20,17 +20,18 @@ import digilib.image.DocuImage; import digilib.image.ImageJobDescription; import digilib.image.ImageOpException; -import digilib.image.ImageWorker; import digilib.io.DocuDirCache; import digilib.io.DocuDirectory; -import digilib.io.ImageFile; +import digilib.io.ImageInput; import digilib.util.DigilibJobCenter; -@SuppressWarnings("serial") +@WebServlet(name="Scaler", urlPatterns={"/Scaler", "/servlet/Scaler/*"}, asyncSupported=true) public class Scaler extends HttpServlet { + private static final long serialVersionUID = 5289386646192471549L; + /** digilib servlet version (for all components) */ - public static final String version = "1.8.4a2"; + public static final String version = "1.9.1a16"; /** servlet error codes */ public static enum Error {UNKNOWN, AUTH, FILE, IMAGE}; @@ -48,31 +49,31 @@ protected static Logger authlog = Logger.getLogger("digilib.auth"); /** DocuDirCache instance */ - DocuDirCache dirCache; + protected DocuDirCache dirCache; /** Image executor */ - DigilibJobCenter<DocuImage> imageJobCenter; + protected DigilibJobCenter<DocuImage> imageJobCenter; /** authentication error image file */ - File denyImgFile; + public static File denyImgFile; /** image error image file */ - File errorImgFile; + public static File errorImgFile; /** not found error image file */ - File notfoundImgFile; + public static File notfoundImgFile; /** send files as is? */ - boolean sendFileAllowed = true; + protected boolean sendFileAllowed = true; /** DigilibConfiguration instance */ - DigilibConfiguration dlConfig; + protected DigilibConfiguration dlConfig; /** use authorization database */ - boolean useAuthorization = true; + protected boolean useAuthorization = true; /** AuthOps instance */ - AuthOps authOp; + protected AuthOps authOp; /** * Initialisation on first run. @@ -94,8 +95,7 @@ // 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) { // no Configuration throw new ServletException("No Configuration!"); @@ -112,15 +112,16 @@ .getValue("servlet.worker.imageexecutor"); denyImgFile = ServletOps.getFile( - (File) dlConfig.getValue("denied-image"), config); + (File) dlConfig.getValue("denied-image"), context); errorImgFile = ServletOps.getFile( - (File) dlConfig.getValue("error-image"), config); + (File) dlConfig.getValue("error-image"), context); notfoundImgFile = ServletOps.getFile( - (File) dlConfig.getValue("notfound-image"), config); + (File) dlConfig.getValue("notfound-image"), context); sendFileAllowed = dlConfig.getAsBoolean("sendfile-allowed"); } - /** Returns modification time relevant to the request for caching. + /** + * Returns modification time relevant to the request for caching. * * @see javax.servlet.http.HttpServlet#getLastModified(javax.servlet.http.HttpServletRequest) */ @@ -128,13 +129,17 @@ accountlog.debug("GetLastModified from " + request.getRemoteAddr() + " for " + request.getQueryString()); long mtime = -1; - // create new request - DigilibRequest dlReq = new DigilibRequest(request); - DocuDirectory dd = dirCache.getDirectory(dlReq.getFilePath()); - if (dd != null) { - mtime = dd.getDirMTime() / 1000 * 1000; + try { + // create new digilib request + DigilibRequest dlReq = new DigilibRequest(request); + DocuDirectory dd = dirCache.getDirectory(dlReq.getFilePath()); + if (dd != null) { + mtime = dd.getDirMTime() / 1000 * 1000; + } + } catch (Exception e) { + logger.error("error in getLastModified: " + e.getMessage()); } - logger.debug(" returns "+mtime); + logger.debug(" returns " + mtime); return mtime; } @@ -183,12 +188,14 @@ accountlog.debug("request: " + request.getQueryString()); logger.debug("request: " + request.getQueryString()); - long startTime = System.currentTimeMillis(); + logger.debug("headers: " + ServletOps.headersToString(request)); + //logger.debug("response:"+ response + " committed=" + response.isCommitted()); + final long startTime = System.currentTimeMillis(); // parse request DigilibRequest dlRequest = new DigilibRequest(request); // extract the job information - ImageJobDescription jobTicket = ImageJobDescription.getInstance(dlRequest, dlConfig); + final ImageJobDescription jobTicket = ImageJobDescription.getInstance(dlRequest, dlConfig); // type of error reporting ErrMsg errMsgType = ErrMsg.IMAGE; @@ -202,7 +209,7 @@ /* * check if we can fast-track without scaling */ - ImageFile fileToLoad = jobTicket.getFileToLoad(); + ImageInput fileToLoad = (ImageInput) jobTicket.getInput(); // check permissions if (useAuthorization) { @@ -246,16 +253,14 @@ response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); return; } + + // worker job is done asynchronously + AsyncContext asyncCtx = request.startAsync(request, response); // create job - ImageWorker job = new ImageWorker(dlConfig, jobTicket); + AsyncServletWorker job = new AsyncServletWorker(dlConfig, jobTicket, asyncCtx, errMsgType, startTime); // submit job - Future<DocuImage> jobResult = imageJobCenter.submit(job); - // wait for result - DocuImage img = jobResult.get(); - // send image - ServletOps.sendImage(img, null, response, logger); - logger.debug("Job Processing Time: " - + (System.currentTimeMillis() - startTime) + "ms"); + imageJobCenter.submit(job); + // we're done for now } catch (ImageOpException e) { logger.error(e.getClass() + ": " + e.getMessage()); @@ -266,15 +271,11 @@ } catch (AuthOpException e) { logger.error(e.getClass() + ": " + e.getMessage()); digilibError(errMsgType, Error.AUTH, null, response); - } catch (InterruptedException e) { - logger.error(e.getClass() + ": " + e.getMessage()); - } catch (ExecutionException e) { - logger.error(e.getClass() + ": " + e.getMessage()); - String causeMsg = e.getCause().getMessage(); - logger.error("caused by: " + causeMsg); - digilibError(errMsgType, Error.IMAGE, causeMsg, response); + } catch (Exception e) { + logger.error("Other Exception: ", e); + // TODO: should we rethrow or swallow? + //throw new ServletException(e); } - } /** @@ -285,7 +286,7 @@ * @param msg * @param response */ - public void digilibError(ErrMsg type, Error error, String msg, + public static void digilibError(ErrMsg type, Error error, String msg, HttpServletResponse response) { try { File img = null; @@ -306,13 +307,12 @@ if (msg == null) { msg = "ERROR: Other image error!"; } - img = this.errorImgFile; + img = errorImgFile; status = HttpServletResponse.SC_BAD_REQUEST; } if (response.isCommitted()) { // response already committed - logger.error("Unable to send error: " + msg); - return; + logger.warn("Response committed for error "+msg); } if (type == ErrMsg.TEXT) { ServletOps.htmlMessage(msg, response);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/servlet/src/digilib/servlet/ScalerNoAsync.java Tue Mar 01 22:00:50 2011 +0100 @@ -0,0 +1,346 @@ +package digilib.servlet; + +import java.io.File; +import java.io.IOException; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.log4j.Logger; + +import digilib.auth.AuthOpException; +import digilib.auth.AuthOps; +import digilib.image.DocuImage; +import digilib.image.ImageJobDescription; +import digilib.image.ImageOpException; +import digilib.image.ImageWorker; +import digilib.io.DocuDirCache; +import digilib.io.DocuDirectory; +import digilib.io.ImageInput; +import digilib.util.DigilibJobCenter; + +/** + * Version of Scaler servlet that uses a thread pool but not Servlet 3.0 async API. + */ +public class ScalerNoAsync extends HttpServlet { + + private static final long serialVersionUID = -5439198888139362735L; + + /** digilib servlet version (for all components) */ + public static final String version = "1.9.0a5 noasync"; + + /** servlet error codes */ + public static enum Error {UNKNOWN, AUTH, FILE, IMAGE}; + + /** type of error message */ + public static enum ErrMsg {IMAGE, TEXT, CODE}; + + /** logger for accounting requests */ + protected static Logger accountlog = Logger.getLogger("account.request"); + + /** gengeral logger for this class */ + protected static Logger logger = Logger.getLogger("digilib.scaler"); + + /** logger for authentication related */ + protected static Logger authlog = Logger.getLogger("digilib.auth"); + + /** DocuDirCache instance */ + protected DocuDirCache dirCache; + + /** Image executor */ + DigilibJobCenter<DocuImage> imageJobCenter; + + /** authentication error image file */ + public static File denyImgFile; + + /** image error image file */ + public static File errorImgFile; + + /** not found error image file */ + public static File notfoundImgFile; + + /** send files as is? */ + protected boolean sendFileAllowed = true; + + /** DigilibConfiguration instance */ + protected DigilibConfiguration dlConfig; + + /** use authorization database */ + protected boolean useAuthorization = true; + + /** AuthOps instance */ + protected AuthOps authOp; + + /** + * Initialisation on first run. + * + * @throws ServletException + * + * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig) + */ + public void init(ServletConfig config) throws ServletException { + super.init(config); + + System.out + .println("***** Digital Image Library Image Scaler Servlet (version " + + version + ") *****"); + // say hello in the log file + logger.info("***** Digital Image Library Image Scaler Servlet (version " + + version + ") *****"); + + // get our ServletContext + ServletContext context = config.getServletContext(); + // see if there is a Configuration instance + dlConfig = (DigilibConfiguration) context + .getAttribute("digilib.servlet.configuration"); + if (dlConfig == null) { + // no Configuration + throw new ServletException("No Configuration!"); + } + // set our AuthOps + useAuthorization = dlConfig.getAsBoolean("use-authorization"); + authOp = (AuthOps) dlConfig.getValue("servlet.auth.op"); + + // DocuDirCache instance + dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache"); + + // Executor + imageJobCenter = (DigilibJobCenter<DocuImage>) dlConfig + .getValue("servlet.worker.imageexecutor"); + + denyImgFile = ServletOps.getFile( + (File) dlConfig.getValue("denied-image"), context); + errorImgFile = ServletOps.getFile( + (File) dlConfig.getValue("error-image"), context); + notfoundImgFile = ServletOps.getFile( + (File) dlConfig.getValue("notfound-image"), context); + sendFileAllowed = dlConfig.getAsBoolean("sendfile-allowed"); + } + + /** Returns modification time relevant to the request for caching. + * + * @see javax.servlet.http.HttpServlet#getLastModified(javax.servlet.http.HttpServletRequest) + */ + public long getLastModified(HttpServletRequest request) { + accountlog.debug("GetLastModified from " + request.getRemoteAddr() + + " for " + request.getQueryString()); + long mtime = -1; + // create new request + DigilibRequest dlReq = new DigilibRequest(request); + DocuDirectory dd = dirCache.getDirectory(dlReq.getFilePath()); + if (dd != null) { + mtime = dd.getDirMTime() / 1000 * 1000; + } + logger.debug(" returns "+mtime); + return mtime; + } + + /* (non-Javadoc) + * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException { + accountlog.info("GET from " + request.getRemoteAddr()); + this.processRequest(request, response); + } + + + /* (non-Javadoc) + * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ + public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException { + accountlog.info("POST from " + request.getRemoteAddr()); + this.processRequest(request, response); + } + + + protected void doHead(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + logger.debug("HEAD from "+req.getRemoteAddr()); + super.doHead(req, resp); + } + + protected void doOptions(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + logger.debug("OPTIONS from "+req.getRemoteAddr()); + super.doOptions(req, resp); + } + + /** Service this request using the response. + * @param request + * @param response + * @throws ServletException + */ + public void processRequest(HttpServletRequest request, + HttpServletResponse response) throws ServletException { + + if (dlConfig == null) { + logger.error("ERROR: No Configuration!"); + throw new ServletException("NO VALID digilib CONFIGURATION!"); + } + + accountlog.debug("request: " + request.getQueryString()); + logger.debug("request: " + request.getQueryString()); + long startTime = System.currentTimeMillis(); + + // parse request + DigilibRequest dlRequest = new DigilibRequest(request); + // extract the job information + ImageJobDescription jobTicket = ImageJobDescription.getInstance(dlRequest, dlConfig); + + // type of error reporting + ErrMsg errMsgType = ErrMsg.IMAGE; + if (dlRequest.hasOption("errtxt")) { + errMsgType = ErrMsg.TEXT; + } else if (dlRequest.hasOption("errcode")) { + errMsgType = ErrMsg.CODE; + } + + try { + /* + * check if we can fast-track without scaling + */ + ImageInput fileToLoad = (ImageInput) jobTicket.getInput(); + + // check permissions + if (useAuthorization) { + // get a list of required roles (empty if no restrictions) + List<String> rolesRequired = authOp.rolesForPath( + jobTicket.getFilePath(), request); + if (rolesRequired != null) { + 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 + throw new AuthOpException(); + } + } + } + + // if requested, send image as a file + if (sendFileAllowed && jobTicket.getSendAsFile()) { + String mt = null; + if (jobTicket.hasOption("rawfile")) { + mt = "application/octet-stream"; + } + logger.debug("Sending RAW File as is."); + ServletOps.sendFile(fileToLoad.getFile(), mt, null, response, logger); + logger.info("Done in " + (System.currentTimeMillis() - startTime) + "ms"); + return; + } + + // if possible, send the image without actually having to transform it + if (! jobTicket.isTransformRequired()) { + logger.debug("Sending File as is."); + ServletOps.sendFile(fileToLoad.getFile(), null, null, response, logger); + logger.info("Done in " + (System.currentTimeMillis() - startTime) + "ms"); + return; + } + + // check load of workers + if (imageJobCenter.isBusy()) { + logger.error("Servlet overloaded!"); + response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); + return; + } + // create job + ImageWorker job = new ImageWorker(dlConfig, jobTicket); + // submit job + Future<DocuImage> jobResult = imageJobCenter.submit(job); + // wait for result + DocuImage img = jobResult.get(); + // forced destination image type + String mt = null; + if (jobTicket.hasOption("jpg")) { + mt = "image/jpeg"; + } else if (jobTicket.hasOption("png")) { + mt = "image/png"; + } + // send image + ServletOps.sendImage(img, mt, response, logger); + logger.debug("Job Processing Time: " + + (System.currentTimeMillis() - startTime) + "ms"); + + } catch (ImageOpException e) { + logger.error(e.getClass() + ": " + e.getMessage()); + digilibError(errMsgType, Error.IMAGE, null, response); + } catch (IOException e) { + logger.error(e.getClass() + ": " + e.getMessage()); + digilibError(errMsgType, Error.FILE, null, response); + } catch (AuthOpException e) { + logger.error(e.getClass() + ": " + e.getMessage()); + digilibError(errMsgType, Error.AUTH, null, response); + } catch (InterruptedException e) { + logger.error(e.getClass() + ": " + e.getMessage()); + } catch (ExecutionException e) { + logger.error(e.getClass() + ": " + e.getMessage()); + String causeMsg = e.getCause().getMessage(); + logger.error("caused by: " + causeMsg); + digilibError(errMsgType, Error.IMAGE, causeMsg, response); + } + + } + + /** + * Sends an error to the client as text or image. + * + * @param type + * @param error + * @param msg + * @param response + */ + public static void digilibError(ErrMsg type, Error error, String msg, + HttpServletResponse response) { + try { + File img = null; + int status = 0; + if (error == Error.AUTH) { + if (msg == null) { + msg = "ERROR: Unauthorized access!"; + } + img = denyImgFile; + status = HttpServletResponse.SC_FORBIDDEN; + } else if (error == Error.FILE) { + if (msg == null) { + msg = "ERROR: Image file not found!"; + } + img = notfoundImgFile; + status = HttpServletResponse.SC_NOT_FOUND; + } else { + if (msg == null) { + msg = "ERROR: Other image error!"; + } + img = errorImgFile; + status = HttpServletResponse.SC_BAD_REQUEST; + } + if (response.isCommitted()) { + // response already committed + logger.error("Unable to send error: " + msg); + return; + } + if (type == ErrMsg.TEXT) { + ServletOps.htmlMessage(msg, response); + } else if (type == ErrMsg.CODE) { + response.sendError(status, msg); + } else if (img != null) { + // default: image + ServletOps.sendFile(img, null, null, response, logger); + } + } catch (Exception e) { + logger.error("Error sending error!", e); + } + + } + + public static String getVersion() { + return version; + } + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/servlet/src/digilib/servlet/ScalerNoThread.java Tue Mar 01 22:00:50 2011 +0100 @@ -0,0 +1,321 @@ +package digilib.servlet; + +import java.io.File; +import java.io.IOException; +import java.util.List; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.log4j.Logger; + +import digilib.auth.AuthOpException; +import digilib.auth.AuthOps; +import digilib.image.DocuImage; +import digilib.image.ImageJobDescription; +import digilib.image.ImageOpException; +import digilib.image.ImageWorker; +import digilib.io.DocuDirCache; +import digilib.io.DocuDirectory; +import digilib.io.ImageInput; + +/** + * Version of Scaler servlet that doesn't use a thread pool. + */ +public class ScalerNoThread extends HttpServlet { + + private static final long serialVersionUID = 1450947819851623306L; + + /** digilib servlet version (for all components) */ + public static final String version = "1.9.0a5 nothread"; + + /** servlet error codes */ + public static enum Error {UNKNOWN, AUTH, FILE, IMAGE}; + + /** type of error message */ + public static enum ErrMsg {IMAGE, TEXT, CODE}; + + /** logger for accounting requests */ + protected static Logger accountlog = Logger.getLogger("account.request"); + + /** gengeral logger for this class */ + protected static Logger logger = Logger.getLogger("digilib.scaler"); + + /** logger for authentication related */ + protected static Logger authlog = Logger.getLogger("digilib.auth"); + + /** DocuDirCache instance */ + protected DocuDirCache dirCache; + + /** authentication error image file */ + public static File denyImgFile; + + /** image error image file */ + public static File errorImgFile; + + /** not found error image file */ + public static File notfoundImgFile; + + /** send files as is? */ + protected boolean sendFileAllowed = true; + + /** DigilibConfiguration instance */ + protected DigilibConfiguration dlConfig; + + /** use authorization database */ + protected boolean useAuthorization = true; + + /** AuthOps instance */ + protected AuthOps authOp; + + /** + * Initialisation on first run. + * + * @throws ServletException + * + * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig) + */ + public void init(ServletConfig config) throws ServletException { + super.init(config); + + System.out + .println("***** Digital Image Library Image Scaler Servlet (version " + + version + ") *****"); + // say hello in the log file + logger.info("***** Digital Image Library Image Scaler Servlet (version " + + version + ") *****"); + + // get our ServletContext + ServletContext context = config.getServletContext(); + // see if there is a Configuration instance + dlConfig = (DigilibConfiguration) context + .getAttribute("digilib.servlet.configuration"); + if (dlConfig == null) { + // no Configuration + throw new ServletException("No Configuration!"); + } + // set our AuthOps + useAuthorization = dlConfig.getAsBoolean("use-authorization"); + authOp = (AuthOps) dlConfig.getValue("servlet.auth.op"); + + // DocuDirCache instance + dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache"); + + denyImgFile = ServletOps.getFile( + (File) dlConfig.getValue("denied-image"), context); + errorImgFile = ServletOps.getFile( + (File) dlConfig.getValue("error-image"), context); + notfoundImgFile = ServletOps.getFile( + (File) dlConfig.getValue("notfound-image"), context); + sendFileAllowed = dlConfig.getAsBoolean("sendfile-allowed"); + } + + /** Returns modification time relevant to the request for caching. + * + * @see javax.servlet.http.HttpServlet#getLastModified(javax.servlet.http.HttpServletRequest) + */ + public long getLastModified(HttpServletRequest request) { + accountlog.debug("GetLastModified from " + request.getRemoteAddr() + + " for " + request.getQueryString()); + long mtime = -1; + // create new request + DigilibRequest dlReq = new DigilibRequest(request); + DocuDirectory dd = dirCache.getDirectory(dlReq.getFilePath()); + if (dd != null) { + mtime = dd.getDirMTime() / 1000 * 1000; + } + logger.debug(" returns "+mtime); + return mtime; + } + + /* (non-Javadoc) + * @see javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ + public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException { + accountlog.info("GET from " + request.getRemoteAddr()); + this.processRequest(request, response); + } + + + /* (non-Javadoc) + * @see javax.servlet.http.HttpServlet#doPost(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) + */ + public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException { + accountlog.info("POST from " + request.getRemoteAddr()); + this.processRequest(request, response); + } + + + protected void doHead(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + logger.debug("HEAD from "+req.getRemoteAddr()); + super.doHead(req, resp); + } + + protected void doOptions(HttpServletRequest req, HttpServletResponse resp) + throws ServletException, IOException { + logger.debug("OPTIONS from "+req.getRemoteAddr()); + super.doOptions(req, resp); + } + + /** Service this request using the response. + * @param request + * @param response + * @throws ServletException + */ + public void processRequest(HttpServletRequest request, + HttpServletResponse response) throws ServletException { + + if (dlConfig == null) { + logger.error("ERROR: No Configuration!"); + throw new ServletException("NO VALID digilib CONFIGURATION!"); + } + + accountlog.debug("request: " + request.getQueryString()); + logger.debug("request: " + request.getQueryString()); + long startTime = System.currentTimeMillis(); + + // parse request + DigilibRequest dlRequest = new DigilibRequest(request); + // extract the job information + ImageJobDescription jobTicket = ImageJobDescription.getInstance(dlRequest, dlConfig); + + // type of error reporting + ErrMsg errMsgType = ErrMsg.IMAGE; + if (dlRequest.hasOption("errtxt")) { + errMsgType = ErrMsg.TEXT; + } else if (dlRequest.hasOption("errcode")) { + errMsgType = ErrMsg.CODE; + } + + try { + /* + * check if we can fast-track without scaling + */ + ImageInput fileToLoad = (ImageInput) jobTicket.getInput(); + + // check permissions + if (useAuthorization) { + // get a list of required roles (empty if no restrictions) + List<String> rolesRequired = authOp.rolesForPath( + jobTicket.getFilePath(), request); + if (rolesRequired != null) { + 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 + throw new AuthOpException(); + } + } + } + + // if requested, send image as a file + if (sendFileAllowed && jobTicket.getSendAsFile()) { + String mt = null; + if (jobTicket.hasOption("rawfile")) { + mt = "application/octet-stream"; + } + logger.debug("Sending RAW File as is."); + ServletOps.sendFile(fileToLoad.getFile(), mt, null, response, logger); + logger.info("Done in " + (System.currentTimeMillis() - startTime) + "ms"); + return; + } + + // if possible, send the image without actually having to transform it + if (! jobTicket.isTransformRequired()) { + logger.debug("Sending File as is."); + ServletOps.sendFile(fileToLoad.getFile(), null, null, response, logger); + logger.info("Done in " + (System.currentTimeMillis() - startTime) + "ms"); + return; + } + + // create job + ImageWorker job = new ImageWorker(dlConfig, jobTicket); + // get result immediately + DocuImage img = job.call(); + // forced destination image type + String mt = null; + if (jobTicket.hasOption("jpg")) { + mt = "image/jpeg"; + } else if (jobTicket.hasOption("png")) { + mt = "image/png"; + } + // send image + ServletOps.sendImage(img, mt, response, logger); + logger.debug("Job Processing Time: " + + (System.currentTimeMillis() - startTime) + "ms"); + + } catch (ImageOpException e) { + logger.error(e.getClass() + ": " + e.getMessage()); + digilibError(errMsgType, Error.IMAGE, null, response); + } catch (IOException e) { + logger.error(e.getClass() + ": " + e.getMessage()); + digilibError(errMsgType, Error.FILE, null, response); + } catch (AuthOpException e) { + logger.error(e.getClass() + ": " + e.getMessage()); + digilibError(errMsgType, Error.AUTH, null, response); + } + + } + + /** + * Sends an error to the client as text or image. + * + * @param type + * @param error + * @param msg + * @param response + */ + public static void digilibError(ErrMsg type, Error error, String msg, + HttpServletResponse response) { + try { + File img = null; + int status = 0; + if (error == Error.AUTH) { + if (msg == null) { + msg = "ERROR: Unauthorized access!"; + } + img = denyImgFile; + status = HttpServletResponse.SC_FORBIDDEN; + } else if (error == Error.FILE) { + if (msg == null) { + msg = "ERROR: Image file not found!"; + } + img = notfoundImgFile; + status = HttpServletResponse.SC_NOT_FOUND; + } else { + if (msg == null) { + msg = "ERROR: Other image error!"; + } + img = errorImgFile; + status = HttpServletResponse.SC_BAD_REQUEST; + } + if (response.isCommitted()) { + // response already committed + logger.error("Unable to send error: " + msg); + return; + } + if (type == ErrMsg.TEXT) { + ServletOps.htmlMessage(msg, response); + } else if (type == ErrMsg.CODE) { + response.sendError(status, msg); + } else if (img != null) { + // default: image + ServletOps.sendFile(img, null, null, response, logger); + } + } catch (Exception e) { + logger.error("Error sending error!", e); + } + + } + + public static String getVersion() { + return version; + } + +}
--- a/servlet/src/digilib/servlet/ServletOps.java Tue Mar 01 17:12:25 2011 +0100 +++ b/servlet/src/digilib/servlet/ServletOps.java Tue Mar 01 22:00:50 2011 +0100 @@ -26,10 +26,14 @@ import java.io.IOException; import java.io.OutputStream; import java.io.PrintWriter; +import java.util.Collection; +import java.util.Enumeration; import java.util.StringTokenizer; -import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; @@ -72,11 +76,11 @@ * @param sc * @return */ - public static File getFile(File f, ServletConfig sc) { + public static File getFile(File f, ServletContext sc) { // is the filename absolute? if (!f.isAbsolute()) { // relative path -> use getRealPath to resolve in WEB-INF - String fn = sc.getServletContext().getRealPath(f.getPath()); + String fn = sc.getRealPath(f.getPath()); f = new File(fn); } return f; @@ -92,12 +96,12 @@ * @param sc * @return */ - public static String getFile(String filename, ServletConfig sc) { + public static String getFile(String filename, ServletContext sc) { File f = new File(filename); // is the filename absolute? if (!f.isAbsolute()) { // relative path -> use getRealPath to resolve in WEB-INF - filename = sc.getServletContext().getRealPath(filename); + filename = sc.getRealPath(filename); } return filename; } @@ -112,7 +116,7 @@ * @param sc * @return */ - public static File getConfigFile(File f, ServletConfig sc) { + public static File getConfigFile(File f, ServletContext sc) { String fn = f.getPath(); // is the filename absolute? if (f.isAbsolute()) { @@ -126,7 +130,7 @@ } } // relative path -> use getRealPath to resolve in WEB-INF - String newfn = sc.getServletContext().getRealPath("WEB-INF/" + fn); + String newfn = sc.getRealPath("WEB-INF/" + fn); f = new File(newfn); return f; } @@ -141,19 +145,18 @@ * @param sc * @return */ - public static String getConfigFile(String filename, ServletConfig sc) { + public static String getConfigFile(String filename, ServletContext sc) { File f = new File(filename); // is the filename absolute? if (!f.isAbsolute()) { // relative path -> use getRealPath to resolve in WEB-INF - filename = sc.getServletContext() - .getRealPath("WEB-INF/" + filename); + filename = sc.getRealPath("WEB-INF/" + filename); } return filename; } /** - * print a servlet response and exit + * print a servlet response */ public static void htmlMessage(String msg, HttpServletResponse response) throws IOException { @@ -161,7 +164,7 @@ } /** - * print a servlet response and exit + * print a servlet response */ public static void htmlMessage(String title, String msg, HttpServletResponse response) throws IOException { @@ -192,10 +195,10 @@ * @throws ImageOpException * @throws ServletException * Exception on sending data. + * @throws IOException */ public static void sendFile(File f, String mt, String name, - HttpServletResponse response) throws ImageOpException, - ServletException { + HttpServletResponse response) throws ImageOpException, IOException { // use default logger ServletOps.sendFile(f, mt, name, response, ServletOps.logger); } @@ -218,13 +221,14 @@ * Logger to use * @throws ImageOpException * @throws ServletException Exception on sending data. + * @throws IOException */ public static void sendFile(File f, String mt, String name, HttpServletResponse response, Logger logger) - throws ImageOpException, ServletException { + throws ImageOpException, IOException { logger.debug("sendRawFile(" + mt + ", " + f + ")"); - if (response.isCommitted()) { - logger.warn("sendFile: response already committed!"); - //return; + if (response == null) { + logger.error("No response!"); + return; } if (mt == null) { // auto-detect mime-type @@ -255,9 +259,6 @@ // copy out file outStream.write(dataBuffer, 0, len); } - } catch (IOException e) { - logger.error("Error sending file:", e); - throw new ServletException("Error sending file:", e); } finally { try { if (inFile != null) { @@ -297,19 +298,26 @@ public static void sendImage(DocuImage img, String mimeType, HttpServletResponse response, Logger logger) throws ImageOpException, ServletException { - if (response.isCommitted()) { - logger.warn("sendImage: response already committed!"); - //return; + if (response == null) { + logger.error("No response!"); + return; } + logger.debug("sending to response: ("+ headersToString(response) + ") committed=" + response.isCommitted()); + // TODO: should we erase or replace old last-modified header? try { OutputStream outstream = response.getOutputStream(); // setup output -- if mime type is set use that otherwise // if source is JPG then dest will be JPG else it's PNG if (mimeType == null) { mimeType = img.getMimetype(); + if (mimeType == null) { + // still no mime-type + logger.warn("sendImage without mime-type! using image/jpeg."); + mimeType = "image/jpeg"; + } } - if ((mimeType.equals("image/jpeg") || mimeType.equals("image/jp2") || mimeType - .equals("image/fpx"))) { + if ((mimeType.equals("image/jpeg") || mimeType.equals("image/jp2") || + mimeType.equals("image/fpx"))) { mimeType = "image/jpeg"; } else { mimeType = "image/png"; @@ -318,10 +326,36 @@ response.setContentType(mimeType); img.writeImage(mimeType, outstream); } catch (IOException e) { - logger.error("Error sending image:", e); throw new ServletException("Error sending image:", e); } // TODO: should we: finally { img.dispose(); } } + /** Returns text representation of headers for debuggging purposes. + * @param req + * @return + */ + public static String headersToString(HttpServletRequest req) { + String s = ""; + Enumeration<String> hns = req.getHeaderNames(); + while (hns.hasMoreElements()) { + String hn = hns.nextElement(); + s += hn + "=" + req.getHeader(hn) + "; "; + } + return s; + } + + /** Returns text representation of headers for debuggging purposes. + * @param resp + * @return + */ + public static String headersToString(HttpServletResponse resp) { + String s = ""; + Collection<String> hns = resp.getHeaderNames(); + for (String hn : hns) { + s += hn + "=" + resp.getHeader(hn) + "; "; + } + return s; + } + } \ No newline at end of file
--- a/servlet/src/digilib/servlet/Texter.java Tue Mar 01 17:12:25 2011 +0100 +++ b/servlet/src/digilib/servlet/Texter.java Tue Mar 01 22:00:50 2011 +0100 @@ -30,7 +30,6 @@ import digilib.auth.AuthOps; import digilib.image.ImageOpException; import digilib.io.DocuDirCache; -import digilib.io.FileOpException; import digilib.io.FileOps; import digilib.io.FileOps.FileClass; import digilib.io.TextFile; @@ -44,8 +43,10 @@ */ public class Texter extends HttpServlet { - /** Servlet version */ - public static String tlVersion = "0.1b2"; + private static final long serialVersionUID = 6678666342141409867L; + + /** Servlet version */ + public static String tlVersion = "0.1b3"; /** DigilibConfiguration instance */ DigilibConfiguration dlConfig = null; @@ -128,36 +129,42 @@ processRequest(request, response); } - protected void processRequest(HttpServletRequest request, - HttpServletResponse response) throws ServletException, IOException { - - /* - * request parameters - */ + protected void processRequest(HttpServletRequest request, + HttpServletResponse response) { + + /* + * request parameters + */ // create new request with defaults DigilibRequest dlRequest = new DigilibRequest(request); - try { - /* - * find the file to load/send - */ - TextFile f = getTextFile(dlRequest, "/txt"); - if (f != null) { - ServletOps.sendFile(f.getFile(), null, null, response, logger); - } else { - f = getTextFile(dlRequest, ""); - if (f != null) { - ServletOps.sendFile(f.getFile(), null, null, response, logger); - } else { - response.sendError(HttpServletResponse.SC_NOT_FOUND, - "Text-File not found!"); - // ServletOps.htmlMessage("No Text-File!", response); - } - } - - } catch (ImageOpException e) { + try { + + /* + * find the file to load/send + */ + TextFile f = getTextFile(dlRequest, "/txt"); + if (f != null) { + ServletOps.sendFile(f.getFile(), null, null, response, logger); + } else { + f = getTextFile(dlRequest, ""); + if (f != null) { + ServletOps.sendFile(f.getFile(), null, null, response, logger); + } else { + response.sendError(HttpServletResponse.SC_NOT_FOUND, "Text-File not found!"); + //ServletOps.htmlMessage("No Text-File!", response); + } + } + + } catch (ImageOpException e) { // most likely wrong file format... logger.error("ERROR sending text file: ", e); - response.sendError(HttpServletResponse.SC_BAD_REQUEST); + try { + response.sendError(HttpServletResponse.SC_BAD_REQUEST); + } catch (IOException e1) { + logger.error("ERROR sending error: ", e1); + } + } catch (IOException e) { + logger.error("ERROR sending text file: ", e); } } @@ -176,7 +183,7 @@ private TextFile getTextFile(DigilibRequest dlRequest, String subDirectory) { String loadPathName = dlRequest.getFilePath() + subDirectory; // find the file(set) - return (TextFile) dirCache.getFile(loadPathName, dlRequest - .getAsInt("pn"), FileClass.TEXT); + return (TextFile) dirCache.getFile(loadPathName, dlRequest.getAsInt("pn"), + FileClass.TEXT); } } \ No newline at end of file
--- a/servlet/src/digilib/util/DigilibJobCenter.java Tue Mar 01 17:12:25 2011 +0100 +++ b/servlet/src/digilib/util/DigilibJobCenter.java Tue Mar 01 22:00:50 2011 +0100 @@ -51,7 +51,7 @@ } } - /** Submit job to execute + /** Submit Callable job that returns a Value to execute. * * @param job * @return Future to control the job @@ -60,6 +60,15 @@ return executor.submit(job); } + /** Submit Runnable job to execute. + * + * @param job + * @return Future to control the job + */ + public Future<?> submit(Runnable job) { + return executor.submit(job); + } + /** Returns if the service is overloaded. * * @return
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/servlet/src/digilib/util/HashTree.java Tue Mar 01 22:00:50 2011 +0100 @@ -0,0 +1,113 @@ +/* HashTree -- Tree in a Hashtable + + Digital Image Library servlet components + + Copyright (C) 2001, 2002 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.util; + +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +/** + * Tree representation wrapper for a HashMap. + * + * The HashTree is constructed from a HashMap filled with 'branches' with + * 'leaves'. The branches are stored as String keys in the HashMap. The String + * values are leaves. + * + * Branches are matched in 'twigs' separated by 'twig separator' Strings. The + * return values for a match are leaf values separated by 'leaf separator' + * Strings. + * + * @author casties + */ +public class HashTree { + + private Map<String, String> table; + + private String twigSep = "/"; + + private String leafSep = ","; + + /** + * Constructor of a HashTree. + * + * Creates a HashTree wrapper around a given HashMap, using the given twig + * separator and leaf separator. + * + * @param t + * @param twig_separator + * @param leaf_separator + */ + public HashTree(Map<String, String> t, String twig_separator, String leaf_separator) { + table = t; + twigSep = twig_separator; + leafSep = leaf_separator; + optimizeTable(); + } + + private void optimizeTable() { + } + + /** + * Matches the given branch against the HashTree. + * + * Returns a LinkedList of all leaves on all matching branches in the tree. + * Branches in the tree match if they are substrings starting at the same + * root. + * + * @param branch + * @return + */ + public List<String> match(String branch) { + String b = ""; + String m; + LinkedList<String> matches = new LinkedList<String>(); + + // split branch + StringTokenizer twig = new StringTokenizer(branch, twigSep); + // walk branch and check with tree + while (twig.hasMoreTokens()) { + if (b.length() == 0) { + b = twig.nextToken(); + } else { + b += twigSep + twig.nextToken(); + } + m = table.get(b); + if (m != null) { + if (m.indexOf(leafSep) < 0) { + // single leaf + matches.add(m); + } else { + // split leaves + StringTokenizer leaf = new StringTokenizer(m, leafSep); + while (leaf.hasMoreTokens()) { + matches.add(leaf.nextToken()); + } + } + } + } + if (matches.size() > 0) { + return matches; + } else { + return null; + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/servlet/src/digilib/util/ImageSize.java Tue Mar 01 22:00:50 2011 +0100 @@ -0,0 +1,230 @@ +/* + * ImageSize.java -- digilib image size class. + * 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 26.08.2003 + */ + +package digilib.util; + +/** Class for image size (width, height). + * + * A width or height of 0 is treated as a 'wildcard' that matches any size. + * + * @author casties + * + */ +public class ImageSize { + public int width; + public int height; + + public ImageSize() { + super(); + } + + public ImageSize(int width, int height) { + this.width = width; + this.height = height; + } + + public ImageSize(ImageSize i) { + this.width = i.width; + this.height = i.height; + } + + public void setSize(int width, int height) { + this.width = width; + this.height = height; + } + + /** + * Returns if the size of this image is smaller in every dimension than the + * other image. + * + * + * + * @param is + * @return + */ + public boolean isTotallySmallerThan(ImageSize is) { + if ((this.width == 0)||(is.width == 0)) { + // width wildcard + return (this.height <= is.height); + } + if ((this.height == 0)||(is.height == 0)) { + // height wildcard + return (this.width <= is.width); + } + return ((this.width <= is.width)&&(this.height <= is.height)); + } + + /** + * Returns if the size of this image is smaller in at least one dimension + * than the other image. + * + * @param is + * @return + */ + public boolean isSmallerThan(ImageSize is) { + if ((this.width == 0)||(is.width == 0)) { + // width wildcard + return (this.height <= is.height); + } + if ((this.height == 0)||(is.height == 0)) { + // height wildcard + return (this.width <= is.width); + } + return ((this.width <= is.width) || (this.height <= is.height)); + } + + /** + * Returns if the size of this image is bigger in every dimension than the + * other image. + * + * + * + * @param is + * @return + */ + public boolean isTotallyBiggerThan(ImageSize is) { + if ((this.width == 0)||(is.width == 0)) { + // width wildcard + return (this.height >= is.height); + } + if ((this.height == 0)||(is.height == 0)) { + // height wildcard + return (this.width >= is.width); + } + return ((this.width >= is.width) && (this.height >= is.height)); + } + + /** + * Returns if the size of this image is bigger in at least one dimension + * than the other image. + * + * + * + * @param is + * @return + */ + public boolean isBiggerThan(ImageSize is) { + if ((this.width == 0)||(is.width == 0)) { + // width wildcard + return (this.height >= is.height); + } + if ((this.height == 0)||(is.height == 0)) { + // height wildcard + return (this.width >= is.width); + } + return ((this.width >= is.width) || (this.height >= is.height)); + } + + /** + * Returns if this image has the same size or height as the other image. + * + * + * + * @param is + * @return + */ + public boolean fitsIn(ImageSize is) { + if ((this.width == 0)||(is.width == 0)) { + // width wildcard + return (this.height == is.height); + } + if ((this.height == 0)||(is.height == 0)) { + // height wildcard + return (this.width == is.width); + } + return ( + (this.width == is.width) + && (this.height <= is.height) + || (this.width <= is.width) + && (this.height == is.height)); + } + + /** + * Returns if the size of this image is the same as the other image. + * + * + * + * @param is + * @return + */ + public boolean equals(ImageSize is) { + if ((this.width == 0)||(is.width == 0)) { + // width wildcard + return (this.height == is.height); + } + if ((this.height == 0)||(is.height == 0)) { + // height wildcard + return (this.width == is.width); + } + return ((this.width == is.width) && (this.height == is.height)); + } + + /** + * @return + */ + public int getHeight() { + return height; + } + + /** + * @param height + */ + public void setHeight(int height) { + this.height = height; + } + + /** + * @return + */ + public int getWidth() { + return width; + } + + /** + * @param width + */ + public void setWidth(int width) { + this.width = width; + } + + /** + * Returns the aspect ratio. + * + * Aspect ratio is (width/height). So it's <1 for portrait and >1 for + * landscape. + * + * @return + */ + public float getAspect() { + return (height > 0) ? ((float) width / (float) height) : 0; + } + + /** + * Returns a scaled copy of this image size. + * + * @param scale + * @return + */ + public ImageSize getScaled(float scale) { + return new ImageSize((int) (width * scale), (int) (height * scale)); + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + String s = "[" + width + "x" + height + "]"; + return s; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/servlet/src/digilib/util/XMLListLoader.java Tue Mar 01 22:00:50 2011 +0100 @@ -0,0 +1,178 @@ +/* XMLListLoader -- Load an XML list into a Hashtable + + Digital Image Library servlet components + + Copyright (C) 2001, 2002 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.util; + +// JAXP packages +import java.io.IOException; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import org.apache.log4j.Logger; +import org.xml.sax.Attributes; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.helpers.DefaultHandler; + +/** Loads a simple XML list into a HashMap. + * + * The XML file has an outer <code>list_tag</code>. Every entry is an + * <code>entry_tag</code> with two attributes: the <code>key_att</code> + * key and the <code>value_att</code> value. + * + * The file is read by the <code>loadURL</code> method, that returns a + * HashMap with the key-value pairs. + * + * @author casties + */ +public class XMLListLoader { + + private Logger logger = Logger.getLogger(this.getClass()); + private String listTag = "list"; + private String entryTag = "entry"; + private String keyAtt = "key"; + private String valueAtt = "value"; + + public XMLListLoader() { + } + + public XMLListLoader( + String list_tag, + String entry_tag, + String key_att, + String value_att) { + logger.debug("xmlListLoader("+list_tag+","+entry_tag+","+key_att+","+value_att+")"); + listTag = list_tag; + entryTag = entry_tag; + keyAtt = key_att; + valueAtt = value_att; + } + + /** + * inner class XMLListParser to be called by the parser + */ + private class XMLListParser extends DefaultHandler { + + private Map<String, String> listData; + private LinkedList<String> tagSpace; + + public Map<String, String> getData() { + return listData; + } + + // Parser calls this once at the beginning of a document + public void startDocument() throws SAXException { + listData = new HashMap<String, String>(); + tagSpace = new LinkedList<String>(); + } + + // Parser calls this for each element in a document + public void startElement( + String namespaceURI, + String localName, + String qName, + Attributes atts) + throws SAXException { + //System.out.println("<"+qName); + // open a new namespace + tagSpace.addLast(qName); + + // ist it an entry tag? + if (qName.equals(entryTag)) { + // is it inside a list tag? + if ((listTag.length() > 0) && (!tagSpace.contains(listTag))) { + logger.error("BOO: Entry " + + entryTag + + " not inside list " + + listTag); + throw new SAXParseException( + "Entry " + entryTag + " not inside list " + listTag, + null); + } + // get the attributes + String key = atts.getValue(keyAtt); + String val = atts.getValue(valueAtt); + if ((key == null) || (val == null)) { + logger.error("BOO: Entry " + + entryTag + + " does not have Attributes " + + keyAtt + + ", " + + valueAtt); + throw new SAXParseException( + "Entry " + + entryTag + + " does not have Attributes " + + keyAtt + + ", " + + valueAtt, + null); + } + // add the values + //System.out.println("DATA: "+key+" = "+val); + listData.put(key, val); + } + } + + public void endElement( + String namespaceURI, + String localName, + String qName) + throws SAXException { + // exit the namespace + tagSpace.removeLast(); + } + + } + + /** + * load and parse a file (as URL) + * returns HashMap with list data + */ + public Map<String, String> loadURL(String path) throws SAXException, IOException { + //System.out.println("loadurl ("+path+")"); + // Create a JAXP SAXParserFactory and configure it + SAXParserFactory spf = SAXParserFactory.newInstance(); + spf.setNamespaceAware(true); + + SAXParser parser = null; + try { + // Create a JAXP SAXParser + parser = spf.newSAXParser(); + + } catch (ParserConfigurationException e) { + throw new SAXException(e); + } + + // create a list parser (keeps the data!) + XMLListParser listParser = new XMLListParser(); + + // Tell the SAXParser to parse the XML document + parser.parse(path, listParser); + + return listParser.getData(); + } + +}