Mercurial > hg > digilib-old
annotate servlet/src/digilib/image/ImageJobDescription.java @ 787:b322f553f92e jquery
more new plugin architecture.
author | robcast |
---|---|
date | Thu, 17 Feb 2011 22:36:49 +0100 |
parents | 4b686a0d44f7 |
children | 4568e539abd2 |
rev | line source |
---|---|
557 | 1 package digilib.image; |
500 | 2 |
3 import java.awt.geom.AffineTransform; | |
4 import java.awt.geom.Rectangle2D; | |
5 import java.io.IOException; | |
6 | |
7 import org.apache.log4j.Logger; | |
8 | |
9 import digilib.io.DocuDirCache; | |
541 | 10 import digilib.io.DocuDirectory; |
500 | 11 import digilib.io.FileOpException; |
12 import digilib.io.FileOps; | |
563 | 13 import digilib.io.FileOps.FileClass; |
500 | 14 import digilib.io.ImageFile; |
15 import digilib.io.ImageFileset; | |
557 | 16 import digilib.servlet.DigilibConfiguration; |
17 import digilib.util.OptionsSet; | |
18 import digilib.util.Parameter; | |
19 import digilib.util.ParameterMap; | |
500 | 20 |
21 | |
22 /** | |
23 * A container class for storing a set of instructional parameters | |
24 * used for content generating classes like MakePDF. | |
25 * | |
511 | 26 * This contains the functionality formerly found in Scaler, processRequest, only factorized. |
27 * | |
28 * TODO clean up... | |
500 | 29 * |
547 | 30 * @author cmielack, casties |
500 | 31 * |
32 */ | |
33 | |
547 | 34 public class ImageJobDescription extends ParameterMap { |
500 | 35 |
36 DigilibConfiguration dlConfig = null; | |
37 protected static Logger logger = Logger.getLogger("digilib.servlet"); | |
38 | |
39 ImageFile fileToLoad = null; | |
547 | 40 ImageFileset fileset = null; |
541 | 41 DocuDirectory fileDir = null; |
42 String filePath = null; | |
500 | 43 ImageSize expectedSourceSize = null; |
44 Float scaleXY = null; | |
45 Rectangle2D userImgArea = null; | |
46 Rectangle2D outerUserImgArea= null; | |
502 | 47 Boolean imageSendable = null; |
547 | 48 String mimeType; |
49 Integer paramDW; | |
50 Integer paramDH; | |
51 | |
52 /** create empty ImageJobDescription. | |
53 * @param dlcfg | |
54 */ | |
55 public ImageJobDescription(DigilibConfiguration dlcfg) { | |
500 | 56 super(30); |
547 | 57 dlConfig = dlcfg; |
552 | 58 } |
59 | |
60 | |
61 /** set up Parameters | |
557 | 62 * @see digilib.util.ParameterMap#initParams() |
552 | 63 */ |
64 @Override | |
65 protected void initParams() { | |
500 | 66 // url of the page/document (second part) |
67 newParameter("fn", "", null, 's'); | |
68 // page number | |
69 newParameter("pn", new Integer(1), null, 's'); | |
70 // width of client in pixels | |
71 newParameter("dw", new Integer(0), null, 's'); | |
72 // height of client in pixels | |
73 newParameter("dh", new Integer(0), null, 's'); | |
74 // left edge of image (float from 0 to 1) | |
75 newParameter("wx", new Float(0), null, 's'); | |
76 // top edge in image (float from 0 to 1) | |
77 newParameter("wy", new Float(0), null, 's'); | |
78 // width of image (float from 0 to 1) | |
79 newParameter("ww", new Float(1), null, 's'); | |
80 // height of image (float from 0 to 1) | |
81 newParameter("wh", new Float(1), null, 's'); | |
82 // scale factor | |
83 newParameter("ws", new Float(1), null, 's'); | |
84 // special options like 'fit' for gifs | |
547 | 85 newParameter("mo", this.options, null, 's'); |
500 | 86 // rotation angle (degree) |
87 newParameter("rot", new Float(0), null, 's'); | |
88 // contrast enhancement factor | |
89 newParameter("cont", new Float(0), null, 's'); | |
90 // brightness enhancement factor | |
91 newParameter("brgt", new Float(0), null, 's'); | |
92 // color multiplicative factors | |
93 newParameter("rgbm", "0/0/0", null, 's'); | |
94 // color additive factors | |
95 newParameter("rgba", "0/0/0", null, 's'); | |
96 // display dpi resolution (total) | |
97 newParameter("ddpi", new Float(0), null, 's'); | |
98 // display dpi X resolution | |
99 newParameter("ddpix", new Float(0), null, 's'); | |
100 // display dpi Y resolution | |
101 newParameter("ddpiy", new Float(0), null, 's'); | |
102 // scale factor for mo=ascale | |
103 newParameter("scale", new Float(1), null, 's'); | |
104 } | |
105 | |
503
fdb824bd57ab
first functional version of PDFCache after restructuring the code
cmielack
parents:
502
diff
changeset
|
106 |
552 | 107 /* (non-Javadoc) |
108 * @see digilib.servlet.ParameterMap#initOptions() | |
547 | 109 */ |
552 | 110 @Override |
111 protected void initOptions() { | |
565 | 112 String s = this.getAsString("mo"); |
113 options = new OptionsSet(s); | |
500 | 114 } |
552 | 115 |
116 | |
117 /** Creates new ImageJobDescription by merging Parameters from another ParameterMap. | |
118 * @param pm | |
119 * @param dlcfg | |
120 * @return | |
121 */ | |
557 | 122 public static ImageJobDescription getInstance(ParameterMap pm, DigilibConfiguration dlcfg) { |
552 | 123 ImageJobDescription newMap = new ImageJobDescription(dlcfg); |
124 // add all params to this map | |
557 | 125 newMap.params.putAll(pm.getParams()); |
552 | 126 newMap.initOptions(); |
127 return newMap; | |
128 } | |
129 | |
500 | 130 |
547 | 131 public String getMimeType() throws IOException { |
132 if (mimeType == null) { | |
133 fileToLoad = getFileToLoad(); | |
134 if(! fileToLoad.isChecked()){ | |
563 | 135 DigilibConfiguration.docuImageIdentify(fileToLoad); |
502 | 136 } |
547 | 137 mimeType = fileToLoad.getMimetype(); |
502 | 138 } |
500 | 139 return mimeType; |
140 } | |
141 | |
547 | 142 public ImageFile getFileToLoad() throws IOException { |
500 | 143 |
144 if(fileToLoad == null){ | |
547 | 145 fileset = getFileset(); |
500 | 146 |
147 /* select a resolution */ | |
547 | 148 if (getHiresOnly()) { |
500 | 149 // get first element (= highest resolution) |
150 fileToLoad = fileset.getBiggest(); | |
547 | 151 } else if (getLoresOnly()) { |
500 | 152 // enforced lores uses next smaller resolution |
547 | 153 fileToLoad = fileset.getNextSmaller(getExpectedSourceSize()); |
500 | 154 if (fileToLoad == null) { |
155 // this is the smallest we have | |
156 fileToLoad = fileset.getSmallest(); | |
157 } | |
158 } else { | |
159 // autores: use next higher resolution | |
547 | 160 fileToLoad = fileset.getNextBigger(getExpectedSourceSize()); |
500 | 161 if (fileToLoad == null) { |
162 // this is the highest we have | |
163 fileToLoad = fileset.getBiggest(); | |
164 } | |
165 } | |
166 logger.info("Planning to load: " + fileToLoad.getFile()); | |
167 } | |
168 | |
169 return fileToLoad; | |
170 | |
171 } | |
172 | |
557 | 173 public DocuDirectory getFileDirectory() throws FileOpException { |
555 | 174 if(fileDir == null){ |
500 | 175 DocuDirCache dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache"); |
555 | 176 String fp = getFilePath(); |
177 fileDir = dirCache.getDirectory(fp); | |
541 | 178 if (fileDir == null) { |
179 throw new FileOpException("Directory " + getFilePath() + " not found."); | |
500 | 180 } |
181 } | |
541 | 182 return fileDir; |
500 | 183 } |
184 | |
557 | 185 public ImageFileset getFileset() throws FileOpException { |
541 | 186 if(fileset==null){ |
187 DocuDirCache dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache"); | |
188 | |
563 | 189 fileset = (ImageFileset) dirCache.getFile(getFilePath(), getAsInt("pn"), FileClass.IMAGE); |
541 | 190 if (fileset == null) { |
191 throw new FileOpException("File " + getFilePath() + "(" | |
192 + getAsInt("pn") + ") not found."); | |
193 } | |
194 } | |
195 return fileset; | |
196 } | |
197 | |
500 | 198 public String getFilePath() { |
541 | 199 if(filePath == null){ |
500 | 200 String s = this.getAsString("request.path"); |
201 s += this.getAsString("fn"); | |
541 | 202 filePath = FileOps.normalName(s); |
500 | 203 } |
541 | 204 return filePath; |
500 | 205 } |
206 | |
547 | 207 public boolean getHiresOnly(){ |
208 return hasOption("clip") || hasOption("hires"); | |
500 | 209 } |
210 | |
547 | 211 public boolean getLoresOnly(){ |
212 return hasOption("lores"); | |
500 | 213 } |
214 | |
547 | 215 public boolean getScaleToFit() { |
216 return !(hasOption("clip") || hasOption("osize") || hasOption("ascale")); | |
500 | 217 } |
218 | |
547 | 219 public boolean getAbsoluteScale(){ |
220 return hasOption("osize") || hasOption("ascale"); | |
500 | 221 } |
222 | |
223 | |
547 | 224 public ImageSize getExpectedSourceSize() throws IOException { |
500 | 225 if (expectedSourceSize == null){ |
226 expectedSourceSize = new ImageSize(); | |
547 | 227 if (getScaleToFit()) { |
500 | 228 // scale to fit -- calculate minimum source size |
229 float scale = (1 / Math.min(getAsFloat("ww"), getAsFloat("wh"))) * getAsFloat("ws"); | |
547 | 230 expectedSourceSize.setSize((int) (getDw() * scale), |
231 (int) (getDh() * scale)); | |
232 } else if (getAbsoluteScale() && hasOption("ascale")) { | |
500 | 233 // absolute scale -- apply scale to hires size |
547 | 234 expectedSourceSize = getHiresSize().getScaled(getAsFloat("scale")); |
500 | 235 } else { |
236 // clip to fit -- source = destination size | |
547 | 237 expectedSourceSize.setSize((int) (getDw() * getAsFloat("ws")), |
238 (int) (getDh() * getAsFloat("ws"))); | |
500 | 239 } |
240 } | |
241 return expectedSourceSize; | |
242 } | |
243 | |
547 | 244 public ImageSize getHiresSize() throws IOException { |
500 | 245 logger.debug("get_hiresSize()"); |
246 | |
247 ImageSize hiresSize = null; | |
547 | 248 ImageFileset fileset = getFileset(); |
249 if (getAbsoluteScale()) { | |
500 | 250 ImageFile hiresFile = fileset.getBiggest(); |
251 if (!hiresFile.isChecked()) { | |
563 | 252 DigilibConfiguration.docuImageIdentify(hiresFile); |
500 | 253 } |
254 hiresSize = hiresFile.getSize(); | |
255 } | |
256 return hiresSize; | |
257 } | |
258 | |
547 | 259 /** Returns image scaling factor. |
260 * Uses image size and user parameters. | |
261 * Modifies scaleXY, userImgArea. | |
262 * @return | |
263 * @throws IOException | |
264 * @throws ImageOpException | |
265 */ | |
266 public float getScaleXY() throws IOException, ImageOpException { | |
500 | 267 //logger.debug("get_scaleXY()"); |
268 if(scaleXY == null){ | |
269 // coordinates and scaling | |
270 float areaWidth; | |
271 float areaHeight; | |
547 | 272 float ws = getAsFloat("ws"); |
273 ImageSize imgSize = getFileToLoad().getSize(); | |
500 | 274 // user window area in [0,1] coordinates |
275 Rectangle2D relUserArea = new Rectangle2D.Float(getAsFloat("wx"), getAsFloat("wy"), | |
276 getAsFloat("ww"), getAsFloat("wh")); | |
277 // transform from relative [0,1] to image coordinates. | |
278 AffineTransform imgTrafo = AffineTransform.getScaleInstance(imgSize | |
279 .getWidth(), imgSize.getHeight()); | |
280 // transform user coordinate area to image coordinate area | |
547 | 281 userImgArea = imgTrafo.createTransformedShape( |
500 | 282 relUserArea).getBounds2D(); |
283 | |
547 | 284 if (getScaleToFit()) { |
285 // calculate scaling factors based on inner user area | |
500 | 286 areaWidth = (float) userImgArea.getWidth(); |
287 areaHeight = (float) userImgArea.getHeight(); | |
547 | 288 float scaleX = getDw() / areaWidth * ws; |
289 float scaleY = getDh() / areaHeight * ws; | |
500 | 290 scaleXY = (scaleX > scaleY) ? scaleY : scaleX; |
547 | 291 } else if (getAbsoluteScale()) { |
292 // absolute scaling factor | |
293 if (hasOption("osize")) { | |
294 // get original resolution from metadata | |
295 fileset.checkMeta(); | |
296 float origResX = fileset.getResX(); | |
297 float origResY = fileset.getResY(); | |
298 if ((origResX == 0) || (origResY == 0)) { | |
299 throw new ImageOpException("Missing image DPI information!"); | |
300 } | |
771 | 301 float ddpix = getAsFloat("ddpix"); |
302 float ddpiy = getAsFloat("ddpiy"); | |
303 if (ddpix == 0 || ddpiy == 0) { | |
304 float ddpi = getAsFloat("ddpi"); | |
305 if (ddpi == 0) { | |
306 throw new ImageOpException("Missing display DPI information!"); | |
307 } else { | |
308 ddpix = ddpi; | |
309 ddpiy = ddpi; | |
310 } | |
547 | 311 } |
312 // calculate absolute scale factor | |
771 | 313 float sx = ddpix / origResX; |
314 float sy = ddpiy / origResY; | |
547 | 315 // currently only same scale -- mean value |
316 scaleXY = (sx + sy) / 2f; | |
317 } else { | |
318 scaleXY = getAsFloat("scale"); | |
319 } | |
500 | 320 // we need to correct the factor if we use a pre-scaled image |
547 | 321 ImageSize hiresSize = getHiresSize(); |
500 | 322 if (imgSize.getWidth() != hiresSize.getWidth()) { |
323 scaleXY *= (float)hiresSize.getWidth() / (float)imgSize.getWidth(); | |
324 } | |
547 | 325 areaWidth = getDw() / scaleXY * ws; |
326 areaHeight = getDh() / scaleXY * ws; | |
500 | 327 // reset user area size |
328 userImgArea.setRect(userImgArea.getX(), userImgArea.getY(), | |
329 areaWidth, areaHeight); | |
330 } else { | |
547 | 331 // crop to fit -- don't scale |
332 areaWidth = getDw() * ws; | |
333 areaHeight = getDh() * ws; | |
500 | 334 // reset user area size |
335 userImgArea.setRect(userImgArea.getX(), userImgArea.getY(), | |
336 areaWidth, areaHeight); | |
337 scaleXY = 1f; | |
338 } | |
339 } | |
340 return (float) scaleXY; | |
341 } | |
342 | |
547 | 343 public int getDw() throws IOException { |
500 | 344 logger.debug("get_paramDW()"); |
547 | 345 if (paramDW == null) { |
500 | 346 |
547 | 347 paramDW = getAsInt("dw"); |
348 paramDH = getAsInt("dh"); | |
349 | |
350 float imgAspect = getFileToLoad().getAspect(); | |
500 | 351 if (paramDW == 0) { |
547 | 352 // calculate dw |
353 paramDW = Math.round(paramDH * imgAspect); | |
500 | 354 setValue("dw", paramDW); |
355 } else if (paramDH == 0) { | |
547 | 356 // calculate dh |
357 paramDH = Math.round(paramDW / imgAspect); | |
358 setValue("dh", paramDH); | |
500 | 359 } |
360 } | |
361 return paramDW; | |
362 } | |
363 | |
547 | 364 public int getDh() throws IOException { |
500 | 365 logger.debug("get_paramDH()"); |
547 | 366 if (paramDH == null) { |
367 | |
368 paramDW = getAsInt("dw"); | |
369 paramDH = getAsInt("dh"); | |
500 | 370 |
547 | 371 float imgAspect = getFileToLoad().getAspect(); |
500 | 372 if (paramDW == 0) { |
547 | 373 // calculate dw |
374 paramDW = Math.round(paramDH * imgAspect); | |
375 setValue("dw", paramDW); | |
500 | 376 } else if (paramDH == 0) { |
547 | 377 // calculate dh |
378 paramDH = Math.round(paramDW / imgAspect); | |
379 setValue("dh", paramDH); | |
500 | 380 } |
381 } | |
382 return paramDH; | |
383 } | |
547 | 384 |
565 | 385 public Integer getScaleQual(){ |
500 | 386 logger.debug("get_scaleQual()"); |
547 | 387 Integer qual = dlConfig.getAsInt("default-quality"); |
388 if(hasOption("q0")) | |
500 | 389 qual = 0; |
547 | 390 else if(hasOption("q1")) |
500 | 391 qual = 1; |
547 | 392 else if(hasOption("q2")) |
500 | 393 qual = 2; |
394 return qual; | |
395 } | |
396 | |
397 | |
547 | 398 public Rectangle2D getUserImgArea() throws IOException, ImageOpException{ |
399 if(userImgArea == null) { | |
400 // getScaleXY sets userImgArea | |
401 getScaleXY(); | |
500 | 402 } |
403 return userImgArea; | |
404 | |
405 } | |
406 | |
547 | 407 public Rectangle2D getOuterUserImgArea() throws IOException, ImageOpException { |
500 | 408 if(outerUserImgArea == null){ |
547 | 409 outerUserImgArea = getUserImgArea(); |
500 | 410 |
411 // image size in pixels | |
547 | 412 ImageSize imgSize = getFileToLoad().getSize(); |
413 Rectangle2D imgBounds = new Rectangle2D.Float(0, 0, imgSize.getWidth(), | |
414 imgSize.getHeight()); | |
500 | 415 |
416 // clip area at the image border | |
417 outerUserImgArea = outerUserImgArea.createIntersection(imgBounds); | |
418 | |
419 // check image parameters sanity | |
547 | 420 scaleXY = getScaleXY(); |
500 | 421 logger.debug("outerUserImgArea.getWidth()=" + outerUserImgArea.getWidth()); |
547 | 422 logger.debug("get_scaleXY() * outerUserImgArea.getWidth() = " + (scaleXY * outerUserImgArea.getWidth())); |
500 | 423 |
424 if ((outerUserImgArea.getWidth() < 1) | |
425 || (outerUserImgArea.getHeight() < 1) | |
547 | 426 || (scaleXY * outerUserImgArea.getWidth() < 2) |
427 || (scaleXY * outerUserImgArea.getHeight() < 2)) { | |
500 | 428 logger.error("ERROR: invalid scale parameter set!"); |
429 throw new ImageOpException("Invalid scale parameter set!"); | |
430 } | |
431 } | |
432 return outerUserImgArea; | |
433 } | |
434 | |
435 | |
547 | 436 public float[] getRGBM(){ |
502 | 437 float[] paramRGBM = null;//{0f,0f,0f}; |
547 | 438 Parameter p = params.get("rgbm"); |
500 | 439 if (p.hasValue() && (!p.getAsString().equals("0/0/0"))) { |
642 | 440 paramRGBM = p.parseAsFloatArray("/"); |
441 if ((paramRGBM == null) || (paramRGBM.length != 3)) { | |
442 return null; | |
443 } | |
500 | 444 } |
445 return paramRGBM; | |
446 } | |
447 | |
547 | 448 public float[] getRGBA(){ |
502 | 449 float[] paramRGBA = null;//{0f,0f,0f}; |
547 | 450 Parameter p = params.get("rgba"); |
500 | 451 if (p.hasValue() && (!p.getAsString().equals("0/0/0"))) { |
452 paramRGBA = p.parseAsFloatArray("/"); | |
642 | 453 if ((paramRGBA == null) || (paramRGBA.length != 3)) { |
454 return null; | |
455 } | |
500 | 456 } |
457 return paramRGBA; | |
458 } | |
459 | |
547 | 460 /** Has send-as-file been requested? |
461 * @return | |
462 */ | |
463 public boolean getSendAsFile(){ | |
464 return hasOption("file") | |
465 || hasOption("rawfile"); | |
500 | 466 } |
502 | 467 |
547 | 468 /** Could the image be sent without processing? |
469 * Takes image type and additional image operations into account. | |
470 * Does not check requested size transformation. | |
471 * @return | |
472 * @throws IOException | |
473 */ | |
474 public boolean isImageSendable() throws IOException { | |
475 // cached result? | |
476 if (imageSendable == null) { | |
477 String mimeType = getMimeType(); | |
502 | 478 imageSendable = ( (mimeType.equals("image/jpeg") |
479 || mimeType.equals("image/png") | |
480 || mimeType.equals("image/gif") ) | |
481 && | |
547 | 482 !(hasOption("hmir") |
483 || hasOption("vmir") | |
484 || (getAsFloat("rot") != 0.0) | |
485 || (getRGBM() != null) | |
486 || (getRGBA() != null) | |
487 || (getAsFloat("cont") != 0.0) | |
488 || (getAsFloat("brgt") != 0.0))); | |
502 | 489 } |
490 | |
491 return imageSendable; | |
492 } | |
493 | |
494 | |
547 | 495 public boolean isTransformRequired() throws IOException { |
496 ImageSize is = getFileToLoad().getSize(); | |
497 ImageSize ess = getExpectedSourceSize(); | |
498 // nt = no transform required | |
499 boolean nt = isImageSendable() && ( | |
500 // lores: send if smaller | |
501 (getLoresOnly() && is.isSmallerThan(ess)) | |
502 // else send if it fits | |
503 || (!(getLoresOnly() || getHiresOnly()) && is.fitsIn(ess))); | |
504 return ! nt; | |
502 | 505 } |
500 | 506 } |