Commit e1f28a2c authored by robcast's avatar robcast

digilib servlet version 2 ("scaleable digilib")

- first stab at using thread pools to limit resource use
- using Dug Leas util.concurrent
- doesn't mix with tomcat :-(
parent 4ca0fa86
/*
* ImageFile.java -- digilib image file 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;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
public String toString() {
String s = "[" + width + "x" + height + "]";
return s;
}
}
/* JAIImageLoaderDocuImage -- Image class implementation using JAI's ImageLoader Plugin
Digital Image Library servlet components
Copyright (C) 2002, 2003 Robert Casties (robcast@mail.berlios.de)
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version.
Please read license.txt for the full details. A copy of the GPL
may be found at http://www.gnu.org/copyleft/lgpl.html
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package digilib.image;
import java.awt.Rectangle;
import java.awt.image.renderable.ParameterBlock;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.RandomAccessFile;
import java.util.Iterator;
import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.FileImageInputStream;
import javax.imageio.stream.ImageInputStream;
import javax.media.jai.JAI;
import digilib.io.FileOpException;
import digilib.io.ImageFile;
/** DocuImage implementation using the Java Advanced Imaging API and the ImageLoader
* API of Java 1.4.
*/
public class JAIImageLoaderDocuImage extends JAIDocuImage {
/** ImageIO image reader */
protected ImageReader reader;
/** current image file */
protected File imgFile;
/* loadSubimage is supported. */
public boolean isSubimageSupported() {
return true;
}
public int getHeight() {
int h = 0;
try {
if (img == null) {
h = reader.getHeight(0);
} else {
h = img.getHeight();
}
} catch (IOException e) {
logger.debug("error in getHeight", e);
}
return h;
}
public int getWidth() {
int w = 0;
try {
if (img == null) {
w = reader.getWidth(0);
} else {
w = img.getWidth();
}
} catch (IOException e) {
logger.debug("error in getHeight", e);
}
return w;
}
/* 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());
if (img == null) {
throw new FileOpException("Unable to load File!");
}
}
/* 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 readers = ImageIO.getImageReadersByMIMEType(f.getMimetype());
if (! readers.hasNext()) {
throw new FileOpException("Unable to load File!");
}
reader = (ImageReader) readers.next();
logger.debug("JAIImageIO: this reader: " + reader.getClass());
while (readers.hasNext()) {
logger.debug(" 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)
throws FileOpException {
logger.debug("loadSubimage: "+f.getFile());
//System.gc();
try {
if ((reader == null) || (imgFile != f.getFile())) {
getReader(f);
}
ImageReadParam readParam = reader.getDefaultReadParam();
readParam.setSourceRegion(region);
readParam.setSourceSubsampling(prescale, prescale, 0, 0);
img = reader.read(0, readParam);
/* JAI imageread seems to ignore the readParam :-(
ImageInputStream istream = (ImageInputStream) reader.getInput();
ParameterBlockJAI pb = new ParameterBlockJAI("imageread");
pb.setParameter("Input", istream);
pb.setParameter("ReadParam", readParam);
pb.setParameter("Reader", reader);
img = JAI.create("imageread", pb);
*/
} catch (IOException e) {
throw new FileOpException("Unable to load File!");
}
if (img == null) {
throw new FileOpException("Unable to load File!");
}
imgFile = f.getFile();
}
/* Write the current image to an OutputStream. */
public void writeImage(String mt, OutputStream ostream)
throws FileOpException {
logger.debug("writeImage");
try {
// setup output
ParameterBlock pb3 = new ParameterBlock();
pb3.addSource(img);
pb3.add(ostream);
if (mt == "image/jpeg") {
pb3.add("JPEG");
} else if (mt == "image/png") {
pb3.add("PNG");
} else {
// unknown mime type
throw new FileOpException("Unknown mime type: " + mt);
}
// render output
JAI.create("ImageWrite", pb3);
} catch (IOException e) {
throw new FileOpException("Error writing image.");
}
}
/* (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!
reader.dispose();
reader = null;
img = null;
}
}
/* Directory -- Filesystem directory object
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.io;
import java.io.File;
import java.util.Arrays;
import org.apache.log4j.Logger;
/** Class for filesystem directories
* @author casties
*
*/
public class Directory {
protected Logger logger = Logger.getLogger(this.getClass());
/** File object pointing to the directory */
protected File dir = null;
/** parent directory */
protected Directory parent = null;
/** list of filenames in the directory */
protected String[] list = null;
/** Default constructor.
*
*/
public Directory() {
super();
}
/** Constructor taking a File object.
*
* @param d
*/
public Directory(File d) {
dir = d;
}
/** Constructor taking a File object and a parent.
*
* @param dir
* @param parent
*/
public Directory(File dir, Directory parent) {
this.dir = dir;
this.parent = parent;
}
/** Constructor taking a directory name.
*
* @param d
*/
public Directory(String dn) {
dir = new File(dn);
}
/** Reads the names of the files in the directory.
* Fills the filenames array. Returns if the operation was successful.
*
* @return
*/
public boolean readDir() {
if (dir != null) {
//logger.debug("reading dir: "+dir.getPath());
list = dir.list();
Arrays.sort(list);
//logger.debug(" done");
}
return (list != null);
}
/**
* @return
*/
public File getDir() {
return dir;
}
/**
* @param dir
*/
public void setDir(File dir) {
this.dir = dir;
}
/**
* @return
*/
Directory getParent() {
return parent;
}
/**
* @param parent
*/
void setParent(Directory parent) {
this.parent = parent;
}
/**
* @return Returns the filenames.
*/
public String[] getFilenames() {
return list;
}
/**
* @param filenames The filenames to set.
*/
public void setFilenames(String[] filenames) {
this.list = filenames;
}
public void clearFilenames() {
this.list = null;
}
}
/*
* DocuDirCache.java
*
* 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 03.03.2003
*/
package digilib.io;
import java.io.File;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import digilib.servlet.DigilibConfiguration;
/**
* @author casties
*/
public class DocuDirCache {
/** general logger for this class */
Logger logger = Logger.getLogger(this.getClass());
/** HashMap of directories */
Map map = null;
/** names of base directories */
String[] baseDirNames = null;
/** array of allowed file classes (image/text) */
private int[] fileClasses = null;
/** number of files in the whole cache (approximate) */
long numFiles = 0;
/** number of cache hits */
long hits = 0;
/** number of cache misses */
long misses = 0;
/** use safe (but slow) indexing */
boolean safeDirIndex = false;
/** the root directory element */
public static Directory ROOT = null;
/**
* Constructor with array of base directory names and file classes.
*
* @param bd
* base directory names
*/
public DocuDirCache(String[] bd, int[] fileClasses,
DigilibConfiguration dlConfig) {
baseDirNames = bd;
map = new HashMap();
this.fileClasses = fileClasses;
safeDirIndex = dlConfig.getAsBoolean("safe-dir-index");
}
/**
* Constructor with array of base directory names.
*
* @param bd
* base directory names
*/
public DocuDirCache(String[] bd) {