Mercurial > hg > digilib-old
comparison 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 |
comparison
equal
deleted
inserted
replaced
556:5cc180bb0a5c | 557:0885f5ca5b24 |
---|---|
1 package digilib.image; | |
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; | |
10 import digilib.io.DocuDirectory; | |
11 import digilib.io.FileOpException; | |
12 import digilib.io.FileOps; | |
13 import digilib.io.ImageFile; | |
14 import digilib.io.ImageFileset; | |
15 import digilib.servlet.DigilibConfiguration; | |
16 import digilib.util.OptionsSet; | |
17 import digilib.util.Parameter; | |
18 import digilib.util.ParameterMap; | |
19 | |
20 | |
21 /** | |
22 * A container class for storing a set of instructional parameters | |
23 * used for content generating classes like MakePDF. | |
24 * | |
25 * This contains the functionality formerly found in Scaler, processRequest, only factorized. | |
26 * | |
27 * TODO clean up... | |
28 * | |
29 * @author cmielack, casties | |
30 * | |
31 */ | |
32 | |
33 public class ImageJobDescription extends ParameterMap { | |
34 | |
35 DigilibConfiguration dlConfig = null; | |
36 protected static Logger logger = Logger.getLogger("digilib.servlet"); | |
37 | |
38 ImageFile fileToLoad = null; | |
39 ImageFileset fileset = null; | |
40 DocuDirectory fileDir = null; | |
41 String filePath = null; | |
42 ImageSize expectedSourceSize = null; | |
43 Float scaleXY = null; | |
44 Rectangle2D userImgArea = null; | |
45 Rectangle2D outerUserImgArea= null; | |
46 Boolean imageSendable = null; | |
47 String mimeType; | |
48 Integer paramDW; | |
49 Integer paramDH; | |
50 | |
51 /** create empty ImageJobDescription. | |
52 * @param dlcfg | |
53 */ | |
54 public ImageJobDescription(DigilibConfiguration dlcfg) { | |
55 super(30); | |
56 dlConfig = dlcfg; | |
57 } | |
58 | |
59 | |
60 /** set up Parameters | |
61 * @see digilib.util.ParameterMap#initParams() | |
62 */ | |
63 @Override | |
64 protected void initParams() { | |
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 | |
84 newParameter("mo", this.options, null, 's'); | |
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 | |
105 | |
106 /* (non-Javadoc) | |
107 * @see digilib.servlet.ParameterMap#initOptions() | |
108 */ | |
109 @Override | |
110 protected void initOptions() { | |
111 if (options == null) { | |
112 String s = this.getAsString("mo"); | |
113 options = new OptionsSet(s); | |
114 } | |
115 } | |
116 | |
117 | |
118 /** Creates new ImageJobDescription by merging Parameters from another ParameterMap. | |
119 * @param pm | |
120 * @param dlcfg | |
121 * @return | |
122 */ | |
123 public static ImageJobDescription getInstance(ParameterMap pm, DigilibConfiguration dlcfg) { | |
124 ImageJobDescription newMap = new ImageJobDescription(dlcfg); | |
125 // add all params to this map | |
126 newMap.params.putAll(pm.getParams()); | |
127 newMap.initOptions(); | |
128 return newMap; | |
129 } | |
130 | |
131 | |
132 public String getMimeType() throws IOException { | |
133 if (mimeType == null) { | |
134 fileToLoad = getFileToLoad(); | |
135 if(! fileToLoad.isChecked()){ | |
136 ImageOps.checkFile(fileToLoad); | |
137 } | |
138 mimeType = fileToLoad.getMimetype(); | |
139 } | |
140 return mimeType; | |
141 } | |
142 | |
143 public ImageFile getFileToLoad() throws IOException { | |
144 | |
145 if(fileToLoad == null){ | |
146 fileset = getFileset(); | |
147 | |
148 /* select a resolution */ | |
149 if (getHiresOnly()) { | |
150 // get first element (= highest resolution) | |
151 fileToLoad = fileset.getBiggest(); | |
152 } else if (getLoresOnly()) { | |
153 // enforced lores uses next smaller resolution | |
154 fileToLoad = fileset.getNextSmaller(getExpectedSourceSize()); | |
155 if (fileToLoad == null) { | |
156 // this is the smallest we have | |
157 fileToLoad = fileset.getSmallest(); | |
158 } | |
159 } else { | |
160 // autores: use next higher resolution | |
161 fileToLoad = fileset.getNextBigger(getExpectedSourceSize()); | |
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 | |
174 public DocuDirectory getFileDirectory() throws FileOpException { | |
175 if(fileDir == null){ | |
176 DocuDirCache dirCache = (DocuDirCache) dlConfig.getValue("servlet.dir.cache"); | |
177 String fp = getFilePath(); | |
178 fileDir = dirCache.getDirectory(fp); | |
179 if (fileDir == null) { | |
180 throw new FileOpException("Directory " + getFilePath() + " not found."); | |
181 } | |
182 } | |
183 return fileDir; | |
184 } | |
185 | |
186 public ImageFileset getFileset() throws FileOpException { | |
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 | |
199 public String getFilePath() { | |
200 if(filePath == null){ | |
201 String s = this.getAsString("request.path"); | |
202 s += this.getAsString("fn"); | |
203 filePath = FileOps.normalName(s); | |
204 } | |
205 return filePath; | |
206 } | |
207 | |
208 public boolean getHiresOnly(){ | |
209 return hasOption("clip") || hasOption("hires"); | |
210 } | |
211 | |
212 public boolean getLoresOnly(){ | |
213 return hasOption("lores"); | |
214 } | |
215 | |
216 public boolean getScaleToFit() { | |
217 return !(hasOption("clip") || hasOption("osize") || hasOption("ascale")); | |
218 } | |
219 | |
220 public boolean getAbsoluteScale(){ | |
221 return hasOption("osize") || hasOption("ascale"); | |
222 } | |
223 | |
224 | |
225 public ImageSize getExpectedSourceSize() throws IOException { | |
226 if (expectedSourceSize == null){ | |
227 expectedSourceSize = new ImageSize(); | |
228 if (getScaleToFit()) { | |
229 // scale to fit -- calculate minimum source size | |
230 float scale = (1 / Math.min(getAsFloat("ww"), getAsFloat("wh"))) * getAsFloat("ws"); | |
231 expectedSourceSize.setSize((int) (getDw() * scale), | |
232 (int) (getDh() * scale)); | |
233 } else if (getAbsoluteScale() && hasOption("ascale")) { | |
234 // absolute scale -- apply scale to hires size | |
235 expectedSourceSize = getHiresSize().getScaled(getAsFloat("scale")); | |
236 } else { | |
237 // clip to fit -- source = destination size | |
238 expectedSourceSize.setSize((int) (getDw() * getAsFloat("ws")), | |
239 (int) (getDh() * getAsFloat("ws"))); | |
240 } | |
241 } | |
242 return expectedSourceSize; | |
243 } | |
244 | |
245 public ImageSize getHiresSize() throws IOException { | |
246 logger.debug("get_hiresSize()"); | |
247 | |
248 ImageSize hiresSize = null; | |
249 ImageFileset fileset = getFileset(); | |
250 if (getAbsoluteScale()) { | |
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 | |
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 { | |
269 //logger.debug("get_scaleXY()"); | |
270 if(scaleXY == null){ | |
271 // coordinates and scaling | |
272 float areaWidth; | |
273 float areaHeight; | |
274 float ws = getAsFloat("ws"); | |
275 ImageSize imgSize = getFileToLoad().getSize(); | |
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 | |
283 userImgArea = imgTrafo.createTransformedShape( | |
284 relUserArea).getBounds2D(); | |
285 | |
286 if (getScaleToFit()) { | |
287 // calculate scaling factors based on inner user area | |
288 areaWidth = (float) userImgArea.getWidth(); | |
289 areaHeight = (float) userImgArea.getHeight(); | |
290 float scaleX = getDw() / areaWidth * ws; | |
291 float scaleY = getDh() / areaHeight * ws; | |
292 scaleXY = (scaleX > scaleY) ? scaleY : scaleX; | |
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 } | |
314 // we need to correct the factor if we use a pre-scaled image | |
315 ImageSize hiresSize = getHiresSize(); | |
316 if (imgSize.getWidth() != hiresSize.getWidth()) { | |
317 scaleXY *= (float)hiresSize.getWidth() / (float)imgSize.getWidth(); | |
318 } | |
319 areaWidth = getDw() / scaleXY * ws; | |
320 areaHeight = getDh() / scaleXY * ws; | |
321 // reset user area size | |
322 userImgArea.setRect(userImgArea.getX(), userImgArea.getY(), | |
323 areaWidth, areaHeight); | |
324 } else { | |
325 // crop to fit -- don't scale | |
326 areaWidth = getDw() * ws; | |
327 areaHeight = getDh() * ws; | |
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 | |
337 public int getDw() throws IOException { | |
338 logger.debug("get_paramDW()"); | |
339 if (paramDW == null) { | |
340 | |
341 paramDW = getAsInt("dw"); | |
342 paramDH = getAsInt("dh"); | |
343 | |
344 float imgAspect = getFileToLoad().getAspect(); | |
345 if (paramDW == 0) { | |
346 // calculate dw | |
347 paramDW = Math.round(paramDH * imgAspect); | |
348 setValue("dw", paramDW); | |
349 } else if (paramDH == 0) { | |
350 // calculate dh | |
351 paramDH = Math.round(paramDW / imgAspect); | |
352 setValue("dh", paramDH); | |
353 } | |
354 } | |
355 return paramDW; | |
356 } | |
357 | |
358 public int getDh() throws IOException { | |
359 logger.debug("get_paramDH()"); | |
360 if (paramDH == null) { | |
361 | |
362 paramDW = getAsInt("dw"); | |
363 paramDH = getAsInt("dh"); | |
364 | |
365 float imgAspect = getFileToLoad().getAspect(); | |
366 if (paramDW == 0) { | |
367 // calculate dw | |
368 paramDW = Math.round(paramDH * imgAspect); | |
369 setValue("dw", paramDW); | |
370 } else if (paramDH == 0) { | |
371 // calculate dh | |
372 paramDH = Math.round(paramDW / imgAspect); | |
373 setValue("dh", paramDH); | |
374 } | |
375 } | |
376 return paramDH; | |
377 } | |
378 | |
379 public Integer get_scaleQual(){ | |
380 logger.debug("get_scaleQual()"); | |
381 Integer qual = dlConfig.getAsInt("default-quality"); | |
382 if(hasOption("q0")) | |
383 qual = 0; | |
384 else if(hasOption("q1")) | |
385 qual = 1; | |
386 else if(hasOption("q2")) | |
387 qual = 2; | |
388 return qual; | |
389 } | |
390 | |
391 | |
392 public Rectangle2D getUserImgArea() throws IOException, ImageOpException{ | |
393 if(userImgArea == null) { | |
394 // getScaleXY sets userImgArea | |
395 getScaleXY(); | |
396 } | |
397 return userImgArea; | |
398 | |
399 } | |
400 | |
401 public Rectangle2D getOuterUserImgArea() throws IOException, ImageOpException { | |
402 if(outerUserImgArea == null){ | |
403 outerUserImgArea = getUserImgArea(); | |
404 | |
405 // image size in pixels | |
406 ImageSize imgSize = getFileToLoad().getSize(); | |
407 Rectangle2D imgBounds = new Rectangle2D.Float(0, 0, imgSize.getWidth(), | |
408 imgSize.getHeight()); | |
409 | |
410 // clip area at the image border | |
411 outerUserImgArea = outerUserImgArea.createIntersection(imgBounds); | |
412 | |
413 // check image parameters sanity | |
414 scaleXY = getScaleXY(); | |
415 logger.debug("outerUserImgArea.getWidth()=" + outerUserImgArea.getWidth()); | |
416 logger.debug("get_scaleXY() * outerUserImgArea.getWidth() = " + (scaleXY * outerUserImgArea.getWidth())); | |
417 | |
418 if ((outerUserImgArea.getWidth() < 1) | |
419 || (outerUserImgArea.getHeight() < 1) | |
420 || (scaleXY * outerUserImgArea.getWidth() < 2) | |
421 || (scaleXY * outerUserImgArea.getHeight() < 2)) { | |
422 logger.error("ERROR: invalid scale parameter set!"); | |
423 throw new ImageOpException("Invalid scale parameter set!"); | |
424 } | |
425 } | |
426 return outerUserImgArea; | |
427 } | |
428 | |
429 | |
430 public int getForceType(){ | |
431 if(hasOption("jpg")) | |
432 return ImageOps.TYPE_JPEG; | |
433 if(hasOption("png")) | |
434 return ImageOps.TYPE_PNG; | |
435 | |
436 return ImageOps.TYPE_AUTO; | |
437 } | |
438 | |
439 public float[] getRGBM(){ | |
440 float[] paramRGBM = null;//{0f,0f,0f}; | |
441 Parameter p = params.get("rgbm"); | |
442 if (p.hasValue() && (!p.getAsString().equals("0/0/0"))) { | |
443 return p.parseAsFloatArray("/"); | |
444 } | |
445 return paramRGBM; | |
446 } | |
447 | |
448 public float[] getRGBA(){ | |
449 float[] paramRGBA = null;//{0f,0f,0f}; | |
450 Parameter p = params.get("rgba"); | |
451 if (p.hasValue() && (!p.getAsString().equals("0/0/0"))) { | |
452 paramRGBA = p.parseAsFloatArray("/"); | |
453 } | |
454 return paramRGBA; | |
455 } | |
456 | |
457 /** Has send-as-file been requested? | |
458 * @return | |
459 */ | |
460 public boolean getSendAsFile(){ | |
461 return hasOption("file") | |
462 || hasOption("rawfile"); | |
463 } | |
464 | |
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(); | |
475 imageSendable = ( (mimeType.equals("image/jpeg") | |
476 || mimeType.equals("image/png") | |
477 || mimeType.equals("image/gif") ) | |
478 && | |
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))); | |
486 } | |
487 | |
488 return imageSendable; | |
489 } | |
490 | |
491 | |
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 } | |
503 } |