Mercurial > hg > digilib-old
annotate servlet/src/digilib/image/ImageLoaderDocuImage.java @ 140:c878ea574c29
Servlet Version 1.12b2
- fixed small error in XML config parser
- improved high quality scaling with minSubsample parameter
author | robcast |
---|---|
date | Fri, 15 Aug 2003 23:52:20 +0200 |
parents | a32e8c80e2f2 |
children | d87a7e2515af |
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(); | |
140 | 123 /* are there more readers? |
124 System.out.println("this reader: " + reader.getClass()); | |
125 while (readers.hasNext()) { | |
126 System.out.println("next reader: " + readers.next().getClass()); | |
127 } | |
128 */ | |
89 | 129 reader.setInput(istream); |
85 | 130 if (reader == null) { |
131 util.dprintln(3, "ERROR(loadImage): unable to load file"); | |
132 throw new FileOpException("Unable to load File!"); | |
133 } | |
86 | 134 imgFile = f; |
85 | 135 } |
136 | |
137 /* Load an image file into the Object. */ | |
138 public void loadSubimage(File f, Rectangle region, int prescale) | |
139 throws FileOpException { | |
140 System.gc(); | |
141 try { | |
86 | 142 if ((reader == null) || (imgFile != f)) { |
85 | 143 preloadImage(f); |
144 } | |
145 // set up reader parameters | |
146 ImageReadParam readParam = reader.getDefaultReadParam(); | |
147 readParam.setSourceRegion(region); | |
148 readParam.setSourceSubsampling(prescale, prescale, 0, 0); | |
149 // read image | |
150 img = reader.read(0, readParam); | |
151 } catch (IOException e) { | |
152 util.dprintln(3, "ERROR(loadImage): unable to load file"); | |
153 throw new FileOpException("Unable to load File!"); | |
154 } | |
155 if (img == null) { | |
156 util.dprintln(3, "ERROR(loadImage): unable to load file"); | |
157 throw new FileOpException("Unable to load File!"); | |
158 } | |
159 } | |
160 | |
86 | 161 /* write image of type mt to Stream */ |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
162 public void writeImage(String mt, OutputStream ostream) |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
163 throws FileOpException { |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
164 util.dprintln(10, "writeImage!"); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
165 try { |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
166 // setup output |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
167 String type = "png"; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
168 if (mt == "image/jpeg") { |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
169 type = "jpeg"; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
170 } else if (mt == "image/png") { |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
171 type = "png"; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
172 } else { |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
173 // unknown mime type |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
174 util.dprintln(2, "ERROR(writeImage): Unknown mime type " + mt); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
175 throw new FileOpException("Unknown mime type: " + mt); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
176 } |
140 | 177 |
178 /* JPEG doesn't do transparency so we have to convert any RGBA image | |
179 * to RGB :-( | |
180 */ | |
181 if ((type == "jpeg") && (img.getColorModel().hasAlpha())) { | |
182 util.dprintln(2, "BARF: JPEG with transparency!!"); | |
183 int w = img.getWidth(); | |
184 int h = img.getHeight(); | |
185 // BufferedImage.TYPE_INT_RGB seems to be fastest (JDK1.4.1, OSX) | |
186 BufferedImage img2; | |
187 img2 = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB); | |
188 img2.createGraphics().drawImage(img, null, 0, 0); | |
189 img = img2; | |
190 } | |
191 | |
192 /* try ImageWriter.write | |
193 Iterator writers = ImageIO.getImageWritersByFormatName(type); | |
194 ImageWriter writer = (ImageWriter) writers.next(); | |
195 System.out.println("this writer: " + writer.getClass()); | |
196 while (writers.hasNext()) { | |
197 System.out.println("next writer: " + writers.next().getClass()); | |
198 } | |
199 //ImageWriteParam param = writer.getDefaultWriteParam(); | |
200 IIOImage iimg = new IIOImage(img, null, null); | |
201 ImageOutputStream iostream = new MemoryCacheImageOutputStream(ostream); | |
202 writer.setOutput(iostream); | |
203 writer.write(iimg); | |
204 */ | |
205 | |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
206 // render output |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
207 if (ImageIO.write(img, type, ostream)) { |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
208 // writing was OK |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
209 return; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
210 } else { |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
211 throw new FileOpException("Error writing image: Unknown image format!"); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
212 } |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
213 } catch (IOException e) { |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
214 // e.printStackTrace(); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
215 throw new FileOpException("Error writing image."); |
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 } |
1 | 218 |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
219 public void scale(double scale) throws ImageOpException { |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
220 // setup scale |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
221 AffineTransformOp scaleOp = |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
222 new AffineTransformOp( |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
223 AffineTransform.getScaleInstance(scale, scale), |
85 | 224 interpol); |
140 | 225 BufferedImage scaledImg = scaleOp.createCompatibleDestImage(img, null); |
226 scaleOp.filter(img, scaledImg); | |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
227 |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
228 if (scaledImg == null) { |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
229 util.dprintln(2, "ERROR(cropAndScale): error in scale"); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
230 throw new ImageOpException("Unable to scale"); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
231 } |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
232 img = scaledImg; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
233 } |
1 | 234 |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
235 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
|
236 throws ImageOpException { |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
237 // setup Crop |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
238 BufferedImage croppedImg = img.getSubimage(x_off, y_off, width, height); |
1 | 239 |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
240 util.dprintln( |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
241 3, |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
242 "CROP:" + croppedImg.getWidth() + "x" + croppedImg.getHeight()); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
243 //DEBUG |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
244 // util.dprintln(2, " time "+(System.currentTimeMillis()-startTime)+"ms"); |
1 | 245 |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
246 if (croppedImg == null) { |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
247 util.dprintln(2, "ERROR(cropAndScale): error in crop"); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
248 throw new ImageOpException("Unable to crop"); |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
249 } |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
250 img = croppedImg; |
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
251 } |
1 | 252 |
86 | 253 public void enhance(float mult, float add) throws ImageOpException { |
254 /* Only one constant should work regardless of the number of bands | |
255 * according to the JDK spec. | |
256 * Doesn't work on JDK 1.4 for OSX and Linux (at least). | |
85 | 257 */ |
86 | 258 /* RescaleOp scaleOp = |
259 new RescaleOp( | |
260 (float)mult, (float)add, | |
261 null); | |
262 scaleOp.filter(img, img); | |
263 */ | |
264 /* The number of constants must match the number of bands in the image. | |
265 */ | |
266 int ncol = img.getColorModel().getNumColorComponents(); | |
267 float[] dm = new float[ncol]; | |
268 float[] da = new float[ncol]; | |
269 for (int i = 0; i < ncol; i++) { | |
270 dm[i] = (float) mult; | |
271 da[i] = (float) add; | |
85 | 272 } |
86 | 273 RescaleOp scaleOp = new RescaleOp(dm, da, null); |
85 | 274 scaleOp.filter(img, img); |
275 | |
276 } | |
277 | |
86 | 278 public void enhanceRGB(float[] rgbm, float[] rgba) |
279 throws ImageOpException { | |
280 /* The number of constants must match the number of bands in the image. | |
281 * We do only 3 (RGB) bands. | |
282 */ | |
283 int ncol = img.getColorModel().getNumColorComponents(); | |
284 if ((ncol != 3) || (rgbm.length != 3) || (rgba.length != 3)) { | |
285 util.dprintln( | |
286 2, | |
287 "ERROR(enhance): unknown number of color bands or coefficients (" | |
288 + ncol | |
289 + ")"); | |
290 return; | |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
291 } |
89 | 292 RescaleOp scaleOp = |
293 new RescaleOp(rgbOrdered(rgbm), rgbOrdered(rgba), null); | |
86 | 294 scaleOp.filter(img, img); |
295 } | |
296 | |
297 /** Ensures that the array f is in the right order to map the images RGB components. | |
298 */ | |
299 public float[] rgbOrdered(float[] fa) { | |
300 float[] fb = new float[3]; | |
301 int t = img.getType(); | |
302 if ((t == BufferedImage.TYPE_3BYTE_BGR) | |
303 || (t == BufferedImage.TYPE_4BYTE_ABGR) | |
304 || (t == BufferedImage.TYPE_4BYTE_ABGR_PRE)) { | |
305 // BGR Type (actually it looks like RBG...) | |
306 fb[0] = fa[0]; | |
307 fb[1] = fa[2]; | |
308 fb[2] = fa[1]; | |
309 } else { | |
310 fb = fa; | |
311 } | |
312 return fb; | |
85 | 313 } |
314 | |
140 | 315 public void rotate(double angle) throws ImageOpException { |
89 | 316 // setup rotation |
317 double rangle = Math.toRadians(angle); | |
101 | 318 // create offset to make shure the rotated image has no negative coordinates |
319 double w = img.getWidth(); | |
320 double h = img.getHeight(); | |
103 | 321 AffineTransform trafo = new AffineTransform(); |
322 // center of rotation | |
323 double x = (w / 2); | |
324 double y = (h / 2); | |
101 | 325 trafo.rotate(rangle, x, y); |
103 | 326 // try rotation to see how far we're out of bounds |
327 AffineTransformOp rotOp = new AffineTransformOp(trafo, interpol); | |
328 Rectangle2D rotbounds = rotOp.getBounds2D(img); | |
329 double xoff = rotbounds.getX(); | |
330 double yoff = rotbounds.getY(); | |
331 // move image back in line | |
140 | 332 trafo.preConcatenate( |
333 AffineTransform.getTranslateInstance(-xoff, -yoff)); | |
101 | 334 // transform image |
103 | 335 rotOp = new AffineTransformOp(trafo, interpol); |
89 | 336 BufferedImage rotImg = rotOp.filter(img, null); |
101 | 337 // calculate new bounding box |
103 | 338 //Rectangle2D bounds = rotOp.getBounds2D(img); |
86 | 339 |
89 | 340 if (rotImg == null) { |
341 util.dprintln(2, "ERROR: error in rotate"); | |
342 throw new ImageOpException("Unable to rotate"); | |
343 } | |
103 | 344 img = rotImg; |
101 | 345 // crop new image (with self-made rounding) |
103 | 346 /* img = |
101 | 347 rotImg.getSubimage( |
348 (int) (bounds.getX()+0.5), | |
349 (int) (bounds.getY()+0.5), | |
350 (int) (bounds.getWidth()+0.5), | |
351 (int) (bounds.getHeight()+0.5)); | |
103 | 352 */ |
86 | 353 } |
85 | 354 |
89 | 355 public void mirror(double angle) throws ImageOpException { |
356 // setup mirror | |
357 double mx = 1; | |
358 double my = 1; | |
359 double tx = 0; | |
360 double ty = 0; | |
361 if (Math.abs(angle - 0) < epsilon) { | |
362 // 0 degree | |
363 mx = -1; | |
364 tx = getWidth(); | |
365 } else if (Math.abs(angle - 90) < epsilon) { | |
366 // 90 degree | |
367 my = -1; | |
368 ty = getHeight(); | |
369 } else if (Math.abs(angle - 180) < epsilon) { | |
370 // 180 degree | |
371 mx = -1; | |
372 tx = getWidth(); | |
373 } else if (Math.abs(angle - 270) < epsilon) { | |
374 // 270 degree | |
375 my = -1; | |
376 ty = getHeight(); | |
377 } else if (Math.abs(angle - 360) < epsilon) { | |
378 // 360 degree | |
379 mx = -1; | |
380 tx = getWidth(); | |
381 } | |
382 AffineTransformOp mirOp = | |
383 new AffineTransformOp( | |
384 new AffineTransform(mx, 0, 0, my, tx, ty), | |
385 interpol); | |
386 BufferedImage mirImg = mirOp.filter(img, null); | |
387 | |
388 if (mirImg == null) { | |
389 util.dprintln(2, "ERROR: error in mirror"); | |
390 throw new ImageOpException("Unable to mirror"); | |
391 } | |
392 img = mirImg; | |
79
63c8186455c1
Servlet version 1.6b. Further cleanup and new functionality:
robcast
parents:
73
diff
changeset
|
393 } |
86 | 394 |
1 | 395 } |