# HG changeset patch
# User robcast
# Date 1100711854 -3600
# Node ID 6d2032b6121da584a5acacb243ee62c1363eb450
# Parent 794a9f25f15c8b4de2a09e55275d30fa50f70870
new directory and cache work
diff -r 794a9f25f15c -r 6d2032b6121d servlet/src/digilib/image/ImageLoaderDocuImage.java
--- a/servlet/src/digilib/image/ImageLoaderDocuImage.java Thu Jan 17 15:25:46 2002 +0100
+++ b/servlet/src/digilib/image/ImageLoaderDocuImage.java Wed Nov 17 18:17:34 2004 +0100
@@ -1,164 +1,480 @@
/* ImageLoaderDocuImage -- Image class implementation using JDK 1.4 ImageLoader
- Digital Image Library servlet components
+ Digital Image Library servlet components
- Copyright (C) 2001, 2002 Robert Casties (robcast@mail.berlios.de)
+ 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
+ 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
-
-*/
+ 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 javax.servlet.*;
-import javax.servlet.http.*;
-import java.io.*;
-import java.util.*;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.AffineTransformOp;
+import java.awt.image.BufferedImage;
+import java.awt.image.ConvolveOp;
+import java.awt.image.Kernel;
+import java.awt.image.RescaleOp;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.RandomAccessFile;
+import java.util.Iterator;
-import java.awt.*;
-import java.awt.image.*;
-import java.awt.geom.*;
-import java.awt.image.renderable.*;
+import javax.imageio.ImageIO;
+import javax.imageio.ImageReadParam;
+import javax.imageio.ImageReader;
+import javax.imageio.stream.FileImageInputStream;
+import javax.imageio.stream.ImageInputStream;
-import javax.imageio.*;
+import digilib.io.FileOpException;
+import digilib.io.ImageFile;
-import digilib.*;
-import digilib.io.*;
-
+/** Implementation of DocuImage using the ImageLoader API of Java 1.4 and Java2D. */
public class ImageLoaderDocuImage extends DocuImageImpl {
- private BufferedImage img;
+ /** image object */
+ protected BufferedImage img;
+
+ /** interpolation type */
+ protected RenderingHints renderHint;
+
+ /** ImageIO image reader */
+ protected ImageReader reader;
+
+ /** File that was read */
+ protected File imgFile;
+
+ /* loadSubimage is supported. */
+ public boolean isSubimageSupported() {
+ return true;
+ }
+
+ public void setQuality(int qual) {
+ quality = qual;
+ renderHint = new RenderingHints(null);
+ //hint.put(RenderingHints.KEY_ANTIALIASING,
+ // RenderingHints.VALUE_ANTIALIAS_OFF);
+ // setup interpolation quality
+ if (qual > 0) {
+ logger.debug("quality q1");
+ renderHint.put(RenderingHints.KEY_INTERPOLATION,
+ RenderingHints.VALUE_INTERPOLATION_BICUBIC);
+ } else {
+ logger.debug("quality q0");
+ renderHint.put(RenderingHints.KEY_INTERPOLATION,
+ RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
+ }
+ }
- public ImageLoaderDocuImage() {
- }
+ 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 ImageLoaderDocuImage(Utils u) {
- util = u;
- }
+ 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 image file */
+ public void loadImage(ImageFile f) throws FileOpException {
+ logger.debug("loadImage " + f);
+ //System.gc();
+ try {
+ img = ImageIO.read(f);
+ if (img == null) {
+ throw new FileOpException("Unable to load File!");
+ }
+ } catch (IOException e) {
+ throw new FileOpException("Error reading image.");
+ }
+ }
- /**
- * load image file
- */
- public void loadImage(File f) throws FileOpException {
- util.dprintln(10, "loadImage!");
- System.gc();
- try {
- for (int i = 0; i < ImageIO.getReaderFormatNames().length; i++) {
- System.out.println("ImageLoader reader:"+ImageIO.getReaderFormatNames()[i]);
- }
- for (int i = 0; i < ImageIO.getWriterFormatNames().length; i++) {
- System.out.println("ImageLoader writer:"+ImageIO.getWriterFormatNames()[i]);
- }
- img = ImageIO.read(f);
- if (img == null) {
- util.dprintln(3, "ERROR(loadImage): unable to load file");
- throw new FileOpException("Unable to load File!");
- }
- }
- catch (IOException e) {
- throw new FileOpException("Error reading image.");
- }
- }
+ /**
+ * Get an ImageReader for the image file.
+ *
+ * @return
+ */
+ public ImageReader getReader(ImageFile f) throws IOException {
+ logger.debug("preloadImage " + f);
+ if (reader != null) {
+ logger.debug("Reader was not null!");
+ // clean up old reader
+ dispose();
+ }
+ //System.gc();
+ RandomAccessFile rf = new RandomAccessFile(f, "r");
+ ImageInputStream istream = new FileImageInputStream(rf);
+ //Iterator readers = ImageIO.getImageReaders(istream);
+ String mt = f.getMimetype();
+ logger.debug("File type:" + mt);
+ Iterator readers = ImageIO.getImageReadersByMIMEType(mt);
+ if (!readers.hasNext()) {
+ throw new FileOpException("Unable to load File!");
+ }
+ reader = (ImageReader) 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;
+ return reader;
+ }
+
+ /* Load an image file into the Object. */
+ public void loadSubimage(ImageFile f, Rectangle region, int prescale)
+ throws FileOpException {
+ logger.debug("loadSubimage");
+ //System.gc();
+ try {
+ if ((reader == null) || (imgFile != f)) {
+ getReader(f);
+ }
+ // set up reader parameters
+ ImageReadParam readParam = reader.getDefaultReadParam();
+ readParam.setSourceRegion(region);
+ if (prescale > 1) {
+ readParam.setSourceSubsampling(prescale, prescale, 0, 0);
+ }
+ // read image
+ logger.debug("loading..");
+ img = reader.read(0, readParam);
+ logger.debug("loaded");
+ } catch (IOException e) {
+ throw new FileOpException("Unable to load File!");
+ }
+ if (img == null) {
+ throw new FileOpException("Unable to load File!");
+ }
+ }
+
+ /* write image of type mt to Stream */
+ public void writeImage(String mt, OutputStream ostream)
+ throws FileOpException {
+ logger.debug("writeImage");
+ try {
+ // setup output
+ String type = "png";
+ if (mt == "image/jpeg") {
+ type = "jpeg";
+ } else if (mt == "image/png") {
+ type = "png";
+ } else {
+ // unknown mime type
+ throw new FileOpException("Unknown mime type: " + mt);
+ }
+
+ /*
+ * JPEG doesn't do transparency so we have to convert any RGBA image
+ * to RGB :-( *Java2D BUG*
+ */
+ if ((type == "jpeg") && (img.getColorModel().hasAlpha())) {
+ logger.debug("BARF: JPEG with transparency!!");
+ int w = img.getWidth();
+ int h = img.getHeight();
+ // BufferedImage.TYPE_INT_RGB seems to be fastest (JDK1.4.1,
+ // OSX)
+ int destType = BufferedImage.TYPE_INT_RGB;
+ BufferedImage img2 = new BufferedImage(w, h, destType);
+ img2.createGraphics().drawImage(img, null, 0, 0);
+ img = img2;
+ }
+
+ // render output
+ logger.debug("writing");
+ if (ImageIO.write(img, type, ostream)) {
+ // writing was OK
+ return;
+ } else {
+ throw new FileOpException(
+ "Error writing image: Unknown image format!");
+ }
+ } catch (IOException e) {
+ throw new FileOpException("Error writing image.");
+ }
+ }
- /**
- * write image of type mt to Stream
- */
- public void writeImage(String mt, ServletResponse res)
- throws FileOpException {
- util.dprintln(10, "writeImage!");
- try {
- // setup output
- String type = "png";
- if (mt == "image/jpeg") {
- type = "jpeg";
- } else if (mt == "image/png") {
- type = "png";
- } else {
- // unknown mime type
- util.dprintln(2, "ERROR(writeImage): Unknown mime type "+mt);
- throw new FileOpException("Unknown mime type: "+mt);
- }
- res.setContentType(mt);
- // render output
- if (ImageIO.write(img, type, res.getOutputStream())) {
- // writing was OK
- return;
- } else {
- throw new FileOpException("Error writing image: Unknown image format!");
- }
- } catch (IOException e) {
- // e.printStackTrace();
- throw new FileOpException("Error writing image.");
- }
- }
+ public void scale(double scale, double scaleY) throws ImageOpException {
+ logger.debug("scale");
+ /* for downscaling in high quality the image is blurred first */
+ if ((scale <= 0.5) && (quality > 1)) {
+ int bl = (int) Math.floor(1 / scale);
+ blur(bl);
+ }
+ /* then scaled */
+ AffineTransformOp scaleOp = new AffineTransformOp(AffineTransform
+ .getScaleInstance(scale, scale), renderHint);
+ BufferedImage scaledImg = null;
+ // enforce destination image type (*Java2D BUG*)
+ int type = img.getType();
+ // FIXME: which type would be best?
+ if ((quality > 0) && (type != 0)) {
+ logger.debug("creating destination image");
+ Rectangle2D dstBounds = scaleOp.getBounds2D(img);
+ scaledImg = new BufferedImage((int) dstBounds.getWidth(),
+ (int) dstBounds.getHeight(), type);
+ }
+ logger.debug("scaling...");
+ scaledImg = scaleOp.filter(img, scaledImg);
+ logger.debug("destination image type " + scaledImg.getType());
+ if (scaledImg == null) {
+ throw new ImageOpException("Unable to scale");
+ }
+ //DEBUG
+ logger.debug("SCALE: " + scale + " ->" + scaledImg.getWidth() + "x"
+ + scaledImg.getHeight());
+ img = scaledImg;
+ scaledImg = null;
+ }
- public int getWidth() {
- if (img != null) {
- return img.getWidth();
- }
- return 0;
- }
+ 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 = new Kernel(klen, klen, kern);
+ // blur with convolve operation
+ ConvolveOp blurOp = new ConvolveOp(blur, ConvolveOp.EDGE_NO_OP,
+ renderHint);
+ // blur needs explicit destination image type for color *Java2D BUG*
+ BufferedImage blurredImg = null;
+ if (img.getType() == BufferedImage.TYPE_3BYTE_BGR) {
+ blurredImg = new BufferedImage(img.getWidth(), img.getHeight(), img
+ .getType());
+ }
+ blurredImg = blurOp.filter(img, blurredImg);
+ if (blurredImg == null) {
+ throw new ImageOpException("Unable to scale");
+ }
+ img = blurredImg;
+ }
+
+ public void crop(int x_off, int y_off, int width, int height)
+ throws ImageOpException {
+ // setup Crop
+ BufferedImage croppedImg = img.getSubimage(x_off, y_off, width, height);
+ logger.debug("CROP:" + croppedImg.getWidth() + "x"
+ + croppedImg.getHeight());
+ //DEBUG
+ // util.dprintln(2, " time
+ // "+(System.currentTimeMillis()-startTime)+"ms");
+ if (croppedImg == null) {
+ throw new ImageOpException("Unable to crop");
+ }
+ img = croppedImg;
+ }
+
+ public void enhance(float mult, float add) throws ImageOpException {
+ /*
+ * Only one constant should work regardless of the number of bands
+ * according to the JDK spec. Doesn't work on JDK 1.4 for OSX and Linux
+ * (at least). RescaleOp scaleOp = new RescaleOp( (float)mult,
+ * (float)add, null); scaleOp.filter(img, img);
+ */
+
+ /* The number of constants must match the number of bands in the image. */
+ int ncol = img.getColorModel().getNumComponents();
+ float[] dm = new float[ncol];
+ float[] da = new float[ncol];
+ for (int i = 0; i < ncol; i++) {
+ dm[i] = (float) mult;
+ da[i] = (float) add;
+ }
+ RescaleOp scaleOp = new RescaleOp(dm, da, null);
+ scaleOp.filter(img, img);
+ }
+
+ public void enhanceRGB(float[] rgbm, float[] rgba) throws ImageOpException {
+
+ /*
+ * The number of constants must match the number of bands in the image.
+ * We do only 3 (RGB) bands.
+ */
+
+ 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 ("
+ + ncol + ")");
+ return;
+ }
+ RescaleOp scaleOp = new RescaleOp(rgbOrdered(rgbm), rgbOrdered(rgba),
+ null);
+ scaleOp.filter(img, img);
+ }
- public int getHeight() {
- if (img != null) {
- return img.getHeight();
- }
- return 0;
- }
-
- /**
- * crop and scale image
- * take rectangle width,height at position x_off,y_off
- * and scale by scale
- */
- public void cropAndScale(int x_off, int y_off, int width, int height,
- float scale, int qual) throws ImageOpException {
- util.dprintln(10, "cropAndScale!");
-
- int scaleInt = 0;
- // setup interpolation quality
- if (qual > 0) {
- util.dprintln(4, "quality q1");
- scaleInt = AffineTransformOp.TYPE_BILINEAR;
- } else {
- util.dprintln(4, "quality q0");
- scaleInt = AffineTransformOp.TYPE_NEAREST_NEIGHBOR;
- }
+ /**
+ * Ensures that the array f is in the right order to map the images RGB
+ * components. (not shure what happens
+ */
+ public float[] rgbOrdered(float[] fa) {
+ /*
+ * TODO: this is UGLY, UGLY!!
+ */
+ float[] fb;
+ int t = img.getType();
+ if (img.getColorModel().hasAlpha()) {
+ fb = new float[4];
+ if ((t == BufferedImage.TYPE_INT_ARGB)
+ || (t == BufferedImage.TYPE_INT_ARGB_PRE)) {
+ // RGB Type
+ fb[0] = fa[0];
+ fb[1] = fa[1];
+ fb[2] = fa[2];
+ fb[3] = 1f;
+ } else {
+ // this isn't tested :-(
+ fb[0] = 1f;
+ fb[1] = fa[0];
+ fb[2] = fa[1];
+ fb[3] = fa[2];
+ }
+ } else {
+ fb = new float[3];
+ if (t == BufferedImage.TYPE_3BYTE_BGR) {
+ // BGR Type (actually it looks like RBG...)
+ fb[0] = fa[0];
+ fb[1] = fa[2];
+ fb[2] = fa[1];
+ } else {
+ fb[0] = fa[0];
+ fb[1] = fa[1];
+ fb[2] = fa[2];
+ }
+ }
+ return fb;
+ }
- // setup Crop
- BufferedImage croppedImg = img.getSubimage(x_off, y_off, width, height);
-
- img = null; // free img
- util.dprintln(3, "CROP:"+croppedImg.getWidth()+"x"+croppedImg.getHeight()); //DEBUG
-// util.dprintln(2, " time "+(System.currentTimeMillis()-startTime)+"ms");
-
- if (croppedImg == null) {
- util.dprintln(2, "ERROR(cropAndScale): error in crop");
- throw new ImageOpException("Unable to crop");
- }
+ public void rotate(double angle) throws ImageOpException {
+ // setup rotation
+ double rangle = Math.toRadians(angle);
+ // create offset to make shure the rotated image has no negative
+ // coordinates
+ double w = img.getWidth();
+ double h = img.getHeight();
+ AffineTransform trafo = new AffineTransform();
+ // center of rotation
+ double x = (w / 2);
+ double y = (h / 2);
+ trafo.rotate(rangle, x, y);
+ // try rotation to see how far we're out of bounds
+ AffineTransformOp rotOp = new AffineTransformOp(trafo, renderHint);
+ Rectangle2D rotbounds = rotOp.getBounds2D(img);
+ double xoff = rotbounds.getX();
+ double yoff = rotbounds.getY();
+ // move image back in line
+ trafo
+ .preConcatenate(AffineTransform.getTranslateInstance(-xoff,
+ -yoff));
+ // transform image
+ rotOp = new AffineTransformOp(trafo, renderHint);
+ BufferedImage rotImg = rotOp.filter(img, null);
+ // calculate new bounding box
+ //Rectangle2D bounds = rotOp.getBounds2D(img);
+ if (rotImg == null) {
+ throw new ImageOpException("Unable to rotate");
+ }
+ img = rotImg;
+ // crop new image (with self-made rounding)
+ /*
+ * img = rotImg.getSubimage( (int) (bounds.getX()+0.5), (int)
+ * (bounds.getY()+0.5), (int) (bounds.getWidth()+0.5), (int)
+ * (bounds.getHeight()+0.5));
+ */
+ }
- // setup scale
- AffineTransformOp scaleOp = new AffineTransformOp(
- AffineTransform.getScaleInstance(scale, scale),
- scaleInt);
- BufferedImage scaledImg = scaleOp.filter(croppedImg, null);
- croppedImg = null; // free opCrop
+ public void mirror(double angle) throws ImageOpException {
+ // setup mirror
+ double mx = 1;
+ double my = 1;
+ double tx = 0;
+ double ty = 0;
+ if (Math.abs(angle - 0) < epsilon) { // 0 degree
+ mx = -1;
+ tx = getWidth();
+ } else if (Math.abs(angle - 90) < epsilon) { // 90 degree
+ my = -1;
+ ty = getHeight();
+ } else if (Math.abs(angle - 180) < epsilon) { // 180 degree
+ mx = -1;
+ tx = getWidth();
+ } else if (Math.abs(angle - 270) < epsilon) { // 270 degree
+ my = -1;
+ ty = getHeight();
+ } else if (Math.abs(angle - 360) < epsilon) { // 360 degree
+ mx = -1;
+ tx = getWidth();
+ }
+ AffineTransformOp mirOp = new AffineTransformOp(new AffineTransform(mx,
+ 0, 0, my, tx, ty), renderHint);
+ BufferedImage mirImg = mirOp.filter(img, null);
+ if (mirImg == null) {
+ throw new ImageOpException("Unable to mirror");
+ }
+ img = mirImg;
+ }
- if (scaledImg == null) {
- util.dprintln(2, "ERROR(cropAndScale): error in scale");
- throw new ImageOpException("Unable to scale");
- }
- img = scaledImg;
- }
+ /*
+ * (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;
+ }
+ img = null;
+ }
}
diff -r 794a9f25f15c -r 6d2032b6121d servlet/src/digilib/image/ImageOps.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/image/ImageOps.java Wed Nov 17 18:17:34 2004 +0100
@@ -0,0 +1,99 @@
+/* ImageOps -- convenience methods for images
+
+ Digital Image Library servlet components
+
+ Copyright (C) 2004 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 13.10.2004
+ */
+package digilib.image;
+
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.Iterator;
+
+import javax.imageio.ImageIO;
+import javax.imageio.ImageReader;
+import javax.imageio.stream.ImageInputStream;
+
+import org.apache.log4j.Logger;
+import org.marcoschmidt.image.ImageInfo;
+
+import digilib.io.FileOpException;
+import digilib.io.FileOps;
+import digilib.io.ImageFile;
+
+/**
+ * convenience methods for images
+ *
+ * @author casties
+ */
+public class ImageOps {
+
+ private static Logger logger = Logger.getLogger(ImageOps.class);
+
+ /** Check and store image size and type of image in ImageFile */
+ public static boolean checkFile(ImageFile imgf) throws IOException {
+ // fileset to store the information
+ RandomAccessFile raf = new RandomAccessFile(imgf, "r");
+ // set up ImageInfo object
+ ImageInfo iif = new ImageInfo();
+ iif.setInput(raf);
+ iif.setCollectComments(false);
+ iif.setDetermineImageNumber(false);
+ logger.debug("identifying (ImageInfo) " + imgf);
+ // 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();
+ iif = null;
+ } else {
+ iif = null;
+ logger.debug("identifying (ImageIO) " + imgf);
+ /*
+ * else use ImageReader
+ */
+ ImageInputStream istream = ImageIO.createImageInputStream(raf);
+ Iterator readers = ImageIO.getImageReaders(istream);
+ if ((readers == null) || (!readers.hasNext())) {
+ throw new FileOpException("ERROR: unknown image file format!");
+ }
+ ImageReader reader = (ImageReader) 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);
+ ImageSize d = new ImageSize(reader.getWidth(0), reader.getHeight(0));
+ imgf.setSize(d);
+ //String t = reader.getFormatName();
+ String t = FileOps.mimeForFile(imgf);
+ imgf.setMimetype(t);
+ //logger.debug(" format:"+t);
+ // dispose the reader to free resources
+ reader.dispose();
+ raf.close();
+ reader = null;
+ }
+ logger.debug("image size: " + imgf.getSize());
+ return true;
+ }
+
+}
diff -r 794a9f25f15c -r 6d2032b6121d servlet/src/digilib/image/JAIDocuImage.java
--- a/servlet/src/digilib/image/JAIDocuImage.java Thu Jan 17 15:25:46 2002 +0100
+++ b/servlet/src/digilib/image/JAIDocuImage.java Wed Nov 17 18:17:34 2004 +0100
@@ -2,7 +2,7 @@
Digital Image Library servlet components
- Copyright (C) 2001, 2002 Robert Casties (robcast@mail.berlios.de)
+ Copyright (C) 2001, 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
@@ -20,149 +20,402 @@
package digilib.image;
-import javax.servlet.*;
-import javax.servlet.http.*;
-import java.io.*;
-import java.util.*;
+import java.awt.RenderingHints;
+import java.awt.image.RenderedImage;
+import java.awt.image.renderable.ParameterBlock;
+import java.io.IOException;
+import java.io.OutputStream;
-import java.awt.*;
-import java.awt.image.*;
-import java.awt.image.renderable.*;
-import javax.media.jai.*;
+import javax.media.jai.BorderExtender;
+import javax.media.jai.Interpolation;
+import javax.media.jai.JAI;
+import javax.media.jai.KernelJAI;
+import javax.media.jai.ParameterBlockJAI;
+import javax.media.jai.operator.TransposeDescriptor;
+import javax.media.jai.operator.TransposeType;
-import digilib.*;
-import digilib.io.*;
+import digilib.io.ImageFile;
+import digilib.io.FileOpException;
-
+/** A DocuImage implementation using Java Advanced Imaging Library. */
public class JAIDocuImage extends DocuImageImpl {
- private RenderedImage img;
+ protected RenderedImage img;
+ protected Interpolation interpol = null;
+
+ /* Load an image file into the Object. */
+ public void loadImage(ImageFile f) throws FileOpException {
+ System.gc();
+ img = JAI.create("fileload", f.getAbsolutePath());
+ if (img == null) {
+ throw new FileOpException("Unable to load File!");
+ }
+ }
- public JAIDocuImage() {
- }
+ /* Write the current image to an OutputStream. */
+ public void writeImage(String mt, OutputStream ostream)
+ throws FileOpException {
+ 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("encode", pb3);
- public JAIDocuImage(Utils u) {
- util = u;
- }
+ } catch (IOException e) {
+ throw new FileOpException("Error writing image.");
+ }
+ }
- /**
- * load image file
- */
- public void loadImage(File f) throws FileOpException {
- System.gc();
- img = JAI.create("fileload", f.getAbsolutePath());
- if (img == null) {
- util.dprintln(3, "ERROR(loadImage): unable to load file");
- throw new FileOpException("Unable to load File!");
- }
- }
+ /* Real setQuality implementation.
+ * Creates the correct Interpolation.
+ */
+ public void setQuality(int qual) {
+ quality = qual;
+ // setup interpolation quality
+ if (qual > 1) {
+ logger.debug("quality q2");
+ interpol = Interpolation.getInstance(Interpolation.INTERP_BICUBIC);
+ } else if (qual == 1) {
+ logger.debug("quality q1");
+ interpol = Interpolation.getInstance(Interpolation.INTERP_BILINEAR);
+ } else {
+ logger.debug("quality q0");
+ interpol = Interpolation.getInstance(Interpolation.INTERP_NEAREST);
+ }
+ }
+
+ /** The width of the curent image in pixel.
+ * @return Image width in pixels.
+ */
+ public int getWidth() {
+ if (img != null) {
+ return img.getWidth();
+ }
+ return 0;
+ }
+
+ /** The height of the curent image in pixel.
+ * @return Image height in pixels.
+ */
+ public int getHeight() {
+ if (img != null) {
+ return img.getHeight();
+ }
+ return 0;
+ }
- /**
- * write image of type mt to Stream
- */
- public void writeImage(String mt, ServletResponse res)
- throws FileOpException {
- try {
- // setup output
- ParameterBlock pb3 = new ParameterBlock();
- pb3.addSource(img);
- pb3.add(res.getOutputStream());
- if (mt == "image/jpeg") {
- pb3.add("JPEG");
- } else if (mt == "image/png") {
- pb3.add("PNG");
- } else {
- // unknown mime type
- util.dprintln(2, "ERROR(writeImage): Unknown mime type "+mt);
- throw new FileOpException("Unknown mime type: "+mt);
- }
- res.setContentType(mt);
- // render output
- JAI.create("encode", pb3);
+ /* scales the current image */
+ public void scale(double scale, double scaleY) throws ImageOpException {
+ logger.debug("scale");
+ if ((scale < 1)
+ && (img.getColorModel().getPixelSize() == 1)
+ && (quality > 0)) {
+ /*
+ * "SubsampleBinaryToGray" for downscaling BW
+ */
+ scaleBinary((float) scale);
+ } else if ((scale <= 0.5) && (quality > 1)) {
+ /*
+ * blur and "Scale" for downscaling color images
+ */
+ int subsample = (int) Math.floor(1 / scale);
+ blur(subsample);
+ scaleAll((float) scale);
+ } else {
+ /*
+ * "Scale" for the rest
+ */
+ scaleAll((float) scale);
+ }
+
+ //DEBUG
+ logger.debug("SCALE: " + scale + " ->" + img.getWidth() + "x" + img.getHeight());
+
+ }
+
+ public void scaleAll(float scale) throws ImageOpException {
+ RenderedImage scaledImg;
+ //DEBUG
+ logger.debug("scaleAll: " + scale);
+ ParameterBlockJAI param = new ParameterBlockJAI("Scale");
+ param.addSource(img);
+ param.setParameter("xScale", scale);
+ param.setParameter("yScale", scale);
+ param.setParameter("interpolation", interpol);
+ // hint with border extender
+ RenderingHints hint =
+ new RenderingHints(
+ JAI.KEY_BORDER_EXTENDER,
+ BorderExtender.createInstance(BorderExtender.BORDER_COPY));
+ // scale
+ scaledImg = JAI.create("Scale", param, hint);
+
+ if (scaledImg == null) {
+ throw new ImageOpException("Unable to scale");
+ }
+ img = scaledImg;
+ }
- } catch (IOException e) {
- throw new FileOpException("Error writing image.");
- }
- }
+ public void blur(int radius) throws ImageOpException {
+ RenderedImage blurredImg;
+ //DEBUG
+ logger.debug("blur: " + radius);
+ int klen = Math.max(radius, 2);
+ int ksize = klen * klen;
+ float f = 1f / ksize;
+ float[] kern = new float[ksize];
+ for (int i = 0; i < ksize; i++) {
+ kern[i] = f;
+ }
+ KernelJAI blur = new KernelJAI(klen, klen, kern);
+ ParameterBlockJAI param = new ParameterBlockJAI("Convolve");
+ param.addSource(img);
+ param.setParameter("kernel", blur);
+ // hint with border extender
+ RenderingHints hint =
+ new RenderingHints(
+ JAI.KEY_BORDER_EXTENDER,
+ BorderExtender.createInstance(BorderExtender.BORDER_COPY));
+ blurredImg = JAI.create("Convolve", param, hint);
+ if (blurredImg == null) {
+ throw new ImageOpException("Unable to scale");
+ }
+ img = blurredImg;
+ }
- public int getWidth() {
- if (img != null) {
- return img.getWidth();
- }
- return 0;
- }
+ public void scaleBinary(float scale) throws ImageOpException {
+ RenderedImage scaledImg;
+ //DEBUG
+ logger.debug("scaleBinary: " + scale);
+ ParameterBlockJAI param =
+ new ParameterBlockJAI("SubsampleBinaryToGray");
+ param.addSource(img);
+ param.setParameter("xScale", scale);
+ param.setParameter("yScale", scale);
+ // hint with border extender
+ RenderingHints hint =
+ new RenderingHints(
+ JAI.KEY_BORDER_EXTENDER,
+ BorderExtender.createInstance(BorderExtender.BORDER_COPY));
+ // scale
+ scaledImg = JAI.create("SubsampleBinaryToGray", param, hint);
+ if (scaledImg == null) {
+ throw new ImageOpException("Unable to scale");
+ }
+ img = scaledImg;
+ }
- public int getHeight() {
- if (img != null) {
- return img.getHeight();
- }
- return 0;
- }
-
+ /* crops the current image */
+ public void crop(int x_off, int y_off, int width, int height)
+ throws ImageOpException {
+ // setup Crop
+ ParameterBlock param = new ParameterBlock();
+ param.addSource(img);
+ param.add((float) x_off);
+ param.add((float) y_off);
+ param.add((float) width);
+ param.add((float) height);
+ RenderedImage croppedImg = JAI.create("crop", param);
- /**
- * crop and scale image
- * take rectangle width,height at position x_off,y_off
- * and scale by scale
- */
- public void cropAndScale(int x_off, int y_off, int width, int height,
- float scale, int qual) throws ImageOpException {
+ logger.debug("CROP: "
+ + x_off
+ + ","
+ + y_off
+ + ", "
+ + width
+ + ","
+ + height
+ + " ->"
+ + croppedImg.getWidth()
+ + "x"
+ + croppedImg.getHeight());
+ //DEBUG
+
+ if (croppedImg == null) {
+ throw new ImageOpException("Unable to crop");
+ }
+ img = croppedImg;
+ }
+
+ /* rotates the current image */
+ public void rotate(double angle) throws ImageOpException {
+ RenderedImage rotImg;
+ // convert degrees to radians
+ double rangle = Math.toRadians(angle);
+ double x = img.getWidth() / 2;
+ double y = img.getHeight() / 2;
- Interpolation scaleInt = null;
- // setup interpolation quality
- if (qual > 1) {
- util.dprintln(4, "quality q2");
- scaleInt = Interpolation.getInstance(Interpolation.INTERP_BICUBIC);
- } else if (qual == 1) {
- util.dprintln(4, "quality q1");
- scaleInt = Interpolation.getInstance(Interpolation.INTERP_BILINEAR);
- } else {
- util.dprintln(4, "quality q0");
- scaleInt = Interpolation.getInstance(Interpolation.INTERP_NEAREST);
- }
+ // optimize rotation by right angles
+ TransposeType rotOp = null;
+ if (Math.abs(angle - 0) < epsilon) {
+ // 0 degree
+ return;
+ } else if (Math.abs(angle - 90) < epsilon) {
+ // 90 degree
+ rotOp = TransposeDescriptor.ROTATE_90;
+ } else if (Math.abs(angle - 180) < epsilon) {
+ // 180 degree
+ rotOp = TransposeDescriptor.ROTATE_180;
+ } else if (Math.abs(angle - 270) < epsilon) {
+ // 270 degree
+ rotOp = TransposeDescriptor.ROTATE_270;
+ } else if (Math.abs(angle - 360) < epsilon) {
+ // 360 degree
+ return;
+ }
+ if (rotOp != null) {
+ // use Transpose operation
+ ParameterBlock pb = new ParameterBlock();
+ pb.addSource(img);
+ pb.add(rotOp);
+ rotImg = JAI.create("transpose", pb);
+ } else {
+ // setup "normal" rotation
+ ParameterBlock param = new ParameterBlock();
+ param.addSource(img);
+ param.add((float) x);
+ param.add((float) y);
+ param.add((float) rangle);
+ param.add(interpol);
- // setup Crop
- ParameterBlock pb1 = new ParameterBlock();
- pb1.addSource(img);
- pb1.add((float)x_off);
- pb1.add((float)y_off);
- pb1.add((float)width);
- pb1.add((float)height);
- RenderedImage croppedImg = JAI.create("crop", pb1);
- img = null; // free img
+ rotImg = JAI.create("rotate", param);
+ }
+
+ logger.debug("ROTATE: "
+ + x
+ + ","
+ + y
+ + ", "
+ + angle
+ + " ("
+ + rangle
+ + ")"
+ + " ->"
+ + rotImg.getWidth()
+ + "x"
+ + rotImg.getHeight());
+ //DEBUG
+
+ if (rotImg == null) {
+ throw new ImageOpException("Unable to rotate");
+ }
+ img = rotImg;
+ }
- util.dprintln(3, "CROP:"+croppedImg.getWidth()+"x"+croppedImg.getHeight()); //DEBUG
+ /* mirrors the current image
+ * works only horizontal and vertical
+ */
+ public void mirror(double angle) throws ImageOpException {
+ RenderedImage mirImg;
+ // only mirroring by right angles
+ TransposeType rotOp = null;
+ if (Math.abs(angle) < epsilon) {
+ // 0 degree
+ rotOp = TransposeDescriptor.FLIP_HORIZONTAL;
+ } else if (Math.abs(angle - 90) < epsilon) {
+ // 90 degree
+ rotOp = TransposeDescriptor.FLIP_VERTICAL;
+ } else if (Math.abs(angle - 180) < epsilon) {
+ // 180 degree
+ rotOp = TransposeDescriptor.FLIP_HORIZONTAL;
+ } else if (Math.abs(angle - 270) < epsilon) {
+ // 270 degree
+ rotOp = TransposeDescriptor.FLIP_VERTICAL;
+ } else if (Math.abs(angle - 360) < epsilon) {
+ // 360 degree
+ rotOp = TransposeDescriptor.FLIP_HORIZONTAL;
+ }
+ // use Transpose operation
+ ParameterBlock param = new ParameterBlock();
+ param.addSource(img);
+ param.add(rotOp);
+ mirImg = JAI.create("transpose", param);
- if (croppedImg == null) {
- util.dprintln(2, "ERROR(cropAndScale): error in crop");
- throw new ImageOpException("Unable to crop");
- }
+ if (mirImg == null) {
+ throw new ImageOpException("Unable to flip");
+ }
+ img = mirImg;
+ }
+
+ /* contrast and brightness enhancement */
+ public void enhance(float mult, float add) throws ImageOpException {
+ RenderedImage enhImg;
+ double[] ma = { mult };
+ double[] aa = { add };
+ // use Rescale operation
+ ParameterBlock param = new ParameterBlock();
+ param.addSource(img);
+ param.add(ma);
+ param.add(aa);
+ enhImg = JAI.create("rescale", param);
- // setup scale
- ParameterBlock pb2 = new ParameterBlock();
- pb2.addSource(croppedImg);
- pb2.add(scale);
- pb2.add(scale);
- pb2.add(0f);
- pb2.add(0f);
- pb2.add(scaleInt);
- // the following is nice but way too slow...
- //if (opCrop.getColorModel().getPixelSize() < 8) {
- // change color model if necessary
- // util.dprintln("converting color model...");
- // BufferedImage bi = new BufferedImage(1, 1, BufferedImage.TYPE_BYTE_GRAY);
- // ImageLayout lay = new ImageLayout(bi);
- // rh = new RenderingHints(JAI.KEY_IMAGE_LAYOUT, lay);
- //}
- RenderedImage scaledImg = JAI.create("scale", pb2);
- croppedImg = null; // free opCrop
+ logger.debug("ENHANCE: *"
+ + mult
+ + ", +"
+ + add
+ + " ->"
+ + enhImg.getWidth()
+ + "x"
+ + enhImg.getHeight());
+ //DEBUG
+
+ if (enhImg == null) {
+ throw new ImageOpException("Unable to enhance");
+ }
+ img = enhImg;
+ }
- if (scaledImg == null) {
- util.dprintln(2, "ERROR(cropAndScale): error in scale");
- throw new ImageOpException("Unable to scale");
- }
+ /* (non-Javadoc)
+ * @see digilib.image.DocuImage#enhanceRGB(float[], float[])
+ */
+ public void enhanceRGB(float[] rgbm, float[] rgba)
+ throws ImageOpException {
+ RenderedImage enhImg;
+ int nb = rgbm.length;
+ double[] ma = new double[nb];
+ double[] aa = new double[nb];
+ for (int i = 0; i < nb; i++) {
+ ma[i] = rgbm[i];
+ aa[i] = rgba[i];
+ }
+ // use Rescale operation
+ ParameterBlock param = new ParameterBlock();
+ param.addSource(img);
+ param.add(ma);
+ param.add(aa);
+ enhImg = JAI.create("rescale", param);
- img = scaledImg;
- }
+ logger.debug("ENHANCE_RGB: *"
+ + rgbm
+ + ", +"
+ + rgba
+ + " ->"
+ + enhImg.getWidth()
+ + "x"
+ + enhImg.getHeight());
+ //DEBUG
+
+ if (enhImg == null) {
+ throw new ImageOpException("Unable to enhanceRGB");
+ }
+ img = enhImg;
+ }
+
+ /* (non-Javadoc)
+ * @see digilib.image.DocuImage#dispose()
+ */
+ public void dispose() {
+ img = null;
+ }
}
diff -r 794a9f25f15c -r 6d2032b6121d servlet/src/digilib/image/JAIImageLoaderDocuImage.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/image/JAIImageLoaderDocuImage.java Wed Nov 17 18:17:34 2004 +0100
@@ -0,0 +1,184 @@
+/* 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);
+ //System.gc();
+ img = JAI.create("ImageRead", f.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);
+ //System.gc();
+ RandomAccessFile rf = new RandomAccessFile(f, "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);
+ //System.gc();
+ try {
+ if ((reader == null) || (imgFile != f)) {
+ 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;
+ }
+
+
+ /* 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;
+ }
+
+}
diff -r 794a9f25f15c -r 6d2032b6121d servlet/src/digilib/io/AliasingDocuDirCache.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/io/AliasingDocuDirCache.java Wed Nov 17 18:17:34 2004 +0100
@@ -0,0 +1,91 @@
+/*
+ * AliasingDocuDirCache -- DocuDirCache using alias entries from config file
+ *
+ * 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 04.11.2003
+ */
+
+package digilib.io;
+
+import java.io.File;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * @author casties
+ *
+ */
+public class AliasingDocuDirCache extends DocuDirCache {
+
+ /**
+ * @param baseDirs
+ * @param fileClasses
+ * @param confFileName
+ * @throws FileOpException
+ */
+ public AliasingDocuDirCache(File confFile) throws FileOpException {
+ // create standard DocuDirCache
+ super();
+ Map pathMap = null;
+ // read alias config file
+ try {
+ // load into pathMap
+ XMLListLoader mapLoader = new XMLListLoader("digilib-aliases",
+ "mapping", "link", "dir");
+ pathMap = mapLoader.loadURL(confFile.toURL().toString());
+ } catch (Exception e) {
+ throw new FileOpException("ERROR loading mapping file: " + e);
+ }
+ if (pathMap == null) {
+ throw new FileOpException("ERROR: unable to load mapping file!");
+ }
+
+ /*
+ * load map entries into cache
+ */
+
+ for (Iterator i = pathMap.keySet().iterator(); i.hasNext();) {
+ String link = FileOps.normalName((String) i.next());
+ String dn = (String) pathMap.get(link);
+ File dir = FileOps.getRealFile(dn);
+ if (dir.isDirectory()) {
+ logger.debug("Aliasing dir: " + link);
+ DigiDirectory destDir = new DigiDirectory(dir, dn, null);
+ // add the alias name
+ putName(link, destDir);
+ // add the real dir
+ putDir(destDir);
+ }
+ }
+ }
+
+ /**
+ * Adds a DocuDirectory under another name to the cache.
+ *
+ * @param name
+ * @param newdir
+ */
+ public void putName(String name, DigiDirectory newdir) {
+ Object oldkey = map.put(name, newdir);
+ if (oldkey != null) {
+ logger
+ .warn("Duplicate key in AliasingDocuDirCache.put -- replaced!");
+ }
+ }
+
+}
diff -r 794a9f25f15c -r 6d2032b6121d servlet/src/digilib/io/DigiDirectory.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/io/DigiDirectory.java Wed Nov 17 18:17:34 2004 +0100
@@ -0,0 +1,380 @@
+/* DigiDirectory.java -- digilib directory object
+ *
+ * Digital Image Library servlet components
+ *
+ * Copyright (C) 2004 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.11.2004
+ */
+package digilib.io;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Map;
+
+import org.xml.sax.SAXException;
+
+/**
+ * digilib directory object
+ *
+ * @author casties
+ *
+ */
+public class DigiDirectory extends DigiDirent {
+
+ protected static boolean isFile = false;
+
+ protected static boolean isDirectory = true;
+
+ protected DigiDirent[] entries;
+
+ protected int[][] indexes;
+
+ protected File dir;
+
+ /** directory name (digilib canonical form) */
+ protected String dlPath = null;
+
+ protected long mtime = 0;
+
+ protected boolean isDirRead = false;
+
+ protected Map unresolvedMeta;
+
+ /**
+ * @param parent
+ * @param dir
+ */
+ public DigiDirectory(String dlPath) {
+ super(FileOps.dlName(dlPath), null);
+ }
+
+ /**
+ * @param dir
+ * @param parent
+ */
+ public DigiDirectory(File dir, DigiDirectory parent) {
+ super(dir.getName(), parent);
+ this.dir = dir;
+ this.dlPath = parent.getDLPath() + "/" + dir.getName();
+ }
+
+ /**
+ * @param dir
+ * @param dlpath
+ * @param parent
+ */
+ public DigiDirectory(File dir, String dlpath, DigiDirectory parent) {
+ super(dir.getName(), parent);
+ this.dlPath = dlpath;
+ this.dir = dir;
+ }
+
+ public boolean exists() {
+ return ((dir != null) && (dir.isDirectory()));
+ }
+
+ /**
+ * Returns the file of the class at the index.
+ *
+ * @param index
+ * @param fc
+ * fileClass
+ * @return
+ */
+ public DigiDirent get(int index, int fc) {
+ if (!isDirRead) {
+ // read directory now
+ if (readDir() < 1) {
+ return null;
+ }
+ }
+ try {
+ return (DigiDirent) entries[indexes[fc][index]];
+ } catch (Exception e) {
+ }
+ return null;
+ }
+
+ /**
+ * Returns the file with the name fn
.
+ *
+ * @param fn
+ * filename
+ * @return
+ */
+ public DigiDirent get(String fn) {
+ if (!isDirRead) {
+ // read directory now
+ if (readDir() < 1) {
+ return null;
+ }
+ }
+ // search for exact match
+ int idx = Arrays.binarySearch(entries, fn);
+ if (idx >= 0) {
+ return entries[idx];
+ } else {
+ // try closest matches without extension
+ idx = -idx - 1;
+ int imax = entries.length;
+ String fb = FileOps.basename(fn);
+ if ((idx < imax)
+ && (FileOps.basename(entries[idx].getName()).equals(fb))) {
+ // idx matches
+ return entries[idx];
+ } else if ((idx > 0)
+ && (FileOps.basename(entries[idx - 1].getName()).equals(fb))) {
+ // idx-1 matches
+ return entries[idx - 1];
+ } else if ((idx + 1 < imax)
+ && (FileOps.basename(entries[idx + 1].getName()).equals(fb))) {
+ // idx+1 matches
+ return entries[idx + 1];
+ }
+ }
+ return null;
+ }
+
+
+ /**
+ * Reads the names of the files in the directory. Fills the filenames array.
+ * Returns the number of files.
+ *
+ * @return
+ */
+ public int readDir() {
+ if (!exists()) {
+ return -1;
+ }
+ File[] allFiles = null;
+ // list all files in the directory
+ allFiles = dir.listFiles();
+ if (allFiles == null) {
+ // not a directory
+ isDirRead = true;
+ return -1;
+ }
+ Arrays.sort(allFiles);
+ int nfiles = allFiles.length;
+ entries = new DigiDirent[nfiles];
+ // create new index lists for all file classes
+ int nfc = FileOps.NUM_CLASSES;
+ indexes = new int[nfc][nfiles];
+ // index pointers for the file classes
+ int[] lastidx = new int[nfc];
+ Map hints = FileOps.newHints();
+ // go through all files
+ for (int dirIdx = 0; dirIdx < nfiles; dirIdx++) {
+ File f = allFiles[dirIdx];
+ String fn = f.getName();
+ int fc = FileOps.classForFilename(fn);
+ // create the right kind of Dirent
+ DigiDirent df = FileOps.fileForClass(fc, f, this, hints);
+ // add the file to our list
+ entries[dirIdx] = df;
+ // add to the indexes
+ if (fc >= 0) {
+ indexes[fc][lastidx[fc]++] = dirIdx;
+ }
+ }
+ // copy out the index arrays
+ for (int i = 0; i < nfc; i++) {
+ int[] idxs = new int[lastidx[i]];
+ System.arraycopy(indexes[i], 0, idxs, 0, lastidx[i]);
+ indexes[i] = idxs;
+ }
+ // update modification time
+ mtime = dir.lastModified();
+ // read metadata as well
+ readMeta();
+ isDirRead = true;
+ return nfiles;
+ }
+
+ /**
+ * Check to see if the directory has been modified and reread if necessary.
+ *
+ * @return boolean the directory is valid
+ */
+ public void check() {
+ if (isDirRead && (dir.lastModified() > mtime)) {
+ // on-disk modification time is more recent
+ readDir();
+ } else if (!isDirRead) {
+ readDir();
+ }
+ }
+
+ /**
+ * Read directory metadata.
+ *
+ */
+ public void readMeta() {
+ // check for directory metadata...
+ File mf = new File(dir, "index.meta");
+ if (mf.canRead()) {
+ XMLMetaLoader ml = new XMLMetaLoader();
+ try {
+ // read directory meta file
+ Map fileMeta = ml.loadURL(mf.getAbsolutePath());
+ if (fileMeta == null) {
+ throw new IOException("XMLMetaloader returned no data!");
+ }
+ // meta for the directory itself is in the "" bin
+ meta = (Map) fileMeta.remove("");
+ // read meta for files in this directory
+ storeFileMeta(fileMeta, null);
+ // is there meta for other files left?
+ if (fileMeta.size() > 0) {
+ unresolvedMeta = fileMeta;
+ }
+ } catch (SAXException e) {
+ logger.warn("error parsing index.meta", e);
+ } catch (IOException e) {
+ logger.warn("error reading index.meta", e);
+ }
+ }
+ readParentMeta();
+ isMetaRead = true;
+ }
+
+ /**
+ * Read metadata from all known parent directories.
+ *
+ */
+ public void readParentMeta() {
+ // check the parent directories for additional file meta
+ DigiDirectory dd = getParent();
+ String path = dir.getName();
+ while (dd != null) {
+ if (dd.hasUnresolvedMeta()) {
+ storeFileMeta(dd.getUnresolvedMeta(), path);
+ }
+ // prepend parent dir path
+ path = dd.getDir().getName() + "/" + path;
+ // become next parent
+ dd = dd.getParent();
+ }
+ }
+
+ /**
+ * Stores metadata in the files in this directory.
+ *
+ * Takes a Map with meta-information, adding the relative path before the
+ * lookup.
+ *
+ * @param fileMeta
+ * @param relPath
+ * @param fc
+ * fileClass
+ */
+ protected void storeFileMeta(Map fileMeta, String relPath) {
+ if (entries == null) {
+ // there are no files
+ return;
+ }
+ String path = (relPath != null) ? (relPath + "/") : "";
+ // iterate through the list of files in this directory
+ for (int i = 0; i < entries.length; i++) {
+ DigiDirent f = entries[i];
+ // prepend path to the filename
+ String fn = path + f.getName();
+ // look up meta for this file
+ if (relPath == null) {
+ // remove from map the same directory
+ f.addMeta((Map) fileMeta.remove(fn));
+ } else {
+ // copy from map in other directories
+ f.addMeta((Map) fileMeta.get(fn));
+ }
+ }
+ }
+
+ /*
+ * boring getters and setters
+ */
+
+ public boolean hasUnresolvedMeta() {
+ return ((unresolvedMeta != null) && unresolvedMeta.isEmpty());
+ }
+
+ /**
+ * @return Returns the unresolvedMeta.
+ */
+ public Map getUnresolvedMeta() {
+ return unresolvedMeta;
+ }
+
+ /**
+ * @return Returns the dir.
+ */
+ public File getDir() {
+ return dir;
+ }
+
+ /**
+ * @param dir
+ * The dir to set.
+ */
+ public void setDir(File dir) {
+ this.dir = dir;
+ }
+
+ /**
+ * @return Returns the dlPath.
+ */
+ public String getDLPath() {
+ return dlPath;
+ }
+
+ /**
+ * @param dlPath
+ * The dlPath to set.
+ */
+ public void setDlPath(String dlPath) {
+ this.dlPath = dlPath;
+ }
+
+ /**
+ * The number of files in this directory.
+ *
+ * @return
+ */
+ public int getSize() {
+ return (entries != null) ? entries.length : 0;
+ }
+
+ /**
+ * The number of files of a file class in this directory.
+ *
+ * @return
+ */
+ public int getSize(int fc) {
+ try {
+ return indexes[fc].length;
+ } catch (Exception e) {
+ }
+ return 0;
+ }
+
+ /**
+ * @return Returns the mtime.
+ */
+ public long getMtime() {
+ return mtime;
+ }
+}
diff -r 794a9f25f15c -r 6d2032b6121d servlet/src/digilib/io/DigiDirent.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/io/DigiDirent.java Wed Nov 17 18:17:34 2004 +0100
@@ -0,0 +1,191 @@
+/* DigiDirent.java -- an entry in a directory
+ *
+ * Digital Image Library servlet components
+ *
+ * Copyright (C) 2004 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.11.2004
+ */
+
+package digilib.io;
+
+import java.io.File;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+
+/**
+ * an entry in a directory
+ *
+ * @author casties
+ *
+ */
+public class DigiDirent implements Comparable {
+
+ protected static Logger logger = Logger.getLogger(DigiDirent.class);
+
+ protected static int fileClass = FileOps.CLASS_NONE;
+
+ protected static boolean isFile = true;
+
+ protected static boolean isDirectory = false;
+
+ protected String name;
+
+ protected DigiDirectory parent;
+
+ protected Map meta;
+
+ protected boolean isMetaRead = false;
+
+ /**
+ *
+ */
+ public DigiDirent() {
+ super();
+ }
+
+ /**
+ * @param name
+ * @param parent
+ */
+ public DigiDirent(String name) {
+ super();
+ this.name = name;
+ }
+
+ /**
+ * @param name
+ * @param parent
+ */
+ public DigiDirent(String name, DigiDirectory parent) {
+ super();
+ this.name = name;
+ this.parent = parent;
+ }
+
+ public boolean isFile() {
+ return isFile;
+ }
+
+ public boolean isDirectory() {
+ return isDirectory;
+ }
+
+ /**
+ * @return Returns the file class.
+ */
+ public int getFileClass() {
+ return fileClass;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * @return Returns the parent.
+ */
+ public DigiDirectory getParent() {
+ return parent;
+ }
+
+ /**
+ * @param parent
+ * The parent to set.
+ */
+ public void setParent(DigiDirectory parent) {
+ this.parent = parent;
+ }
+
+ /**
+ * @return Returns the meta.
+ */
+ public Map getMeta() {
+ return meta;
+ }
+
+ /**
+ * @param meta
+ * The meta to set.
+ */
+ public void setMeta(Map meta) {
+ this.meta = meta;
+ }
+
+ /**
+ * Adds metadata to this files metadata.
+ *
+ * @param meta
+ */
+ public void addMeta(Map meta) {
+ if (meta == null) {
+ return;
+ }
+ if ((this.meta == null) || (this.meta.isEmpty())) {
+ this.meta = meta;
+ } else {
+ this.meta.putAll(meta);
+ }
+ }
+
+ /**
+ * Reads meta-data for this file if there is any.
+ *
+ */
+ public void readMeta() {
+ if (isMetaRead || (parent == null) || (!parent.exists())) {
+ // there is already metadata or there is no file
+ return;
+ }
+ // metadata is in the file {filename}.meta
+ String fn = parent.getDir().getAbsolutePath();
+ File mf = new File(fn, name + ".meta");
+ if (mf.canRead()) {
+ XMLMetaLoader ml = new XMLMetaLoader();
+ try {
+ // read meta file
+ Map fileMeta = ml.loadURL(mf.getAbsolutePath());
+ // meta for this file is in an entry with its name
+ addMeta((Map)fileMeta.get(name));
+ } catch (Exception e) {
+ Logger.getLogger(this.getClass()).warn(
+ "error reading file .meta", e);
+ }
+ }
+ isMetaRead = true;
+ }
+
+ /**
+ * Checks metadata.
+ *
+ */
+ public void check() {
+ if (isMetaRead) {
+ return;
+ }
+ // read the metadata file
+ readMeta();
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ public int compareTo(Object o) {
+ // TODO Auto-generated method stub
+ return (getName().compareTo(o));
+ }
+
+}
diff -r 794a9f25f15c -r 6d2032b6121d servlet/src/digilib/io/DocuDirCache.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/io/DocuDirCache.java Wed Nov 17 18:17:34 2004 +0100
@@ -0,0 +1,240 @@
+/*
+ * 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.Map;
+
+import org.apache.log4j.Logger;
+
+/**
+ * Cache of digilib directories.
+ *
+ * @author casties
+ */
+public class DocuDirCache {
+
+ /** general logger for this class */
+ protected static Logger logger = Logger.getLogger(DocuDirCache.class);
+
+ /** Map of directories */
+ Map map = 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;
+
+ /** the root directory element */
+ public DigiDirectory rootDir = null;
+
+ /**
+ * Default constructor.
+ */
+ public DocuDirCache() {
+ map = new HashMap();
+ // add root directory
+ rootDir = new DigiDirectory(FileOps.getBaseDirs()[0], "", null);
+ map.put("", rootDir);
+ }
+
+ /**
+ * The number of directories in the cache.
+ *
+ * @return
+ */
+ public int size() {
+ return (map != null) ? map.size() : 0;
+ }
+
+ /**
+ * Add a DocuDirectory to the cache.
+ *
+ * @param newdir
+ */
+ public void put(DigiDirectory newdir) {
+ String s = newdir.getDLPath();
+ Object oldkey = map.put(s, newdir);
+ if (oldkey != null) {
+ logger.warn("Duplicate key in DocuDirCache.put -- overwritten!");
+ }
+ numFiles += newdir.getSize();
+ }
+
+ /**
+ * Add a directory to the cache and check its parents.
+ *
+ * @param newDir
+ */
+ public synchronized void putDir(DigiDirectory newDir) {
+ put(newDir);
+ }
+
+ /**
+ * Returns a DigiDirectory from the cache.
+ *
+ * @param path
+ * @return
+ */
+ public DigiDirectory get(String path) {
+ return (DigiDirectory) map.get(path);
+ }
+
+ /**
+ * Returns the DigiDirectory indicated by the pathname fn
.
+ *
+ * If fn
is a file then its parent directory is returned.
+ *
+ * @param fn
+ * digilib pathname
+ * @return
+ */
+ public DigiDirectory getDirectory(String pn) {
+ /*
+ * first, assume pn is a directory and look in the cache
+ */
+ DigiDirectory dd = (DigiDirectory) map.get(pn);
+ if (dd != null) {
+ // cache hit
+ hits++;
+ return dd;
+ } else {
+ /*
+ * maybe it's a file? try the parent directory
+ */
+ String dn = FileOps.dlParent(pn);
+ // try it in the cache
+ dd = (DigiDirectory) map.get(dn);
+ if (dd != null) {
+ // cache hit
+ hits++;
+ return dd;
+ } else {
+ // cache miss
+ misses++;
+ /*
+ * try to read from disk
+ */
+ File f = FileOps.getRealFile(pn);
+ /*
+ * is it a directory?
+ */
+ if (f.isDirectory()) {
+ dd = new DigiDirectory(f, pn, null);
+ // add to the cache
+ putDir(dd);
+ return dd;
+ } else {
+ /*
+ * then maybe a file? try the parent as a directory
+ */
+ File d = FileOps.getRealFile(dn);
+ if (d.isDirectory()) {
+ dd = new DigiDirectory(d, dn, null);
+ // add to the cache
+ putDir(dd);
+ return dd;
+ }
+ }
+ }
+ }
+ /*
+ * otherwise it's crap
+ */
+ return null;
+ }
+
+ /**
+ * Returns the DigiDirent with the pathname fn
and the index
+ * in
and the class fc
.
+ *
+ * If fn
is a file then the corresponding DocuDirent is
+ * returned and the index is ignored.
+ *
+ * @param pn
+ * digilib pathname
+ * @param in
+ * file index
+ * @param fc
+ * file class
+ * @return
+ */
+ public DigiDirent getFile(String pn, int in, int fc) {
+ // file number is 1-based, vector index is 0-based
+ int n = in - 1;
+ // get the (parent) directory
+ DigiDirectory dd = getDirectory(pn);
+ if (dd != null) {
+ // get the directory's name
+ String dn = dd.getDLPath();
+ if (dn.equals(pn)) {
+ // return the file at the index
+ return dd.get(n, fc);
+ } else {
+ // then the last part must be the filename
+ String fn = FileOps.dlName(pn);
+ return dd.get(fn);
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @return long
+ */
+ public long getNumFiles() {
+ return numFiles;
+ }
+
+ /**
+ * @return long
+ */
+ public long getHits() {
+ return hits;
+ }
+
+ /**
+ * @return long
+ */
+ public long getMisses() {
+ return misses;
+ }
+
+ /**
+ * @return Returns the rootDir.
+ */
+ public DigiDirectory getRootDir() {
+ return rootDir;
+ }
+ /**
+ * @param rootDir The rootDir to set.
+ */
+ public void setRootDir(DigiDirectory rootDir) {
+ this.rootDir = rootDir;
+ }
+}
diff -r 794a9f25f15c -r 6d2032b6121d servlet/src/digilib/io/FileOps.java
--- a/servlet/src/digilib/io/FileOps.java Thu Jan 17 15:25:46 2002 +0100
+++ b/servlet/src/digilib/io/FileOps.java Wed Nov 17 18:17:34 2004 +0100
@@ -1,188 +1,675 @@
-/* FileOps -- Utility class for file operations
-
- 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
-
-*/
+/*
+ * FileOps -- Utility class for file operations
+ *
+ * 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;
-import java.io.*;
-import java.util.*;
+import java.io.File;
+import java.io.FileFilter;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
-import digilib.*;
-
+import org.apache.log4j.Logger;
public class FileOps {
- private Utils util = null;
- public static String[] fileTypes = {
- "jpg", "image/jpeg",
- "jpeg", "image/jpeg",
- "png", "image/png",
- "gif", "image/gif",
- "tif", "image/tiff",
- "tiff", "image/tiff"};
+ private static Logger logger = Logger.getLogger(FileOps.class);
+
+ /**
+ * Array of file extensions and corresponding mime-types.
+ */
+ private static String[][] ft = { { "jpg", "image/jpeg" },
+ { "jpeg", "image/jpeg" }, { "jp2", "image/jp2" },
+ { "png", "image/png" }, { "gif", "image/gif" },
+ { "tif", "image/tiff" }, { "tiff", "image/tiff" },
+ { "txt", "text/plain" }, { "html", "text/html" },
+ { "htm", "text/html" }, { "xml", "text/xml" },
+ { "svg", "image/svg+xml" } };
+
+ public static Map fileTypes;
+
+ public static List imageExtensions;
+
+ public static List textExtensions;
+
+ public static List svgExtensions;
+
+ public static final int CLASS_NONE = -1;
+
+ public static final int CLASS_IMAGE = 0;
+
+ public static final int CLASS_TEXT = 1;
+
+ public static final int CLASS_SVG = 2;
+
+ public static final int NUM_CLASSES = 3;
- public FileOps() {
- util = new Utils();
- }
+ public static int[] fileClasses = {};
+
+ public static int[] fcIndexes = {};
+
+ public static final Integer HINT_BASEDIRS = new Integer(1);
+
+ public static final Integer HINT_FILEEXT = new Integer(2);
+
+ public static final Integer HINT_DIRS = new Integer(3);
+
+ public static File[] baseDirs = {};
+
+ public static DocuDirCache cache;
- public FileOps(Utils u) {
- util = u;
- }
+ /**
+ * static initializer for FileOps
+ */
+ static {
+ fileTypes = new HashMap();
+ imageExtensions = new ArrayList();
+ textExtensions = new ArrayList();
+ svgExtensions = new ArrayList();
+ // iterate through file types in ft and fill the Map and Lists
+ for (int i = 0; i < ft.length; i++) {
+ String ext = ft[i][0];
+ String mt = ft[i][1];
+ fileTypes.put(ext, mt);
+ if (classForMimetype(mt) == CLASS_IMAGE) {
+ imageExtensions.add(ext);
+ } else if (classForMimetype(mt) == CLASS_TEXT) {
+ textExtensions.add(ext);
+ } else if (classForMimetype(mt) == CLASS_SVG) {
+ svgExtensions.add(ext);
+ }
+ }
+ }
- public void setUtils(Utils u) {
- util = u;
- }
+ /** sets the array of actually used file classes */
+ public static void setFileClasses(int[] fc) {
+ fileClasses = fc;
+ fcIndexes = new int[NUM_CLASSES];
+ for (int i = 0; i < fc.length; i++) {
+ fcIndexes[fc[i]] = i;
+ }
+ }
+ /** returns the array of actually used file classes */
+ public static int[] getFileClasses() {
+ return fileClasses;
+ }
+
+ /** returns an element from the array of actally used file classes */
+ public static int getFileClass(int idx) {
+ try {
+ return fileClasses[idx];
+ } catch (Exception e) {
+ }
+ return CLASS_NONE;
+ }
- /**
- * get the mime type for a file format (by extension)
- */
- public static String mimeForFile(File f) {
- String fn = f.getName();
- for (int i = 0; i < fileTypes.length; i += 2) {
- if (fn.toLowerCase().endsWith(fileTypes[i])) {
- return fileTypes[i+1];
- }
- }
- return null;
- }
+ /** Returns the index number for the given file class.
+ * @param fc
+ * @return
+ */
+ public static int getFCindex(int fc) {
+ try {
+ return fcIndexes[fc];
+ } catch (Exception e) {
+ }
+ return -1;
+ }
+
+ /**
+ * returns the file class for a mime-type
+ *
+ * @param mt
+ * @return
+ */
+ public static int classForMimetype(String mt) {
+ if (mt == null) {
+ return CLASS_NONE;
+ }
+ if (mt.startsWith("image/svg")) {
+ return CLASS_SVG;
+ } else if (mt.startsWith("image")) {
+ return CLASS_IMAGE;
+ } else if (mt.startsWith("text")) {
+ return CLASS_TEXT;
+ }
+ return CLASS_NONE;
+ }
+
+ /**
+ * get the mime type for a file format (by extension)
+ */
+ public static String mimeForFile(File f) {
+ return (String) fileTypes.get(extname(f.getName().toLowerCase()));
+ }
+
+ /**
+ * get the file class for the filename (by extension)
+ *
+ * @param fn
+ * @return
+ */
+ public static int classForFilename(String fn) {
+ String mt = (String) fileTypes.get(extname(fn).toLowerCase());
+ return classForMimetype(mt);
+ }
- /**
- * get a filehandle for a file or directory name
- * returns File number n if fn is directory (starts with 1)
- */
- public File getFile(String fn, int n) throws FileOpException {
- util.dprintln(4, "getFile ("+fn+", "+n+")");
+ /**
+ * get the file class for the file (by extension)
+ *
+ * @param fn
+ * @return
+ */
+ public static int classForFile(File f) {
+ return classForFilename(f.getName());
+ }
+
+ public static Iterator getImageExtensionIterator() {
+ return imageExtensions.iterator();
+ }
+
+ public static Iterator getTextExtensionIterator() {
+ return textExtensions.iterator();
+ }
+
+ public static Iterator getSVGExtensionIterator() {
+ return svgExtensions.iterator();
+ }
+
+ /**
+ * convert a string with a list of pathnames into an array of strings using
+ * the system's path separator string
+ */
+ public static String[] pathToArray(String paths) {
+ // split list into directories
+ StringTokenizer dirs = new StringTokenizer(paths, File.pathSeparator);
+ int n = dirs.countTokens();
+ if (n < 1) {
+ return null;
+ }
+ // add directories into array
+ String[] pathArray = new String[n];
+ for (int i = 0; i < n; i++) {
+ String s = dirs.nextToken();
+ // make shure the dir name ends with a directory separator
+ if (s.endsWith(File.separator)) {
+ pathArray[i] = s;
+ } else {
+ pathArray[i] = s + File.separator;
+ }
+ }
+ return pathArray;
+ }
+
+ /**
+ * Extract the base of a file name (sans extension).
+ *
+ * Returns the filename without the extension. The extension is the part
+ * behind the last dot in the filename. If the filename has no dot the full
+ * file name is returned.
+ *
+ * @param fn
+ * @return
+ */
+ public static String basename(String fn) {
+ if (fn == null) {
+ return null;
+ }
+ int i = fn.lastIndexOf('.');
+ if (i > 0) {
+ return fn.substring(0, i);
+ }
+ return fn;
+ }
- File f = new File(fn);
- // if fn is a file name then return file
- if (f.isFile()) {
- return f;
- }
- // if fn is a directory name then open directory
- if (f.isDirectory()) {
- File[] fl = f.listFiles(new ImgFileFilter());
- Arrays.sort(fl);
- if ((n > 0) && (n <= fl.length)) {
- return fl[n - 1];
- }
- }
- throw new FileOpException("Unable to find file: "+fn);
- }
+ /**
+ * Extract the base of a file name (sans extension).
+ *
+ * Returns the filename without the extension. The extension is the part
+ * behind the last dot in the filename. If the filename has no dot the full
+ * file name is returned.
+ *
+ * @param f
+ * @return
+ */
+ public static String basename(File f) {
+ if (f == null) {
+ return null;
+ }
+ return basename(f.getName());
+ }
+
+ /**
+ * Extract the extension of a file name.
+ *
+ * Returns the extension of a file name. The extension is the part behind
+ * the last dot in the filename. If the filename has no dot the empty string
+ * is returned.
+ *
+ * @param fn
+ * @return
+ */
+ public static String extname(String fn) {
+ if (fn == null) {
+ return null;
+ }
+ int i = fn.lastIndexOf('.');
+ if (i > 0) {
+ return fn.substring(i + 1);
+ }
+ return "";
+ }
- /**
- * get the number of files in a directory
- * (almost the same as getFile)
- * returns 0 in case of problems
- */
- public int getNumFiles(String fn) throws FileOpException {
- util.dprintln(4, "getNumFiles ("+fn+")");
+ /**
+ * Extract the parent directory of a (digilib) path name.
+ *
+ * Returns the parent directory of a path name. The parent is the part
+ * before the last slash in the path name. If the path name has no slash the
+ * empty string is returned.
+ *
+ * @param fn
+ * @return
+ */
+ public static String dlParent(String fn) {
+ if (fn == null) {
+ return null;
+ }
+ int i = fn.lastIndexOf('/');
+ if (i > 0) {
+ return fn.substring(0, i);
+ }
+ return "";
+ }
- File f = new File(fn);
- // if fn is a file name then return 1
- if (f.isFile()) {
- return 1;
- }
- // if fn is a directory name then return the number of files
- if (f.isDirectory()) {
- return f.listFiles(new ImgFileFilter()).length;
- }
- // then fn must be something strange...
- return 0;
- }
+ /**
+ * Extract the dir/file name of a (digilib) path name.
+ *
+ * The file/dir name is the part after the last slash in the path name. If
+ * the path name has no slash the same string is returned.
+ *
+ * @param path
+ * @return
+ */
+ public static String dlName(String path) {
+ if (path == null) {
+ return null;
+ }
+ int i = path.lastIndexOf('/');
+ if (i > 0) {
+ return path.substring(i+1);
+ }
+ return path;
+ }
+ /**
+ * Normalize a path name.
+ *
+ * Removes leading and trailing slashes. Returns null if there is other
+ * unwanted stuff in the path name.
+ *
+ * @param pathname
+ * @return
+ */
+ public static String normalName(String pathname) {
+ if (pathname == null) {
+ return null;
+ }
+ // upper-dir references are unwanted
+ if (pathname.indexOf("../") >= 0) {
+ return null;
+ }
+ int a = 0;
+ int e = pathname.length() - 1;
+ if (e < 0) {
+ return pathname;
+ }
+ // leading and trailing "/" are removed
+ while ((a <= e) && (pathname.charAt(a) == '/')) {
+ a++;
+ }
+ while ((a < e) && (pathname.charAt(e) == '/')) {
+ e--;
+ }
+ return pathname.substring(a, e + 1);
+ }
- /**
- * get a filehandle for a file or directory name out of a list
- * dirs is a list of base directories, fn is the appended file/dirname
- * searches dirs until fn exists (backwards if fwd is false)
- * returns File number n if fn is directory (starts with 1)
- */
- public File getFileVariant(String[] dirs, String fn, int n, boolean fwd) throws FileOpException {
- util.dprintln(4, "getVariantFile ("+dirs+", "+fn+", "+n+")");
+ public static StringTokenizer dlPathIterator(String path) {
+ return new StringTokenizer(path, "/");
+ }
+
+
+ /**
+ * FileFilter for general files
+ */
+ static class ReadableFileFilter implements FileFilter {
+
+ public boolean accept(File f) {
+ return f.canRead();
+ }
+ }
+
+ /**
+ * FileFilter for image types (helper class for getFile)
+ */
+ static class ImageFileFilter implements FileFilter {
+
+ public boolean accept(File f) {
+ return (classForFilename(f.getName()) == CLASS_IMAGE);
+ }
+ }
+
+ /**
+ * FileFilter for text types (helper class for getFile)
+ */
+ static class TextFileFilter implements FileFilter {
+
+ public boolean accept(File f) {
+ return (classForFilename(f.getName()) == CLASS_TEXT);
+ }
+ }
+
+ /**
+ * FileFilter for svg types (helper class for getFile).
+ *
+ */
+ static class SVGFileFilter implements FileFilter {
- File f = null;
- int start = 0;
- int inc = 1;
- int end = dirs.length;
- if (fwd == false) {
- start = dirs.length - 1;
- inc = -1;
- end = 0;
- }
+ public boolean accept(File f) {
+ return (classForFilename(f.getName()) == CLASS_SVG);
+ }
+ }
+
+ /**
+ * Factory for FileFilters (image or text).
+ *
+ * @param fileClass
+ * @return
+ */
+ public static FileFilter filterForClass(int fileClass) {
+ if (fileClass == CLASS_IMAGE) {
+ return new ImageFileFilter();
+ }
+ if (fileClass == CLASS_TEXT) {
+ return new TextFileFilter();
+ }
+ if (fileClass == CLASS_SVG) {
+ return new SVGFileFilter();
+ }
+ return null;
+ }
- for (int i = start; i != end; i += inc) {
- try {
- f = getFile(dirs[i]+fn, n);
- } catch (FileOpException e) {
- f = null;
- }
- if (f != null) {
- return f;
- }
- }
- throw new FileOpException("Unable to find file: "+fn);
- }
+ /**
+ * Factory for DocuDirents based on file class.
+ *
+ * Returns an ImageFileset, TextFile or SVGFile.
+ *
+ * @param fileClass
+ * @param file
+ * @param parent
+ * @param hints
+ * optional additional parameters
+ * @return
+ */
+ public static DigiDirent fileForClass(int fileClass, File file,
+ DigiDirectory parent, Map hints) {
+ // what class of file do we have?
+ if (fileClass == CLASS_IMAGE) {
+ // image file
+ return new ImageFileset(file, parent, hints);
+ } else if (fileClass == CLASS_TEXT) {
+ // text file
+ return new TextFile(file, parent);
+ } else if (fileClass == CLASS_SVG) {
+ // text file
+ return new SVGFile(file, parent);
+ }
+ // anything else is a generic dir or file
+ if (file.isDirectory()) {
+ return getCachedDirectory(file, null, parent);
+ }
+ return new DigiDirent(file.getName(), parent);
+ }
+
+ /**
+ * Filters a list of Files through a FileFilter.
+ *
+ * @param files
+ * @param filter
+ * @return
+ */
+ public static File[] listFiles(File[] files, FileFilter filter) {
+ if (files == null) {
+ return null;
+ }
+ File[] ff = new File[files.length];
+ int ffi = 0;
+ for (int i = 0; i < files.length; i++) {
+ if (filter.accept(files[i])) {
+ ff[ffi] = files[i];
+ ffi++;
+ }
+ }
+ File[] fff = new File[ffi];
+ System.arraycopy(ff, 0, fff, 0, ffi);
+ return fff;
+ }
- /**
- * get the number of files in a directory
- * (almost the same as getFileVariant)
- * returns 0 in case of problems
- */
- public int getNumFilesVariant(String[] dirs, String fn, boolean fwd) throws FileOpException {
- util.dprintln(4, "getNumFilesVariant ("+dirs+", "+fn+")");
+ /**
+ * Returns the closest matching file out of an array.
+ *
+ * Compares the files sans extensions if no direct match is found. Returns
+ * null if no match is found.
+ *
+ * @param fn
+ * @param files
+ * @return
+ */
+ public static File findFile(File fn, File[] files) {
+ // try the same filename as the original
+ int fileIdx = Arrays.binarySearch(files, fn);
+ if (fileIdx >= 0) {
+ return files[fileIdx];
+ } else {
+ // try closest matches without extension
+ String fb = FileOps.basename(fn);
+ fileIdx = -fileIdx - 1;
+ if ((fileIdx < files.length)
+ && (FileOps.basename(files[fileIdx]).equals(fb))) {
+ // idx ok
+ return files[fileIdx];
+ } else if ((fileIdx > 0)
+ && (FileOps.basename(files[fileIdx - 1]).equals(fb))) {
+ // idx-1 ok
+ return files[fileIdx - 1];
+ } else if ((fileIdx + 1 < files.length)
+ && (FileOps.basename(files[fileIdx + 1]).equals(fb))) {
+ // idx+1 ok
+ return files[fileIdx + 1];
+ }
+ }
+ // unknown
+ return null;
+ }
- int nf = 0;
- int start = 0;
- int inc = 1;
- int end = dirs.length;
- if (fwd == false) {
- start = dirs.length - 1;
- inc = -1;
- end = 0;
- }
+ /**
+ * Returns the closest matching file out of an array.
+ *
+ * Compares the files sans extensions if no direct match is found. Returns
+ * null if no match is found.
+ *
+ * @param fn
+ * @param files
+ * @return
+ */
+ public static String findFilename(String fn, String[] files) {
+ // try the same filename as the original
+ int fileIdx = Arrays.binarySearch(files, fn);
+ if (fileIdx >= 0) {
+ return files[fileIdx];
+ } else {
+ // try closest matches without extension
+ String fb = FileOps.basename(fn);
+ fileIdx = -fileIdx - 1;
+ if ((fileIdx < files.length)
+ && (FileOps.basename(files[fileIdx]).equals(fb))) {
+ // idx ok
+ return files[fileIdx];
+ } else if ((fileIdx > 0)
+ && (FileOps.basename(files[fileIdx - 1]).equals(fb))) {
+ // idx-1 ok
+ return files[fileIdx - 1];
+ } else if ((fileIdx + 1 < files.length)
+ && (FileOps.basename(files[fileIdx + 1]).equals(fb))) {
+ // idx+1 ok
+ return files[fileIdx + 1];
+ }
+ }
+ // unknown
+ return null;
+ }
+ /**
+ * Returns a File for a base directory and a digilib-path.
+ *
+ * @param basedir
+ * @param dlpath
+ * @return
+ */
+ public static File getRealFile(File basedir, String dlpath) {
+ // does this work on all platforms??
+ return new File(basedir, dlpath);
+ }
+
+ /** Returns a File for a digilib-path.
+ *
+ * The file is assumed to be in the first base directory.
+ *
+ * @param dlpath
+ * @return
+ */
+ public static File getRealFile(String dlpath) {
+ // does this work on all platforms??
+ return new File(baseDirs[0], dlpath);
+ }
- for (int i = start; i != end; i += inc) {
- try {
- nf = getNumFiles(dirs[i]+fn);
- } catch (FileOpException e) {
- nf = 0;
- }
- if (nf > 0) {
- return nf;
- }
- }
- return 0;
- }
+ /**
+ * Creates a new empty hints Map.
+ *
+ * @return
+ */
+ public static Map newHints() {
+ Map m = new HashMap();
+ return m;
+ }
+
+ /**
+ * Creates a new hints Map with the given first element.
+ *
+ * @param type
+ * @param value
+ * @return
+ */
+ public static Map newHints(Integer type, Object value) {
+ Map m = new HashMap();
+ if (type != null) {
+ m.put(type, value);
+ }
+ return m;
+ }
+
+ /**
+ * @return Returns the baseDirs.
+ */
+ public static File[] getBaseDirs() {
+ return baseDirs;
+ }
+
+ /**
+ * @param baseDirs
+ * The baseDirs to set.
+ */
+ public static void setBaseDirs(File[] baseDirs) {
+ FileOps.baseDirs = baseDirs;
+ }
- /**
- * FileFilter for image types (helper class for getFile)
- */
- private class ImgFileFilter implements FileFilter {
-
- public boolean accept(File f) {
- if (f.isFile()) {
- return (mimeForFile(f) != null);
- } else {
- return false;
- }
- }
- }
-
+
+ /**
+ * Returns a DigiDirectory instance that is guaranteed to be unique in the
+ * cache.
+ *
+ * @param dir
+ * @param parent
+ * @return
+ */
+ public static DigiDirectory getCachedDirectory(File dir, String dlpath, DigiDirectory parent) {
+ if (dir == null) {
+ dir = FileOps.getRealFile(dlpath);
+ }
+ DigiDirectory dd = null;
+ if (parent == null) {
+ // create a new parent by starting at the root
+ StringBuffer ps = new StringBuffer();
+ DigiDirectory p = cache.getRootDir();
+ // walk the path
+ for (StringTokenizer i = dlPathIterator(dlpath); i.hasMoreTokens();) {
+ p.check();
+ String dn = i.nextToken();
+ ps.append("/");
+ ps.append(dn);
+ DigiDirectory d = cache.get(dn);
+ if (d == null) {
+ dd = new DigiDirectory(FileOps.getRealFile(dn), ps.toString(), p);
+ }
+ if (d.getParent() != p) {
+ logger.warn("digidirectory "+d.getDLPath()+" has wrong parent: "+p.getDLPath());
+ }
+ p = d;
+ }
+ } else {
+ if (dlpath == null) {
+ dlpath = parent.getDLPath() + "/" + dir.getName();
+ }
+ dd = cache.get(dlpath);
+ if (dd == null) {
+ dd = new DigiDirectory(dir, dlpath, parent);
+ } else {
+ logger.debug("reusing directory:" + dlpath);
+ }
+ }
+ return dd;
+ }
+
+ /**
+ * @return Returns the cache.
+ */
+ public static DocuDirCache getCache() {
+ return cache;
+ }
+ /**
+ * @param cache The cache to set.
+ */
+ public static void setCache(DocuDirCache cache) {
+ FileOps.cache = cache;
+ }
}
diff -r 794a9f25f15c -r 6d2032b6121d servlet/src/digilib/io/ImageFile.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/io/ImageFile.java Wed Nov 17 18:17:34 2004 +0100
@@ -0,0 +1,99 @@
+/* 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 25.02.2003
+ */
+
+package digilib.io;
+
+import java.io.File;
+import java.io.IOException;
+
+import digilib.image.ImageOps;
+import digilib.image.ImageSize;
+
+/**
+ * @author casties
+ */
+public class ImageFile extends File {
+
+ private static final long serialVersionUID = 1L;
+
+ /** file mime-type */
+ private String mimetype = null;
+
+ /** image size in pixels */
+ private ImageSize pixelSize = null;
+
+ /**
+ * @param pathname
+ */
+ public ImageFile(String pathname) {
+ super(pathname);
+ }
+
+ /**
+ * @param file
+ */
+ public ImageFile(File file) {
+ super(file.getPath());
+ }
+
+ /**
+ * @return ImageSize
+ */
+ public ImageSize getSize() {
+ return pixelSize;
+ }
+
+ /**
+ * Sets the imageSize.
+ * @param imageSize The imageSize to set
+ */
+ public void setSize(ImageSize imageSize) {
+ this.pixelSize = imageSize;
+ }
+
+ /**
+ * @return String
+ */
+ public String getMimetype() {
+ return mimetype;
+ }
+
+ /**
+ * Sets the mimetype.
+ * @param mimetype The mimetype to set
+ */
+ public void setMimetype(String filetype) {
+ this.mimetype = filetype;
+ }
+
+ /**
+ * Checks image size.
+ * @throws IOException
+ *
+ */
+ public void check() throws IOException {
+ if (pixelSize != null) {
+ return;
+ }
+ ImageOps.checkFile(this);
+ }
+
+}
diff -r 794a9f25f15c -r 6d2032b6121d servlet/src/digilib/io/ImageFileset.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/io/ImageFileset.java Wed Nov 17 18:17:34 2004 +0100
@@ -0,0 +1,326 @@
+/* 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.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+
+import digilib.image.ImageOps;
+import digilib.image.ImageSize;
+
+/**
+ * @author casties
+ */
+public class ImageFileset extends DigiDirent {
+
+ /** this is an image file */
+ protected static int FILE_CLASS = FileOps.CLASS_IMAGE;
+
+ /** list of files (ImageFile) */
+ private List files;
+
+ /** resolution of the biggest image (DPI) */
+ private float resX = 0;
+
+ /** resolution of the biggest image (DPI) */
+ private float resY = 0;
+
+ /**
+ * Constructor with a file and hints.
+ *
+ * The hints are expected to contain 'basedirs' and 'scaledfilext' keys.
+ *
+ * @param file
+ * @param hints
+ */
+ public ImageFileset(File file, DigiDirectory parent, Map hints) {
+ super(file.getName(), parent);
+ files = new ArrayList(FileOps.getBaseDirs().length);
+ fill(file, hints);
+ }
+
+ /**
+ * Gets the default File.
+ *
+ */
+ public ImageFile getFile() {
+ return (files != null) ? (ImageFile) files.get(0) : null;
+ }
+
+ /**
+ * Get the ImageFile at the index.
+ *
+ *
+ * @param index
+ * @return
+ */
+ public ImageFile get(int index) {
+ return (files != null) ? (ImageFile) files.get(index) : null;
+ }
+
+ /**
+ * 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 i = getHiresIterator(); i.hasNext();) {
+ ImageFile f = (ImageFile) i.next();
+ try {
+ ImageOps.checkFile(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 i = getLoresIterator(); i.hasPrevious();) {
+ ImageFile f = (ImageFile) i.previous();
+ try {
+ ImageOps.checkFile(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 (ImageFile) files.get(0);
+ }
+
+ /**
+ * Returns the biggest ImageFile in the set.
+ *
+ *
+ * @return
+ */
+ public ImageFile getSmallest() {
+ return (ImageFile) files.get(files.size() - 1);
+ }
+
+ /**
+ * Get an Iterator for this Fileset starting at the highest resolution
+ * images.
+ *
+ *
+ * @return
+ */
+ public ListIterator getHiresIterator() {
+ return files.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 getLoresIterator() {
+ return files.listIterator(files.size());
+ }
+
+ /**
+ * Fill the ImageFileset with files from different base directories.
+ *
+ *
+ * @param dirs
+ * list of base directories
+ * @param imf
+ * file (from first base dir)
+ * @param hints
+ *
+ */
+ void fill(File imf, Map hints) {
+ File[][] scaledirs = (File[][]) hints.get(FileOps.HINT_BASEDIRS);
+ File[] bd = FileOps.getBaseDirs();
+ int nb = bd.length;
+ if (scaledirs == null) {
+ // read all scaled directories
+ scaledirs = new File[nb][];
+ for (int i = 1; i < nb; i++) {
+ // check basedir + digilib path
+ File d = FileOps.getRealFile(bd[i], parent.getDLPath());
+ scaledirs[i] = d.listFiles();
+ }
+ hints.put(FileOps.HINT_BASEDIRS, scaledirs);
+ }
+ // add the first ImageFile to the ImageFileset
+ files.add(new ImageFile(imf));
+ // iterate the remaining base directories
+ for (int dirIdx = 1; dirIdx < nb; dirIdx++) {
+ if (scaledirs[dirIdx] == null) {
+ continue;
+ }
+ // find the file in the directory
+ File fn = FileOps.findFile(imf, scaledirs[dirIdx]);
+ if (fn == null) {
+ continue;
+ }
+ if (FileOps.classForFile(fn) == FileOps.CLASS_IMAGE) {
+ // add to the fileset
+ files.add(new ImageFile(fn));
+ }
+ }
+ }
+
+ /**
+ * Reads metadata and sets resolution in resX and resY.
+ *
+ */
+ public void readMeta() {
+ if (isMetaRead) {
+ return;
+ }
+ // read the metadata file
+ super.readMeta();
+ if (meta == null) {
+ // try directory metadata
+ meta = parent.getMeta();
+ if (meta == null) {
+ // no metadata available
+ isMetaRead = true;
+ return;
+ }
+ }
+ isMetaRead = true;
+ String s;
+ 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 (meta.containsKey("original-dpi")) {
+ try {
+ dpi = Float.parseFloat((String) meta.get("original-dpi"));
+ } catch (NumberFormatException e) {
+ }
+ if (dpi != 0) {
+ resX = dpi;
+ resY = dpi;
+ return;
+ }
+ }
+ // DPI-X and DPI-Y
+ if (meta.containsKey("original-dpi-x")
+ && meta.containsKey("original-dpi-y")) {
+ try {
+ dpix = Float.parseFloat((String) meta.get("original-dpi-x"));
+ dpiy = Float.parseFloat((String) meta.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 (meta.containsKey("original-size-x")
+ && meta.containsKey("original-size-y")
+ && meta.containsKey("original-pixel-x")
+ && meta.containsKey("original-pixel-y")) {
+ try {
+ sizex = Float.parseFloat((String) meta.get("original-size-x"));
+ sizey = Float.parseFloat((String) meta.get("original-size-y"));
+ pixx = Float.parseFloat((String) meta.get("original-pixel-x"));
+ pixy = Float.parseFloat((String) meta.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;
+ }
+ }
+ }
+
+ /**
+ * Returns the aspect ratio of the images.
+ *
+ * @return
+ */
+ public float getAspect() {
+ for (Iterator i = files.iterator(); i.hasNext();) {
+ ImageFile f = (ImageFile) i.next();
+ ImageSize s = f.getSize();
+ if (s != null) {
+ return s.getAspect();
+ }
+ }
+ return 0f;
+ }
+
+ /**
+ * @return
+ */
+ public float getResX() {
+ return resX;
+ }
+
+ /**
+ * @return
+ */
+ public float getResY() {
+ return resY;
+ }
+
+}
\ No newline at end of file
diff -r 794a9f25f15c -r 6d2032b6121d servlet/src/digilib/io/SVGFile.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/io/SVGFile.java Wed Nov 17 18:17:34 2004 +0100
@@ -0,0 +1,71 @@
+/* SVGFile -- Class for SVG files
+
+ 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 25.11.2003 by casties
+ *
+ */
+package digilib.io;
+
+import java.io.File;
+
+
+/** Class for SVG files.
+ *
+ * @author casties
+ *
+ */
+public class SVGFile extends DigiDirent {
+ /** this is a SVG file */
+ protected static final int FILE_CLASS = FileOps.CLASS_SVG;
+
+ protected File file;
+
+ /**
+ * @param name
+ * @param parent
+ * @param file
+ */
+ public SVGFile(File file, DigiDirectory parent) {
+ super(file.getName(), parent);
+ this.file = file;
+ }
+
+ /**
+ * @param name
+ * @param parent
+ */
+ public SVGFile(String name, File file, DigiDirectory parent) {
+ super(name, parent);
+ this.file = file;
+ }
+
+ /**
+ * @return Returns the file.
+ */
+ public File getFile() {
+ return file;
+ }
+
+ /**
+ * @param file The file to set.
+ */
+ public void setFile(File file) {
+ this.file = file;
+ }
+
+}
diff -r 794a9f25f15c -r 6d2032b6121d servlet/src/digilib/io/TextFile.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/io/TextFile.java Wed Nov 17 18:17:34 2004 +0100
@@ -0,0 +1,70 @@
+/* TextFile.java -- Class for text files
+
+ 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;
+
+/**
+ * Class for text files.
+ *
+ * @author casties
+ *
+ */
+public class TextFile extends DigiDirent {
+ /** this is a text file */
+ protected static final int fileClass = FileOps.CLASS_TEXT;
+
+ protected File file;
+
+ /**
+ * @param name
+ * @param parent
+ * @param file
+ */
+ public TextFile(File file, DigiDirectory parent) {
+ super(file.getName(), parent);
+ this.file = file;
+ }
+
+ /**
+ * @param name
+ * @param parent
+ */
+ public TextFile(String name, File file, DigiDirectory parent) {
+ super(name, parent);
+ this.file = file;
+ }
+
+ /**
+ * @return Returns the file.
+ */
+ public File getFile() {
+ return file;
+ }
+
+ /**
+ * @param file The file to set.
+ */
+ public void setFile(File file) {
+ this.file = file;
+ }
+}
diff -r 794a9f25f15c -r 6d2032b6121d servlet/src/digilib/servlet/DigilibConfiguration.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/servlet/DigilibConfiguration.java Wed Nov 17 18:17:34 2004 +0100
@@ -0,0 +1,257 @@
+/*
+ * DigilibConfiguration -- Holding all parameters for digilib servlet.
+ *
+ * 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.servlet;
+
+import java.io.File;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+
+import org.apache.log4j.BasicConfigurator;
+import org.apache.log4j.Logger;
+
+import digilib.image.DocuImage;
+import digilib.image.DocuImageImpl;
+import digilib.io.FileOps;
+import digilib.io.XMLListLoader;
+
+/**
+ * Class to hold the digilib servlet configuration parameters. The parameters
+ * can be read from the digilib-config file and be passed to other servlets or
+ * beans.
errorImgFileName: image file to send in case of error.
+ * denyImgFileName: image file to send if access is denied.
baseDirs:
+ * array of base directories in order of preference (prescaled versions first).
+ *
useAuth: use authentication information.
authConfPath:
+ * authentication configuration file.
...
+ *
+ * @author casties
+ *
+ */
+public class DigilibConfiguration extends ParameterMap {
+
+ private static final long serialVersionUID = -6630487070791637120L;
+
+ /** DocuImage class instance */
+ private Class docuImageClass = null;
+
+ /** Log4J logger */
+ private Logger logger = Logger.getLogger("digilib.config");
+
+ /**
+ * Default constructor defines all parameters and their default values.
+ *
+ */
+ public DigilibConfiguration() {
+ // create HashMap(20)
+ super(20);
+ // we start with a default logger config
+ BasicConfigurator.configure();
+
+ /*
+ * Definition of parameters and default values. System parameters that
+ * are not read from config file have a type 's'.
+ */
+
+ // digilib servlet version
+ newParameter(
+ "servlet.version",
+ digilib.servlet.Scaler.dlVersion,
+ null,
+ 's');
+ // configuration file location
+ newParameter("servlet.config.file", null, null, 's');
+ // DocuDirCache instance
+ newParameter("servlet.dir.cache", null, null, 's');
+ // DocuImage class instance
+ newParameter(
+ "servlet.docuimage.class",
+ digilib.image.JAIDocuImage.class,
+ null,
+ 's');
+ // AuthOps instance for authentication
+ newParameter("servlet.auth.op", null, null, 's');
+
+ /*
+ * parameters that can be read from config file have a type 'f'
+ */
+
+ // image file to send in case of error
+ newParameter(
+ "error-image",
+ new File("/docuserver/images/icons/scalerror.gif"),
+ null,
+ 'f');
+ // image file to send if access is denied
+ newParameter(
+ "denied-image",
+ new File("/docuserver/images/icons/denied.gif"),
+ null,
+ 'f');
+ // base directories in order of preference (prescaled versions last)
+ String[] bd = { "/docuserver/images", "/docuserver/scaled/small" };
+ newParameter("basedir-list", bd, null, 'f');
+ // use authentication information
+ newParameter("use-authorization", Boolean.FALSE, null, 'f');
+ // authentication configuration file
+ newParameter("auth-file", new File("digilib-auth.xml"), null, 'f');
+ // sending image files as-is allowed
+ newParameter("sendfile-allowed", Boolean.TRUE, null, 'f');
+ // Debug level
+ newParameter("debug-level", new Integer(5), null, 'f');
+ // Type of DocuImage instance
+ newParameter(
+ "docuimage-class",
+ "digilib.image.JAIDocuImage",
+ null,
+ 'f');
+ // part of URL used to indicate authorized access
+ newParameter("auth-url-path", "authenticated/", null, 'f');
+ // degree of subsampling on image load
+ newParameter("subsample-minimum", new Float(2f), null, 'f');
+ // default scaling quality
+ newParameter("default-quality", new Integer(1), null, 'f');
+ // use mapping file to translate paths
+ newParameter("use-mapping", Boolean.FALSE, null, 'f');
+ // mapping file location
+ newParameter("mapping-file", new File("digilib-map.xml"), null, 'f');
+ // log4j config file location
+ newParameter("log-config-file", new File("log4j-config.xml"), null, 'f');
+ // maximum destination image size (0 means no limit)
+ newParameter("max-image-size", new Integer(0), null, 'f');
+ // use safe (but slower) directory indexing
+ newParameter("safe-dir-index", Boolean.FALSE, null, 'f');
+ // number of working threads
+ newParameter("worker-threads", new Integer(1), null, 'f');
+
+ }
+
+ /**
+ * Constructor taking a ServletConfig. Reads the config file location from
+ * an init parameter and loads the config file. Calls readConfig()
.
+ *
+ * @see readConfig()
+ */
+ public DigilibConfiguration(ServletConfig c) throws Exception {
+ this();
+ readConfig(c);
+ }
+
+ /**
+ * read parameter list from the XML file in init parameter "config-file"
+ */
+ public void readConfig(ServletConfig c) throws Exception {
+
+ /*
+ * Get config file name. The file name is first looked for as an init
+ * parameter, then in a fixed location in the webapp.
+ */
+ if (c == null) {
+ // no config no file...
+ return;
+ }
+ String fn = c.getInitParameter("config-file");
+ if (fn == null) {
+ fn = ServletOps.getConfigFile("digilib-config.xml", c);
+ if (fn == null) {
+ logger.fatal("readConfig: no param config-file");
+ throw new ServletException("ERROR: no digilib config file!");
+ }
+ }
+ File f = new File(fn);
+ // setup config file list reader
+ XMLListLoader lilo =
+ new XMLListLoader("digilib-config", "parameter", "name", "value");
+ // read config file into HashMap
+ Map confTable = lilo.loadURL(f.toURL().toString());
+
+ // set config file path parameter
+ setValue("servlet.config.file", f.getCanonicalPath());
+
+ /*
+ * read parameters
+ */
+
+ for (Iterator i = confTable.keySet().iterator(); i.hasNext();) {
+ String key = (String) i.next();
+ String val = (String) confTable.get(key);
+ Parameter p = get(key);
+ if (p != null) {
+ if (p.getType() == 's') {
+ // type 's' Parameters are not overwritten.
+ continue;
+ }
+ if (!p.setValueFromString(val)) {
+ /*
+ * automatic conversion failed -- try special cases
+ */
+
+ // basedir-list
+ if (key.equals("basedir-list")) {
+ // split list into directories
+ String[] sa = FileOps.pathToArray(val);
+ if (sa != null) {
+ p.setValue(sa);
+ }
+ }
+ }
+ } else {
+ // parameter unknown -- just add
+ newParameter(key, null, val, 'f');
+ }
+ }
+
+ }
+
+ /**
+ * Creates a new DocuImage instance.
+ *
+ * The type of DocuImage is specified by docuImageType.
+ *
+ * @return DocuImage
+ */
+ public DocuImage getDocuImageInstance() {
+ DocuImageImpl di = null;
+ try {
+ if (docuImageClass == null) {
+ docuImageClass = Class.forName(getAsString("docuimage-class"));
+ }
+ di = (DocuImageImpl) docuImageClass.newInstance();
+ } catch (Exception e) {
+ }
+ return di;
+ }
+
+ /**
+ * @return Returns the docuImageClass.
+ */
+ public Class getDocuImageClass() {
+ return docuImageClass;
+ }
+ /**
+ * @param docuImageClass The docuImageClass to set.
+ */
+ public void setDocuImageClass(Class docuImageClass) {
+ this.docuImageClass = docuImageClass;
+ }
+}
diff -r 794a9f25f15c -r 6d2032b6121d servlet/src/digilib/servlet/DocumentBean.java
--- a/servlet/src/digilib/servlet/DocumentBean.java Thu Jan 17 15:25:46 2002 +0100
+++ b/servlet/src/digilib/servlet/DocumentBean.java Wed Nov 17 18:17:34 2004 +0100
@@ -1,198 +1,296 @@
-/* DocumentBean -- Access control bean for JSP
-
- 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
-
-*/
+/*
+ * DocumentBean -- Access control bean for JSP
+ *
+ * Digital Image Library servlet components
+ *
+ * Copyright (C) 2001, 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.servlet;
+import java.util.List;
-import java.util.*;
-import javax.servlet.*;
-import javax.servlet.http.*;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.log4j.Logger;
-import digilib.*;
-import digilib.io.*;
-import digilib.auth.*;
+import digilib.auth.AuthOpException;
+import digilib.auth.AuthOps;
+import digilib.io.DigiDirectory;
+import digilib.io.DocuDirCache;
+import digilib.io.FileOps;
+import digilib.io.ImageFileset;
-public class DocumentBean implements AuthOps {
+public class DocumentBean {
+
+ // general logger
+ private static Logger logger = Logger.getLogger("digilib.docubean");
+
+ // AuthOps object to check authorization
+ private AuthOps authOp;
- // Utils object for logging
- private Utils util = new Utils(5);
- // AuthOps object to check authorization
- private AuthOps authOp;
- // FileOps object
- private FileOps fileOp = new FileOps(util);
+ // use authorization database
+ private boolean useAuthentication = true;
+
+ // path to add for authenticated access
+ private String authURLPath = "";
+
+ // DocuDirCache
+ private DocuDirCache dirCache = null;
+
+ // DigilibConfiguration object
+ private DigilibConfiguration dlConfig;
+
+ // DigilibRequest object
+ private DigilibRequest dlRequest = null;
- // base directories in order of preference (prescaled versions first)
- private String[] baseDirs = {"/docuserver/scaled/small", "/docuserver/images", "/docuserver/scans/quellen"};
- // part of URL path to prepend for authenticated access
- private String authURLpath = "authenticated/";
+ /**
+ * Constructor for DocumentBean.
+ */
+ public DocumentBean() {
+ super();
+ }
-
- public DocumentBean() {
- }
+ public DocumentBean(ServletConfig conf) {
+ try {
+ setConfig(conf);
+ } catch (Exception e) {
+ logger.fatal("ERROR: Unable to read config: ", e);
+ }
+ }
- public void setConfig(ServletConfig conf) throws ServletException {
- util.dprintln(10, "setConfig");
- // servletOps takes a ServletConfig to get the config file name
- ServletOps servletOp = new ServletOps(util, conf);
- /**
- * basedir-list : List of document directories
- */
- String bl = servletOp.tryToGetInitParam("basedir-list", null);
- if ((bl != null)&&(bl.length() > 0)) {
- // split list into directories
- StringTokenizer dirs = new StringTokenizer(bl, ":");
- int n = dirs.countTokens();
- if (n > 0) {
- // add directories into array
- baseDirs = new String[n];
- for (int i = 0; i < n; i++) {
- baseDirs[i] = dirs.nextToken();
- }
- }
- util.dprintln(3, "basedir-list: "+bl);
- }
- /**
- * auth-url-path : part of URL to indicate authenticated access
- */
- String au = servletOp.tryToGetInitParam("auth-url-path", null);
- if ((au != null)&&(au.length() > 0)) {
- authURLpath = au;
- util.dprintln(3, "auth-url-path: "+au);
- }
- /**
- * authentication
- */
- try {
- // DB version
- //private AuthOps authOp = new DBAuthOpsImpl(util);
- // XML version
- String cp = servletOp.tryToGetInitParam("auth-file", "/docuserver/www/digitallibrary/WEB-INF/digilib-auth.xml");
- util.dprintln(3, "auth-file: "+cp);
- authOp = new XMLAuthOps(util, cp);
- } catch (AuthOpException e) {
- throw new ServletException(e);
- }
- }
+ public void setConfig(ServletConfig conf) throws ServletException {
+ logger.debug("setConfig");
+ // get our ServletContext
+ ServletContext context = conf.getServletContext();
+ // see if there is a Configuration instance
+ dlConfig = (DigilibConfiguration) context
+ .getAttribute("digilib.servlet.configuration");
+ if (dlConfig == null) {
+ // create new Configuration
+ throw new ServletException("ERROR: No configuration!");
+ }
+
+ // get cache
+ dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache");
+
+ /*
+ * authentication
+ */
+ useAuthentication = dlConfig.getAsBoolean("use-authorization");
+ authOp = (AuthOps) dlConfig.getValue("servlet.auth.op");
+ authURLPath = dlConfig.getAsString("auth-url-path");
+ if (useAuthentication && (authOp == null)) {
+ throw new ServletException(
+ "ERROR: use-authorization configured but no AuthOp!");
+ }
+ }
+
+ /**
+ * check if the request must be authorized to access filepath
+ */
+ public boolean isAuthRequired(DigilibRequest request)
+ throws AuthOpException {
+ logger.debug("isAuthRequired");
+ return useAuthentication ? authOp.isAuthRequired(request) : false;
+ }
+
+ /**
+ * check if the request is allowed to access filepath
+ */
+ public boolean isAuthorized(DigilibRequest request) throws AuthOpException {
+ logger.debug("isAuthorized");
+ return useAuthentication ? authOp.isAuthorized(request) : true;
+ }
+
+ /**
+ * return a list of authorization roles needed for request to access the
+ * specified path
+ */
+ public List rolesForPath(DigilibRequest request) throws AuthOpException {
+ logger.debug("rolesForPath");
+ return useAuthentication ? authOp.rolesForPath(request) : null;
+ }
+
+ /**
+ * check request authorization against a list of roles
+ */
+ public boolean isRoleAuthorized(List roles, DigilibRequest request) {
+ logger.debug("isRoleAuthorized");
+ return useAuthentication ? authOp.isRoleAuthorized(roles, request)
+ : true;
+ }
+
+ /**
+ * check for authenticated access and redirect if necessary
+ */
+ public boolean doAuthentication(HttpServletResponse response)
+ throws Exception {
+ return doAuthentication(dlRequest, response);
+ }
- public String getDocuPath(HttpServletRequest request) {
- util.dprintln(10, "getDocuPath");
- // fetch query string
- String qs = request.getQueryString();
- String fn = "";
- if (qs != null && qs.length() > 0) {
- // the file name is in the request before the first "+"
- int endfn = qs.indexOf("+");
- if (endfn > 0) {
- fn = qs.substring(0, endfn);
- } else {
- fn = qs;
- }
- }
- util.dprintln(4, "docuPath: "+fn);
- return fn;
- }
-
- /**
- * check if the request must be authorized to access filepath
- */
- public boolean isAuthRequired(HttpServletRequest request) throws AuthOpException {
- util.dprintln(10, "isAuthRequired");
- return authOp.isAuthRequired(getDocuPath(request), request);
- }
+ /**
+ * check for authenticated access and redirect if necessary
+ */
+ public boolean doAuthentication(DigilibRequest request,
+ HttpServletResponse response) throws Exception {
+ logger.debug("doAuthentication");
+ if (!useAuthentication) {
+ // shortcut if no authentication
+ return true;
+ }
+ // check if we are already authenticated
+ if (((HttpServletRequest) request.getServletRequest()).getRemoteUser() == null) {
+ logger.debug("unauthenticated so far");
+ // if not maybe we must?
+ if (isAuthRequired(request)) {
+ logger.debug("auth required, redirect");
+ // we are not yet authenticated -> redirect
+ response.sendRedirect(authURLPath
+ + ((HttpServletRequest) request.getServletRequest())
+ .getServletPath()
+ + "?"
+ + ((HttpServletRequest) request.getServletRequest())
+ .getQueryString());
+ }
+ }
+ return true;
+ }
- public boolean isAuthRequired(String filepath, HttpServletRequest request) throws AuthOpException {
- util.dprintln(10, "isAuthRequired");
- return authOp.isAuthRequired(filepath, request);
- }
-
- /**
- * check if the request is allowed to access filepath
- */
- public boolean isAuthorized(HttpServletRequest request) throws AuthOpException {
- util.dprintln(10, "isAuthorized");
- return authOp.isAuthorized(getDocuPath(request), request);
- }
+ /**
+ * Sets the current DigilibRequest. Also completes information in the request.
+ *
+ * @param dlRequest
+ * The dlRequest to set.
+ */
+ public void setRequest(DigilibRequest dlRequest) throws Exception {
+ this.dlRequest = dlRequest;
+ if (dirCache == null) {
+ return;
+ }
+ String fn = dlRequest.getFilePath();
+ // get information about the file
+ ImageFileset fileset = (ImageFileset) dirCache.getFile(fn, dlRequest
+ .getAsInt("pn"), FileOps.CLASS_IMAGE);
+ if (fileset == null) {
+ return;
+ }
+ // add file name
+ dlRequest.setValue("img.fn", fileset.getName());
+ // add dpi
+ fileset.check();
+ dlRequest.setValue("img.dpix", new Double(fileset.getResX()));
+ dlRequest.setValue("img.dpiy", new Double(fileset.getResY()));
+ // get number of pages in directory
+ DigiDirectory dd = dirCache.getDirectory(fn);
+ if (dd != null) {
+ dlRequest.setValue("pt", dd.getSize(FileOps.CLASS_IMAGE));
+ }
+ }
- public boolean isAuthorized(String filepath, HttpServletRequest request) throws AuthOpException {
- util.dprintln(10, "isAuthorized");
- return authOp.isAuthorized(filepath, request);
- }
+ /**
+ * get the first page number in the directory (not yet functional)
+ */
+ public int getFirstPage(DigilibRequest request) {
+ logger.debug("getFirstPage");
+ return 1;
+ }
- /**
- * return a list of authorization roles needed for request
- * to access the specified path
- */
- public List rolesForPath(String filepath, HttpServletRequest request) throws AuthOpException {
- util.dprintln(10, "rolesForPath");
- return authOp.rolesForPath(filepath, request);
- }
+ /**
+ * get the number of pages/files in the directory
+ */
+ public int getNumPages() throws Exception {
+ return getNumPages(dlRequest);
+ }
- /**
- * check request authorization against a list of roles
- */
- public boolean isRoleAuthorized(List roles, HttpServletRequest request) {
- util.dprintln(10, "isRoleAuthorized");
- return authOp.isRoleAuthorized(roles, request);
- }
+ /**
+ * get the number of pages/files in the directory
+ */
+ public int getNumPages(DigilibRequest request) throws Exception {
+ logger.debug("getNumPages");
+ DigiDirectory dd = (dirCache != null) ? dirCache.getDirectory(request
+ .getFilePath()) : null;
+ if (dd != null) {
+ return dd.getSize(FileOps.CLASS_IMAGE);
+ }
+ return 0;
+ }
- /**
- * check for authenticated access and redirect if necessary
- */
- public boolean doAuthentication(HttpServletRequest request, HttpServletResponse response) throws Exception {
- util.dprintln(10, "doAuthentication");
- // check if we are already authenticated
- if (request.getRemoteUser() == null) {
- util.dprintln(3, "unauthenticated so far");
- // if not maybe we must?
- if (isAuthRequired(request)) {
- util.dprintln(3, "auth required, redirect");
- // we are not yet authenticated -> redirect
- response.sendRedirect(authURLpath+request.getServletPath()+"?"+request.getQueryString());
- }
- }
- return true;
- }
+ /**
+ * Returns the dlConfig.
+ *
+ * @return DigilibConfiguration
+ */
+ public DigilibConfiguration getDlConfig() {
+ return dlConfig;
+ }
+
+ /**
+ * returns if the zoom area in the request can be moved
+ *
+ * @return
+ */
+ public boolean canMoveRight() {
+ float ww = dlRequest.getAsFloat("ww");
+ float wx = dlRequest.getAsFloat("wx");
+ return (ww + wx < 1.0);
+ }
- /**
- * get the first page number in the directory
- * (not yet functional)
- */
- public int getFirstPage(HttpServletRequest request) {
- return getFirstPage(getDocuPath(request), request);
- }
-
- public int getFirstPage(String filepath, HttpServletRequest request) {
- util.dprintln(10, "getFirstPage");
- return 1;
- }
+ /**
+ * returns if the zoom area in the request can be moved
+ *
+ * @return
+ */
+ public boolean canMoveLeft() {
+ float ww = dlRequest.getAsFloat("ww");
+ float wx = dlRequest.getAsFloat("wx");
+ return ((ww < 1.0) && (wx > 0));
+ }
- /**
- * get the number of pages/files in the directory
- */
- public int getNumPages(HttpServletRequest request) throws Exception {
- return getNumPages(getDocuPath(request), request);
- }
+ /**
+ * returns if the zoom area in the request can be moved
+ *
+ * @return
+ */
+ public boolean canMoveUp() {
+ float wh = dlRequest.getAsFloat("wh");
+ float wy = dlRequest.getAsFloat("wy");
+ return ((wh < 1.0) && (wy > 0));
+ }
- public int getNumPages(String filepath, HttpServletRequest request) throws Exception {
- util.dprintln(10, "getNumPages");
- return fileOp.getNumFilesVariant(baseDirs, "/"+filepath, true);
- }
+ /**
+ * returns if the zoom area in the request can be moved
+ *
+ * @return
+ */
+ public boolean canMoveDown() {
+ float wh = dlRequest.getAsFloat("wh");
+ float wy = dlRequest.getAsFloat("wy");
+ return (wh + wy < 1.0);
+ }
-}
+ /**
+ * @return Returns the dlRequest.
+ */
+ public DigilibRequest getRequest() {
+ return dlRequest;
+ }
+
+}
\ No newline at end of file
diff -r 794a9f25f15c -r 6d2032b6121d servlet/src/digilib/servlet/Initialiser.java
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/servlet/src/digilib/servlet/Initialiser.java Wed Nov 17 18:17:34 2004 +0100
@@ -0,0 +1,175 @@
+/* Initialiser.java -- initalisation servlet for setup tasks
+ *
+ * Digital Image Library servlet components
+ *
+ * Copyright (C) 2004 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 18.10.2004
+ */
+package digilib.servlet;
+
+import java.io.File;
+
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+
+import org.apache.log4j.Logger;
+import org.apache.log4j.xml.DOMConfigurator;
+
+import EDU.oswego.cs.dl.util.concurrent.FIFOSemaphore;
+import EDU.oswego.cs.dl.util.concurrent.Semaphore;
+import digilib.auth.AuthOps;
+import digilib.auth.XMLAuthOps;
+import digilib.io.AliasingDocuDirCache;
+import digilib.io.DocuDirCache;
+import digilib.io.FileOps;
+
+/**
+ * Initalisation servlet for setup tasks.
+ *
+ * @author casties
+ *
+ */
+public class Initialiser extends HttpServlet {
+
+ private static final long serialVersionUID = -5126621114382549343L;
+
+ /** servlet version */
+ public static final String iniVersion = "0.1b1";
+
+ /** gengeral logger for this class */
+ private static Logger logger = Logger.getLogger("digilib.init");
+
+ /** AuthOps instance */
+ AuthOps authOp;
+
+ /** DocuDirCache instance */
+ DocuDirCache dirCache;
+
+ /** DigilibConfiguration instance */
+ DigilibConfiguration dlConfig;
+
+ /** use authorization database */
+ boolean useAuthentication = false;
+
+ /**
+ * Initialisation on first run.
+ *
+ * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig)
+ */
+ public void init(ServletConfig config) throws ServletException {
+ super.init(config);
+
+ System.out
+ .println("***** Digital Image Library Initialisation Servlet (version "
+ + iniVersion + ") *****");
+
+ // 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);
+
+ /*
+ * further initialization
+ */
+
+ // set up the logger
+ File logConf = ServletOps.getConfigFile((File) dlConfig
+ .getValue("log-config-file"), config);
+ DOMConfigurator.configure(logConf.getAbsolutePath());
+ dlConfig.setValue("log-config-file", logConf);
+ // say hello in the log file
+ logger
+ .info("***** Digital Image Library Initialisation Servlet (version "
+ + iniVersion + ") *****");
+ // base directories
+ String[] bd = (String[]) dlConfig.getValue("basedir-list");
+ File[] dirs = new File[bd.length];
+ int ndirs = 0;
+ for (int i = 0; i < bd.length; i++) {
+ File d = new File(bd[i]);
+ if (d.isDirectory()) {
+ dirs[ndirs++] = d;
+ }
+ }
+ File[] bdirs = new File[ndirs];
+ System.arraycopy(dirs, 0, bdirs, 0, ndirs);
+ FileOps.setBaseDirs(bdirs);
+ // file classes
+ int[] fcs = { FileOps.CLASS_IMAGE, FileOps.CLASS_TEXT,
+ FileOps.CLASS_SVG };
+ FileOps.setFileClasses(fcs);
+ // directory cache
+ if (dlConfig.getAsBoolean("use-mapping")) {
+ // with mapping file
+ File mapConf = ServletOps.getConfigFile((File) dlConfig
+ .getValue("mapping-file"), config);
+ dirCache = new AliasingDocuDirCache(mapConf);
+ dlConfig.setValue("mapping-file", mapConf);
+ } else {
+ // without mapping
+ dirCache = new DocuDirCache();
+ }
+ dlConfig.setValue("servlet.dir.cache", dirCache);
+ FileOps.setCache(dirCache);
+ // useAuthentication
+ if (dlConfig.getAsBoolean("use-authorization")) {
+ // DB version
+ //authOp = new DBAuthOpsImpl(util);
+ // XML version
+ File authConf = ServletOps.getConfigFile((File) dlConfig
+ .getValue("auth-file"), config);
+ authOp = new XMLAuthOps(authConf);
+ dlConfig.setValue("servlet.auth.op", authOp);
+ dlConfig.setValue("auth-file", authConf);
+ }
+ // DocuImage class
+ Class cl = Class.forName(dlConfig
+ .getAsString("docuimage-class"));
+ dlConfig.setDocuImageClass(cl);
+ dlConfig.setValue("servlet.docuimage.class", cl.getName());
+ // worker threads
+ int nt = dlConfig.getAsInt("worker-threads");
+ Semaphore lck = new FIFOSemaphore(nt);
+ DigilibWorker.setLock(lck);
+ // set as the servlets main config
+ context.setAttribute("digilib.servlet.configuration", dlConfig);
+
+ } catch (Exception e) {
+ throw new ServletException(e);
+ }
+ } else {
+ // say hello in the log file
+ logger
+ .info("***** Digital Image Library Initialisation Servlet (version "
+ + iniVersion + ") *****");
+ logger.warn("Already initialised?");
+ // set our AuthOps
+ useAuthentication = dlConfig.getAsBoolean("use-authorization");
+ // AuthOps instance
+ authOp = (AuthOps) dlConfig.getValue("servlet.auth.op");
+ // DocuDirCache instance
+ dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache");
+ }
+ }
+
+}
diff -r 794a9f25f15c -r 6d2032b6121d servlet/src/digilib/servlet/Scaler.java
--- a/servlet/src/digilib/servlet/Scaler.java Thu Jan 17 15:25:46 2002 +0100
+++ b/servlet/src/digilib/servlet/Scaler.java Wed Nov 17 18:17:34 2004 +0100
@@ -1,377 +1,701 @@
-/* Scaler -- Scaler servlet main class
-
- 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
-
-*/
+/*
+ * Scaler -- Scaler servlet main class
+ *
+ * Digital Image Library servlet components
+ *
+ * Copyright (C) 200-2004 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.servlet;
-import javax.servlet.*;
-import javax.servlet.http.*;
-import java.io.*;
-import java.util.*;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.NoninvertibleTransformException;
+import java.awt.geom.Rectangle2D;
+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.*;
-import digilib.io.*;
-import digilib.image.*;
-import digilib.auth.*;
+import digilib.auth.AuthOpException;
+import digilib.auth.AuthOps;
+import digilib.image.ImageOpException;
+import digilib.image.ImageSize;
+import digilib.io.DigiDirectory;
+import digilib.io.DigiDirent;
+import digilib.io.DocuDirCache;
+import digilib.io.FileOpException;
+import digilib.io.FileOps;
+import digilib.io.ImageFile;
+import digilib.io.ImageFileset;
-
+/**
+ * @author casties
+ */
//public class Scaler extends HttpServlet implements SingleThreadModel {
public class Scaler extends HttpServlet {
- // Utils instance with debuglevel
- Utils util;
- // ServletOpss instance
- ServletOps servletOp;
- // FileOps instance
- FileOps fileOp;
- // AuthOps instance
- AuthOps authOp;
- // global DocuImage instance (don't reuse inside a request!)
- DocuImage globalImage;
+ private static final long serialVersionUID = -325080527268912852L;
+
+ /** digilib servlet version (for all components) */
+ public static final String dlVersion = "1.6.0a";
+
+ /** logger for accounting requests */
+ private static Logger accountlog = Logger.getLogger("account.request");
+
+ /** gengeral logger for this class */
+ private static Logger logger = Logger.getLogger("digilib.servlet");
+
+ /** logger for authentication related */
+ private static Logger authlog = Logger.getLogger("digilib.auth");
+
+ /** general error code */
+ public static final int ERROR_UNKNOWN = 0;
+
+ /** error code for authentication error */
+ public static final int ERROR_AUTH = 1;
+
+ /** error code for file operation error */
+ public static final int ERROR_FILE = 2;
+
+ /** error code for image operation error */
+ public static final int ERROR_IMAGE = 3;
+
+ /** servlet start time */
+ long starttime = 0;
+
+ /** DocuDirCache instance */
+ DocuDirCache dirCache;
+
+ /** authentication error image file */
+ File denyImgFile;
+
+ /** image error image file */
+ File errorImgFile;
+
+ /** subsampling before scaling */
+ float minSubsample = 2f;
+
+ /** send files as is? */
+ boolean sendFileAllowed = true;
+
+ /** default scaling quality */
+ int defaultQuality = 1;
+
+ /** DigilibConfiguration instance */
+ DigilibConfiguration dlConfig;
+
+ /** use authorization database */
+ boolean useAuthorization = true;
+
+ /** AuthOps instance */
+ AuthOps authOp;
+
+ // EXPRIMENTAL
+ /** try to enlarge cropping area for "oblique" angles */
+ boolean wholeRotArea = false;
+
+ /**
+ * Initialisation on first run.
+ *
+ * @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 "
+ + dlVersion + ") *****");
+ // say hello in the log file
+ logger
+ .info("***** Digital Image Library Image Scaler Servlet (version "
+ + dlVersion + ") *****");
- // use authorization database
- boolean useAuthentication = true;
- // image file to send in case of error
- File errorImgFile = new File("/docuserver/images/icons/scalerror.gif");
- // image file to send if access is denied
- File denyImgFile = new File("/docuserver/images/icons/denied.gif");
- // base directories in order of preference (prescaled versions first)
- String[] baseDirs = {"/docuserver/scaled/small", "/docuserver/images", "/docuserver/scans/quellen"};
+ starttime = System.currentTimeMillis();
+ // 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 = (File) dlConfig.getValue("denied-image");
+ errorImgFile = (File) dlConfig.getValue("error-image");
+ sendFileAllowed = dlConfig.getAsBoolean("sendfile-allowed");
+ minSubsample = dlConfig.getAsFloat("subsample-minimum");
+ defaultQuality = dlConfig.getAsInt("default-quality");
+ }
+
+ /** Process the HTTP Get request */
+ public void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ accountlog.info("GET from " + request.getRemoteAddr());
+ // create new request with defaults
+ DigilibRequest dlReq = new DigilibRequest();
+ // set with request parameters
+ dlReq.setWithRequest(request);
+ // add DigilibRequest to ServletRequest
+ request.setAttribute("digilib.servlet.request", dlReq);
+ // do the processing
+ processRequest(request, response);
+ }
- /*********************************************************
- * Initialize global variables
- *********************************************************/
- public void init(ServletConfig config) throws ServletException {
- super.init(config);
+ /** Process the HTTP Post request */
+ public void doPost(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ accountlog.info("POST from " + request.getRemoteAddr());
+ // create new request with defaults
+ DigilibRequest dlReq = new DigilibRequest();
+ // set with request parameters
+ dlReq.setWithRequest(request);
+ // add DigilibRequest to ServletRequest
+ request.setAttribute("digilib.servlet.request", dlReq);
+ // do the processing
+ processRequest(request, response);
+ }
- // first we need an Utils to setup ServletOps UGLY!!
- util = new Utils(5);
- // servletOps takes a ServletConfig to get the config file name
- servletOp = new ServletOps(util, config);
- // then we can start reading parameters UGLY!!
+ /*
+ * (non-Javadoc)
+ *
+ * @see javax.servlet.http.HttpServlet#getLastModified(javax.servlet.http.HttpServletRequest)
+ */
+ protected long getLastModified(HttpServletRequest request) {
+ accountlog.debug("GetLastModified from " + request.getRemoteAddr()
+ + " for " + request.getQueryString());
+ long mtime = -1;
+ // create new request with defaults
+ DigilibRequest dlReq = new DigilibRequest();
+ // set with request parameters
+ dlReq.setWithRequest(request);
+ // find the requested file
+ DigiDirent f = findFile(dlReq);
+ if (f != null) {
+ DigiDirectory dd = f.getParent();
+ mtime = dd.getMtime() / 1000 * 1000;
+ }
+ // limit time to servlet start time
+ if (mtime < starttime) {
+ mtime = starttime;
+ }
+ return mtime;
+ }
+
+ /** main request handler. */
+ void processRequest(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException {
- // Utils instance with debuglevel
- int debugLevel = servletOp.tryToGetInitParam("debug-level", 10);
- util = new Utils(debugLevel);
- // reset Util for ServletOps instance
- servletOp.setUtils(util);
- // image file to send in case of error
- String errorImgFileName = servletOp.tryToGetInitParam("error-image", "/docuserver/images/icons/scalerror.gif");
- errorImgFile = new File(errorImgFileName);
- // image file to send if access is denied
- String denyImgFileName = servletOp.tryToGetInitParam("denied-image", "/docuserver/images/icons/denied.gif");
- denyImgFile = new File(denyImgFileName);
- // base directories in order of preference (prescaled versions first)
- String baseDirList = servletOp.tryToGetInitParam("basedir-list", "/docuserver/scaled/small:/docuserver/images:/docuserver/scans/quellen");
- // split list into directories
- StringTokenizer dirs = new StringTokenizer(baseDirList, ":");
- int n = dirs.countTokens();
- // add directories into array
- baseDirs = new String[n];
- for (int i = 0; i < n; i++) {
- baseDirs[i] = dirs.nextToken();
- }
- // use authentication information
- String useAuth = servletOp.tryToGetInitParam("use-authorization", "true");
- if ((useAuth.indexOf("false") > 0)||(useAuth.indexOf("FALSE") > 0)) {
- useAuthentication = false;
- } else {
- useAuthentication = true;
- try {
- // DB version
- //authOp = new DBAuthOpsImpl(util);
- // XML version
- String cnfPath = servletOp.tryToGetInitParam("auth-file", "/docuserver/www/digitallibrary/WEB-INF/digilib-auth.xml");
- authOp = new XMLAuthOps(util, cnfPath);
- } catch (AuthOpException e) {
- throw new ServletException(e);
- }
- }
- // FileOps instance
- fileOp = new FileOps(util);
- // global DocuImage instance (don't reuse inside a request!)
- globalImage = new JAIDocuImage(util);
-// globalImage = new JIMIDocuImage(util);
- //globalImage = new ImageLoaderDocuImage(util);
+ if (dlConfig == null) {
+ throw new ServletException("ERROR: No Configuration!");
+ }
+
+ accountlog.debug("request: " + request.getQueryString());
+ logger.debug("request: " + request.getQueryString());
+
+ // time for benchmarking
+ long startTime = System.currentTimeMillis();
+ // output mime-type
+ String mimeType = "image/png";
+
+ /* parameters for a session */
- }
+ // scale the image file to fit window size i.e. respect dw,dh
+ boolean scaleToFit = true;
+ // scale the image by a fixed factor only
+ boolean absoluteScale = false;
+ // only crop the image to fit
+ boolean cropToFit = false;
+ // send the file as is
+ boolean sendFile = false;
+ // use low resolution images only
+ boolean loresOnly = false;
+ // use hires images only
+ boolean hiresOnly = false;
+ // send the image always as JPEG
+ boolean forceJPEG = false;
+ // interpolation to use for scaling
+ int scaleQual = defaultQuality;
+ // send html error message (or image file)
+ boolean errorMsgHtml = false;
+ // mirror the image
+ boolean doMirror = false;
+ // angle of mirror axis
+ float mirrorAngle = 0;
+ // original (hires) image resolution
+ float origResX = 0;
+ float origResY = 0;
+
+ /* request parameters */
+
+ DigilibRequest dlRequest = (DigilibRequest) request
+ .getAttribute("digilib.servlet.request");
- /**Process the HTTP Get request*/
- public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- util.dprintln(1, "The servlet has received a GET!");
- processRequest(request, response);
- }
-
- /**Process the HTTP Post request*/
- public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
- util.dprintln(1, "The servlet has received a POST!");
- processRequest(request, response);
- }
-
- /**Clean up resources*/
- public void destroy() {
- }
-
-/**********************************************************************
- * main request handler
- **********************************************************************/
-
- void processRequest(HttpServletRequest request, HttpServletResponse response)
- throws ServletException, IOException {
+ // destination image width
+ int paramDW = dlRequest.getAsInt("dw");
+ // destination image height
+ int paramDH = dlRequest.getAsInt("dh");
+ // relative area x_offset (0..1)
+ float paramWX = dlRequest.getAsFloat("wx");
+ // relative area y_offset
+ float paramWY = dlRequest.getAsFloat("wy");
+ // relative area width (0..1)
+ float paramWW = dlRequest.getAsFloat("ww");
+ // relative area height
+ float paramWH = dlRequest.getAsFloat("wh");
+ // scale factor (additional to dw/width, dh/height)
+ float paramWS = dlRequest.getAsFloat("ws");
+ // rotation angle
+ float paramROT = dlRequest.getAsFloat("rot");
+ // contrast enhancement
+ float paramCONT = dlRequest.getAsFloat("cont");
+ // brightness enhancement
+ float paramBRGT = dlRequest.getAsFloat("brgt");
+ // color modification
+ float[] paramRGBM = null;
+ Parameter p = dlRequest.get("rgbm");
+ if (p.hasValue() && (!p.getAsString().equals("0/0/0"))) {
+ paramRGBM = p.parseAsFloatArray("/");
+ }
+ float[] paramRGBA = null;
+ p = dlRequest.get("rgba");
+ if (p.hasValue() && (!p.getAsString().equals("0/0/0"))) {
+ paramRGBA = p.parseAsFloatArray("/");
+ }
+ // destination resolution (DPI)
+ float paramDDPIX = dlRequest.getAsFloat("ddpix");
+ float paramDDPIY = dlRequest.getAsFloat("ddpiy");
+ if ((paramDDPIX == 0) || (paramDDPIY == 0)) {
+ // if X or Y resolution isn't set, use DDPI
+ paramDDPIX = dlRequest.getAsFloat("ddpi");
+ paramDDPIY = paramDDPIX;
+ }
- // time for benchmarking
- long startTime = System.currentTimeMillis();
- // output mime/type
- String mimeType = "image/png";
-
- /**
- * parameters for a session
- */
+ /*
+ * operation mode: "fit": always fit to page, "clip": send original
+ * resolution cropped, "file": send whole file (if allowed)
+ */
+ if (dlRequest.hasOption("mo", "clip")) {
+ scaleToFit = false;
+ absoluteScale = false;
+ cropToFit = true;
+ sendFile = false;
+ hiresOnly = true;
+ } else if (dlRequest.hasOption("mo", "fit")) {
+ scaleToFit = true;
+ absoluteScale = false;
+ cropToFit = false;
+ sendFile = false;
+ hiresOnly = false;
+ } else if (dlRequest.hasOption("mo", "osize")) {
+ scaleToFit = false;
+ absoluteScale = true;
+ cropToFit = false;
+ sendFile = false;
+ hiresOnly = true;
+ }
+ // operation mode: "lores": try to use scaled image, "hires": use
+ // unscaled image
+ // "autores": try best fitting resolution
+ if (dlRequest.hasOption("mo", "lores")) {
+ loresOnly = true;
+ hiresOnly = false;
+ } else if (dlRequest.hasOption("mo", "hires")) {
+ loresOnly = false;
+ hiresOnly = true;
+ } else if (dlRequest.hasOption("mo", "autores")) {
+ loresOnly = false;
+ hiresOnly = false;
+ }
+ // operation mode: "errtxt": error message in html, "errimg": error
+ // image
+ if (dlRequest.hasOption("mo", "errtxt")) {
+ errorMsgHtml = true;
+ } else if (dlRequest.hasOption("mo", "errimg")) {
+ errorMsgHtml = false;
+ }
+ // operation mode: "q0" - "q2": interpolation quality
+ if (dlRequest.hasOption("mo", "q0")) {
+ scaleQual = 0;
+ } else if (dlRequest.hasOption("mo", "q1")) {
+ scaleQual = 1;
+ } else if (dlRequest.hasOption("mo", "q2")) {
+ scaleQual = 2;
+ }
+ // operation mode: "jpg": always use JPEG
+ if (dlRequest.hasOption("mo", "jpg")) {
+ forceJPEG = true;
+ }
- // scale the image file to fit window size
- boolean scaleToFit = true;
- // use heuristics (GIF?) to scale or not
- boolean forcedScale = false;
- // try prescaled images first
- boolean preScaledFirst = true;
- // interpolation to use for scaling
- int scaleQual = 0;
- // send html error message (or image file)
- boolean errorMsgHtml = false;
+ // check with the maximum allowed size (if set)
+ int maxImgSize = dlConfig.getAsInt("max-image-size");
+ if (maxImgSize > 0) {
+ paramDW = (paramDW * paramWS > maxImgSize) ? (int) (maxImgSize / paramWS)
+ : paramDW;
+ paramDH = (paramDH * paramWS > maxImgSize) ? (int) (maxImgSize / paramWS)
+ : paramDH;
+ }
- /**
- * request parameter
- */
+ //"big" try for all file/image actions
+ try {
+
+ // ImageFileset of the image to load
+ ImageFileset fileset = null;
+
+ /* find the file to load/send */
+
+ // get PathInfo
+ String loadPathName = dlRequest.getFilePath();
- // file/dir to load
- String param_fn = servletOp.tryToGetParam("fn", "", request);
- // page number
- int param_pn = servletOp.tryToGetParam("pn", 1, request);
- // destination image width
- int param_dw = servletOp.tryToGetParam("dw", 300, request);
- // destination image height
- int param_dh = servletOp.tryToGetParam("dh", 400, request);
- // relative area x_offset (0..1)
- float param_wx = servletOp.tryToGetParam("wx", 0f, request);
- // relative area y_offset
- float param_wy = servletOp.tryToGetParam("wy", 0f, request);
- // relative area width (0..1)
- float param_ww = servletOp.tryToGetParam("ww", 1f, request);
- // relative area height
- float param_wh = servletOp.tryToGetParam("wh", 1f, request);
- // scale factor (additional to dw/width, dh/height)
- float param_ws = servletOp.tryToGetParam("ws", 1f, request);
- // operation mode: flags separated by "+"
- String param_mo = servletOp.tryToGetParam("mo", "", request);
- // operation mode: "fit": always fit to page, "file": send as-is
- if (param_mo.indexOf("fit") >= 0) {
- scaleToFit = true;
- forcedScale = true;
- } else if (param_mo.indexOf("file") >= 0) {
- scaleToFit = false;
- forcedScale = true;
- }
- // operation mode: "errtxt": error message in html, "errimg": error image
- if (param_mo.indexOf("errtxt") >= 0) {
- errorMsgHtml = true;
- } else if (param_mo.indexOf("errimg") >= 0) {
- errorMsgHtml = false;
- }
- // operation mode: "q0" - "q2": interpolation quality
- if (param_mo.indexOf("q0") >= 0) {
- scaleQual = 0;
- } else if (param_mo.indexOf("q1") >= 0) {
- scaleQual = 1;
- } else if (param_mo.indexOf("q2") >= 0) {
- scaleQual = 2;
- }
- // operation mode: "lores": try to use scaled image, "hires": unscaled image
- if (param_mo.indexOf("lores") >= 0) {
- preScaledFirst = true;
- } else if (param_mo.indexOf("hires") >= 0) {
- preScaledFirst = false;
- }
+ /* check permissions */
+ if (useAuthorization) {
+ // get a list of required roles (empty if no restrictions)
+ List rolesRequired = authOp.rolesForPath(loadPathName, 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();
+ }
+ }
+ }
+
+ // find the file
+ fileset = (ImageFileset) findFile(dlRequest);
+ if (fileset == null) {
+ throw new FileOpException("File " + loadPathName + "("
+ + dlRequest.getAsInt("pn") + ") not found.");
+ }
+
+ /* calculate expected source image size */
+ ImageSize expectedSourceSize = new ImageSize();
+ if (scaleToFit) {
+ float scale = (1 / Math.min(paramWW, paramWH)) * paramWS;
+ expectedSourceSize.setSize((int) (paramDW * scale),
+ (int) (paramDH * scale));
+ } else {
+ expectedSourceSize.setSize((int) (paramDW * paramWS),
+ (int) (paramDH * paramWS));
+ }
- Utils.dprintln(1, "Parameter values: fn:"+param_fn+" pn:"+param_pn+" dw:"+param_dw+" dh:"+param_dh+" wx:"+param_wx+" wy:"+param_wy+" ww:"+param_ww+" wh:"+param_wh+" ws:"+param_ws+" mo:"+param_mo);
+ ImageFile fileToLoad;
+ /* select a resolution */
+ if (hiresOnly) {
+ // get first element (= highest resolution)
+ fileToLoad = fileset.getBiggest();
+ } else if (loresOnly) {
+ // enforced lores uses next smaller resolution
+ fileToLoad = fileset.getNextSmaller(expectedSourceSize);
+ if (fileToLoad == null) {
+ // this is the smallest we have
+ fileToLoad = fileset.getSmallest();
+ }
+ } else {
+ // autores: use next higher resolution
+ fileToLoad = fileset.getNextBigger(expectedSourceSize);
+ if (fileToLoad == null) {
+ // this is the highest we have
+ fileToLoad = fileset.getBiggest();
+ }
+ }
+ logger.info("Planning to load: " + fileToLoad);
- //"big" try for all file/image actions
- try {
+ /*
+ * send the image if its mo=(raw)file
+ */
+ if (dlRequest.hasOption("mo", "file")
+ || dlRequest.hasOption("mo", "rawfile")) {
+ if (sendFileAllowed) {
+ String mt = null;
+ if (dlRequest.hasOption("mo", "rawfile")) {
+ mt = "application/octet-stream";
+ }
+ logger.debug("Sending RAW File as is.");
+ ServletOps.sendFile(fileToLoad, mt, response);
+ logger.info("Done in "
+ + (System.currentTimeMillis() - startTime) + "ms");
+ return;
+ }
+ }
- // DocuImage instance
- DocuImage docuImage = new JAIDocuImage(util);
-// DocuImage docuImage = new JIMIDocuImage(util);
- //DocuImage docuImage = new ImageLoaderDocuImage(util);
+ // check the source image
+ fileToLoad.check();
+ // get the source image type
+ mimeType = fileToLoad.getMimetype();
+ // get the source image size
+ ImageSize imgSize = fileToLoad.getSize();
-
- /**
- * find the file to load/send
- */
+ // decide if the image can be sent as is
+ boolean mimetypeSendable = mimeType.equals("image/jpeg")
+ || mimeType.equals("image/png")
+ || mimeType.equals("image/gif");
+ boolean imagoOptions = dlRequest.hasOption("mo", "hmir")
+ || dlRequest.hasOption("mo", "vmir") || (paramROT != 0)
+ || (paramRGBM != null) || (paramRGBA != null)
+ || (paramCONT != 0) || (paramBRGT != 0);
+ boolean imageSendable = mimetypeSendable && !imagoOptions;
- String loadPathName = "";
- // if there's PathInfo, append
- if (request.getPathInfo() != null) {
- loadPathName += request.getPathInfo();
- }
- // append fn parameter
- loadPathName += param_fn;
- // if it's zoomed, try hires version (to be optimized...)
- if ((param_ww < 1f) || (param_wh < 1f)) {
- preScaledFirst = false;
- }
+ /*
+ * if not autoRes and image smaller than requested size then send as
+ * is. if autoRes and image has requested size then send as is. if
+ * not autoScale and not scaleToFit nor cropToFit then send as is
+ * (mo=file)
+ */
+ if (imageSendable
+ && ((loresOnly && fileToLoad.getSize().isSmallerThan(
+ expectedSourceSize)) || (!(loresOnly || hiresOnly) && fileToLoad
+ .getSize().fitsIn(expectedSourceSize)))) {
+
+ logger.debug("Sending File as is.");
+
+ ServletOps.sendFile(fileToLoad, null, response);
+
+ logger.info("Done in "
+ + (System.currentTimeMillis() - startTime) + "ms");
+ return;
+ }
- if (useAuthentication) {
- // check permissions
- List rolesRequired = authOp.rolesForPath(loadPathName, request);
- if (rolesRequired != null) {
- Utils.dprintln(1, "Role required: "+rolesRequired);
- Utils.dprintln(2, "User: "+request.getRemoteUser());
- if (! authOp.isRoleAuthorized(rolesRequired, request)) {
- Utils.dprintln(1, "ERROR: access denied!");
- if (errorMsgHtml) {
- servletOp.htmlMessage("ERROR: Unauthorized access!", response);
- } else {
- docuImage.sendFile(denyImgFile, response);
- }
- return;
- }
- }
- }
+ // set missing dw or dh from aspect ratio
+ float imgAspect = imgSize.getAspect();
+ if (paramDW == 0) {
+ paramDW = (int) Math.round(paramDH * imgAspect);
+ } else if (paramDH == 0) {
+ paramDH = (int) Math.round(paramDW / imgAspect);
+ }
+
+ /*
+ * prepare resolution for original size
+ */
+ if (absoluteScale) {
+ // get original resolution from metadata
+ fileset.check();
+ origResX = fileset.getResX();
+ origResY = fileset.getResY();
+ if ((origResX == 0) || (origResY == 0)) {
+ throw new ImageOpException("Missing image DPI information!");
+ }
- // find the file
- File fileToLoad = fileOp.getFileVariant(baseDirs, loadPathName, param_pn, preScaledFirst);
+ if ((paramDDPIX == 0) || (paramDDPIY == 0)) {
+ throw new ImageOpException(
+ "Missing display DPI information!");
+ }
+ }
- Utils.dprintln(1, "Loading: "+fileToLoad);
+ /* crop and scale the image */
- // get the source image type (if it's known)
- mimeType = fileOp.mimeForFile(fileToLoad);
+ logger.debug("IMG: " + imgSize.getWidth() + "x"
+ + imgSize.getHeight());
+ logger.debug("time " + (System.currentTimeMillis() - startTime)
+ + "ms");
- // if not forced and source is GIF/PNG then send-as-is if not zoomed
- if((!forcedScale && (mimeType == "image/gif" || mimeType == "image/png")
- && (param_ww == 1f) && (param_wh == 1f)) || (forcedScale && !scaleToFit)) {
-
- Utils.dprintln(1, "Sending File as is.");
+ // coordinates and scaling
+ float areaXoff;
+ float areaYoff;
+ float areaWidth;
+ float areaHeight;
+ float scaleX;
+ float scaleY;
+ float scaleXY;
- docuImage.sendFile(fileToLoad, response);
-
- Utils.dprintln(1, "Done in "+(System.currentTimeMillis()-startTime)+"ms");
- return;
- }
-
- // load file
- docuImage.loadImage(fileToLoad);
-
- /**
- * crop and scale the image
- */
-
- // get size
- int imgWidth = docuImage.getWidth();
- int imgHeight = docuImage.getHeight();
-
- util.dprintln(2, "IMG: "+imgWidth+"x"+imgHeight);
- util.dprintln(2, "time "+(System.currentTimeMillis()-startTime)+"ms");
+ // coordinates using Java2D
+ // image size in pixels
+ Rectangle2D imgBounds = new Rectangle2D.Float(0, 0, imgSize
+ .getWidth(), imgSize.getHeight());
+ // user window area in [0,1] coordinates
+ Rectangle2D relUserArea = new Rectangle2D.Float(paramWX, paramWY,
+ paramWW, paramWH);
+ // transform from relative [0,1] to image coordinates.
+ AffineTransform imgTrafo = AffineTransform.getScaleInstance(imgSize
+ .getWidth(), imgSize.getHeight());
+ // transform user coordinate area to image coordinate area
+ Rectangle2D userImgArea = imgTrafo.createTransformedShape(
+ relUserArea).getBounds2D();
- // calculate absolute from relative coordinates
- float areaXoff = param_wx * imgWidth;
- float areaYoff = param_wy * imgHeight;
- float areaWidth = param_ww * imgWidth;
- float areaHeight = param_wh * imgHeight;
- // calculate scaling factors
- float scaleX = param_dw / areaWidth * param_ws;
- float scaleY = param_dh / areaHeight * param_ws;
- float scaleXY = (scaleX > scaleY) ? scaleY : scaleX;
-
- util.dprintln(1, "Scale "+scaleXY+"("+scaleX+","+scaleY+") on "+areaXoff+","+areaYoff+" "+areaWidth+"x"+areaHeight);
+ // calculate scaling factors based on inner user area
+ if (scaleToFit) {
+ areaWidth = (float) userImgArea.getWidth();
+ areaHeight = (float) userImgArea.getHeight();
+ scaleX = paramDW / areaWidth * paramWS;
+ scaleY = paramDH / areaHeight * paramWS;
+ scaleXY = (scaleX > scaleY) ? scaleY : scaleX;
+ } else if (absoluteScale) {
+ // absolute scale
+ scaleX = paramDDPIX / origResX;
+ scaleY = paramDDPIY / origResY;
+ // currently only same scale :-(
+ scaleXY = scaleX;
+ areaWidth = paramDW / scaleXY * paramWS;
+ areaHeight = paramDH / scaleXY * paramWS;
+ // reset user area size
+ userImgArea.setRect(userImgArea.getX(), userImgArea.getY(),
+ areaWidth, areaHeight);
+ } else {
+ // crop to fit
+ areaWidth = paramDW * paramWS;
+ areaHeight = paramDH * paramWS;
+ // reset user area size
+ userImgArea.setRect(userImgArea.getX(), userImgArea.getY(),
+ areaWidth, areaHeight);
+ scaleX = 1f;
+ scaleY = 1f;
+ scaleXY = 1f;
+ }
- // fit area to image
- areaWidth = (areaXoff + areaWidth > imgWidth) ? imgWidth - areaXoff : areaWidth;
- areaHeight = (areaYoff + areaHeight > imgHeight) ? imgHeight - areaYoff : areaHeight;
-
- util.dprintln(2, "cropped: "+areaXoff+","+areaYoff+" "+areaWidth+"x"+areaHeight);
+ // enlarge image area for rotations to cover additional pixels
+ Rectangle2D outerUserImgArea = userImgArea;
+ Rectangle2D innerUserImgArea = userImgArea;
+ if (wholeRotArea) {
+ if (paramROT != 0) {
+ try {
+ // rotate user area coordinates around center of user
+ // area
+ AffineTransform rotTrafo = AffineTransform
+ .getRotateInstance(Math.toRadians(paramROT),
+ userImgArea.getCenterX(), userImgArea
+ .getCenterY());
+ // get bounds from rotated end position
+ innerUserImgArea = rotTrafo.createTransformedShape(
+ userImgArea).getBounds2D();
+ // get bounds from back-rotated bounds
+ outerUserImgArea = rotTrafo.createInverse()
+ .createTransformedShape(innerUserImgArea)
+ .getBounds2D();
+ } catch (NoninvertibleTransformException e1) {
+ // this shouldn't happen anyway
+ logger.error(e1);
+ }
+ }
+ }
- // check image parameters
- if ((areaWidth < 1)||(areaHeight < 1)
- ||(scaleXY * areaWidth < 2)||(scaleXY * areaHeight < 2)) {
- Utils.dprintln(1, "ERROR: invalid scale parameter set!");
- throw new ImageOpException("Invalid scale parameter set!");
- }
+ logger.debug("Scale " + scaleXY + "(" + scaleX + "," + scaleY
+ + ") on " + outerUserImgArea);
+
+ // clip area at the image border
+ outerUserImgArea = outerUserImgArea.createIntersection(imgBounds);
- // crop and scale image
- docuImage.cropAndScale((int)areaXoff, (int)areaYoff, (int)areaWidth, (int)areaHeight,
- scaleXY, scaleQual);
-
- util.dprintln(2, "time "+(System.currentTimeMillis()-startTime)+"ms");
+ // check image parameters sanity
+ if ((outerUserImgArea.getWidth() < 1)
+ || (outerUserImgArea.getHeight() < 1)
+ || (scaleXY * outerUserImgArea.getWidth() < 2)
+ || (scaleXY * outerUserImgArea.getHeight() < 2)) {
+ logger.error("ERROR: invalid scale parameter set!");
+ throw new ImageOpException("Invalid scale parameter set!");
+ }
- /**
- * write the resulting image
- */
+ /*
+ * submit the image worker job
+ */
+
+ DigilibWorker job = new DigilibImageWorker(dlConfig, response,
+ mimeType, scaleQual, dlRequest, paramROT, paramCONT,
+ paramBRGT, paramRGBM, paramRGBA, fileToLoad, scaleXY,
+ outerUserImgArea, innerUserImgArea, minSubsample,
+ wholeRotArea, forceJPEG);
- // setup output -- if source is JPG then dest will be JPG else it's PNG
- if (mimeType != "image/jpeg") {
- mimeType="image/png";
- }
+ job.run();
+ if (job.hasError()) {
+ throw new ImageOpException(job.getError().toString());
+ }
+
+ logger.debug("servlet done in "
+ + (System.currentTimeMillis() - startTime));
+
+ /* error handling */
- // write the image
- docuImage.writeImage(mimeType, response);
-
- util.dprintln(1, "Done in "+(System.currentTimeMillis()-startTime)+"ms");
-
- /**
- * error handling
- */
+ } // end of "big" try
+ catch (IOException e) {
+ logger.error("ERROR: File IO Error: " + e);
+ digilibError(errorMsgHtml, ERROR_FILE,
+ "ERROR: File IO Error: " + e, response);
+ } catch (AuthOpException e) {
+ logger.error("ERROR: Authorization error: " + e);
+ digilibError(errorMsgHtml, ERROR_AUTH,
+ "ERROR: Authorization error: " + e, response);
+ } catch (ImageOpException e) {
+ logger.error("ERROR: Image Error: " + e);
+ digilibError(errorMsgHtml, ERROR_IMAGE,
+ "ERROR: Image Operation Error: " + e, response);
+ } catch (RuntimeException e) {
+ // JAI likes to throw RuntimeExceptions ;-(
+ logger.error("ERROR: Other Image Error: " + e);
+ digilibError(errorMsgHtml, ERROR_IMAGE,
+ "ERROR: Other Image Operation Error: " + e, response);
+ }
+ }
- }//"big" try
- catch (FileOpException e) {
- util.dprintln(1, "ERROR: File IO Error: "+e);
- try {
- if (errorMsgHtml) {
- servletOp.htmlMessage("ERROR: File IO Error: "+e, response);
- } else {
- globalImage.sendFile(errorImgFile, response);
- }
- } catch (FileOpException ex) {} // so we don't get a loop
- return;
- }
- catch (AuthOpException e) {
- Utils.dprintln(1, "ERROR: Authorization error: "+e);
- try {
- if (errorMsgHtml) {
- servletOp.htmlMessage("ERROR: Authorization error: "+e, response);
- } else {
- globalImage.sendFile(errorImgFile, response);
- }
- } catch (FileOpException ex) {} // so we don't get a loop
- return;
- }
- catch (ImageOpException e) {
- Utils.dprintln(1, "ERROR: Image Error: "+e);
- try {
- if (errorMsgHtml) {
- servletOp.htmlMessage("ERROR: Image Operation Error: "+e, response);
- } else {
- globalImage.sendFile(errorImgFile, response);
- }
- } catch (FileOpException ex) {} // so we don't get a loop
- return;
- }
+ /**
+ * Returns the DocuDirent corresponding to the DigilibRequest.
+ *
+ * @param dlRequest
+ * @return
+ */
+ public DigiDirent findFile(DigilibRequest dlRequest) {
+ // find the file(set)
+ DigiDirent f = dirCache.getFile(dlRequest.getFilePath(), dlRequest
+ .getAsInt("pn"), FileOps.CLASS_IMAGE);
+ return f;
+ }
- }
+ /**
+ * Sends an error to the client as text or image.
+ *
+ * @param asHTML
+ * @param type
+ * @param msg
+ * @param response
+ */
+ public void digilibError(boolean asHTML, int type, String msg,
+ HttpServletResponse response) {
+ try {
+ File img = null;
+ if (type == ERROR_AUTH) {
+ if (msg == null) {
+ msg = "ERROR: Unauthorized access!";
+ }
+ img = denyImgFile;
+ } else {
+ if (msg == null) {
+ msg = "ERROR: Other image error!";
+ }
+ img = this.errorImgFile;
+ }
+ if (asHTML && (img != null)) {
+ ServletOps.htmlMessage(msg, response);
+ } else {
+ ServletOps.sendFile(img, null, response);
+ }
+ } catch (IOException e) {
+ logger.error("Error sending error!", e);
+ }
-}//Scaler class
+ }
+
+} //Scaler class