| 1 18 package org.apache.batik.ext.awt.image; 19 20 import java.awt.Composite ; 21 import java.awt.Graphics2D ; 22 import java.awt.GraphicsConfiguration ; 23 import java.awt.GraphicsDevice ; 24 import java.awt.Point ; 25 import java.awt.Rectangle ; 26 import java.awt.RenderingHints ; 27 import java.awt.Shape ; 28 import java.awt.color.ColorSpace ; 29 import java.awt.geom.AffineTransform ; 30 import java.awt.geom.Rectangle2D ; 31 import java.awt.image.BufferedImage ; 32 import java.awt.image.ColorModel ; 33 import java.awt.image.ComponentSampleModel ; 34 import java.awt.image.DataBuffer ; 35 import java.awt.image.DataBufferByte ; 36 import java.awt.image.DataBufferInt ; 37 import java.awt.image.DataBufferShort ; 38 import java.awt.image.DataBufferUShort ; 39 import java.awt.image.DirectColorModel ; 40 import java.awt.image.Raster ; 41 import java.awt.image.RenderedImage ; 42 import java.awt.image.SampleModel ; 43 import java.awt.image.SinglePixelPackedSampleModel ; 44 import java.awt.image.WritableRaster ; 45 import java.awt.image.renderable.RenderContext ; 46 import java.awt.image.renderable.RenderableImage ; 47 import java.lang.ref.Reference ; 48 import java.lang.ref.WeakReference ; 49 50 import org.apache.batik.ext.awt.RenderingHintsKeyExt; 51 import org.apache.batik.ext.awt.image.renderable.PaintRable; 52 import org.apache.batik.ext.awt.image.rendered.AffineRed; 53 import org.apache.batik.ext.awt.image.rendered.Any2LsRGBRed; 54 import org.apache.batik.ext.awt.image.rendered.Any2sRGBRed; 55 import org.apache.batik.ext.awt.image.rendered.BufferedImageCachableRed; 56 import org.apache.batik.ext.awt.image.rendered.CachableRed; 57 import org.apache.batik.ext.awt.image.rendered.FormatRed; 58 import org.apache.batik.ext.awt.image.rendered.RenderedImageCachableRed; 59 import org.apache.batik.ext.awt.image.rendered.TranslateRed; 60 61 62 70 public class GraphicsUtil { 71 72 public static AffineTransform IDENTITY = new AffineTransform (); 73 74 82 public static void drawImage(Graphics2D g2d, 83 RenderedImage ri) { 84 drawImage(g2d, wrap(ri)); 85 } 86 87 95 public static void drawImage(Graphics2D g2d, 96 CachableRed cr) { 97 98 100 AffineTransform at = null; 101 while (true) { 102 if (cr instanceof AffineRed) { 103 AffineRed ar = (AffineRed)cr; 104 if (at == null) 105 at = ar.getTransform(); 106 else 107 at.concatenate(ar.getTransform()); 108 cr = ar.getSource(); 109 continue; 110 } else if (cr instanceof TranslateRed) { 111 TranslateRed tr = (TranslateRed)cr; 112 int dx = tr.getDeltaX(); 114 int dy = tr.getDeltaY(); 115 if (at == null) 116 at = AffineTransform.getTranslateInstance(dx, dy); 117 else 118 at.translate(dx, dy); 119 cr = tr.getSource(); 120 continue; 121 } 122 break; 123 } 124 AffineTransform g2dAt = g2d.getTransform(); 125 if ((at == null) || (at.isIdentity())) 126 at = g2dAt; 127 else 128 at.preConcatenate(g2dAt); 129 130 ColorModel srcCM = cr.getColorModel(); 131 ColorSpace g2dCS = getDestinationColorSpace(g2d); 132 ColorModel g2dCM = getDestinationColorModel(g2d); 133 if (g2dCS == null) 134 g2dCS = ColorSpace.getInstance(ColorSpace.CS_sRGB); 136 ColorModel drawCM = g2dCM; 137 if ((g2dCM == null) || !g2dCM.hasAlpha()) { 138 drawCM = sRGB_Unpre; 142 } 143 144 if (cr instanceof BufferedImageCachableRed) { 145 if (g2dCS.equals(srcCM.getColorSpace()) && 149 drawCM.equals(srcCM)) { 150 g2d.setTransform(at); 152 BufferedImageCachableRed bicr; 153 bicr = (BufferedImageCachableRed)cr; 154 g2d.drawImage(bicr.getBufferedImage(), 155 bicr.getMinX(), bicr.getMinY(), null); 156 g2d.setTransform(g2dAt); 157 return; 158 } 159 } 160 161 double determinant = at.getDeterminant(); 163 if (!at.isIdentity() && (determinant <= 1.0)) { 164 if (at.getType() != AffineTransform.TYPE_TRANSLATION) 165 cr = new AffineRed(cr, at, g2d.getRenderingHints()); 166 else { 167 int xloc = cr.getMinX() + (int)at.getTranslateX(); 168 int yloc = cr.getMinY() + (int)at.getTranslateY(); 169 cr = new TranslateRed(cr, xloc, yloc); 170 } 171 } 172 173 if (g2dCS != srcCM.getColorSpace()) { 174 if (g2dCS == ColorSpace.getInstance(ColorSpace.CS_sRGB)) 182 cr = convertTosRGB(cr); 183 else if (g2dCS == ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB)) 184 cr = convertToLsRGB(cr); 185 } 186 srcCM = cr.getColorModel(); 187 if (!drawCM.equals(srcCM)) 188 cr = FormatRed.construct(cr, drawCM); 189 190 if (!at.isIdentity() && (determinant > 1.0)) 192 cr = new AffineRed(cr, at, g2d.getRenderingHints()); 193 194 g2d.setTransform(IDENTITY); 196 197 Composite g2dComposite = g2d.getComposite(); 202 if (g2d.getRenderingHint(RenderingHintsKeyExt.KEY_TRANSCODING) == 203 RenderingHintsKeyExt.VALUE_TRANSCODING_PRINTING) { 204 if (SVGComposite.OVER.equals(g2dComposite)) { 205 g2d.setComposite(SVGComposite.OVER); 206 } 207 } 208 Rectangle crR = cr.getBounds(); 209 Shape clip = g2d.getClip(); 210 211 try { 212 Rectangle clipR; 213 if (clip == null) { 214 clip = crR; 215 clipR = crR; 216 } else { 217 clipR = clip.getBounds(); 218 219 if (clipR.intersects(crR) == false) 220 return; clipR = clipR.intersection(crR); 222 } 223 224 Rectangle gcR = getDestinationBounds(g2d); 225 if (gcR != null) { 227 if (clipR.intersects(gcR) == false) 228 return; clipR = clipR.intersection(gcR); 230 } 231 232 235 boolean useDrawRenderedImage = false; 236 237 srcCM = cr.getColorModel(); 238 SampleModel srcSM = cr.getSampleModel(); 239 if ((srcSM.getWidth()*srcSM.getHeight()) >= 240 (clipR.width*clipR.height)) 241 useDrawRenderedImage = true; 244 245 Object atpHint = g2d.getRenderingHint 246 (RenderingHintsKeyExt.KEY_AVOID_TILE_PAINTING); 247 248 if (atpHint == RenderingHintsKeyExt.VALUE_AVOID_TILE_PAINTING_ON) 249 useDrawRenderedImage = true; 251 if (atpHint == RenderingHintsKeyExt.VALUE_AVOID_TILE_PAINTING_OFF) 252 useDrawRenderedImage = false; 253 254 255 WritableRaster wr; 256 if (useDrawRenderedImage) { 257 Raster r = cr.getData(clipR); 261 wr = ((WritableRaster )r).createWritableChild 262 (clipR.x, clipR.y, clipR.width, clipR.height, 263 0, 0, null); 264 265 BufferedImage bi = new BufferedImage  266 (srcCM, wr, srcCM.isAlphaPremultiplied(), null); 267 268 g2d.drawImage(bi, clipR.x, clipR.y, null); 273 } else { 274 wr = Raster.createWritableRaster(srcSM, new Point (0,0)); 276 BufferedImage bi = new BufferedImage  277 (srcCM, wr, srcCM.isAlphaPremultiplied(), null); 278 279 int xt0 = cr.getMinTileX(); 280 int xt1 = xt0+cr.getNumXTiles(); 281 int yt0 = cr.getMinTileY(); 282 int yt1 = yt0+cr.getNumYTiles(); 283 int tw = srcSM.getWidth(); 284 int th = srcSM.getHeight(); 285 286 Rectangle tR = new Rectangle (0,0,tw,th); 287 Rectangle iR = new Rectangle (0,0,0,0); 288 289 if (false) { 290 System.err.println("SrcCM: " + srcCM); 291 System.err.println("CR: " + cr); 292 System.err.println("CRR: " + crR + " TG: [" + 293 xt0 +"," + 294 yt0 +"," + 295 xt1 +"," + 296 yt1 +"] Off: " + 297 cr.getTileGridXOffset() +"," + 298 cr.getTileGridYOffset()); 299 } 300 301 int yloc = yt0*th+cr.getTileGridYOffset(); 302 int skip = (clipR.y-yloc)/th; 303 if (skip <0) skip = 0; 304 yt0+=skip; 305 306 int xloc = xt0*tw+cr.getTileGridXOffset(); 307 skip = (clipR.x-xloc)/tw; 308 if (skip <0) skip = 0; 309 xt0+=skip; 310 311 int endX = clipR.x+clipR.width-1; 312 int endY = clipR.y+clipR.height-1; 313 314 if (false) { 315 System.out.println("clipR: " + clipR + " TG: [" + 316 xt0 +"," + 317 yt0 +"," + 318 xt1 +"," + 319 yt1 +"] Off: " + 320 cr.getTileGridXOffset() +"," + 321 cr.getTileGridYOffset()); 322 } 323 324 325 yloc = yt0*th+cr.getTileGridYOffset(); 326 int minX = xt0*tw+cr.getTileGridXOffset(); 327 int xStep = tw; 328 xloc = minX; 329 for (int y=yt0; y<yt1; y++, yloc += th) { 330 if (yloc > endY) break; 331 for (int x=xt0; x<xt1; x++, xloc+=xStep) { 332 if ((xloc<minX) || (xloc > endX)) break; 333 tR.x = xloc; 334 tR.y = yloc; 335 Rectangle2D.intersect(crR, tR, iR); 336 337 WritableRaster twr; 338 twr = wr.createWritableChild(0, 0, 339 iR.width, iR.height, 340 iR.x, iR.y, null); 341 342 cr.copyData(twr); 344 345 BufferedImage subBI; 347 subBI = bi.getSubimage(0, 0, iR.width, iR.height); 348 349 if (false) { 350 System.out.println("Drawing: " + tR); 351 System.out.println("IR: " + iR); 352 } 353 354 g2d.drawImage(subBI, iR.x, iR.y, null); 358 362 } 366 xStep = -xStep; xloc += xStep; } 369 } 370 373 374 } finally { 375 g2d.setTransform(g2dAt); 376 g2d.setComposite(g2dComposite); 377 } 378 379 } 381 382 383 398 public static void drawImage(Graphics2D g2d, 399 RenderableImage filter, 400 RenderContext rc) { 401 402 AffineTransform origDev = g2d.getTransform(); 403 Shape origClip = g2d.getClip(); 404 RenderingHints origRH = g2d.getRenderingHints(); 405 406 Shape clip = rc.getAreaOfInterest(); 407 if (clip != null) 408 g2d.clip(clip); 409 g2d.transform(rc.getTransform()); 410 g2d.setRenderingHints(rc.getRenderingHints()); 411 412 drawImage(g2d, filter); 413 414 g2d.setTransform(origDev); 415 g2d.setClip(origClip); 416 g2d.setRenderingHints(origRH); 417 } 418 419 432 public static void drawImage(Graphics2D g2d, 433 RenderableImage filter) { 434 if (filter instanceof PaintRable) { 435 PaintRable pr = (PaintRable)filter; 436 if (pr.paintRable(g2d)) 437 return; 439 } 440 441 AffineTransform at = g2d.getTransform(); 444 RenderedImage ri = filter.createRendering 445 (new RenderContext (at, g2d.getClip(), g2d.getRenderingHints())); 446 447 if (ri == null) 448 return; 449 450 g2d.setTransform(IDENTITY); 451 drawImage(g2d, GraphicsUtil.wrap(ri)); 452 g2d.setTransform(at); 453 } 454 455 467 public static Graphics2D createGraphics(BufferedImage bi, 468 RenderingHints hints) { 469 Graphics2D g2d = bi.createGraphics(); 470 if (hints != null) 471 g2d.addRenderingHints(hints); 472 g2d.setRenderingHint(RenderingHintsKeyExt.KEY_BUFFERED_IMAGE, 473 new WeakReference (bi)); 474 g2d.clip(new Rectangle (0, 0, bi.getWidth(), bi.getHeight())); 475 return g2d; 476 } 477 478 479 public static Graphics2D createGraphics(BufferedImage bi) { 480 Graphics2D g2d = bi.createGraphics(); 481 g2d.setRenderingHint(RenderingHintsKeyExt.KEY_BUFFERED_IMAGE, 482 new WeakReference (bi)); 483 g2d.clip(new Rectangle (0, 0, bi.getWidth(), bi.getHeight())); 484 return g2d; 485 } 486 487 488 public final static boolean WARN_DESTINATION = true; 489 490 public static BufferedImage getDestination(Graphics2D g2d) { 491 Object o = g2d.getRenderingHint 492 (RenderingHintsKeyExt.KEY_BUFFERED_IMAGE); 493 if (o != null) 494 return (BufferedImage )(((Reference )o).get()); 495 496 GraphicsConfiguration gc = g2d.getDeviceConfiguration(); 498 GraphicsDevice gd = gc.getDevice(); 499 if (WARN_DESTINATION && 500 (gd.getType() == GraphicsDevice.TYPE_IMAGE_BUFFER) && 501 (g2d.getRenderingHint(RenderingHintsKeyExt.KEY_TRANSCODING) != 502 RenderingHintsKeyExt.VALUE_TRANSCODING_PRINTING)) 503 System.out.println 505 ("Graphics2D from BufferedImage lacks BUFFERED_IMAGE hint"); 506 507 return null; 508 } 509 510 public static ColorModel getDestinationColorModel(Graphics2D g2d) { 511 BufferedImage bi = getDestination(g2d); 512 if (bi != null) 513 return bi.getColorModel(); 514 515 GraphicsConfiguration gc = g2d.getDeviceConfiguration(); 516 517 if (gc.getDevice().getType() == GraphicsDevice.TYPE_IMAGE_BUFFER) { 520 if (g2d.getRenderingHint(RenderingHintsKeyExt.KEY_TRANSCODING) == 521 RenderingHintsKeyExt.VALUE_TRANSCODING_PRINTING) 522 return sRGB_Unpre; 523 524 return null; 527 } 528 529 return gc.getColorModel(); 530 } 531 532 public static ColorSpace getDestinationColorSpace(Graphics2D g2d) { 533 ColorModel cm = getDestinationColorModel(g2d); 534 if (cm != null) return cm.getColorSpace(); 535 536 return null; 537 } 538 539 public static Rectangle getDestinationBounds(Graphics2D g2d) { 540 BufferedImage bi = getDestination(g2d); 541 if (bi != null) 542 return new Rectangle (0, 0, bi.getWidth(), bi.getHeight()); 543 544 GraphicsConfiguration gc = g2d.getDeviceConfiguration(); 545 546 if (gc.getDevice().getType() == GraphicsDevice.TYPE_IMAGE_BUFFER) 549 return null; 550 551 return null; 554 } 555 556 557 559 public final static ColorModel Linear_sRGB = 560 new DirectColorModel (ColorSpace.getInstance 561 (ColorSpace.CS_LINEAR_RGB), 24, 562 0x00FF0000, 0x0000FF00, 563 0x000000FF, 0x0, false, 564 DataBuffer.TYPE_INT); 565 568 public final static ColorModel Linear_sRGB_Pre = 569 new DirectColorModel (ColorSpace.getInstance 570 (ColorSpace.CS_LINEAR_RGB), 32, 571 0x00FF0000, 0x0000FF00, 572 0x000000FF, 0xFF000000, true, 573 DataBuffer.TYPE_INT); 574 577 public final static ColorModel Linear_sRGB_Unpre = 578 new DirectColorModel (ColorSpace.getInstance 579 (ColorSpace.CS_LINEAR_RGB), 32, 580 0x00FF0000, 0x0000FF00, 581 0x000000FF, 0xFF000000, false, 582 DataBuffer.TYPE_INT); 583 584 587 public final static ColorModel sRGB = 588 new DirectColorModel (ColorSpace.getInstance 589 (ColorSpace.CS_sRGB), 24, 590 0x00FF0000, 0x0000FF00, 591 0x000000FF, 0x0, false, 592 DataBuffer.TYPE_INT); 593 596 public final static ColorModel sRGB_Pre = 597 new DirectColorModel (ColorSpace.getInstance 598 (ColorSpace.CS_sRGB), 32, 599 0x00FF0000, 0x0000FF00, 600 0x000000FF, 0xFF000000, true, 601 DataBuffer.TYPE_INT); 602 605 public final static ColorModel sRGB_Unpre = 606 new DirectColorModel (ColorSpace.getInstance 607 (ColorSpace.CS_sRGB), 32, 608 0x00FF0000, 0x0000FF00, 609 0x000000FF, 0xFF000000, false, 610 DataBuffer.TYPE_INT); 611 612 620 public static ColorModel makeLinear_sRGBCM(boolean premult) { 621 if (premult) 622 return Linear_sRGB_Pre; 623 return Linear_sRGB_Unpre; 624 } 625 626 633 public static BufferedImage makeLinearBufferedImage(int width, 634 int height, 635 boolean premult) { 636 ColorModel cm = makeLinear_sRGBCM(premult); 637 WritableRaster wr = cm.createCompatibleWritableRaster(width, height); 638 return new BufferedImage (cm, wr, premult, null); 639 } 640 641 652 public static CachableRed convertToLsRGB(CachableRed src) { 653 ColorModel cm = src.getColorModel(); 654 ColorSpace cs = cm.getColorSpace(); 655 if (cs == ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB)) 656 return src; 657 658 return new Any2LsRGBRed(src); 659 } 660 661 671 public static CachableRed convertTosRGB(CachableRed src) { 672 ColorModel cm = src.getColorModel(); 673 ColorSpace cs = cm.getColorSpace(); 674 if (cs == ColorSpace.getInstance(ColorSpace.CS_sRGB)) 675 return src; 676 677 return new Any2sRGBRed(src); 678 } 679 680 693 public static CachableRed wrap( |