1 7 8 package java.awt.image; 9 10 import java.awt.geom.AffineTransform ; 11 import java.awt.geom.NoninvertibleTransformException ; 12 import java.awt.geom.Rectangle2D ; 13 import java.awt.geom.Point2D ; 14 import java.awt.AlphaComposite ; 15 import java.awt.GraphicsEnvironment ; 16 import java.awt.Rectangle ; 17 import java.awt.RenderingHints ; 18 import java.awt.Transparency ; 19 import sun.awt.image.ImagingLib; 20 21 48 public class AffineTransformOp implements BufferedImageOp , RasterOp { 49 private AffineTransform xform; 50 RenderingHints hints; 51 52 55 public static final int TYPE_NEAREST_NEIGHBOR = 1; 56 57 60 public static final int TYPE_BILINEAR = 2; 61 62 65 public static final int TYPE_BICUBIC = 3; 66 67 int interpolationType = TYPE_NEAREST_NEIGHBOR; 68 69 89 public AffineTransformOp(AffineTransform xform, RenderingHints hints){ 90 validateTransform(xform); 91 this.xform = (AffineTransform ) xform.clone(); 92 this.hints = hints; 93 94 if (hints != null) { 95 Object value = hints.get(hints.KEY_INTERPOLATION); 96 if (value == null) { 97 value = hints.get(hints.KEY_RENDERING); 98 if (value == hints.VALUE_RENDER_SPEED) { 99 interpolationType = TYPE_NEAREST_NEIGHBOR; 100 } 101 else if (value == hints.VALUE_RENDER_QUALITY) { 102 interpolationType = TYPE_BILINEAR; 103 } 104 } 105 else if (value == hints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR) { 106 interpolationType = TYPE_NEAREST_NEIGHBOR; 107 } 108 else if (value == hints.VALUE_INTERPOLATION_BILINEAR) { 109 interpolationType = TYPE_BILINEAR; 110 } 111 else if (value == hints.VALUE_INTERPOLATION_BICUBIC) { 112 interpolationType = TYPE_BICUBIC; 113 } 114 } 115 else { 116 interpolationType = TYPE_NEAREST_NEIGHBOR; 117 } 118 } 119 120 132 public AffineTransformOp(AffineTransform xform, int interpolationType) { 133 validateTransform(xform); 134 this.xform = (AffineTransform )xform.clone(); 135 switch(interpolationType) { 136 case TYPE_NEAREST_NEIGHBOR: 137 case TYPE_BILINEAR: 138 case TYPE_BICUBIC: 139 break; 140 default: 141 throw new IllegalArgumentException ("Unknown interpolation type: "+ 142 interpolationType); 143 } 144 this.interpolationType = interpolationType; 145 } 146 147 154 public final int getInterpolationType() { 155 return interpolationType; 156 } 157 158 193 public final BufferedImage filter(BufferedImage src, BufferedImage dst) { 194 195 if (src == null) { 196 throw new NullPointerException ("src image is null"); 197 } 198 if (src == dst) { 199 throw new IllegalArgumentException ("src image cannot be the "+ 200 "same as the dst image"); 201 } 202 203 boolean needToConvert = false; 204 ColorModel srcCM = src.getColorModel(); 205 ColorModel dstCM; 206 BufferedImage origDst = dst; 207 208 if (dst == null) { 209 dst = createCompatibleDestImage(src, null); 210 dstCM = srcCM; 211 origDst = dst; 212 } 213 else { 214 dstCM = dst.getColorModel(); 215 if (srcCM.getColorSpace().getType() != 216 dstCM.getColorSpace().getType()) 217 { 218 int type = xform.getType(); 219 boolean needTrans = ((type& 220 (xform.TYPE_MASK_ROTATION| 221 xform.TYPE_GENERAL_TRANSFORM)) 222 != 0); 223 if (! needTrans && type != xform.TYPE_TRANSLATION && type != xform.TYPE_IDENTITY) 224 { 225 double[] mtx = new double[4]; 226 xform.getMatrix(mtx); 227 needTrans = (mtx[0] != (int)mtx[0] || mtx[3] != (int)mtx[3]); 230 } 231 232 if (needTrans && 233 srcCM.getTransparency() == Transparency.OPAQUE) 234 { 235 ColorConvertOp ccop = new ColorConvertOp (hints); 237 BufferedImage tmpSrc = null; 238 int sw = src.getWidth(); 239 int sh = src.getHeight(); 240 if (dstCM.getTransparency() == Transparency.OPAQUE) { 241 tmpSrc = new BufferedImage (sw, sh, 242 BufferedImage.TYPE_INT_ARGB); 243 } 244 else { 245 WritableRaster r = 246 dstCM.createCompatibleWritableRaster(sw, sh); 247 tmpSrc = new BufferedImage (dstCM, r, 248 dstCM.isAlphaPremultiplied(), 249 null); 250 } 251 src = ccop.filter(src, tmpSrc); 252 } 253 else { 254 needToConvert = true; 255 dst = createCompatibleDestImage(src, null); 256 } 257 } 258 259 } 260 261 if (interpolationType != TYPE_NEAREST_NEIGHBOR && 262 dst.getColorModel() instanceof IndexColorModel ) { 263 dst = new BufferedImage (dst.getWidth(), dst.getHeight(), 264 BufferedImage.TYPE_INT_ARGB); 265 } 266 if (ImagingLib.filter(this, src, dst) == null) { 267 throw new ImagingOpException ("Unable to transform src image"); 268 } 269 270 if (needToConvert) { 271 ColorConvertOp ccop = new ColorConvertOp (hints); 272 ccop.filter(dst, origDst); 273 } 274 else if (origDst != dst) { 275 java.awt.Graphics2D g = origDst.createGraphics(); 276 try { 277 g.setComposite(AlphaComposite.Src); 278 g.drawImage(dst, 0, 0, null); 279 } finally { 280 g.dispose(); 281 } 282 } 283 284 return origDst; 285 } 286 287 320 public final WritableRaster filter(Raster src, WritableRaster dst) { 321 if (src == null) { 322 throw new NullPointerException ("src image is null"); 323 } 324 if (dst == null) { 325 dst = createCompatibleDestRaster(src); 326 } 327 if (src == dst) { 328 throw new IllegalArgumentException ("src image cannot be the "+ 329 "same as the dst image"); 330 } 331 if (src.getNumBands() != dst.getNumBands()) { 332 throw new IllegalArgumentException ("Number of src bands ("+ 333 src.getNumBands()+ 334 ") does not match number of "+ 335 " dst bands ("+ 336 dst.getNumBands()+")"); 337 } 338 339 if (ImagingLib.filter(this, src, dst) == null) { 340 throw new ImagingOpException ("Unable to transform src image"); 341 } 342 return dst; 343 } 344 345 356 public final Rectangle2D getBounds2D (BufferedImage src) { 357 return getBounds2D(src.getRaster()); 358 } 359 360 371 public final Rectangle2D getBounds2D (Raster src) { 372 int w = src.getWidth(); 373 int h = src.getHeight(); 374 375 float[] pts = {0, 0, w, 0, w, h, 0, h}; 377 xform.transform(pts, 0, pts, 0, 4); 378 379 float fmaxX = pts[0]; 381 float fmaxY = pts[1]; 382 float fminX = pts[0]; 383 float fminY = pts[1]; 384 int maxX; 385 int maxY; 386 for (int i=2; i < 8; i+=2) { 387 if (pts[i] > fmaxX) { 388 fmaxX = pts[i]; 389 } 390 else if (pts[i] < fminX) { 391 fminX = pts[i]; 392 } 393 if (pts[i+1] > fmaxY) { 394 fmaxY = pts[i+1]; 395 } 396 else if (pts[i+1] < fminY) { 397 fminY = pts[i+1]; 398 } 399 } 400 401 return new Rectangle2D.Float (fminX, fminY, fmaxX-fminX, fmaxY-fminY); 402 } 403 404 420 public BufferedImage createCompatibleDestImage (BufferedImage src, 421 ColorModel destCM) { 422 BufferedImage image; 423 Rectangle r = getBounds2D(src).getBounds(); 424 425 int w = r.x + r.width; 430 int h = r.y + r.height; 431 if (w <= 0) { 432 throw new RasterFormatException ("Transformed width ("+w+ 433 ") is less than or equal to 0."); 434 } 435 if (h <= 0) { 436 throw new RasterFormatException ("Transformed height ("+h+ 437 ") is less than or equal to 0."); 438 } 439 440 if (destCM == null) { 441 ColorModel cm = src.getColorModel(); 442 if (interpolationType != TYPE_NEAREST_NEIGHBOR && 443 (cm instanceof IndexColorModel || 444 cm.getTransparency() == Transparency.OPAQUE)) 445 { 446 image = new BufferedImage (w, h, 447 BufferedImage.TYPE_INT_ARGB); 448 } 449 else { 450 image = new BufferedImage (cm, 451 src.getRaster().createCompatibleWritableRaster(w,h), 452 cm.isAlphaPremultiplied(), null); 453 } 454 } 455 else { 456 image = new BufferedImage (destCM, 457 destCM.createCompatibleWritableRaster(w,h), 458 destCM.isAlphaPremultiplied(), null); 459 } 460 461 return image; 462 } 463 464 473 public WritableRaster createCompatibleDestRaster (Raster src) { 474 Rectangle2D r = getBounds2D(src); 475 476 return src.createCompatibleWritableRaster((int)r.getX(), 477 (int)r.getY(), 478 (int)r.getWidth(), 479 (int)r.getHeight()); 480 } 481 482 494 public final Point2D getPoint2D (Point2D srcPt, Point2D dstPt) { 495 return xform.transform (srcPt, dstPt); 496 } 497 498 503 public final AffineTransform getTransform() { 504 return (AffineTransform ) xform.clone(); 505 } 506 507 512 public final RenderingHints getRenderingHints() { 513 if (hints == null) { 514 Object val; 515 switch(interpolationType) { 516 case TYPE_NEAREST_NEIGHBOR: 517 val = RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR; 518 break; 519 case TYPE_BILINEAR: 520 val = RenderingHints.VALUE_INTERPOLATION_BILINEAR; 521 break; 522 case TYPE_BICUBIC: 523 val = RenderingHints.VALUE_INTERPOLATION_BICUBIC; 524 break; 525 default: 526 throw new InternalError ("Unknown interpolation type "+ 528 interpolationType); 529 530 } 531 hints = new RenderingHints (RenderingHints.KEY_INTERPOLATION, val); 532 } 533 534 return hints; 535 } 536 537 void validateTransform(AffineTransform xform) { 541 if (Math.abs(xform.getDeterminant()) <= Double.MIN_VALUE) { 542 throw new ImagingOpException ("Unable to invert transform "+xform); 543 } 544 } 545 } 546 | Popular Tags |