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