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