Mercurial > hg > digilib-old
annotate servlet/src/digilib/servlet/Scaler.java @ 145:d76006c12e89
corrected bugs with Java2D on Linux...
author | robcast |
---|---|
date | Wed, 20 Aug 2003 00:24:21 +0200 |
parents | d87a7e2515af |
children | bdd6789d21e0 |
rev | line source |
---|---|
1 | 1 /* Scaler -- Scaler servlet main class |
2 | |
3 Digital Image Library servlet components | |
4 | |
73 | 5 Copyright (C) 2001, 2002, 2003 Robert Casties (robcast@mail.berlios.de) |
1 | 6 |
7 This program is free software; you can redistribute it and/or modify it | |
8 under the terms of the GNU General Public License as published by the | |
9 Free Software Foundation; either version 2 of the License, or (at your | |
10 option) any later version. | |
11 | |
12 Please read license.txt for the full details. A copy of the GPL | |
13 may be found at http://www.gnu.org/copyleft/lgpl.html | |
14 | |
15 You should have received a copy of the GNU General Public License | |
16 along with this program; if not, write to the Free Software | |
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 | |
19 */ | |
20 | |
21 package digilib.servlet; | |
22 | |
86 | 23 import java.awt.Dimension; |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
24 import java.awt.geom.AffineTransform; |
100 | 25 import java.awt.geom.NoninvertibleTransformException; |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
26 import java.awt.geom.Rectangle2D; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
27 import java.io.File; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
28 import java.io.IOException; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
29 import java.util.List; |
1 | 30 |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
31 import javax.servlet.ServletConfig; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
32 import javax.servlet.ServletContext; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
33 import javax.servlet.ServletException; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
34 import javax.servlet.http.HttpServlet; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
35 import javax.servlet.http.HttpServletRequest; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
36 import javax.servlet.http.HttpServletResponse; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
37 |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
38 import digilib.Utils; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
39 import digilib.auth.AuthOpException; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
40 import digilib.auth.AuthOps; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
41 import digilib.image.DocuImage; |
122 | 42 import digilib.image.DocuInfo; |
43 import digilib.image.ImageLoaderDocuInfo; | |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
44 import digilib.image.ImageOpException; |
86 | 45 import digilib.io.DocuDirCache; |
46 import digilib.io.DocuFile; | |
47 import digilib.io.DocuFileset; | |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
48 import digilib.io.FileOpException; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
49 import digilib.io.FileOps; |
1 | 50 |
64
5ea1999befd4
New JAI ImageLoader plugin. Currently uses first beta version of the plugin.
robcast
parents:
62
diff
changeset
|
51 //import tilecachetool.*; |
1 | 52 |
73 | 53 /** |
54 * @author casties | |
55 * | |
56 */ | |
1 | 57 //public class Scaler extends HttpServlet implements SingleThreadModel { |
58 public class Scaler extends HttpServlet { | |
59 | |
73 | 60 // digilib servlet version (for all components) |
145 | 61 public static final String dlVersion = "1.12b6"; |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
62 |
73 | 63 // Utils instance with debuglevel |
64 Utils util; | |
65 // FileOps instance | |
66 FileOps fileOp; | |
67 // AuthOps instance | |
68 AuthOps authOp; | |
69 // ServletOps instance | |
70 ServletOps servletOp; | |
86 | 71 // DocuDirCache instance |
72 DocuDirCache dirCache; | |
1 | 73 |
94 | 74 // DigilibConfiguration instance |
73 | 75 DigilibConfiguration dlConfig; |
1 | 76 |
73 | 77 // use authorization database |
78 boolean useAuthentication = true; | |
1 | 79 |
100 | 80 // EXPRIMENTAL |
81 // try to enlarge cropping area for "oblique" angles | |
82 boolean wholeRotArea = false; | |
83 | |
73 | 84 /** Initialisation on first run. |
85 * | |
86 * @see javax.servlet.Servlet#init(javax.servlet.ServletConfig) | |
87 */ | |
88 public void init(ServletConfig config) throws ServletException { | |
89 super.init(config); | |
1 | 90 |
73 | 91 // Debuggin! |
92 //TCTool tctool = new TCTool(); | |
140 | 93 System.out.println("***** Digital Image Library Servlet (version "+dlVersion+") *****"); |
1 | 94 |
73 | 95 // get our ServletContext |
96 ServletContext context = config.getServletContext(); | |
97 // see if there is a Configuration instance | |
98 dlConfig = | |
99 (DigilibConfiguration) context.getAttribute( | |
86 | 100 "digilib.servlet.configuration"); |
73 | 101 if (dlConfig == null) { |
102 // create new Configuration | |
103 try { | |
104 dlConfig = new DigilibConfiguration(config); | |
86 | 105 context.setAttribute("digilib.servlet.configuration", dlConfig); |
73 | 106 } catch (Exception e) { |
107 throw new ServletException(e); | |
108 } | |
109 } | |
110 // set the servlet version | |
111 dlConfig.setServletVersion(dlVersion); | |
112 // first we need an Utils | |
113 util = dlConfig.getUtil(); | |
114 // set our AuthOps | |
115 useAuthentication = dlConfig.isUseAuthentication(); | |
116 authOp = dlConfig.getAuthOp(); | |
117 // FileOps instance | |
118 fileOp = new FileOps(util); | |
119 // AuthOps instance | |
120 servletOp = new ServletOps(util); | |
86 | 121 // DocuDirCache instance |
122 dirCache = dlConfig.getDirCache(); | |
73 | 123 } |
1 | 124 |
73 | 125 /** Process the HTTP Get request*/ |
126 public void doGet(HttpServletRequest request, HttpServletResponse response) | |
127 throws ServletException, IOException { | |
128 util.dprintln(1, "The servlet has received a GET!"); | |
129 // create new request with defaults | |
130 DigilibRequest dlReq = new DigilibRequest(); | |
131 // set with request parameters | |
132 dlReq.setWithRequest(request); | |
133 // add DigilibRequest to ServletRequest | |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
134 request.setAttribute("digilib.servlet.request", dlReq); |
73 | 135 // do the processing |
136 processRequest(request, response); | |
137 } | |
1 | 138 |
73 | 139 /**Process the HTTP Post request*/ |
140 public void doPost( | |
141 HttpServletRequest request, | |
142 HttpServletResponse response) | |
143 throws ServletException, IOException { | |
144 util.dprintln(1, "The servlet has received a POST!"); | |
145 // create new request with defaults | |
146 DigilibRequest dlReq = new DigilibRequest(); | |
147 // set with request parameters | |
148 dlReq.setWithRequest(request); | |
149 // add DigilibRequest to ServletRequest | |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
150 request.setAttribute("digilib.servlet.request", dlReq); |
73 | 151 // do the processing |
152 processRequest(request, response); | |
153 } | |
154 | |
155 /** main request handler. */ | |
156 void processRequest( | |
157 HttpServletRequest request, | |
158 HttpServletResponse response) | |
159 throws ServletException, IOException { | |
1 | 160 |
73 | 161 // time for benchmarking |
162 long startTime = System.currentTimeMillis(); | |
163 // output mime/type | |
164 String mimeType = "image/png"; | |
1 | 165 |
73 | 166 /* |
167 * parameters for a session | |
168 */ | |
1 | 169 |
73 | 170 // scale the image file to fit window size i.e. respect dw,dh |
171 boolean scaleToFit = true; | |
100 | 172 // scale the image by a fixed factor only |
173 boolean absoluteScale = false; | |
122 | 174 // only crop the image to fit |
175 boolean cropToFit = false; | |
176 // try different resolution images automatically | |
177 boolean autoRes = true; | |
178 // use hires images (if autoRes == false) | |
179 boolean hiresOnly = false; | |
73 | 180 // interpolation to use for scaling |
142 | 181 int scaleQual = 1; |
73 | 182 // send html error message (or image file) |
183 boolean errorMsgHtml = false; | |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
184 // mirror the image |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
185 boolean doMirror = false; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
186 // angle of mirror axis |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
187 double mirrorAngle = 0; |
130 | 188 // original (hires) image resolution |
189 double origResX = 0; | |
190 double origResY = 0; | |
1 | 191 |
73 | 192 /* |
193 * request parameters | |
194 */ | |
195 | |
196 DigilibRequest dlRequest = | |
197 (DigilibRequest) request.getAttribute("digilib.servlet.request"); | |
1 | 198 |
73 | 199 // destination image width |
200 int paramDW = dlRequest.getDw(); | |
201 // destination image height | |
202 int paramDH = dlRequest.getDh(); | |
122 | 203 // dw and dh shouldn't be empty, if they are, set dw=dh |
204 if (paramDW <= 0) { | |
205 paramDW = paramDH; | |
206 } | |
207 if (paramDH <= 0) { | |
208 paramDH = paramDW; | |
209 } | |
73 | 210 // relative area x_offset (0..1) |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
211 double paramWX = dlRequest.getWx(); |
73 | 212 // relative area y_offset |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
213 double paramWY = dlRequest.getWy(); |
73 | 214 // relative area width (0..1) |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
215 double paramWW = dlRequest.getWw(); |
73 | 216 // relative area height |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
217 double paramWH = dlRequest.getWh(); |
73 | 218 // scale factor (additional to dw/width, dh/height) |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
219 double paramWS = dlRequest.getWs(); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
220 // rotation angle |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
221 double paramROT = dlRequest.getRot(); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
222 // contrast enhancement |
86 | 223 float paramCONT = dlRequest.getCont(); |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
224 // brightness enhancement |
86 | 225 float paramBRGT = dlRequest.getBrgt(); |
226 // color modification | |
227 float[] paramRGBM = dlRequest.getRgbm(); | |
228 float[] paramRGBA = dlRequest.getRgba(); | |
130 | 229 // destination resolution (DPI) |
230 float paramDDPIX = dlRequest.getDdpix(); | |
231 float paramDDPIY = dlRequest.getDdpiy(); | |
232 if ((paramDDPIX == 0) || (paramDDPIY == 0)) { | |
233 // if X or Y resolution isn't set, use DDPI | |
234 paramDDPIX = dlRequest.getDdpi(); | |
235 paramDDPIY = dlRequest.getDdpi(); | |
236 } | |
1 | 237 |
73 | 238 /* operation mode: "fit": always fit to page, |
239 * "clip": send original resolution cropped, "file": send whole file (if | |
240 * allowed) | |
241 */ | |
242 if (dlRequest.isOption("clip")) { | |
243 scaleToFit = false; | |
100 | 244 absoluteScale = false; |
73 | 245 cropToFit = true; |
122 | 246 autoRes = true; |
73 | 247 } else if (dlRequest.isOption("fit")) { |
248 scaleToFit = true; | |
100 | 249 absoluteScale = false; |
122 | 250 cropToFit = false; |
251 autoRes = true; | |
130 | 252 } else if (dlRequest.isOption("osize")) { |
100 | 253 scaleToFit = false; |
254 absoluteScale = true; | |
122 | 255 cropToFit = false; |
256 autoRes = false; | |
257 hiresOnly = true; | |
73 | 258 } else if (dlRequest.isOption("file")) { |
259 scaleToFit = false; | |
100 | 260 absoluteScale = false; |
73 | 261 if (dlConfig.isSendFileAllowed()) { |
262 cropToFit = false; | |
263 } else { | |
122 | 264 // crop to fit if send file not allowed |
73 | 265 cropToFit = true; |
266 } | |
122 | 267 autoRes = false; |
268 hiresOnly = true; | |
73 | 269 } |
270 // operation mode: "errtxt": error message in html, "errimg": error image | |
271 if (dlRequest.isOption("errtxt")) { | |
272 errorMsgHtml = true; | |
273 } else if (dlRequest.isOption("errimg")) { | |
274 errorMsgHtml = false; | |
275 } | |
276 // operation mode: "q0" - "q2": interpolation quality | |
277 if (dlRequest.isOption("q0")) { | |
278 scaleQual = 0; | |
279 } else if (dlRequest.isOption("q1")) { | |
280 scaleQual = 1; | |
281 } else if (dlRequest.isOption("q2")) { | |
282 scaleQual = 2; | |
283 } | |
284 // operation mode: "lores": try to use scaled image, "hires": use unscaled image | |
122 | 285 // "autores": try best fitting resolution |
73 | 286 if (dlRequest.isOption("lores")) { |
122 | 287 autoRes = false; |
288 hiresOnly = false; | |
73 | 289 } else if (dlRequest.isOption("hires")) { |
122 | 290 autoRes = false; |
291 hiresOnly = true; | |
292 } else if (dlRequest.isOption("autores")) { | |
293 autoRes = true; | |
73 | 294 } |
1 | 295 |
73 | 296 //"big" try for all file/image actions |
297 try { | |
298 | |
86 | 299 // new DocuImage instance |
73 | 300 DocuImage docuImage = dlConfig.getDocuImageInstance(); |
301 if (docuImage == null) { | |
302 throw new ImageOpException("Unable to load DocuImage class!"); | |
303 } | |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
304 |
122 | 305 // new DocuInfo instance |
306 DocuInfo docuInfo = new ImageLoaderDocuInfo(); | |
307 | |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
308 // set interpolation quality |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
309 docuImage.setQuality(scaleQual); |
73 | 310 |
311 /* | |
312 * find the file to load/send | |
313 */ | |
1 | 314 |
73 | 315 // get PathInfo |
316 String loadPathName = dlRequest.getFilePath(); | |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
317 |
73 | 318 /* |
319 * check permissions | |
320 */ | |
321 if (useAuthentication) { | |
322 // get a list of required roles (empty if no restrictions) | |
323 List rolesRequired = authOp.rolesForPath(loadPathName, request); | |
324 if (rolesRequired != null) { | |
325 util.dprintln(1, "Role required: " + rolesRequired); | |
326 util.dprintln(2, "User: " + request.getRemoteUser()); | |
327 // is the current request/user authorized? | |
328 if (!authOp.isRoleAuthorized(rolesRequired, request)) { | |
329 // send deny answer and abort | |
330 util.dprintln(1, "ERROR: access denied!"); | |
331 if (errorMsgHtml) { | |
332 ServletOps.htmlMessage( | |
333 "ERROR: Unauthorized access!", | |
334 response); | |
335 } else { | |
336 servletOp.sendFile( | |
337 new File(dlConfig.getDenyImgFileName()), | |
338 response); | |
339 } | |
340 return; | |
341 } | |
342 } | |
343 } | |
1 | 344 |
122 | 345 // find the file(set) |
86 | 346 DocuFile fileToLoad; |
94 | 347 DocuFileset fileset = |
348 dirCache.getFileset(loadPathName, dlRequest.getPn()); | |
349 if (fileset == null) { | |
350 throw new FileOpException( | |
351 "File " | |
352 + loadPathName | |
353 + "(" | |
354 + dlRequest.getPn() | |
355 + ") not found."); | |
356 } | |
357 | |
122 | 358 /* |
359 * calculate expected source image size | |
360 * | |
361 */ | |
362 Dimension expectedSourceSize = new Dimension(); | |
363 if (scaleToFit) { | |
364 double scale = (1 / Math.min(paramWW, paramWH)) * paramWS; | |
365 expectedSourceSize.setSize(paramDW * scale, paramDH * scale); | |
366 } else { | |
367 expectedSourceSize.setSize( | |
368 paramDW * paramWS, | |
369 paramDH * paramWS); | |
100 | 370 } |
371 | |
122 | 372 /* |
373 * select a resolution | |
374 */ | |
375 if (autoRes) { | |
130 | 376 // autores: use next higher resolution |
122 | 377 fileToLoad = |
378 fileset.getNextBigger(expectedSourceSize, docuInfo); | |
379 if (fileToLoad == null) { | |
130 | 380 // this is the highest we have |
122 | 381 fileToLoad = fileset.get(0); |
382 } | |
86 | 383 } else { |
122 | 384 // enforced hires or lores |
385 if (hiresOnly) { | |
386 // get first element | |
387 fileToLoad = fileset.get(0); | |
388 } else { | |
389 // enforced lores uses next smaller resolution | |
390 fileToLoad = | |
391 fileset.getNextSmaller(expectedSourceSize, docuInfo); | |
392 if (fileToLoad == null) { | |
393 // this is the smallest we have | |
394 fileToLoad = fileset.get(fileset.size() - 1); | |
395 } | |
396 } | |
86 | 397 } |
398 util.dprintln(1, "Loading: " + fileToLoad.getFile()); | |
73 | 399 |
130 | 400 if (absoluteScale) { |
401 // get original resolution from metadata | |
402 fileset.checkMeta(); | |
403 origResX = fileset.getResX(); | |
404 origResY = fileset.getResY(); | |
139
11cfe4c89fdc
Servlet version 1.11b1 with improved original-size.
robcast
parents:
130
diff
changeset
|
405 if ((origResX == 0) || (origResY == 0)) { |
11cfe4c89fdc
Servlet version 1.11b1 with improved original-size.
robcast
parents:
130
diff
changeset
|
406 throw new ImageOpException("Missing image DPI information!"); |
11cfe4c89fdc
Servlet version 1.11b1 with improved original-size.
robcast
parents:
130
diff
changeset
|
407 } |
11cfe4c89fdc
Servlet version 1.11b1 with improved original-size.
robcast
parents:
130
diff
changeset
|
408 |
11cfe4c89fdc
Servlet version 1.11b1 with improved original-size.
robcast
parents:
130
diff
changeset
|
409 if ((paramDDPIX == 0) || (paramDDPIY == 0)) { |
11cfe4c89fdc
Servlet version 1.11b1 with improved original-size.
robcast
parents:
130
diff
changeset
|
410 throw new ImageOpException("Missing display DPI information!"); |
11cfe4c89fdc
Servlet version 1.11b1 with improved original-size.
robcast
parents:
130
diff
changeset
|
411 } |
130 | 412 } |
413 | |
86 | 414 // check the source image |
122 | 415 if (!fileToLoad.isChecked()) { |
416 fileToLoad.check(docuInfo); | |
417 } | |
86 | 418 // get the source image type |
419 mimeType = fileToLoad.getMimetype(); | |
130 | 420 // decide if the image can be sent as is |
421 boolean mimetypeSendable = | |
122 | 422 mimeType.equals("image/jpeg") |
423 || mimeType.equals("image/png") | |
424 || mimeType.equals("image/gif"); | |
130 | 425 boolean imagoOptions = |
426 dlRequest.isOption("hmir") | |
427 || dlRequest.isOption("vmir") | |
428 || (paramROT != 0) | |
429 || (paramRGBM != null) | |
430 || (paramRGBA != null) | |
431 || (paramCONT != 0) | |
432 || (paramBRGT != 0); | |
139
11cfe4c89fdc
Servlet version 1.11b1 with improved original-size.
robcast
parents:
130
diff
changeset
|
433 boolean imageSendable = mimetypeSendable && !imagoOptions; |
73 | 434 |
122 | 435 /* if not autoRes and image smaller than requested |
436 * size then send as is. | |
100 | 437 * if not autoScale and not scaleToFit nor cropToFit |
122 | 438 * then send as is (mo=file) |
73 | 439 */ |
122 | 440 if ((!autoRes |
441 && imageSendable | |
442 && (fileToLoad.getSize().width <= expectedSourceSize.width) | |
443 && (fileToLoad.getSize().height <= expectedSourceSize.height)) | |
130 | 444 || (!autoRes && !scaleToFit && !cropToFit && !absoluteScale)) { |
73 | 445 |
446 util.dprintln(1, "Sending File as is."); | |
1 | 447 |
86 | 448 servletOp.sendFile(fileToLoad.getFile(), response); |
1 | 449 |
73 | 450 util.dprintln( |
451 1, | |
452 "Done in " | |
453 + (System.currentTimeMillis() - startTime) | |
454 + "ms"); | |
455 return; | |
456 } | |
1 | 457 |
73 | 458 /* |
459 * crop and scale the image | |
460 */ | |
1 | 461 |
86 | 462 int imgWidth = 0; |
463 int imgHeight = 0; | |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
464 // get image size |
86 | 465 if (fileToLoad.getSize() == null) { |
466 // size unknown so far | |
467 imgWidth = docuImage.getWidth(); | |
468 imgHeight = docuImage.getHeight(); | |
469 // remember size | |
470 fileToLoad.setSize(new Dimension(imgWidth, imgHeight)); | |
471 } else { | |
472 imgWidth = fileToLoad.getSize().width; | |
473 imgHeight = fileToLoad.getSize().height; | |
474 } | |
94 | 475 |
73 | 476 util.dprintln(2, "IMG: " + imgWidth + "x" + imgHeight); |
477 util.dprintln( | |
478 2, | |
479 "time " + (System.currentTimeMillis() - startTime) + "ms"); | |
1 | 480 |
73 | 481 // coordinates and scaling |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
482 double areaXoff; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
483 double areaYoff; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
484 double areaWidth; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
485 double areaHeight; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
486 double scaleX; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
487 double scaleY; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
488 double scaleXY; |
1 | 489 |
100 | 490 // coordinates using Java2D |
491 // image size in pixels | |
492 Rectangle2D imgBounds = | |
493 new Rectangle2D.Double(0, 0, imgWidth, imgHeight); | |
494 // user window area in [0,1] coordinates | |
495 Rectangle2D relUserArea = | |
496 new Rectangle2D.Double(paramWX, paramWY, paramWW, paramWH); | |
497 // transform from relative [0,1] to image coordinates. | |
498 AffineTransform imgTrafo = | |
499 AffineTransform.getScaleInstance(imgWidth, imgHeight); | |
85 | 500 // transform user coordinate area to image coordinate area |
100 | 501 Rectangle2D userImgArea = |
502 imgTrafo.createTransformedShape(relUserArea).getBounds2D(); | |
503 | |
504 // calculate scaling factors based on inner user area | |
73 | 505 if (scaleToFit) { |
100 | 506 areaWidth = userImgArea.getWidth(); |
507 areaHeight = userImgArea.getHeight(); | |
73 | 508 scaleX = paramDW / areaWidth * paramWS; |
509 scaleY = paramDH / areaHeight * paramWS; | |
510 scaleXY = (scaleX > scaleY) ? scaleY : scaleX; | |
100 | 511 } else if (absoluteScale) { |
512 // absolute scale | |
130 | 513 scaleX = paramDDPIX / origResX; |
514 scaleY = paramDDPIY / origResY; | |
515 // currently only same scale :-( | |
516 scaleXY = scaleX; | |
517 areaWidth = paramDW / scaleXY * paramWS; | |
518 areaHeight = paramDH / scaleXY * paramWS; | |
100 | 519 // reset user area size |
520 userImgArea.setRect( | |
521 userImgArea.getX(), | |
522 userImgArea.getY(), | |
523 areaWidth, | |
524 areaHeight); | |
73 | 525 } else { |
526 // crop to fit | |
85 | 527 areaWidth = paramDW * paramWS; |
528 areaHeight = paramDH * paramWS; | |
100 | 529 // reset user area size |
530 userImgArea.setRect( | |
531 userImgArea.getX(), | |
532 userImgArea.getY(), | |
533 areaWidth, | |
534 areaHeight); | |
73 | 535 scaleX = 1f; |
536 scaleY = 1f; | |
537 scaleXY = 1f; | |
100 | 538 } |
85 | 539 |
100 | 540 // enlarge image area for rotations to cover additional pixels |
541 Rectangle2D outerUserImgArea = userImgArea; | |
542 Rectangle2D innerUserImgArea = userImgArea; | |
543 if (wholeRotArea) { | |
544 if (paramROT != 0) { | |
545 try { | |
546 // rotate user area coordinates around center of user area | |
547 AffineTransform rotTrafo = | |
548 AffineTransform.getRotateInstance( | |
549 Math.toRadians(paramROT), | |
550 userImgArea.getCenterX(), | |
551 userImgArea.getCenterY()); | |
552 // get bounds from rotated end position | |
553 innerUserImgArea = | |
554 rotTrafo | |
555 .createTransformedShape(userImgArea) | |
556 .getBounds2D(); | |
557 // get bounds from back-rotated bounds | |
558 outerUserImgArea = | |
559 rotTrafo | |
560 .createInverse() | |
561 .createTransformedShape(innerUserImgArea) | |
562 .getBounds2D(); | |
563 } catch (NoninvertibleTransformException e1) { | |
564 // this shouldn't happen anyway | |
565 e1.printStackTrace(); | |
566 } | |
567 } | |
73 | 568 } |
1 | 569 |
73 | 570 util.dprintln( |
571 1, | |
572 "Scale " | |
573 + scaleXY | |
574 + "(" | |
575 + scaleX | |
576 + "," | |
577 + scaleY | |
578 + ") on " | |
100 | 579 + outerUserImgArea); |
1 | 580 |
73 | 581 // clip area at the image border |
100 | 582 outerUserImgArea = outerUserImgArea.createIntersection(imgBounds); |
85 | 583 |
100 | 584 areaWidth = outerUserImgArea.getWidth(); |
585 areaHeight = outerUserImgArea.getHeight(); | |
586 areaXoff = outerUserImgArea.getX(); | |
587 areaYoff = outerUserImgArea.getY(); | |
1 | 588 |
73 | 589 util.dprintln( |
590 2, | |
85 | 591 "crop: " |
73 | 592 + areaXoff |
593 + "," | |
594 + areaYoff | |
595 + " " | |
596 + areaWidth | |
597 + "x" | |
598 + areaHeight); | |
1 | 599 |
73 | 600 // check image parameters sanity |
601 if ((areaWidth < 1) | |
602 || (areaHeight < 1) | |
603 || (scaleXY * areaWidth < 2) | |
604 || (scaleXY * areaHeight < 2)) { | |
605 util.dprintln(1, "ERROR: invalid scale parameter set!"); | |
606 throw new ImageOpException("Invalid scale parameter set!"); | |
607 } | |
1 | 608 |
85 | 609 /* |
610 * crop and scale image | |
611 */ | |
612 | |
613 // use subimage loading if possible | |
614 if (docuImage.isSubimageSupported()) { | |
615 System.out.println( | |
616 "Subimage: scale " + scaleXY + " = " + (1 / scaleXY)); | |
617 double subf = 1d; | |
618 double subsamp = 1d; | |
619 if (scaleXY < 1) { | |
620 subf = 1 / scaleXY; | |
140 | 621 // for higher quality reduce subsample factor by minSubsample |
622 if (scaleQual > 0) { | |
623 subsamp = | |
624 Math.max( | |
625 Math.floor(subf / dlConfig.getMinSubsample()), | |
626 1d); | |
627 } else { | |
628 subsamp = Math.floor(subf); | |
629 } | |
85 | 630 scaleXY = subsamp / subf; |
631 System.out.println( | |
632 "Using subsampling: " + subsamp + " rest " + scaleXY); | |
633 } | |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
634 |
85 | 635 docuImage.loadSubimage( |
86 | 636 fileToLoad.getFile(), |
100 | 637 outerUserImgArea.getBounds(), |
85 | 638 (int) subsamp); |
639 | |
640 System.out.println( | |
641 "SUBSAMP: " | |
642 + subsamp | |
643 + " -> " | |
644 + docuImage.getWidth() | |
645 + "x" | |
646 + docuImage.getHeight()); | |
647 | |
648 docuImage.scale(scaleXY); | |
649 | |
650 } else { | |
100 | 651 // else load and crop the whole file |
86 | 652 docuImage.loadImage(fileToLoad.getFile()); |
85 | 653 docuImage.crop( |
654 (int) areaXoff, | |
655 (int) areaYoff, | |
656 (int) areaWidth, | |
657 (int) areaHeight); | |
658 | |
659 docuImage.scale(scaleXY); | |
660 } | |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
661 |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
662 // mirror image |
100 | 663 // operation mode: "hmir": mirror horizontally, "vmir": mirror vertically |
664 if (dlRequest.isOption("hmir")) { | |
665 docuImage.mirror(0); | |
666 } | |
667 if (dlRequest.isOption("vmir")) { | |
668 docuImage.mirror(90); | |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
669 } |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
670 |
100 | 671 // rotate image |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
672 if (paramROT != 0) { |
94 | 673 docuImage.rotate(paramROT); |
100 | 674 if (wholeRotArea) { |
675 // crop to the inner bounding box | |
676 double xcrop = | |
677 docuImage.getWidth() | |
678 - innerUserImgArea.getWidth() * scaleXY; | |
679 double ycrop = | |
680 docuImage.getHeight() | |
681 - innerUserImgArea.getHeight() * scaleXY; | |
682 if ((xcrop > 0) || (ycrop > 0)) { | |
683 // only crop smaller | |
684 xcrop = (xcrop > 0) ? xcrop : 0; | |
685 ycrop = (ycrop > 0) ? ycrop : 0; | |
686 // crop image | |
687 docuImage.crop( | |
688 (int) (xcrop / 2), | |
689 (int) (ycrop / 2), | |
690 (int) (docuImage.getWidth() - xcrop), | |
691 (int) (docuImage.getHeight() - ycrop)); | |
692 } | |
693 } | |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
694 |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
695 } |
1 | 696 |
86 | 697 // color modification |
698 if ((paramRGBM != null) || (paramRGBA != null)) { | |
699 // make shure we actually have two arrays | |
700 if (paramRGBM == null) { | |
701 paramRGBM = new float[3]; | |
702 } | |
703 if (paramRGBA == null) { | |
704 paramRGBA = new float[3]; | |
705 } | |
100 | 706 // calculate "contrast" values (c=2^x) |
86 | 707 float[] mult = new float[3]; |
708 for (int i = 0; i < 3; i++) { | |
94 | 709 mult[i] = (float) Math.pow(2, (double) paramRGBM[i]); |
86 | 710 } |
711 docuImage.enhanceRGB(mult, paramRGBA); | |
712 } | |
94 | 713 |
100 | 714 // contrast and brightness enhancement |
715 if ((paramCONT != 0) || (paramBRGT != 0)) { | |
716 double mult = Math.pow(2, paramCONT); | |
717 docuImage.enhance((float) mult, (float) paramBRGT); | |
718 } | |
719 | |
73 | 720 util.dprintln( |
721 2, | |
722 "time " + (System.currentTimeMillis() - startTime) + "ms"); | |
723 | |
724 /* | |
725 * write the resulting image | |
726 */ | |
1 | 727 |
73 | 728 // setup output -- if source is JPG then dest will be JPG else it's PNG |
100 | 729 if (mimeType.equals("image/jpeg") |
730 || mimeType.equals("image/jp2")) { | |
731 mimeType = "image/jpeg"; | |
732 } else { | |
73 | 733 mimeType = "image/png"; |
734 } | |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
735 response.setContentType(mimeType); |
1 | 736 |
73 | 737 // write the image |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
738 docuImage.writeImage(mimeType, response.getOutputStream()); |
1 | 739 |
73 | 740 util.dprintln( |
741 1, | |
742 "Done in " + (System.currentTimeMillis() - startTime) + "ms"); | |
743 | |
744 /* | |
745 * error handling | |
746 */ | |
1 | 747 |
73 | 748 } // end of "big" try |
749 catch (FileOpException e) { | |
750 util.dprintln(1, "ERROR: File IO Error: " + e); | |
751 try { | |
752 if (errorMsgHtml) { | |
753 ServletOps.htmlMessage( | |
754 "ERROR: File IO Error: " + e, | |
755 response); | |
756 } else { | |
757 servletOp.sendFile( | |
758 new File(dlConfig.getErrorImgFileName()), | |
759 response); | |
760 } | |
761 } catch (FileOpException ex) { | |
762 } // so we don't get a loop | |
763 return; | |
764 } catch (AuthOpException e) { | |
765 util.dprintln(1, "ERROR: Authorization error: " + e); | |
766 try { | |
767 if (errorMsgHtml) { | |
768 ServletOps.htmlMessage( | |
769 "ERROR: Authorization error: " + e, | |
770 response); | |
771 } else { | |
772 servletOp.sendFile( | |
773 new File(dlConfig.getErrorImgFileName()), | |
774 response); | |
775 } | |
776 } catch (FileOpException ex) { | |
777 } // so we don't get a loop | |
778 return; | |
779 } catch (ImageOpException e) { | |
780 util.dprintln(1, "ERROR: Image Error: " + e); | |
781 try { | |
782 if (errorMsgHtml) { | |
783 ServletOps.htmlMessage( | |
784 "ERROR: Image Operation Error: " + e, | |
785 response); | |
786 } else { | |
787 servletOp.sendFile( | |
788 new File(dlConfig.getErrorImgFileName()), | |
789 response); | |
790 } | |
791 } catch (FileOpException ex) { | |
792 } // so we don't get a loop | |
793 return; | |
794 } catch (RuntimeException e) { | |
795 // JAI likes to throw RuntimeExceptions ;-( | |
796 util.dprintln(1, "ERROR: Other Image Error: " + e); | |
797 try { | |
798 if (errorMsgHtml) { | |
799 ServletOps.htmlMessage( | |
800 "ERROR: Other Image Operation Error: " + e, | |
801 response); | |
802 } else { | |
803 servletOp.sendFile( | |
804 new File(dlConfig.getErrorImgFileName()), | |
805 response); | |
806 } | |
807 } catch (FileOpException ex) { | |
808 } // so we don't get a loop | |
809 return; | |
810 } | |
811 } | |
1 | 812 |
73 | 813 } //Scaler class |