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 }