Mercurial > hg > digilib-old
annotate servlet/src/digilib/image/ImageLoaderDocuImage.java @ 103:0e49645f98c8
Servlet V1.9b2
Fixes error in rotation for ImageLoader DocuImage.
author | robcast |
---|---|
date | Mon, 12 May 2003 22:33:44 +0200 |
parents | 78f52a1876fe |
children | a32e8c80e2f2 |
rev | line source |
---|---|
1 | 1 /* ImageLoaderDocuImage -- Image class implementation using JDK 1.4 ImageLoader |
2 | |
3 Digital Image Library servlet components | |
4 | |
85 | 5 Copyright (C) 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.image; | |
22 | |
86 | 23 import java.awt.Dimension; |
85 | 24 import java.awt.Rectangle; |
73 | 25 import java.awt.geom.AffineTransform; |
101 | 26 import java.awt.geom.Rectangle2D; |
73 | 27 import java.awt.image.AffineTransformOp; |
28 import java.awt.image.BufferedImage; | |
85 | 29 import java.awt.image.RescaleOp; |
73 | 30 import java.io.File; |
31 import java.io.IOException; | |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
32 import java.io.OutputStream; |
89 | 33 import java.io.RandomAccessFile; |
85 | 34 import java.util.Iterator; |
1 | 35 |
73 | 36 import javax.imageio.ImageIO; |
85 | 37 import javax.imageio.ImageReadParam; |
38 import javax.imageio.ImageReader; | |
39 import javax.imageio.stream.ImageInputStream; | |
1 | 40 |
86 | 41 import digilib.io.DocuFile; |
73 | 42 import digilib.io.FileOpException; |
86 | 43 import digilib.io.FileOps; |
1 | 44 |
73 | 45 /** Implementation of DocuImage using the ImageLoader API of Java 1.4 and Java2D. */ |
1 | 46 public class ImageLoaderDocuImage extends DocuImageImpl { |
47 | |
86 | 48 /** image object */ |
49 protected BufferedImage img; | |
50 /** interpolation type */ | |
51 protected int interpol; | |
52 /** ImageIO image reader */ | |
53 protected ImageReader reader; | |
54 /** File that was read */ | |
55 protected File imgFile; | |
85 | 56 |
57 /* loadSubimage is supported. */ | |
58 public boolean isSubimageSupported() { | |
59 return true; | |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
60 } |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
61 |
85 | 62 public void setQuality(int qual) { |
63 quality = qual; | |
64 // setup interpolation quality | |
65 if (qual > 0) { | |
66 util.dprintln(4, "quality q1"); | |
67 interpol = AffineTransformOp.TYPE_BILINEAR; | |
68 } else { | |
69 util.dprintln(4, "quality q0"); | |
70 interpol = AffineTransformOp.TYPE_NEAREST_NEIGHBOR; | |
71 } | |
72 } | |
86 | 73 |
85 | 74 public int getHeight() { |
75 int h = 0; | |
76 try { | |
77 if (img == null) { | |
78 h = reader.getHeight(0); | |
79 } else { | |
80 h = img.getHeight(); | |
81 } | |
82 } catch (IOException e) { | |
83 e.printStackTrace(); | |
84 } | |
85 return h; | |
86 } | |
87 | |
88 public int getWidth() { | |
89 int w = 0; | |
90 try { | |
91 if (img == null) { | |
92 w = reader.getWidth(0); | |
93 } else { | |
94 w = img.getWidth(); | |
95 } | |
96 } catch (IOException e) { | |
97 e.printStackTrace(); | |
98 } | |
99 return w; | |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
100 } |
1 | 101 |
86 | 102 /* load image file */ |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
103 public void loadImage(File f) throws FileOpException { |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
104 util.dprintln(10, "loadImage!"); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
105 System.gc(); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
106 try { |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
107 img = ImageIO.read(f); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
108 if (img == null) { |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
109 util.dprintln(3, "ERROR(loadImage): unable to load file"); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
110 throw new FileOpException("Unable to load File!"); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
111 } |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
112 } catch (IOException e) { |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
113 throw new FileOpException("Error reading image."); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
114 } |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
115 } |
1 | 116 |
86 | 117 /** Get an ImageReader for the image file. |
118 * | |
119 */ | |
89 | 120 public void preloadImage(File f) throws IOException { |
85 | 121 System.gc(); |
89 | 122 RandomAccessFile rf = new RandomAccessFile(f, "r"); |
123 ImageInputStream istream = ImageIO.createImageInputStream(rf); | |
124 Iterator readers = ImageIO.getImageReaders(istream); | |
125 reader = (ImageReader) readers.next(); | |
126 reader.setInput(istream); | |
85 | 127 if (reader == null) { |
128 util.dprintln(3, "ERROR(loadImage): unable to load file"); | |
129 throw new FileOpException("Unable to load File!"); | |
130 } | |
86 | 131 imgFile = f; |
85 | 132 } |
133 | |
134 /* Load an image file into the Object. */ | |
135 public void loadSubimage(File f, Rectangle region, int prescale) | |
136 throws FileOpException { | |
137 System.gc(); | |
138 try { | |
86 | 139 if ((reader == null) || (imgFile != f)) { |
85 | 140 preloadImage(f); |
141 } | |
142 // set up reader parameters | |
143 ImageReadParam readParam = reader.getDefaultReadParam(); | |
144 readParam.setSourceRegion(region); | |
145 readParam.setSourceSubsampling(prescale, prescale, 0, 0); | |
146 // read image | |
147 img = reader.read(0, readParam); | |
148 } catch (IOException e) { | |
149 util.dprintln(3, "ERROR(loadImage): unable to load file"); | |
150 throw new FileOpException("Unable to load File!"); | |
151 } | |
152 if (img == null) { | |
153 util.dprintln(3, "ERROR(loadImage): unable to load file"); | |
154 throw new FileOpException("Unable to load File!"); | |
155 } | |
156 } | |
157 | |
86 | 158 /* write image of type mt to Stream */ |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
159 public void writeImage(String mt, OutputStream ostream) |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
160 throws FileOpException { |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
161 util.dprintln(10, "writeImage!"); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
162 try { |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
163 // setup output |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
164 String type = "png"; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
165 if (mt == "image/jpeg") { |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
166 type = "jpeg"; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
167 } else if (mt == "image/png") { |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
168 type = "png"; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
169 } else { |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
170 // unknown mime type |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
171 util.dprintln(2, "ERROR(writeImage): Unknown mime type " + mt); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
172 throw new FileOpException("Unknown mime type: " + mt); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
173 } |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
174 // render output |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
175 if (ImageIO.write(img, type, ostream)) { |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
176 // writing was OK |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
177 return; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
178 } else { |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
179 throw new FileOpException("Error writing image: Unknown image format!"); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
180 } |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
181 } catch (IOException e) { |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
182 // e.printStackTrace(); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
183 throw new FileOpException("Error writing image."); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
184 } |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
185 } |
1 | 186 |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
187 public void scale(double scale) throws ImageOpException { |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
188 // setup scale |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
189 AffineTransformOp scaleOp = |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
190 new AffineTransformOp( |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
191 AffineTransform.getScaleInstance(scale, scale), |
85 | 192 interpol); |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
193 BufferedImage scaledImg = scaleOp.filter(img, null); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
194 |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
195 if (scaledImg == null) { |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
196 util.dprintln(2, "ERROR(cropAndScale): error in scale"); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
197 throw new ImageOpException("Unable to scale"); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
198 } |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
199 img = scaledImg; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
200 } |
1 | 201 |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
202 public void crop(int x_off, int y_off, int width, int height) |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
203 throws ImageOpException { |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
204 // setup Crop |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
205 BufferedImage croppedImg = img.getSubimage(x_off, y_off, width, height); |
1 | 206 |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
207 util.dprintln( |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
208 3, |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
209 "CROP:" + croppedImg.getWidth() + "x" + croppedImg.getHeight()); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
210 //DEBUG |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
211 // util.dprintln(2, " time "+(System.currentTimeMillis()-startTime)+"ms"); |
1 | 212 |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
213 if (croppedImg == null) { |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
214 util.dprintln(2, "ERROR(cropAndScale): error in crop"); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
215 throw new ImageOpException("Unable to crop"); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
216 } |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
217 img = croppedImg; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
218 } |
1 | 219 |
86 | 220 public void enhance(float mult, float add) throws ImageOpException { |
221 /* Only one constant should work regardless of the number of bands | |
222 * according to the JDK spec. | |
223 * Doesn't work on JDK 1.4 for OSX and Linux (at least). | |
85 | 224 */ |
86 | 225 /* RescaleOp scaleOp = |
226 new RescaleOp( | |
227 (float)mult, (float)add, | |
228 null); | |
229 scaleOp.filter(img, img); | |
230 */ | |
231 /* The number of constants must match the number of bands in the image. | |
232 */ | |
233 int ncol = img.getColorModel().getNumColorComponents(); | |
234 float[] dm = new float[ncol]; | |
235 float[] da = new float[ncol]; | |
236 for (int i = 0; i < ncol; i++) { | |
237 dm[i] = (float) mult; | |
238 da[i] = (float) add; | |
85 | 239 } |
86 | 240 RescaleOp scaleOp = new RescaleOp(dm, da, null); |
85 | 241 scaleOp.filter(img, img); |
242 | |
243 } | |
244 | |
86 | 245 public void enhanceRGB(float[] rgbm, float[] rgba) |
246 throws ImageOpException { | |
247 /* The number of constants must match the number of bands in the image. | |
248 * We do only 3 (RGB) bands. | |
249 */ | |
250 int ncol = img.getColorModel().getNumColorComponents(); | |
251 if ((ncol != 3) || (rgbm.length != 3) || (rgba.length != 3)) { | |
252 util.dprintln( | |
253 2, | |
254 "ERROR(enhance): unknown number of color bands or coefficients (" | |
255 + ncol | |
256 + ")"); | |
257 return; | |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
258 } |
89 | 259 RescaleOp scaleOp = |
260 new RescaleOp(rgbOrdered(rgbm), rgbOrdered(rgba), null); | |
86 | 261 scaleOp.filter(img, img); |
262 } | |
263 | |
264 /** Ensures that the array f is in the right order to map the images RGB components. | |
265 */ | |
266 public float[] rgbOrdered(float[] fa) { | |
267 float[] fb = new float[3]; | |
268 int t = img.getType(); | |
269 if ((t == BufferedImage.TYPE_3BYTE_BGR) | |
270 || (t == BufferedImage.TYPE_4BYTE_ABGR) | |
271 || (t == BufferedImage.TYPE_4BYTE_ABGR_PRE)) { | |
272 // BGR Type (actually it looks like RBG...) | |
273 fb[0] = fa[0]; | |
274 fb[1] = fa[2]; | |
275 fb[2] = fa[1]; | |
276 } else { | |
277 fb = fa; | |
278 } | |
279 return fb; | |
85 | 280 } |
281 | |
101 | 282 public void rotate(double angle) |
283 throws ImageOpException { | |
89 | 284 // setup rotation |
285 double rangle = Math.toRadians(angle); | |
101 | 286 // create offset to make shure the rotated image has no negative coordinates |
287 double w = img.getWidth(); | |
288 double h = img.getHeight(); | |
103 | 289 AffineTransform trafo = new AffineTransform(); |
290 // center of rotation | |
291 double x = (w / 2); | |
292 double y = (h / 2); | |
101 | 293 trafo.rotate(rangle, x, y); |
103 | 294 // try rotation to see how far we're out of bounds |
295 AffineTransformOp rotOp = new AffineTransformOp(trafo, interpol); | |
296 Rectangle2D rotbounds = rotOp.getBounds2D(img); | |
297 double xoff = rotbounds.getX(); | |
298 double yoff = rotbounds.getY(); | |
299 // move image back in line | |
300 trafo.preConcatenate(AffineTransform.getTranslateInstance(-xoff, -yoff)); | |
101 | 301 // transform image |
103 | 302 rotOp = new AffineTransformOp(trafo, interpol); |
89 | 303 BufferedImage rotImg = rotOp.filter(img, null); |
101 | 304 // calculate new bounding box |
103 | 305 //Rectangle2D bounds = rotOp.getBounds2D(img); |
86 | 306 |
89 | 307 if (rotImg == null) { |
308 util.dprintln(2, "ERROR: error in rotate"); | |
309 throw new ImageOpException("Unable to rotate"); | |
310 } | |
103 | 311 img = rotImg; |
101 | 312 // crop new image (with self-made rounding) |
103 | 313 /* img = |
101 | 314 rotImg.getSubimage( |
315 (int) (bounds.getX()+0.5), | |
316 (int) (bounds.getY()+0.5), | |
317 (int) (bounds.getWidth()+0.5), | |
318 (int) (bounds.getHeight()+0.5)); | |
103 | 319 */ |
86 | 320 } |
85 | 321 |
89 | 322 public void mirror(double angle) throws ImageOpException { |
323 // setup mirror | |
324 double mx = 1; | |
325 double my = 1; | |
326 double tx = 0; | |
327 double ty = 0; | |
328 if (Math.abs(angle - 0) < epsilon) { | |
329 // 0 degree | |
330 mx = -1; | |
331 tx = getWidth(); | |
332 } else if (Math.abs(angle - 90) < epsilon) { | |
333 // 90 degree | |
334 my = -1; | |
335 ty = getHeight(); | |
336 } else if (Math.abs(angle - 180) < epsilon) { | |
337 // 180 degree | |
338 mx = -1; | |
339 tx = getWidth(); | |
340 } else if (Math.abs(angle - 270) < epsilon) { | |
341 // 270 degree | |
342 my = -1; | |
343 ty = getHeight(); | |
344 } else if (Math.abs(angle - 360) < epsilon) { | |
345 // 360 degree | |
346 mx = -1; | |
347 tx = getWidth(); | |
348 } | |
349 AffineTransformOp mirOp = | |
350 new AffineTransformOp( | |
351 new AffineTransform(mx, 0, 0, my, tx, ty), | |
352 interpol); | |
353 BufferedImage mirImg = mirOp.filter(img, null); | |
354 | |
355 if (mirImg == null) { | |
356 util.dprintln(2, "ERROR: error in mirror"); | |
357 throw new ImageOpException("Unable to mirror"); | |
358 } | |
359 img = mirImg; | |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
360 } |
86 | 361 |
89 | 362 /* check image size and type and store in DocuFile f */ |
363 public boolean checkFile(DocuFile f) throws IOException { | |
364 // see if f is already loaded | |
365 if ((reader == null) || (imgFile != f.getFile())) { | |
366 preloadImage(f.getFile()); | |
367 } | |
368 Dimension d = new Dimension(); | |
369 d.setSize(reader.getWidth(0), reader.getHeight(0)); | |
370 f.setSize(d); | |
371 String t = reader.getFormatName(); | |
372 t = FileOps.mimeForFile(f.getFile()); | |
373 f.setMimetype(t); | |
374 f.setChecked(true); | |
375 return true; | |
86 | 376 } |
1 | 377 |
378 } |