Mercurial > hg > digilib-old
annotate servlet/src/digilib/image/ImageJobDescription.java @ 557:0885f5ca5b24 digilibPDF
more refactoring and rearranging
pdf and image generation works now
| author | robcast |
|---|---|
| date | Thu, 16 Dec 2010 21:19:11 +0100 |
| parents | servlet/src/digilib/servlet/ImageJobDescription.java@88ed97d08b97 |
| children | baaa5bab5e16 |
| 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; | |
| 13 import digilib.io.ImageFile; | |
| 14 import digilib.io.ImageFileset; | |
| 557 | 15 import digilib.servlet.DigilibConfiguration; |
| 16 import digilib.util.OptionsSet; | |
| 17 import digilib.util.Parameter; | |
| 18 import digilib.util.ParameterMap; | |
| 500 | 19 |
| 20 | |
| 21 /** | |
| 22 * A container class for storing a set of instructional parameters | |
| 23 * used for content generating classes like MakePDF. | |
| 24 * | |
| 511 | 25 * This contains the functionality formerly found in Scaler, processRequest, only factorized. |
| 26 * | |
| 27 * TODO clean up... | |
| 500 | 28 * |
| 547 | 29 * @author cmielack, casties |
| 500 | 30 * |
| 31 */ | |
| 32 | |
| 547 | 33 public class ImageJobDescription extends ParameterMap { |
| 500 | 34 |
| 35 DigilibConfiguration dlConfig = null; | |
| 36 protected static Logger logger = Logger.getLogger("digilib.servlet"); | |
| 37 | |
| 38 ImageFile fileToLoad = null; | |
| 547 | 39 ImageFileset fileset = null; |
| 541 | 40 DocuDirectory fileDir = null; |
| 41 String filePath = null; | |
| 500 | 42 ImageSize expectedSourceSize = null; |
| 43 Float scaleXY = null; | |
| 44 Rectangle2D userImgArea = null; | |
| 45 Rectangle2D outerUserImgArea= null; | |
| 502 | 46 Boolean imageSendable = null; |
| 547 | 47 String mimeType; |
| 48 Integer paramDW; | |
| 49 Integer paramDH; | |
| 50 | |
| 51 /** create empty ImageJobDescription. | |
| 52 * @param dlcfg | |
| 53 */ | |
| 54 public ImageJobDescription(DigilibConfiguration dlcfg) { | |
| 500 | 55 super(30); |
| 547 | 56 dlConfig = dlcfg; |
| 552 | 57 } |
| 58 | |
| 59 | |
| 60 /** set up Parameters | |
| 557 | 61 * @see digilib.util.ParameterMap#initParams() |
| 552 | 62 */ |
| 63 @Override | |
| 64 protected void initParams() { | |
| 500 | 65 // url of the page/document (second part) |
| 66 newParameter("fn", "", null, 's'); | |
| 67 // page number | |
| 68 newParameter("pn", new Integer(1), null, 's'); | |
| 69 // width of client in pixels | |
| 70 newParameter("dw", new Integer(0), null, 's'); | |
| 71 // height of client in pixels | |
| 72 newParameter("dh", new Integer(0), null, 's'); | |
| 73 // left edge of image (float from 0 to 1) | |
| 74 newParameter("wx", new Float(0), null, 's'); | |
| 75 // top edge in image (float from 0 to 1) | |
| 76 newParameter("wy", new Float(0), null, 's'); | |
| 77 // width of image (float from 0 to 1) | |
| 78 newParameter("ww", new Float(1), null, 's'); | |
| 79 // height of image (float from 0 to 1) | |
| 80 newParameter("wh", new Float(1), null, 's'); | |
| 81 // scale factor | |
| 82 newParameter("ws", new Float(1), null, 's'); | |
| 83 // special options like 'fit' for gifs | |
| 547 | 84 newParameter("mo", this.options, null, 's'); |
| 500 | 85 // rotation angle (degree) |
| 86 newParameter("rot", new Float(0), null, 's'); | |
| 87 // contrast enhancement factor | |
| 88 newParameter("cont", new Float(0), null, 's'); | |
| 89 // brightness enhancement factor | |
| 90 newParameter("brgt", new Float(0), null, 's'); | |
| 91 // color multiplicative factors | |
| 92 newParameter("rgbm", "0/0/0", null, 's'); | |
| 93 // color additive factors | |
| 94 newParameter("rgba", "0/0/0", null, 's'); | |
| 95 // display dpi resolution (total) | |
| 96 newParameter("ddpi", new Float(0), null, 's'); | |
| 97 // display dpi X resolution | |
| 98 newParameter("ddpix", new Float(0), null, 's'); | |
| 99 // display dpi Y resolution | |
| 100 newParameter("ddpiy", new Float(0), null, 's'); | |
| 101 // scale factor for mo=ascale | |
| 102 newParameter("scale", new Float(1), null, 's'); | |
| 103 } | |
| 104 | |
|
503
fdb824bd57ab
first functional version of PDFCache after restructuring the code
cmielack
parents:
502
diff
changeset
|
105 |
| 552 | 106 /* (non-Javadoc) |
| 107 * @see digilib.servlet.ParameterMap#initOptions() | |
| 547 | 108 */ |
| 552 | 109 @Override |
| 110 protected void initOptions() { | |
| 111 if (options == null) { | |
| 112 String s = this.getAsString("mo"); | |
| 113 options = new OptionsSet(s); | |
| 114 } | |
| 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()){ | |
| 502 | 136 ImageOps.checkFile(fileToLoad); |
| 137 } | |
| 547 | 138 mimeType = fileToLoad.getMimetype(); |
| 502 | 139 } |
| 500 | 140 return mimeType; |
| 141 } | |
| 142 | |
| 547 | 143 public ImageFile 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 } | |
| 167 logger.info("Planning to load: " + fileToLoad.getFile()); | |
| 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 | |
| 557 | 186 public ImageFileset getFileset() throws FileOpException { |
| 541 | 187 if(fileset==null){ |
| 188 DocuDirCache dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache"); | |
| 189 | |
| 190 fileset = (ImageFileset) dirCache.getFile(getFilePath(), getAsInt("pn"), FileOps.CLASS_IMAGE); | |
| 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; | |
| 547 | 249 ImageFileset fileset = getFileset(); |
| 250 if (getAbsoluteScale()) { | |
| 500 | 251 ImageFile hiresFile = fileset.getBiggest(); |
| 252 if (!hiresFile.isChecked()) { | |
| 253 ImageOps.checkFile(hiresFile); | |
| 254 } | |
| 255 hiresSize = hiresFile.getSize(); | |
| 256 } | |
| 257 return hiresSize; | |
| 258 | |
| 259 } | |
| 260 | |
| 547 | 261 /** Returns image scaling factor. |
| 262 * Uses image size and user parameters. | |
| 263 * Modifies scaleXY, userImgArea. | |
| 264 * @return | |
| 265 * @throws IOException | |
| 266 * @throws ImageOpException | |
| 267 */ | |
| 268 public float getScaleXY() throws IOException, ImageOpException { | |
| 500 | 269 //logger.debug("get_scaleXY()"); |
| 270 if(scaleXY == null){ | |
| 271 // coordinates and scaling | |
| 272 float areaWidth; | |
| 273 float areaHeight; | |
| 547 | 274 float ws = getAsFloat("ws"); |
| 275 ImageSize imgSize = getFileToLoad().getSize(); | |
| 500 | 276 // user window area in [0,1] coordinates |
| 277 Rectangle2D relUserArea = new Rectangle2D.Float(getAsFloat("wx"), getAsFloat("wy"), | |
| 278 getAsFloat("ww"), getAsFloat("wh")); | |
| 279 // transform from relative [0,1] to image coordinates. | |
| 280 AffineTransform imgTrafo = AffineTransform.getScaleInstance(imgSize | |
| 281 .getWidth(), imgSize.getHeight()); | |
| 282 // transform user coordinate area to image coordinate area | |
| 547 | 283 userImgArea = imgTrafo.createTransformedShape( |
| 500 | 284 relUserArea).getBounds2D(); |
| 285 | |
| 547 | 286 if (getScaleToFit()) { |
| 287 // calculate scaling factors based on inner user area | |
| 500 | 288 areaWidth = (float) userImgArea.getWidth(); |
| 289 areaHeight = (float) userImgArea.getHeight(); | |
| 547 | 290 float scaleX = getDw() / areaWidth * ws; |
| 291 float scaleY = getDh() / areaHeight * ws; | |
| 500 | 292 scaleXY = (scaleX > scaleY) ? scaleY : scaleX; |
| 547 | 293 } else if (getAbsoluteScale()) { |
| 294 // absolute scaling factor | |
| 295 if (hasOption("osize")) { | |
| 296 // get original resolution from metadata | |
| 297 fileset.checkMeta(); | |
| 298 float origResX = fileset.getResX(); | |
| 299 float origResY = fileset.getResY(); | |
| 300 if ((origResX == 0) || (origResY == 0)) { | |
| 301 throw new ImageOpException("Missing image DPI information!"); | |
| 302 } | |
| 303 if ((getAsFloat("ddpix") == 0) || (getAsFloat("ddpiy") == 0)) { | |
| 304 throw new ImageOpException("Missing display DPI information!"); | |
| 305 } | |
| 306 // calculate absolute scale factor | |
| 307 float sx = getAsFloat("ddpix") / origResX; | |
| 308 float sy = getAsFloat("ddpiy") / origResY; | |
| 309 // currently only same scale -- mean value | |
| 310 scaleXY = (sx + sy) / 2f; | |
| 311 } else { | |
| 312 scaleXY = getAsFloat("scale"); | |
| 313 } | |
| 500 | 314 // we need to correct the factor if we use a pre-scaled image |
| 547 | 315 ImageSize hiresSize = getHiresSize(); |
| 500 | 316 if (imgSize.getWidth() != hiresSize.getWidth()) { |
| 317 scaleXY *= (float)hiresSize.getWidth() / (float)imgSize.getWidth(); | |
| 318 } | |
| 547 | 319 areaWidth = getDw() / scaleXY * ws; |
| 320 areaHeight = getDh() / scaleXY * ws; | |
| 500 | 321 // reset user area size |
| 322 userImgArea.setRect(userImgArea.getX(), userImgArea.getY(), | |
| 323 areaWidth, areaHeight); | |
| 324 } else { | |
| 547 | 325 // crop to fit -- don't scale |
| 326 areaWidth = getDw() * ws; | |
| 327 areaHeight = getDh() * ws; | |
| 500 | 328 // reset user area size |
| 329 userImgArea.setRect(userImgArea.getX(), userImgArea.getY(), | |
| 330 areaWidth, areaHeight); | |
| 331 scaleXY = 1f; | |
| 332 } | |
| 333 } | |
| 334 return (float) scaleXY; | |
| 335 } | |
| 336 | |
| 547 | 337 public int getDw() throws IOException { |
| 500 | 338 logger.debug("get_paramDW()"); |
| 547 | 339 if (paramDW == null) { |
| 500 | 340 |
| 547 | 341 paramDW = getAsInt("dw"); |
| 342 paramDH = getAsInt("dh"); | |
| 343 | |
| 344 float imgAspect = getFileToLoad().getAspect(); | |
| 500 | 345 if (paramDW == 0) { |
| 547 | 346 // calculate dw |
| 347 paramDW = Math.round(paramDH * imgAspect); | |
| 500 | 348 setValue("dw", paramDW); |
| 349 } else if (paramDH == 0) { | |
| 547 | 350 // calculate dh |
| 351 paramDH = Math.round(paramDW / imgAspect); | |
| 352 setValue("dh", paramDH); | |
| 500 | 353 } |
| 354 } | |
| 355 return paramDW; | |
| 356 } | |
| 357 | |
| 547 | 358 public int getDh() throws IOException { |
| 500 | 359 logger.debug("get_paramDH()"); |
| 547 | 360 if (paramDH == null) { |
| 361 | |
| 362 paramDW = getAsInt("dw"); | |
| 363 paramDH = getAsInt("dh"); | |
| 500 | 364 |
| 547 | 365 float imgAspect = getFileToLoad().getAspect(); |
| 500 | 366 if (paramDW == 0) { |
| 547 | 367 // calculate dw |
| 368 paramDW = Math.round(paramDH * imgAspect); | |
| 369 setValue("dw", paramDW); | |
| 500 | 370 } else if (paramDH == 0) { |
| 547 | 371 // calculate dh |
| 372 paramDH = Math.round(paramDW / imgAspect); | |
| 373 setValue("dh", paramDH); | |
| 500 | 374 } |
| 375 } | |
| 376 return paramDH; | |
| 377 } | |
| 547 | 378 |
| 500 | 379 public Integer get_scaleQual(){ |
| 380 logger.debug("get_scaleQual()"); | |
| 547 | 381 Integer qual = dlConfig.getAsInt("default-quality"); |
| 382 if(hasOption("q0")) | |
| 500 | 383 qual = 0; |
| 547 | 384 else if(hasOption("q1")) |
| 500 | 385 qual = 1; |
| 547 | 386 else if(hasOption("q2")) |
| 500 | 387 qual = 2; |
| 388 return qual; | |
| 389 } | |
| 390 | |
| 391 | |
| 547 | 392 public Rectangle2D getUserImgArea() throws IOException, ImageOpException{ |
| 393 if(userImgArea == null) { | |
| 394 // getScaleXY sets userImgArea | |
| 395 getScaleXY(); | |
| 500 | 396 } |
| 397 return userImgArea; | |
| 398 | |
| 399 } | |
| 400 | |
| 547 | 401 public Rectangle2D getOuterUserImgArea() throws IOException, ImageOpException { |
| 500 | 402 if(outerUserImgArea == null){ |
| 547 | 403 outerUserImgArea = getUserImgArea(); |
| 500 | 404 |
| 405 // image size in pixels | |
| 547 | 406 ImageSize imgSize = getFileToLoad().getSize(); |
| 407 Rectangle2D imgBounds = new Rectangle2D.Float(0, 0, imgSize.getWidth(), | |
| 408 imgSize.getHeight()); | |
| 500 | 409 |
| 410 // clip area at the image border | |
| 411 outerUserImgArea = outerUserImgArea.createIntersection(imgBounds); | |
| 412 | |
| 413 // check image parameters sanity | |
| 547 | 414 scaleXY = getScaleXY(); |
| 500 | 415 logger.debug("outerUserImgArea.getWidth()=" + outerUserImgArea.getWidth()); |
| 547 | 416 logger.debug("get_scaleXY() * outerUserImgArea.getWidth() = " + (scaleXY * outerUserImgArea.getWidth())); |
| 500 | 417 |
| 418 if ((outerUserImgArea.getWidth() < 1) | |
| 419 || (outerUserImgArea.getHeight() < 1) | |
| 547 | 420 || (scaleXY * outerUserImgArea.getWidth() < 2) |
| 421 || (scaleXY * outerUserImgArea.getHeight() < 2)) { | |
| 500 | 422 logger.error("ERROR: invalid scale parameter set!"); |
| 423 throw new ImageOpException("Invalid scale parameter set!"); | |
| 424 } | |
| 425 } | |
| 426 return outerUserImgArea; | |
| 427 } | |
| 428 | |
| 429 | |
| 547 | 430 public int getForceType(){ |
| 431 if(hasOption("jpg")) | |
| 500 | 432 return ImageOps.TYPE_JPEG; |
| 547 | 433 if(hasOption("png")) |
| 500 | 434 return ImageOps.TYPE_PNG; |
| 435 | |
| 436 return ImageOps.TYPE_AUTO; | |
| 437 } | |
| 438 | |
| 547 | 439 public float[] getRGBM(){ |
| 502 | 440 float[] paramRGBM = null;//{0f,0f,0f}; |
| 547 | 441 Parameter p = params.get("rgbm"); |
| 500 | 442 if (p.hasValue() && (!p.getAsString().equals("0/0/0"))) { |
| 443 return p.parseAsFloatArray("/"); | |
| 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("/"); | |
| 453 } | |
| 454 return paramRGBA; | |
| 455 } | |
| 456 | |
| 547 | 457 /** Has send-as-file been requested? |
| 458 * @return | |
| 459 */ | |
| 460 public boolean getSendAsFile(){ | |
| 461 return hasOption("file") | |
| 462 || hasOption("rawfile"); | |
| 500 | 463 } |
| 502 | 464 |
| 547 | 465 /** Could the image be sent without processing? |
| 466 * Takes image type and additional image operations into account. | |
| 467 * Does not check requested size transformation. | |
| 468 * @return | |
| 469 * @throws IOException | |
| 470 */ | |
| 471 public boolean isImageSendable() throws IOException { | |
| 472 // cached result? | |
| 473 if (imageSendable == null) { | |
| 474 String mimeType = getMimeType(); | |
| 502 | 475 imageSendable = ( (mimeType.equals("image/jpeg") |
| 476 || mimeType.equals("image/png") | |
| 477 || mimeType.equals("image/gif") ) | |
| 478 && | |
| 547 | 479 !(hasOption("hmir") |
| 480 || hasOption("vmir") | |
| 481 || (getAsFloat("rot") != 0.0) | |
| 482 || (getRGBM() != null) | |
| 483 || (getRGBA() != null) | |
| 484 || (getAsFloat("cont") != 0.0) | |
| 485 || (getAsFloat("brgt") != 0.0))); | |
| 502 | 486 } |
| 487 | |
| 488 return imageSendable; | |
| 489 } | |
| 490 | |
| 491 | |
| 547 | 492 public boolean isTransformRequired() throws IOException { |
| 493 ImageSize is = getFileToLoad().getSize(); | |
| 494 ImageSize ess = getExpectedSourceSize(); | |
| 495 // nt = no transform required | |
| 496 boolean nt = isImageSendable() && ( | |
| 497 // lores: send if smaller | |
| 498 (getLoresOnly() && is.isSmallerThan(ess)) | |
| 499 // else send if it fits | |
| 500 || (!(getLoresOnly() || getHiresOnly()) && is.fitsIn(ess))); | |
| 501 return ! nt; | |
| 502 | 502 } |
| 500 | 503 } |
