# HG changeset patch # User cmielack # Date 1235396722 -3600 # Node ID b2325b33b77b72294ccf3de125bd85175f5b13d6 # Parent 794a9f25f15c8b4de2a09e55275d30fa50f70870 completely restructured the scaler diff -r 794a9f25f15c -r b2325b33b77b servlet/src/digilib/servlet/DigilibImageWorker.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/servlet/src/digilib/servlet/DigilibImageWorker.java Mon Feb 23 14:45:22 2009 +0100 @@ -0,0 +1,295 @@ +/* DigilibImageWorker.java -- worker for image operations + * + * 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 19.10.2004 + */ + +package digilib.servlet; + +import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import javax.servlet.http.HttpServletResponse; + +import digilib.image.DocuImage; +import digilib.image.ImageOpException; +import digilib.image.ImageOps; +import digilib.io.FileOpException; +import digilib.io.ImageFile; + +/** + * worker for image operations. + * + * @author casties + * + */ +public class DigilibImageWorker extends DigilibWorker { + + private DigilibConfiguration dlConfig; + + //HttpServletResponse response; + + OutputStream outstream; + + long startTime; + + String mimeType; + + int scaleQual; + + //DigilibRequest dlRequest; + + //ImageJobInformation ijd; + + float paramROT; + + float paramCONT; + + float paramBRGT; + + float[] paramRGBM; + + float[] paramRGBA; + + ImageFile fileToLoad; + + float areaXoff; + + float areaYoff; + + float areaWidth; + + float areaHeight; + + float scaleXY; + + Rectangle2D outerUserImgArea; + + Rectangle2D innerUserImgArea; + + float minSubsample; + + boolean wholeRotArea; + + boolean vmir; + boolean hmir; + + int forceType; + + /** + * @param dlConfig + * @param response + * @param mimeType + * @param scaleQual + * @param dlRequest + * @param paramROT + * @param paramCONT + * @param paramBRGT + * @param paramRGBM + * @param paramRGBA + * @param fileToLoad + * @param areaXoff + * @param outerUserImgArea + * @param innerUserImgArea + * @param minSubsample + * @param wholeRotArea + * @param forceType + */ + public DigilibImageWorker(DigilibConfiguration dlConfig, + OutputStream outstream, String mimeType, int scaleQual, + //DigilibRequest dlRequest, + //ImageJobInformation ijd, + float paramROT, float paramCONT, + float paramBRGT, float[] paramRGBM, float[] paramRGBA, + ImageFile fileToLoad, float scaleXY, Rectangle2D outerUserImgArea, + Rectangle2D innerUserImgArea, float minSubsample, + boolean wholeRotArea, int forceType, boolean hmir, boolean vmir) { + super(); + this.dlConfig = dlConfig; + this.outstream = outstream; + this.mimeType = mimeType; + this.scaleQual = scaleQual; + //this.dlRequest = dlRequest; + //this.ijd = ijd; + this.paramROT = paramROT; + this.paramCONT = paramCONT; + this.paramBRGT = paramBRGT; + this.paramRGBM = paramRGBM; + this.paramRGBA = paramRGBA; + this.fileToLoad = fileToLoad; + this.scaleXY = scaleXY; + this.outerUserImgArea = outerUserImgArea; + this.innerUserImgArea = innerUserImgArea; + this.minSubsample = minSubsample; + this.wholeRotArea = wholeRotArea; + this.forceType = forceType; + this.hmir = hmir; + this.vmir = vmir; + } + + /* + * do the work + */ + public DocuImage render() throws FileOpException, IOException, ImageOpException { + ; + logger.debug("image worker " + this.getName() + " working"); + startTime = System.currentTimeMillis(); + + /* crop and scale image */ + + // new DocuImage instance + DocuImage docuImage = dlConfig.getDocuImageInstance(); + if (docuImage == null) { + throw new ImageOpException("Unable to load DocuImage class!"); + } + + // set interpolation quality + docuImage.setQuality(scaleQual); + + Rectangle loadRect = outerUserImgArea.getBounds(); + // use subimage loading if possible + if (docuImage.isSubimageSupported()) { + logger.debug("Subimage: scale " + scaleXY + " = " + (1 / scaleXY)); + float subf = 1f; + float subsamp = 1f; + if (scaleXY < 1) { + subf = 1 / scaleXY; + // for higher quality reduce subsample factor by + // minSubsample + if (scaleQual > 0) { + subsamp = (float) Math.max(Math.floor(subf / minSubsample), + 1d); + } else { + subsamp = (float) Math.floor(subf); + } + scaleXY = subsamp / subf; + logger.debug("Using subsampling: " + subsamp + " rest " + + scaleXY); + } + + docuImage.loadSubimage(fileToLoad, loadRect, (int) subsamp); + + logger.debug("SUBSAMP: " + subsamp + " -> " + docuImage.getWidth() + + "x" + docuImage.getHeight()); + + docuImage.scale(scaleXY, scaleXY); + + } else { + // else load and crop the whole file + docuImage.loadImage(fileToLoad); + docuImage.crop((int) loadRect.getX(), (int) loadRect.getY(), + (int) loadRect.getWidth(), (int) loadRect.getHeight()); + + docuImage.scale(scaleXY, scaleXY); + } + + // mirror image + // operation mode: "hmir": mirror horizontally, "vmir": mirror + // vertically + if (hmir) { + docuImage.mirror(0); + } + if (vmir) { + docuImage.mirror(90); + } + + // rotate image + if (paramROT != 0d) { + docuImage.rotate(paramROT); + if (wholeRotArea) { + // crop to the inner bounding box + float xcrop = (float) (docuImage.getWidth() - innerUserImgArea + .getWidth() + * scaleXY); + float ycrop = (float) (docuImage.getHeight() - innerUserImgArea + .getHeight() + * scaleXY); + if ((xcrop > 0) || (ycrop > 0)) { + // only crop smaller + xcrop = (xcrop > 0) ? xcrop : 0; + ycrop = (ycrop > 0) ? ycrop : 0; + // crop image + docuImage.crop((int) (xcrop / 2), (int) (ycrop / 2), + (int) (docuImage.getWidth() - xcrop), + (int) (docuImage.getHeight() - ycrop)); + } + } + + } + + // color modification + if ((paramRGBM != null) || (paramRGBA != null)) { + // make shure we actually have two arrays + if (paramRGBM == null) { + paramRGBM = new float[3]; + } + if (paramRGBA == null) { + paramRGBA = new float[3]; + } + // calculate "contrast" values (c=2^x) + float[] mult = new float[3]; + for (int i = 0; i < 3; i++) { + mult[i] = (float) Math.pow(2, (float) paramRGBM[i]); + } + docuImage.enhanceRGB(mult, paramRGBA); + } + + // contrast and brightness enhancement + if ((paramCONT != 0f) || (paramBRGT != 0f)) { + float mult = (float) Math.pow(2, paramCONT); + docuImage.enhance(mult, paramBRGT); + } + + logger.debug("rendered in " + (System.currentTimeMillis() - startTime) + "ms"); + + return docuImage; + } + + public void write(DocuImage img) throws FileOpException, IOException { + /* write the resulting image */ + + // setup output -- if output type is forced use that otherwise + // if source is JPG then dest will be JPG else it's PNG + if (forceType != ImageOps.TYPE_AUTO) { + if (forceType == ImageOps.TYPE_JPEG) { + mimeType = "image/jpeg"; + } + if (forceType == ImageOps.TYPE_PNG) { + mimeType = "image/png"; + } + } else if ((mimeType.equals("image/jpeg") + || mimeType.equals("image/jp2") || mimeType.equals("image/fpx"))) { + mimeType = "image/jpeg"; + } else { + mimeType = "image/png"; + } + + // write the image + img.writeImage(mimeType, outstream); + outstream.flush(); + + + logger.info("image worker " + this.getName() + " done in " + + (System.currentTimeMillis() - startTime)); + + img.dispose(); + } +} diff -r 794a9f25f15c -r b2325b33b77b servlet/src/digilib/servlet/DigilibPDFWorker.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/servlet/src/digilib/servlet/DigilibPDFWorker.java Mon Feb 23 14:45:22 2009 +0100 @@ -0,0 +1,227 @@ +/* DigilibImageWorker.java -- worker for image operations + * + * 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 19.10.2004 + */ + +package digilib.servlet; + +import java.awt.Rectangle; +import java.awt.geom.Rectangle2D; +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import javax.servlet.http.HttpServletResponse; + +import com.lowagie.text.BadElementException; +import com.lowagie.text.Document; +import com.lowagie.text.DocumentException; +import com.lowagie.text.Image; +import com.lowagie.text.PageSize; + +import digilib.image.DocuImage; +import digilib.image.DocuImageImpl; +import digilib.image.ImageLoaderDocuImage; +import digilib.image.ImageOpException; +import digilib.image.ImageOps; +import digilib.servlet.DigilibImageWorker; +import digilib.io.FileOpException; +import digilib.io.ImageFile; + +/** + * worker for image operations. + * + * @author casties + * + */ +public class DigilibPDFWorker extends DigilibImageWorker { + + private DigilibConfiguration dlConfig; + + + long startTime; + + String mimeType; + + int scaleQual; + + DigilibRequest dlRequest; + + float paramROT; + + float paramCONT; + + float paramBRGT; + + float[] paramRGBM; + + float[] paramRGBA; + + ImageFile fileToLoad; + + float areaXoff; + + float areaYoff; + + float areaWidth; + + float areaHeight; + + float scaleXY; + + Rectangle2D outerUserImgArea; + + Rectangle2D innerUserImgArea; + + float minSubsample; + + boolean wholeRotArea; + + int forceType; + + Document doc; + + + //public ImageLoaderDocuImage render();// throws Exception; + + + /** + * @param dlConfig + * @param response + * @param mimeType + * @param scaleQual + * @param dlRequest + * @param paramROT + * @param paramCONT + * @param paramBRGT + * @param paramRGBM + * @param paramRGBA + * @param fileToLoad + * @param areaXoff + * @param outerUserImgArea + * @param innerUserImgArea + * @param minSubsample + * @param wholeRotArea + * @param forceType + */ + public DigilibPDFWorker(DigilibConfiguration dlConfig, + BufferedOutputStream outstream, String mimeType, int scaleQual, + DigilibRequest dlRequest, float paramCONT, + float paramBRGT, float[] paramRGBM, float[] paramRGBA, + ImageFile fileToLoad, float scaleXY, Rectangle2D outerUserImgArea, + Rectangle2D innerUserImgArea, float minSubsample, + boolean wholeRotArea, int forceType, Document doc) { + super(dlConfig, + outstream, mimeType, scaleQual, + dlRequest, 0.0f , paramCONT, + paramBRGT, paramRGBM,paramRGBA, + fileToLoad, scaleXY, outerUserImgArea, + innerUserImgArea,minSubsample, + wholeRotArea, forceType); + + this.dlConfig = dlConfig; + this.outstream = outstream; + this.mimeType = mimeType; + this.scaleQual = scaleQual; + this.dlRequest = dlRequest; + //this.paramROT = paramROT; + this.paramCONT = paramCONT; + this.paramBRGT = paramBRGT; + this.paramRGBM = paramRGBM; + this.paramRGBA = paramRGBA; + this.fileToLoad = fileToLoad; + this.scaleXY = scaleXY; + this.outerUserImgArea = outerUserImgArea; + this.innerUserImgArea = innerUserImgArea; + this.minSubsample = minSubsample; + this.wholeRotArea = wholeRotArea; + this.forceType = forceType; + this.doc = doc; + } + + public void run() { + //logger.debug((++waitingThreads) + " waiting threads"); + ImageLoaderDocuImage img = null; + try { + sem.acquire(); + //waitingThreads--; + } catch (InterruptedException e) { + error = e; + //waitingThreads--; + // should we reinterrupt? + return; + } + //logger.debug((++runningThreads) + " running threads"); + try { + /* + * do rendering under the semaphore + */ + img = (ImageLoaderDocuImage) super.render(); + } catch (Throwable e) { + error = e; + logger.error(e); + } finally { + // runningThreads--; + sem.release(); + } + /* + * write the result without semaphore + */ + if (!hasError()) { + try{ + write(img); + } catch (Throwable e) { + error = e; + logger.error(e); + } + } + } + + public void write(ImageLoaderDocuImage img) throws FileOpException, IOException { + /* write the resulting image */ + + + try { + long timing = System.currentTimeMillis(); + Image theimg = Image.getInstance(img.getImage(),null); + + theimg.scaleToFit(PageSize.A4.getWidth(),PageSize.A4.getHeight()); + + logger.debug(" --- loading and scaling took "+(-timing+System.currentTimeMillis())+"ms"); + + timing = System.currentTimeMillis(); + + doc.add(theimg); + logger.debug(" --- adding took "+(-timing+System.currentTimeMillis())+"ms"); + + } catch (BadElementException e) { + e.printStackTrace(); + logger.debug("------DigilibPDFWorker write BadElementException"); + + } catch (DocumentException e) { + e.printStackTrace(); + logger.debug("------DigilibPDFWorker write DocumentException"); + + } + + logger.info("pdf worker " + this.getName() + " done in " + + (System.currentTimeMillis() - startTime)); + + } +} \ No newline at end of file diff -r 794a9f25f15c -r b2325b33b77b servlet/src/digilib/servlet/ImageJobInformation.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/servlet/src/digilib/servlet/ImageJobInformation.java Mon Feb 23 14:45:22 2009 +0100 @@ -0,0 +1,620 @@ +package digilib.servlet; + +import java.awt.geom.AffineTransform; +import java.awt.geom.NoninvertibleTransformException; +import java.awt.geom.Rectangle2D; +import java.io.IOException; +import java.util.StringTokenizer; + +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; + +import org.apache.log4j.Logger; + +import digilib.image.ImageOpException; +import digilib.image.ImageOps; +import digilib.image.ImageSize; +import digilib.io.DocuDirCache; +import digilib.io.DocuDirent; +import digilib.io.FileOpException; +import digilib.io.FileOps; +import digilib.io.ImageFile; +import digilib.io.ImageFileset; + + +/** + * A container class for storing a set of instructional parameters + * used for content generating classes like MakePDF. + * + * TODO aufraeumen, zwischenwerte in der ParameterMap cachen + * + * @author cmielack + * + */ + +public class ImageJobInformation extends ParameterMap { + + String[] parameter_list = {"fn","pn","dw","dh", + "wx", "wy", "ww", "wh", "ws", + "mo", "rot", "cont", "brgt", "rgbm", "rbgm", + "ddpi", "ddpix", "ddpiy", "scale"}; + DigilibConfiguration dlConfig = null; + protected static Logger logger = Logger.getLogger("digilib.servlet"); + + ImageFile fileToLoad = null; + ImageFileset fileset=null; + String FilePath = null; + ImageSize expectedSourceSize = null; + Float scaleXY = null; + Rectangle2D userImgArea = null; + Rectangle2D outerUserImgArea= null; + +// Integer paramDW = null; +// Integer paramDH + public ImageJobInformation() { + super(30); + + // url of the page/document (second part) + newParameter("fn", "", null, 's'); + // page number + newParameter("pn", new Integer(1), null, 's'); + // width of client in pixels + newParameter("dw", new Integer(0), null, 's'); + // height of client in pixels + newParameter("dh", new Integer(0), null, 's'); + // left edge of image (float from 0 to 1) + newParameter("wx", new Float(0), null, 's'); + // top edge in image (float from 0 to 1) + newParameter("wy", new Float(0), null, 's'); + // width of image (float from 0 to 1) + newParameter("ww", new Float(1), null, 's'); + // height of image (float from 0 to 1) + newParameter("wh", new Float(1), null, 's'); + // scale factor + newParameter("ws", new Float(1), null, 's'); + // special options like 'fit' for gifs + newParameter("mo", "", null, 's'); + // rotation angle (degree) + newParameter("rot", new Float(0), null, 's'); + // contrast enhancement factor + newParameter("cont", new Float(0), null, 's'); + // brightness enhancement factor + newParameter("brgt", new Float(0), null, 's'); + // color multiplicative factors + newParameter("rgbm", "0/0/0", null, 's'); + // color additive factors + newParameter("rgba", "0/0/0", null, 's'); + // display dpi resolution (total) + newParameter("ddpi", new Float(0), null, 's'); + // display dpi X resolution + newParameter("ddpix", new Float(0), null, 's'); + // display dpi Y resolution + newParameter("ddpiy", new Float(0), null, 's'); + // scale factor for mo=ascale + newParameter("scale", new Float(1), null, 's'); + + /* + * Parameters of type 'i' are not exchanged between client and server, + * but are for the servlets or JSPs internal use. + */ + + // url of the page/document (first part, may be empty) + newParameter("request.path", "", null, 'i'); + // base URL (from http:// to below /servlet) + newParameter("base.url", null, null, 'i'); + + /* + * Parameters of type 'c' are for the clients use + */ +/* + // "real" filename + newParameter("img.fn", "", null, 'c'); + // image dpi x + newParameter("img.dpix", new Integer(0), null, 'c'); + // image dpi y + newParameter("img.dpiy", new Integer(0), null, 'c'); + // hires image size x + newParameter("img.pix_x", new Integer(0), null, 'c'); + // hires image size y + newParameter("img.pix_y", new Integer(0), null, 'c'); + // total number of pages + newParameter("pt", new Integer(0), null, 'c'); + // display level of digilib (0 = just image, 1 = one HTML page + // 2 = in frameset, 3 = XUL-'frameset' + // 4 = XUL-Sidebar ) + newParameter("lv", new Integer(2), null, 'c'); + // marks + newParameter("mk", "", null, 'c'); +*/ + } + + public void setConfig(DigilibConfiguration dlcfg){ + dlConfig = dlcfg; + } + + public void setWithRequest(HttpServletRequest request) { + for (String param : parameter_list){ + if (request.getParameterMap().containsKey(param)){ + //request.get +// put(param, request.getParameter(param)); + this.setValueFromString(param, request.getParameter(param)); + } + } + setValueFromString("request.path", ((HttpServletRequest) request).getPathInfo()); + + } + + public String[] getParameterList(){ + return parameter_list; + } + + + public boolean hasOption(String param, String opt) { + String s = getAsString(param); + if (s != null) { + StringTokenizer i = new StringTokenizer(s, ","); + while (i.hasMoreTokens()) { + if (i.nextToken().equals(opt)) { + return true; + } + } + } + return false; + } + + + /** + * evaluate request data in order to gain the parameters for the image worker + * + * @throws ImageOpException + * @throws IOException + * */ + + public String get_mimeType() throws IOException, ImageOpException{ + String mimeType = "image/png"; + ImageFile fileToLoad = get_fileToLoad(); + if(fileToLoad != null) + mimeType = fileToLoad.getMimetype(); + return mimeType; + } + + public ImageFile get_fileToLoad() throws IOException, ImageOpException{ + + //logger.debug("get_fileToLoad()"); + if(fileToLoad == null){ + ImageFileset fileset = get_fileset(); + + /* select a resolution */ + if (get_hiresOnly()) { + // get first element (= highest resolution) + fileToLoad = fileset.getBiggest(); + } else if (get_loresOnly()) { + // enforced lores uses next smaller resolution + fileToLoad = fileset.getNextSmaller(get_expectedSourceSize()); + if (fileToLoad == null) { + // this is the smallest we have + fileToLoad = fileset.getSmallest(); + } + } else { + // autores: use next higher resolution + fileToLoad = fileset.getNextBigger(get_expectedSourceSize()); + if (fileToLoad == null) { + // this is the highest we have + fileToLoad = fileset.getBiggest(); + } + } + logger.info("Planning to load: " + fileToLoad.getFile()); + } + + return fileToLoad; + + } + + public ImageFileset get_fileset() throws FileOpException{ + //logger.debug("get_fileset()"); + if(fileset==null){ + DocuDirCache dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache"); + + fileset = (ImageFileset) dirCache.getFile(getFilePath(), getAsInt("pn"), FileOps.CLASS_IMAGE); + if (fileset == null) { + throw new FileOpException("File " + getFilePath() + "(" + + getAsInt("pn") + ") not found."); + } + } + return fileset; + } + + public String getFilePath() { + //logger.debug("getFilePath()"); + if(FilePath == null){ + String s = this.getAsString("request.path"); + s += this.getAsString("fn"); + FilePath = FileOps.normalName(s); + } + return FilePath; + } + + public boolean get_hiresOnly(){ + //logger.debug("get_hiresOnly()"); + return hasOption("mo","clip") || hasOption("mo","osize") || hasOption("mo","hires"); + } + + public boolean get_loresOnly(){ + //logger.debug("get_loresOnly()"); + + return hasOption("mo","lores"); + } + + public boolean get_scaleToFit() { + //logger.debug("get_scaleToFit()"); + + return !(hasOption("mo","clip") || hasOption("mo","osize") || hasOption("mo","ascale")); + } + + public boolean get_absoluteScale(){ + //logger.debug("get_absoluteScale()"); + + return hasOption("mo","osize") || hasOption("mo","ascale"); + } + + + public ImageSize get_expectedSourceSize() throws IOException, ImageOpException{ + //logger.debug("get_expectedSourceSize()"); + + if (expectedSourceSize == null){ + expectedSourceSize = new ImageSize(); + + if (get_scaleToFit()) { + // scale to fit -- calculate minimum source size + float scale = (1 / Math.min(getAsFloat("ww"), getAsFloat("wh"))) * getAsFloat("ws"); + expectedSourceSize.setSize((int) (getAsInt("dw") * scale), + (int) (getAsInt("dh") * scale)); + } else if (get_absoluteScale() && hasOption("mo", "ascale")) { + // absolute scale -- apply scale to hires size + expectedSourceSize = get_hiresSize().getScaled(getAsFloat("scale")); + } else { + // clip to fit -- source = destination size + expectedSourceSize.setSize((int) (getAsInt("dw") * getAsFloat("ws")), + (int) (getAsInt("dh") * getAsFloat("ws"))); + } + } + return expectedSourceSize; + } + + public ImageSize get_hiresSize() throws IOException, ImageOpException{ + logger.debug("get_hiresSize()"); + + ImageSize hiresSize = null; + ImageFileset fileset = get_fileset(); + if (get_absoluteScale()) { + ImageFile hiresFile = fileset.getBiggest(); + if (!hiresFile.isChecked()) { + ImageOps.checkFile(hiresFile); + } + hiresSize = hiresFile.getSize(); + + /* prepare resolution and scale factor for original size */ + if (hasOption("mo", "osize")) { + // get original resolution from metadata + fileset.checkMeta(); + float origResX = fileset.getResX(); + float origResY = fileset.getResY(); + if ((origResX == 0) || (origResY == 0)) { + throw new ImageOpException("Missing image DPI information!"); + } + + if ((getAsFloat("ddpix") == 0) || (getAsFloat("ddpiy") == 0)) { + throw new ImageOpException( + "Missing display DPI information!"); + } + // calculate absolute scale factor + float sx = getAsFloat("ddpix") / origResX; + float sy = getAsFloat("ddpiy") / origResY; + // currently only same scale :-( + put("scale", (sx + sy)/2f); + } + + } + return hiresSize; + + } + + public float get_scaleXY() throws IOException, ImageOpException{ + //logger.debug("get_scaleXY()"); + if(scaleXY == null){ + // coordinates and scaling + float areaWidth; + float areaHeight; + float scaleX; + float scaleY; + ImageSize imgSize = get_fileToLoad().getSize(); + ImageSize hiresSize = get_hiresSize(); + // 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(getAsFloat("wx"), getAsFloat("wy"), + getAsFloat("ww"), getAsFloat("wh")); + // 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 scaling factors based on inner user area + if (get_scaleToFit()) { + areaWidth = (float) userImgArea.getWidth(); + areaHeight = (float) userImgArea.getHeight(); + scaleX = get_paramDW() / areaWidth * getAsFloat("ws"); + scaleY = get_paramDH() / areaHeight * getAsFloat("ws"); + scaleXY = (scaleX > scaleY) ? scaleY : scaleX; + } else if (get_absoluteScale()) { + scaleXY = getAsFloat("scale"); + // we need to correct the factor if we use a pre-scaled image + if (imgSize.getWidth() != hiresSize.getWidth()) { + scaleXY *= (float)hiresSize.getWidth() / (float)imgSize.getWidth(); + } + //scaleX = scaleXY; + //scaleY = scaleXY; + areaWidth = get_paramDW() / scaleXY * getAsFloat("ws"); + areaHeight = get_paramDH() / scaleXY * getAsFloat("ws"); + // reset user area size + userImgArea.setRect(userImgArea.getX(), userImgArea.getY(), + areaWidth, areaHeight); + } else { + // crop to fit + areaWidth = get_paramDW() * getAsFloat("ws"); + areaHeight = get_paramDH() * getAsFloat("ws"); + // reset user area size + userImgArea.setRect(userImgArea.getX(), userImgArea.getY(), + areaWidth, areaHeight); + scaleX = 1f; + scaleY = 1f; + scaleXY = 1f; + } + } + + return (float) scaleXY; + } + + public int get_paramDW(){ + logger.debug("get_paramDW()"); + + int paramDW = getAsInt("dw"); + int paramDH = getAsInt("dh"); + + float imgAspect; + try { + imgAspect = get_fileToLoad().getAspect(); + if (paramDW == 0) { + paramDW = (int) Math.round(paramDH * imgAspect); + setValue("dw", paramDW); + } else if (paramDH == 0) { + setValue("dh", (int) Math.round(paramDW / imgAspect)); + } + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ImageOpException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return paramDW; + } + + public int get_paramDH(){ + logger.debug("get_paramDH()"); + + int paramDW = getAsInt("dw"); + int paramDH = getAsInt("dh"); + + float imgAspect; + try { + imgAspect = get_fileToLoad().getAspect(); + if (paramDW == 0) { + setValue("dw", (int) Math.round(paramDH * imgAspect)); + } else if (paramDH == 0) { + paramDH = (int) Math.round(paramDW / imgAspect); + setValue("dh", paramDH ); + } + + + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (ImageOpException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + return paramDH; + } + public Integer get_scaleQual(){ + logger.debug("get_scaleQual()"); + + Integer qual = dlConfig.getAsInt("default-quality"); + if(hasOption("mo","q0")) + qual = 0; + else if(hasOption("mo","q1")) + qual = 1; + else if(hasOption("mo","q2")) + qual = 2; + return qual; + } + + + public ImageSize get_imgSize() throws IOException, ImageOpException{ + logger.debug("get_imgSize()"); + + ImageSize imgSize = get_fileToLoad().getSize(); + return imgSize; + } + + public Rectangle2D get_userImgArea() throws IOException, ImageOpException{ + //logger.debug("get_userImgArea()"); + + if(userImgArea==null){ + // transform from relative [0,1] to image coordinates. + AffineTransform imgTrafo = AffineTransform.getScaleInstance(get_imgSize() + .getWidth(), get_imgSize().getHeight()); + + // user window area in [0,1] coordinates + Rectangle2D relUserArea = new Rectangle2D.Float(getAsFloat("wx"), getAsFloat("wy"), + getAsFloat("ww"), getAsFloat("wh")); + + // transform user coordinate area to image coordinate area + userImgArea = imgTrafo.createTransformedShape( + relUserArea).getBounds2D(); + + if(get_absoluteScale()){ + float areaWidth = getAsInt("dw") / get_scaleXY() * getAsFloat("ws"); + float areaHeight = getAsInt("dh") / get_scaleXY() * getAsFloat("ws"); + // reset user area size + userImgArea.setRect(userImgArea.getX(), userImgArea.getY(), + areaWidth, areaHeight); + } else if (!get_scaleToFit()){ + // crop to fit + float areaWidth = getAsInt("dw") * getAsFloat("ws"); + float areaHeight = getAsInt("dh") * getAsFloat("ws"); + // reset user area size + userImgArea.setRect(userImgArea.getX(), userImgArea.getY(), + areaWidth, areaHeight); + } + } + return userImgArea; + + } + + public Rectangle2D get_outerUserImgArea() throws IOException, ImageOpException{ + //logger.debug("get_outerUserImgArea()"); + + if(outerUserImgArea == null){ + Rectangle2D userImgArea = get_userImgArea(); + + // image size in pixels + Rectangle2D imgBounds = new Rectangle2D.Float(0, 0, get_imgSize() + .getWidth(), get_imgSize().getHeight()); + + + + + outerUserImgArea = userImgArea; + Rectangle2D innerUserImgArea = userImgArea; + if (get_wholeRotArea()) { + if (getAsFloat("rot") != 0) { + try { + // rotate user area coordinates around center of user + // area + AffineTransform rotTrafo = AffineTransform + .getRotateInstance(Math.toRadians(getAsFloat("rot")), + 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); + } + } + } + + // logger.debug("Scale " + scaleXY + "(" + scaleX + "," + scaleY + //+ ") on " + outerUserImgArea); + + // clip area at the image border + outerUserImgArea = outerUserImgArea.createIntersection(imgBounds); + + // check image parameters sanity + logger.debug("outerUserImgArea.getWidth()=" + outerUserImgArea.getWidth()); + logger.debug("get_scaleXY() * outerUserImgArea.getWidth() = " + (get_scaleXY() * outerUserImgArea.getWidth())); + + if ((outerUserImgArea.getWidth() < 1) + || (outerUserImgArea.getHeight() < 1) + || (get_scaleXY() * outerUserImgArea.getWidth() < 2) + || (get_scaleXY() * outerUserImgArea.getHeight() < 2)) { + logger.error("ERROR: invalid scale parameter set!"); + throw new ImageOpException("Invalid scale parameter set!"); + } + } + return outerUserImgArea; + } + + + public Rectangle2D get_innerUserImgArea() throws IOException, ImageOpException{ + logger.debug("get_innerUserImgArea()"); + + Rectangle2D userImgArea = get_userImgArea(); + Rectangle2D innerUserImgArea = get_userImgArea(); + if (get_wholeRotArea()) { + if (getAsFloat("rot") != 0) { + // rotate user area coordinates around center of user + // area + AffineTransform rotTrafo = AffineTransform + .getRotateInstance(Math.toRadians(getAsFloat("rot")), + userImgArea.getCenterX(), userImgArea + .getCenterY()); + // get bounds from rotated end position + innerUserImgArea = rotTrafo.createTransformedShape( + userImgArea).getBounds2D(); + } + } + return innerUserImgArea; + + } + public boolean get_wholeRotArea(){ + // TODO this is not really implemented yet + //boolean wholeRotArea = false; + return false;//wholeRotArea; + } + + public int get_forceType(){ + + if(hasOption("mo","jpg")) + return ImageOps.TYPE_JPEG; + if(hasOption("mo","png")) + return ImageOps.TYPE_PNG; + + return ImageOps.TYPE_AUTO; + } + + public float[] get_paramRGBM(){ + logger.debug("get_paramRGBM()"); + + float[] paramRGBM = {0f,0f,0f}; + Parameter p = get("rgbm"); + if (p.hasValue() && (!p.getAsString().equals("0/0/0"))) { + return p.parseAsFloatArray("/"); + } + return paramRGBM; + } + + public float[] get_paramRGBA(){ + logger.debug("get_paramRGBA()"); + + float[] paramRGBA = {0f,0f,0f}; + Parameter p = get("rgba"); + if (p.hasValue() && (!p.getAsString().equals("0/0/0"))) { + paramRGBA = p.parseAsFloatArray("/"); + } + return paramRGBA; + } + + public boolean get_hmir(){ + logger.debug("get_hmir()"); + + return hasOption("mo","hmir"); + } + + public boolean get_vmir(){ + logger.debug("get_vmir()"); + + return hasOption("mo","vmir"); + } +} \ No newline at end of file diff -r 794a9f25f15c -r b2325b33b77b servlet/src/digilib/servlet/PDFCache.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/servlet/src/digilib/servlet/PDFCache.java Mon Feb 23 14:45:22 2009 +0100 @@ -0,0 +1,60 @@ +package digilib.servlet; + +import java.io.InputStream; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +public class PDFCache extends RequestHandler { + + + public static Integer STATUS_DONE = 0; // document exists in cache + + public static Integer STATUS_WIP = 1; // document is "work in progress" + + public static Integer STATUS_NONEXISTENT = 2; // document does not exist in cache and is not in progress + + public static Integer STATUS_ERROR = 3; // an error occurred while processing the request + + + + + @Override + public void processRequest(HttpServletRequest request, + HttpServletResponse response) { + + // evaluate request ( make a PDFJobDeclaration , get the DocumentId) + + // check, which state the requested document is in (ready, work in progress, non existent) + + // if necessary, initialize document generation (and notify the user) + + // send the document + } + + @Override + public void sendFile(InputStream is, HttpServletResponse response, String filename) { + + } + + public String getDocumentId(PDFJobDeclaration jobdeclaration){ + // generate an unambiguous ID from the request (this is used for filenames etc) + String id; + + String fn = jobdeclaration.getAsString("fn"); + String dh = jobdeclaration.getAsString("dh"); + String pgs = jobdeclaration.getAsString("pgs"); + + id = "fn=" + fn + "&dh=" + dh + "&pgs=" + pgs + ".pdf"; + + return id; + } + + + /** check the status of the document corresponding to the documentid */ + public Integer getStatus(String documentid){ + + + return 0; + } +} diff -r 794a9f25f15c -r b2325b33b77b servlet/src/digilib/servlet/PDFJobDeclaration.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/servlet/src/digilib/servlet/PDFJobDeclaration.java Mon Feb 23 14:45:22 2009 +0100 @@ -0,0 +1,112 @@ +package digilib.servlet; + +import javax.servlet.http.HttpServletRequest; + + +/** + * A container class for storing a set of instructional parameters + * used for content generating classes like MakePDF. + * + * + * @author cmielack + * + */ + + + +public class PDFJobDeclaration extends ParameterMap { + + String[] parameter_list = {"fn","pgs","dw","dh"};/*, + "wx", "wy", "ww", "wh", "ws", + "mo", "rot", "cont", "brgt", "rgbm", "rbgm", + "ddpi", "ddpix", "ddpiy", "scale"};*/ + + public PDFJobDeclaration() { + super(30); + + // url of the page/document (second part) + newParameter("fn", "", null, 's'); + // page number + newParameter("pgs", "", null, 's'); + // width of client in pixels + newParameter("dw", new Integer(0), null, 's'); + // height of client in pixels + newParameter("dh", new Integer(0), null, 's'); + // left edge of image (float from 0 to 1) +/* newParameter("wx", new Float(0), null, 's'); + // top edge in image (float from 0 to 1) + newParameter("wy", new Float(0), null, 's'); + // width of image (float from 0 to 1) + newParameter("ww", new Float(1), null, 's'); + // height of image (float from 0 to 1) + newParameter("wh", new Float(1), null, 's'); + // scale factor + newParameter("ws", new Float(1), null, 's'); + // special options like 'fit' for gifs + newParameter("mo", "", null, 's'); + // rotation angle (degree) + newParameter("rot", new Float(0), null, 's'); + // contrast enhancement factor + newParameter("cont", new Float(0), null, 's'); + // brightness enhancement factor + newParameter("brgt", new Float(0), null, 's'); + // color multiplicative factors + newParameter("rgbm", "0/0/0", null, 's'); + // color additive factors + newParameter("rgba", "0/0/0", null, 's'); + // display dpi resolution (total) + newParameter("ddpi", new Float(0), null, 's'); + // display dpi X resolution + newParameter("ddpix", new Float(0), null, 's'); + // display dpi Y resolution + newParameter("ddpiy", new Float(0), null, 's'); + // scale factor for mo=ascale + newParameter("scale", new Float(1), null, 's'); +*/ + /* + * Parameters of type 'i' are not exchanged between client and server, + * but are for the servlets or JSPs internal use. + */ + +/* // url of the page/document (first part, may be empty) + newParameter("request.path", "", null, 'i'); + // base URL (from http:// to below /servlet) + newParameter("base.url", null, null, 'i'); + // DocuImage instance for this request +*/ + /* + * Parameters of type 'c' are for the clients use + */ + +/* // "real" filename + newParameter("img.fn", "", null, 'c'); + // image dpi x + newParameter("img.dpix", new Integer(0), null, 'c'); + // image dpi y + newParameter("img.dpiy", new Integer(0), null, 'c'); + // hires image size x + newParameter("img.pix_x", new Integer(0), null, 'c'); + // hires image size y + newParameter("img.pix_y", new Integer(0), null, 'c'); + // total number of pages + newParameter("pt", new Integer(0), null, 'c'); + // display level of digilib (0 = just image, 1 = one HTML page + // 2 = in frameset, 3 = XUL-'frameset' + // 4 = XUL-Sidebar ) + newParameter("lv", new Integer(2), null, 'c'); + // marks + newParameter("mk", "", null, 'c'); +*/ + + } + + public void setWithRequest(HttpServletRequest request) { + for (String param : parameter_list){ + if (request.getParameterMap().containsKey(param)){ + put(param, request.getAttribute(param)); + } + } + } + + +} \ No newline at end of file diff -r 794a9f25f15c -r b2325b33b77b servlet/src/digilib/servlet/PDFMaker.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/servlet/src/digilib/servlet/PDFMaker.java Mon Feb 23 14:45:22 2009 +0100 @@ -0,0 +1,931 @@ +/* + * MakePDF + * + * 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 java.awt.geom.AffineTransform; +import java.awt.geom.NoninvertibleTransformException; +import java.awt.geom.Rectangle2D; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.List; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.log4j.Logger; + +import com.lowagie.text.*; +import com.lowagie.text.pdf.PdfWriter; + +import digilib.auth.AuthOpException; +import digilib.auth.AuthOps; +import digilib.image.ImageOpException; +import digilib.image.ImageOps; +import digilib.image.ImageSize; +import digilib.io.DocuDirCache; +import digilib.io.DocuDirectory; +import digilib.io.DocuDirent; +import digilib.io.FileOpException; +import digilib.io.FileOps; +import digilib.io.ImageFile; +import digilib.io.ImageFileset; + +/** + * generates pdf-files from a digilib images. + * This is a very quick and dirty but functional version and will + * (hopefully soon) be replaced by a parallelized and more sophisticated one. + * + * @author cmielack + */ + +public class PDFMaker extends HttpServlet implements Runnable{ + + private static final long serialVersionUID = -325080527268912852L; + + /** digilib servlet version (for all components) */ + public static final String dlVersion = "1.7.0b"; + + /** 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; + + /** DocuDirCache instance */ + DocuDirCache dirCache; + + /** authentication error image file */ + File denyImgFile; + + /** image error image file */ + File errorImgFile; + + /** not found error image file */ + File notfoundImgFile; + + /** 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; + + HttpServletRequest mpdf_request = null; + HttpServletResponse mpdf_response = null; + String mpdf_filename = ""; + + String default_filename = "digilib_pages.pdf"; + + + // 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 MakePDF Servlet (version " + + dlVersion + ") *****"); + // say hello in the log file + logger + .info("***** Digital Image Library Image MakePDF Servlet (version " + + dlVersion + ") *****"); + + // get our ServletContext + ServletContext context = config.getServletContext(); + // see if there is a Configuration instance + dlConfig = (DigilibConfiguration) context + .getAttribute("digilib.servlet.configuration"); + if (dlConfig == null) { + // no Configuration + throw new ServletException("No Configuration!"); + } + // set our AuthOps + useAuthorization = dlConfig.getAsBoolean("use-authorization"); + authOp = (AuthOps) dlConfig.getValue("servlet.auth.op"); + + // DocuDirCache instance + dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache"); + denyImgFile = ServletOps.getFile((File) dlConfig.getValue("denied-image"), config); + errorImgFile = ServletOps.getFile((File) dlConfig.getValue("error-image"), config); + notfoundImgFile = ServletOps.getFile((File) dlConfig.getValue("notfound-image"), config); + sendFileAllowed = dlConfig.getAsBoolean("sendfile-allowed"); + minSubsample = dlConfig.getAsFloat("subsample-minimum"); + defaultQuality = dlConfig.getAsInt("default-quality"); + + + context.setAttribute("digilib.servlet.MakePDF", this); // register this instance globally, so PDFCache can access it + } + + + public void doCreate(HttpServletRequest request, HttpServletResponse response, String filename) + 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); + + + mpdf_request = request; + mpdf_response = response; + mpdf_filename = filename; + + } + +/* 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,default_filename); + }*/ + +/* 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,default_filename); + }*/ + + /* + * (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 + DocuDirent f = findFile(dlReq); + if (f != null) { + DocuDirectory dd = (DocuDirectory) f.getParent(); + mtime = dd.getDirMTime() / 1000 * 1000; + } + return mtime; + } + + void createPDFfile(HttpServletRequest request, HttpServletResponse response, String filename) + throws javax.servlet.ServletException, java.io.IOException { + + Hashtable cache_hash = (Hashtable) this.getServletContext().getAttribute("digilib.servlet.PDFCache"); + BufferedOutputStream pdfOutStream = null; + FileOutputStream fos = null; + + String file_only = filename.split("/")[filename.split("/").length-1]; + + try { + + cache_hash.put(file_only, 2); // register the file as 'pending' + + // TODO check, if file can be created without overwriting another file etc. + + fos = new FileOutputStream(filename); + + pdfOutStream = generatePDFcontent(request, response, this.getServletContext(), fos); + + fos.flush(); + + cache_hash.put(file_only, 1); // register the file as 'done' + + } + catch (DocumentException de){ + // inform the user about what went wrong + response.setContentType("text/html"); + PrintWriter writer = response.getWriter(); + writer.println(this.getClass().getName() + " caught an exception: " + + de.getClass().getName() + "
");
+			de.printStackTrace(writer);
+			writer.println("
"); + } + + finally { + if (pdfOutStream != null){ + pdfOutStream.close(); + } + if (fos!=null){ + fos.close(); + } + } + } + + + + + void addImageToPDF(HttpServletRequest request, HttpServletResponse response, int pn, Document doc) + throws ServletException { + /** until now, this is taken from the Scaler-method processRequest and modified ...*/ + + + if (dlConfig == null) { + throw new ServletException("ERROR: No Configuration!"); + } + + accountlog.debug("request: " + request.getQueryString()); + logger.debug("request: " + request.getQueryString()); + + // output mime-type + String mimeType = "image/png"; + + /* preset request parameters */ + + // 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; + // use low resolution images only + boolean loresOnly = false; + // use hires images only + boolean hiresOnly = false; + // send the image always as a specific type (e.g. JPEG or PNG) + int forceType = ImageOps.TYPE_AUTO; + // interpolation to use for scaling + int scaleQual = defaultQuality; + // send html error message (or image file) + boolean errorMsgHtml = false; + // original (hires) image resolution + float origResX = 0; + float origResY = 0; + + /* request parameters */ + + DigilibRequest dlRequest = (DigilibRequest) request + .getAttribute("digilib.servlet.request"); + + dlRequest.setValue("pn", pn); + //dlRequest.setValue("mo", "osize"); + //dlRequest.setValue("ddpix",72); + //dlRequest.setValue("ddpix",72); + + // 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; + } + // absolute scale factor for mo=ascale (and mo=osize) + float paramSCALE = dlRequest.getAsFloat("scale"); + + /* + * 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; + hiresOnly = true; + } else if (dlRequest.hasOption("mo", "fit")) { + scaleToFit = true; + absoluteScale = false; + hiresOnly = false; + } else if (dlRequest.hasOption("mo", "osize")) { + scaleToFit = false; + absoluteScale = true; + hiresOnly = true; + } else if (dlRequest.hasOption("mo", "ascale")) { + scaleToFit = false; + absoluteScale = true; + hiresOnly = false; + } + + // 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")) { + forceType = ImageOps.TYPE_JPEG; + } + // operation mode: "png": always use PNG + if (dlRequest.hasOption("mo", "png")) { + forceType = ImageOps.TYPE_PNG; + } + + // 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; + } + + // "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(); + + /* 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."); + } + + /* for absolute scale and original size we need the hires size */ + ImageSize hiresSize = null; + if (absoluteScale) { + ImageFile hiresFile = fileset.getBiggest(); + if (!hiresFile.isChecked()) { + ImageOps.checkFile(hiresFile); + } + hiresSize = hiresFile.getSize(); + + /* prepare resolution and scale factor for original size */ + if (dlRequest.hasOption("mo", "osize")) { + // get original resolution from metadata + fileset.checkMeta(); + origResX = fileset.getResX(); + origResY = fileset.getResY(); + if ((origResX == 0) || (origResY == 0)) { + throw new ImageOpException("Missing image DPI information!"); + } + + if ((paramDDPIX == 0) || (paramDDPIY == 0)) { + throw new ImageOpException( + "Missing display DPI information!"); + } + // calculate absolute scale factor + float sx = paramDDPIX / origResX; + float sy = paramDDPIY / origResY; + // currently only same scale :-( + paramSCALE = (sx + sy)/2f; + } + + } + + + /* calculate expected source image size */ + ImageSize expectedSourceSize = new ImageSize(); + if (scaleToFit) { + // scale to fit -- calculate minimum source size + float scale = (1 / Math.min(paramWW, paramWH)) * paramWS; + expectedSourceSize.setSize((int) (paramDW * scale), + (int) (paramDH * scale)); + } else if (absoluteScale && dlRequest.hasOption("mo", "ascale")) { + // absolute scale -- apply scale to hires size + expectedSourceSize = hiresSize.getScaled(paramSCALE); + } else { + // clip to fit -- source = destination size + expectedSourceSize.setSize((int) (paramDW * paramWS), + (int) (paramDH * paramWS)); + } + + 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.getFile()); + + /* + * 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.getFile(), mt, response); + return; + } + } + + // check the source image + if (!fileToLoad.isChecked()) { + ImageOps.checkFile(fileToLoad); + } + // get the source image type + mimeType = fileToLoad.getMimetype(); + // get the source image size + ImageSize imgSize = fileToLoad.getSize(); + + // 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; + + /* + * 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.getFile(), null, response); + + logger.info("Done in " + + (System.currentTimeMillis() - startTime) + "ms"); + return; + } +*/ + + + /* + * stop here if we're overloaded... + * + * 503 Service Unavailable + * The server is currently unable to + * handle the request due to a temporary overloading or maintenance + * of the server. The implication is that this is a temporary + * condition which will be alleviated after some delay. If known, + * the length of the delay MAY be indicated in a Retry-After header. + * If no Retry-After is given, the client SHOULD handle the response + * as it would for a 500 response. Note: The existence of the 503 + * status code does not imply that a server must use it when + * becoming overloaded. Some servers may wish to simply refuse the + * connection. + * (RFC2616 HTTP1.1) + */ + if (! DigilibWorker.canRun()) { + logger.error("Servlet overloaded!"); + response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); + return; + } + + // set missing dw or dh from aspect ratio + float imgAspect = fileToLoad.getAspect(); + if (paramDW == 0) { + paramDW = (int) Math.round(paramDH * imgAspect); + } else if (paramDH == 0) { + paramDH = (int) Math.round(paramDW / imgAspect); + } + + /* crop and scale the image */ + + logger.debug("IMG: " + imgSize.getWidth() + "x" + + imgSize.getHeight()); + + // coordinates and scaling + float areaWidth; + float areaHeight; + float scaleX; + float scaleY; + float scaleXY; + + // 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 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) { + scaleXY = paramSCALE; + // we need to correct the factor if we use a pre-scaled image + if (imgSize.getWidth() != hiresSize.getWidth()) { + scaleXY *= (float)hiresSize.getWidth() / (float)imgSize.getWidth(); + } + scaleX = scaleXY; + scaleY = scaleXY; + 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; + } + + // 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); + } + } + } + + logger.debug("Scale " + scaleXY + "(" + scaleX + "," + scaleY + + ") on " + outerUserImgArea); + + // clip area at the image border + outerUserImgArea = outerUserImgArea.createIntersection(imgBounds); + + // 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!"); + } + + /* + * submit the image worker job + */ + + DigilibPDFWorker job = new DigilibPDFWorker(dlConfig, response, + mimeType, scaleQual, dlRequest, paramCONT, + paramBRGT, paramRGBM, paramRGBA, fileToLoad, scaleXY, + outerUserImgArea, innerUserImgArea, minSubsample, + wholeRotArea, forceType, doc); + + job.run(); + if (job.hasError()) { + throw new ImageOpException(job.getError().toString()); + } + + /* 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); + } + } + + /** + * Returns the DocuDirent corresponding to the DigilibRequest. + * + * @param dlRequest + * @return + */ + public DocuDirent findFile(DigilibRequest dlRequest) { + // find the file(set) + DocuDirent 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 (type == ERROR_FILE) { + if (msg == null) { + msg = "ERROR: Image file not found!"; + } + img = notfoundImgFile; + } 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); + } + + } + + /** + * @return the dlVersion + */ + public static String getVersion() { + return dlVersion; + } + + + protected BufferedOutputStream generatePDFcontent(HttpServletRequest request, HttpServletResponse response, + ServletContext servletcontext, OutputStream out) + throws DocumentException { + + /** This method sets up a document and calls the addImage method to add all the images */ + Document doc = new Document(PageSize.A4,0,0,0,0); + BufferedOutputStream outstream = new BufferedOutputStream(out); + + PdfWriter docwriter = null; + + + try{ + + docwriter = PdfWriter.getInstance(doc, outstream); + + + doc.addAuthor(this.getClass().getName()); + doc.addCreationDate(); + doc.addKeywords("digilib"); + doc.addTitle("digilib PDF"); + doc.addCreator(this.getClass().getName()); + + doc.open(); + + + // get width and height from the request +/* float docW = PageSize.A4.getWidth() - 2*PageSize.A4.getBorder(); + float docH= PageSize.A4.getHeight()- 2*PageSize.A4.getBorder(); +*/ + + // evaluate the pgs parameter (which pages go into the pdf) + String pages = request.getParameter("pgs"); + ArrayList pgs=new ArrayList(); // a list of the requested page numbers + String intervals[] = pages.split(","); + + // convert the page-interval-strings into a list containing every single page + for(String interval: intervals){ + if(interval.indexOf("-") > -1){ + String nums[] = interval.split("-"); + + for(int i=Integer.valueOf(nums[0]); i <= Integer.valueOf(nums[1]); i++){ + pgs.add(i); + } + } + else{ + pgs.add(Integer.valueOf(interval)); + } + } + + + + + // add all the images/pages to the pdf + for(int i=0; i 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); + /** 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 + ") *****"); - /**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 { + // 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"); - // time for benchmarking - long startTime = System.currentTimeMillis(); - // output mime/type - String mimeType = "image/png"; - - /** - * parameters for a session - */ + // DocuDirCache instance + dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache"); + denyImgFile = ServletOps.getFile((File) dlConfig.getValue("denied-image"), config); + errorImgFile = ServletOps.getFile((File) dlConfig.getValue("error-image"), config); + notfoundImgFile = ServletOps.getFile((File) dlConfig.getValue("notfound-image"), config); + sendFileAllowed = dlConfig.getAsBoolean("sendfile-allowed"); + minSubsample = dlConfig.getAsFloat("subsample-minimum"); + defaultQuality = dlConfig.getAsInt("default-quality"); + } - // 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; + @Override + public void processRequest(HttpServletRequest request, + HttpServletResponse response) throws ServletException, ImageOpException { - /** - * request parameter - */ + + if (dlConfig == null) { + throw new ServletException("ERROR: No Configuration!"); + } + + accountlog.debug("request: " + request.getQueryString()); + logger.debug("request: " + request.getQueryString()); + + + + // define the job information + ImageJobInformation jobdeclaration = new ImageJobInformation(); - // 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; - } - - 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); - - //"big" try for all file/image actions - try { + jobdeclaration.setWithRequest(request); + jobdeclaration.setConfig(dlConfig); + + + + + // TODO check, if file can be sent without transformations + + + + + OutputStream outputstream = null; + try { + outputstream = response.getOutputStream(); + } catch (IOException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + logger.error(e1.getMessage()); + } + + + DigilibWorker job=null; + try { + +/* logger.debug(outputstream.toString()); + logger.debug(jobdeclaration.get_mimeType().toString()); + logger.debug(jobdeclaration.get_scaleQual().toString()); + logger.debug(jobdeclaration.getAsFloat("rot")); + logger.debug(jobdeclaration.getAsFloat("cont")); + logger.debug(jobdeclaration.getAsFloat("brgt")); + logger.debug(jobdeclaration.get_paramRGBM().toString()); + logger.debug(jobdeclaration.get_paramRGBA().toString()); + logger.debug("fileToLoad " + jobdeclaration.get_fileToLoad().toString()); + logger.debug("scaleXY " + jobdeclaration.get_scaleXY()); + logger.debug("get_outerUserImgArea " + jobdeclaration.get_outerUserImgArea().toString()); + logger.debug("get_innerUserImgArea " + jobdeclaration.get_innerUserImgArea().toString()); + logger.debug("minSubsample " + minSubsample); + logger.debug("get_wholeRotArea " + jobdeclaration.get_wholeRotArea()); + logger.debug("get_forceType "+jobdeclaration.get_forceType()); */ + + float scaleXY = jobdeclaration.get_scaleXY(); + + long startTime = System.currentTimeMillis(); - // DocuImage instance - DocuImage docuImage = new JAIDocuImage(util); -// DocuImage docuImage = new JIMIDocuImage(util); - //DocuImage docuImage = new ImageLoaderDocuImage(util); - - - /** - * find the file to load/send - */ - - 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; - } + + job = new DigilibImageWorker(dlConfig, + outputstream , + jobdeclaration.get_mimeType(), + jobdeclaration.get_scaleQual(), + //jobdeclaration, + jobdeclaration.getAsFloat("rot"), + jobdeclaration.getAsFloat("cont"), + jobdeclaration.getAsFloat("brgt"), + jobdeclaration.get_paramRGBM(), + jobdeclaration.get_paramRGBA(), + jobdeclaration.get_fileToLoad(), + scaleXY, + jobdeclaration.get_outerUserImgArea(), + jobdeclaration.get_innerUserImgArea(), + minSubsample, + jobdeclaration.get_wholeRotArea(), + jobdeclaration.get_forceType(), + jobdeclaration.get_hmir(), + jobdeclaration.get_vmir()); - 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; - } - } - } + job.run(); - // find the file - File fileToLoad = fileOp.getFileVariant(baseDirs, loadPathName, param_pn, preScaledFirst); - - Utils.dprintln(1, "Loading: "+fileToLoad); - - // get the source image type (if it's known) - mimeType = fileOp.mimeForFile(fileToLoad); - - // 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."); + if (job.hasError()) { + throw new ImageOpException(job.getError().toString()); + } - 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"); + try { + outputstream.flush(); + logger.debug("Job Processing Time: "+ (System.currentTimeMillis()-startTime) + "ms"); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + logger.error(e.getMessage()); + response.sendError(1); + } - // 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; + + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + logger.error(e.getClass()+": "+ e.getMessage()); + //response.sendError(1); + } catch (ImageOpException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + logger.error(e.getClass()+": "+ e.getMessage()); + //response.sendError(1); + } - util.dprintln(1, "Scale "+scaleXY+"("+scaleX+","+scaleY+") on "+areaXoff+","+areaYoff+" "+areaWidth+"x"+areaHeight); + + - // 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); - - // 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!"); - } - - // crop and scale image - docuImage.cropAndScale((int)areaXoff, (int)areaYoff, (int)areaWidth, (int)areaHeight, - scaleXY, scaleQual); - - util.dprintln(2, "time "+(System.currentTimeMillis()-startTime)+"ms"); + + /*boolean errorMsgHtml = false; + + if(jobdeclaration.hasOption("mo","errtxt")){ + errorMsgHtml = true; + } else if (jobdeclaration.hasOption("mo","errimg")) { + errorMsgHtml = true; + } + + + + */ + + + } - /** - * write the resulting image - */ - - // setup output -- if source is JPG then dest will be JPG else it's PNG - if (mimeType != "image/jpeg") { - mimeType="image/png"; - } - - // write the image - docuImage.writeImage(mimeType, response); - - util.dprintln(1, "Done in "+(System.currentTimeMillis()-startTime)+"ms"); - - /** - * error handling - */ + + + /** + * 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 (type == ERROR_FILE) { + if (msg == null) { + msg = "ERROR: Image file not found!"; + } + img = notfoundImgFile; + } 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); + } - }//"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; - } + } - } + public static String getVersion(){ + return dlVersion; + } + -}//Scaler class +}