| 1 7 8 17 18 package java.awt.image; 19 20 import java.awt.Point ; 21 import java.awt.Graphics2D ; 22 import java.awt.color.*; 23 import sun.awt.color.ICC_Transform; 24 import sun.awt.color.ProfileDeferralMgr; 25 import java.awt.geom.Rectangle2D ; 26 import java.awt.geom.Point2D ; 27 import java.awt.RenderingHints ; 28 29 51 public class ColorConvertOp implements BufferedImageOp , RasterOp { 52 ICC_Profile[] profileList; 53 ColorSpace[] CSList; 54 ICC_Transform thisTransform, thisRasterTransform; 55 ICC_Profile thisSrcProfile, thisDestProfile; 56 RenderingHints hints; 57 boolean gotProfiles; 58 float[] srcMinVals, srcMaxVals, dstMinVals, dstMaxVals; 59 60 61 static { 62 if (ProfileDeferralMgr.deferring) { 63 ProfileDeferralMgr.activateProfiles(); 64 } 65 } 66 67 78 public ColorConvertOp (RenderingHints hints) 79 { 80 profileList = new ICC_Profile [0]; 81 this.hints = hints; 82 } 83 84 100 public ColorConvertOp (ColorSpace cspace, RenderingHints hints) 101 { 102 if (cspace == null) { 103 throw new NullPointerException ("ColorSpace cannot be null"); 104 } 105 if (cspace instanceof ICC_ColorSpace) { 106 profileList = new ICC_Profile [1]; 107 108 profileList [0] = ((ICC_ColorSpace) cspace).getProfile(); 109 } 110 else { 111 CSList = new ColorSpace[1]; 112 CSList[0] = cspace; 113 } 114 this.hints = hints; 115 } 116 117 118 135 public ColorConvertOp(ColorSpace srcCspace, ColorSpace dstCspace, 136 RenderingHints hints) 137 { 138 if ((srcCspace == null) || (dstCspace == null)) { 139 throw new NullPointerException ("ColorSpaces cannot be null"); 140 } 141 if ((srcCspace instanceof ICC_ColorSpace) && 142 (dstCspace instanceof ICC_ColorSpace)) { 143 profileList = new ICC_Profile [2]; 144 145 profileList [0] = ((ICC_ColorSpace) srcCspace).getProfile(); 146 profileList [1] = ((ICC_ColorSpace) dstCspace).getProfile(); 147 148 getMinMaxValsFromColorSpaces(srcCspace, dstCspace); 149 } else { 150 151 CSList = new ColorSpace[2]; 152 CSList[0] = srcCspace; 153 CSList[1] = dstCspace; 154 } 155 this.hints = hints; 156 } 157 158 159 186 public ColorConvertOp (ICC_Profile[] profiles, RenderingHints hints) 187 { 188 if (profiles == null) { 189 throw new NullPointerException ("Profiles cannot be null"); 190 } 191 gotProfiles = true; 192 profileList = new ICC_Profile[profiles.length]; 193 for (int i1 = 0; i1 < profiles.length; i1++) { 194 profileList[i1] = profiles[i1]; 195 } 196 this.hints = hints; 197 } 198 199 200 209 public final ICC_Profile[] getICC_Profiles() { 210 if (gotProfiles) { 211 ICC_Profile[] profiles = new ICC_Profile[profileList.length]; 212 for (int i1 = 0; i1 < profileList.length; i1++) { 213 profiles[i1] = profileList[i1]; 214 } 215 return profiles; 216 } 217 return null; 218 } 219 220 234 public final BufferedImage filter(BufferedImage src, BufferedImage dest) { 235 ColorSpace srcColorSpace, destColorSpace; 236 BufferedImage savdest = null; 237 238 if (src.getColorModel() instanceof IndexColorModel ) { 239 IndexColorModel icm = (IndexColorModel ) src.getColorModel(); 240 src = icm.convertToIntDiscrete(src.getRaster(), true); 241 } 242 srcColorSpace = src.getColorModel().getColorSpace(); 243 if (dest != null) { 244 if (dest.getColorModel() instanceof IndexColorModel ) { 245 savdest = dest; 246 dest = null; 247 destColorSpace = null; 248 } else { 249 destColorSpace = dest.getColorModel().getColorSpace(); 250 } 251 } else { 252 destColorSpace = null; 253 } 254 255 if ((CSList != null) || 256 (!(srcColorSpace instanceof ICC_ColorSpace)) || 257 ((dest != null) && 258 (!(destColorSpace instanceof ICC_ColorSpace)))) { 259 260 dest = nonICCBIFilter(src, srcColorSpace, dest, destColorSpace); 261 } else { 262 dest = ICCBIFilter(src, srcColorSpace, dest, destColorSpace); 263 } 264 265 if (savdest != null) { 266 Graphics2D big = savdest.createGraphics(); 267 try { 268 big.drawImage(dest, 0, 0, null); 269 } finally { 270 big.dispose(); 271 } 272 return savdest; 273 } else { 274 return dest; 275 } 276 } 277 278 private final BufferedImage ICCBIFilter(BufferedImage src, 279 ColorSpace srcColorSpace, 280 BufferedImage dest, 281 ColorSpace destColorSpace) { 282 int nProfiles = profileList.length; 283 ICC_Profile srcProfile = null, destProfile = null; 284 285 srcProfile = ((ICC_ColorSpace) srcColorSpace).getProfile(); 286 287 if (dest == null) { 289 if (nProfiles == 0) { 290 throw new IllegalArgumentException ( 291 "Destination ColorSpace is undefined"); 292 } 293 destProfile = profileList [nProfiles - 1]; 294 dest = createCompatibleDestImage(src, null); 295 } 296 else { 297 if (src.getHeight() != dest.getHeight() || 298 src.getWidth() != dest.getWidth()) { 299 throw new IllegalArgumentException ( 300 "Width or height of BufferedImages do not match"); 301 } 302 destProfile = ((ICC_ColorSpace) destColorSpace).getProfile(); 303 } 304 305 306 if ((thisTransform == null) || (thisSrcProfile != srcProfile) || 307 (thisDestProfile != destProfile) ) { 308 updateBITransform(srcProfile, destProfile); 309 } 310 311 312 thisTransform.colorConvert(src, dest); 313 314 return dest; 315 } 316 317 private void updateBITransform(ICC_Profile srcProfile, 318 ICC_Profile destProfile) { 319 ICC_Profile[] theProfiles; 320 int i1, nProfiles, nTransforms, whichTrans, renderState; 321 ICC_Transform[] theTransforms; 322 boolean useSrc = false, useDest = false; 323 324 nProfiles = profileList.length; 325 nTransforms = nProfiles; 326 if ((nProfiles == 0) || (srcProfile != profileList[0])) { 327 nTransforms += 1; 328 useSrc = true; 329 } 330 if ((nProfiles == 0) || (destProfile != profileList[nProfiles - 1]) || 331 (nTransforms < 2)) { 332 nTransforms += 1; 333 useDest = true; 334 } 335 336 337 theProfiles = new ICC_Profile[nTransforms]; 339 340 int idx = 0; 341 if (useSrc) { 342 343 theProfiles[idx++] = srcProfile; 344 } 345 346 for (i1 = 0; i1 < nProfiles; i1++) { 347 348 theProfiles[idx++] = profileList [i1]; 349 } 350 351 if (useDest) { 352 353 theProfiles[idx] = destProfile; 354 } 355 356 357 theTransforms = new ICC_Transform [nTransforms]; 358 359 360 if (theProfiles[0].getProfileClass() == ICC_Profile.CLASS_OUTPUT) { 361 363 renderState = ICC_Profile.icRelativeColorimetric; 364 } 365 else { 366 renderState = ICC_Profile.icPerceptual; 368 } 369 370 whichTrans = ICC_Transform.In; 371 372 373 for (i1 = 0; i1 < nTransforms; i1++) { 374 if (i1 == nTransforms -1) { 375 whichTrans = ICC_Transform.Out; 376 } 377 else { 378 if ((whichTrans == ICC_Transform.Simulation) && 379 (theProfiles[i1].getProfileClass () == 380 ICC_Profile.CLASS_ABSTRACT)) { 381 renderState = ICC_Profile.icPerceptual; 382 whichTrans = ICC_Transform.In; 383 } 384 } 385 386 theTransforms[i1] = new ICC_Transform (theProfiles[i1], 387 renderState, whichTrans); 388 389 391 renderState = getRenderingIntent(theProfiles[i1]); 392 393 394 whichTrans = ICC_Transform.Simulation; 395 } 396 397 398 thisTransform = new ICC_Transform (theTransforms); 399 400 401 thisSrcProfile = srcProfile; 402 thisDestProfile = destProfile; 403 } 404 405 425 public final WritableRaster filter (Raster src, WritableRaster dest) { 426 427 if (CSList != null) { 428 429 return nonICCRasterFilter(src, dest); 430 } 431 int nProfiles = profileList.length; 432 if (nProfiles < 2) { 433 throw new IllegalArgumentException ( 434 "Source or Destination ColorSpace is undefined"); 435 } 436 if (src.getNumBands() != profileList[0].getNumComponents()) { 437 throw new IllegalArgumentException ( 438 "Numbers of source Raster bands and source color space " + 439 "components do not match"); 440 } 441 if (dest == null) { 442 dest = createCompatibleDestRaster(src); 443 } 444 else { 445 if (src.getHeight() != dest.getHeight() || 446 src.getWidth() != dest.getWidth()) { 447 throw new IllegalArgumentException ( 448 "Width or height of Rasters do not match"); 449 } 450 if (dest.getNumBands() != 451 profileList[nProfiles-1].getNumComponents()) { 452 throw new IllegalArgumentException ( 453 "Numbers of destination Raster bands and destination " + 454 "color space components do not match"); 455 } 456 } 457 458 459 if (thisRasterTransform == null) { 460 int i1, whichTrans, renderState; 461 ICC_Transform[] theTransforms; 462 463 464 theTransforms = new ICC_Transform [nProfiles]; 465 466 467 if (profileList[0].getProfileClass() == ICC_Profile.CLASS_OUTPUT) { 468 470 renderState = ICC_Profile.icRelativeColorimetric; 471 } 472 else { 473 renderState = ICC_Profile.icPerceptual; 475 } 476 477 whichTrans = ICC_Transform.In; 478 479 480 for (i1 = 0; i1 < nProfiles; i1++) { 481 if (i1 == nProfiles -1) { 482 whichTrans = ICC_Transform.Out; 483 } 484 else { 485 if ((whichTrans == ICC_Transform.Simulation) && 486 (profileList[i1].getProfileClass () == 487 ICC_Profile.CLASS_ABSTRACT)) { 488 renderState = ICC_Profile.icPerceptual; 489 whichTrans = ICC_Transform.In; 490 } 491 } 492 493 theTransforms[i1] = new ICC_Transform (profileList[i1], 494 renderState, whichTrans); 495 496 498 renderState = getRenderingIntent(profileList[i1]); 499 500 501 whichTrans = ICC_Transform.Simulation; 502 } 503 504 505 thisRasterTransform = new ICC_Transform (theTransforms); 506 } 507 508 int srcTransferType = src.getTransferType(); 509 int dstTransferType = dest.getTransferType(); 510 if ((srcTransferType == DataBuffer.TYPE_FLOAT) || 511 (srcTransferType == DataBuffer.TYPE_DOUBLE) || 512 (dstTransferType == DataBuffer.TYPE_FLOAT) || 513 (dstTransferType == DataBuffer.TYPE_DOUBLE)) { 514 if (srcMinVals == null) { 515 getMinMaxValsFromProfiles(profileList[0], 516 profileList[nProfiles-1]); 517 } 518 519 thisRasterTransform.colorConvert(src, dest, 520 srcMinVals, srcMaxVals, 521 dstMinVals, dstMaxVals); 522 } else { 523 524 thisRasterTransform.colorConvert(src, dest); 525 } 526 527 528 return dest; 529 } 530 531 539 public final Rectangle2D getBounds2D (BufferedImage src) { 540 return getBounds2D(src.getRaster()); 541 } 542 543 551 public final Rectangle2D getBounds2D (Raster src) { 552 555 return src.getBounds(); 556 } 557 558 571 public BufferedImage createCompatibleDestImage (BufferedImage src, 572 ColorModel destCM) { 573 ColorSpace cs = null;; 574 if (destCM == null) { 575 if (CSList == null) { 576 577 int nProfiles = profileList.length; 578 if (nProfiles == 0) { 579 throw new IllegalArgumentException ( 580 "Destination ColorSpace is undefined"); 581 } 582 ICC_Profile destProfile = profileList[nProfiles - 1]; 583 cs = new ICC_ColorSpace(destProfile); 584 } else { 585 586 int nSpaces = CSList.length; 587 cs = CSList[nSpaces - 1]; 588 } 589 } 590 return createCompatibleDestImage(src, destCM, cs); 591 } 592 593 private BufferedImage createCompatibleDestImage(BufferedImage src, 594 ColorModel destCM, 595 ColorSpace destCS) { 596 BufferedImage image; 597 if (destCM == null) { 598 ColorModel srcCM = src.getColorModel(); 599 int nbands = destCS.getNumComponents(); 600 boolean hasAlpha = srcCM.hasAlpha(); 601 if (hasAlpha) { 602 nbands += 1; 603 } 604 int[] nbits = new int[nbands]; 605 for (int i = 0; i < nbands; i++) { 606 nbits[i] = 8; 607 } 608 destCM = new ComponentColorModel (destCS, nbits, hasAlpha, 609 srcCM.isAlphaPremultiplied(), 610 srcCM.getTransparency(), 611 DataBuffer.TYPE_BYTE); 612 } 613 int w = src.getWidth(); 614 int h = src.getHeight(); 615 image = new BufferedImage (destCM, 616 destCM.createCompatibleWritableRaster(w, h), 617 destCM.isAlphaPremultiplied(), null); 618 return image; 619 } 620 621 622 632 public WritableRaster createCompatibleDestRaster (Raster src) { 633 int ncomponents; 634 635 if (CSList != null) { 636 637 if (CSList.length != 2) { 638 throw new IllegalArgumentException ( 639 "Destination ColorSpace is undefined"); 640 } 641 ncomponents = CSList[1].getNumComponents(); 642 } else { 643 644 int nProfiles = profileList.length; 645 if (nProfiles < 2) { 646 throw new IllegalArgumentException ( 647 "Destination ColorSpace is undefined"); 648 } 649 ncomponents = profileList[nProfiles-1].getNumComponents(); 650 } 651 652 WritableRaster dest = 653 Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, 654 src.getWidth(), 655 src.getHeight(), 656 ncomponents, 657 new Point (src.getMinX(), src.getMinY())); 658 return dest; 659 } 660 661 672 public final Point2D getPoint2D (Point2D srcPt, Point2D dstPt) { 673 if (dstPt == null) { 674 dstPt = new Point2D.Float (); 675 } 676 dstPt.setLocation(srcPt.getX(), srcPt.getY()); 677 678 return dstPt; 679 } 680 681 682 685 private int getRenderingIntent (ICC_Profile profile) { 686 byte[] header = profile.getData(ICC_Profile.icSigHead); 687 int index = ICC_Profile.icHdrRenderingIntent; 688 return (((header[index] & 0xff) << 24) | 689 ((header[index+1] & 0xff) << 16) | 690 ((header[index+2] & 0xff) << 8) | 691 (header[index+3] & 0xff)); 692 } 693 694 699 public final RenderingHints getRenderingHints() { 700 return hints; 701 } 702 703 private final BufferedImage nonICCBIFilter(BufferedImage src, 704 ColorSpace srcColorSpace, 705 BufferedImage dst, 706 ColorSpace dstColorSpace) { 707 708 int w = src.getWidth(); 709 int h = src.getHeight(); 710 ICC_ColorSpace ciespace = 711 (ICC_ColorSpace) ColorSpace.getInstance(ColorSpace.CS_CIEXYZ); 712 if (dst == null) { 713 dst = createCompatibleDestImage(src, null); 714 dstColorSpace = dst.getColorModel().getColorSpace(); 715 } else { 716 if ((h != dst.getHeight()) || (w != dst.getWidth())) { 717 throw new IllegalArgumentException ( 718 "Width or height of BufferedImages do not match"); 719 } 720 } 721 Raster srcRas = src.getRaster(); 722 WritableRaster dstRas = dst.getRaster(); 723 ColorModel srcCM = src.getColorModel(); 724 ColorModel dstCM = dst.getColorModel(); 725 int srcNumComp = srcCM.getNumColorComponents(); 726 int dstNumComp = dstCM.getNumColorComponents(); 727 boolean dstHasAlpha = dstCM.hasAlpha(); 728 boolean needSrcAlpha = srcCM.hasAlpha() && dstHasAlpha; 729 ColorSpace[] list; 730 if ((CSList == null) && (profileList.length != 0)) { 731 732 boolean nonICCSrc, nonICCDst; 733 ICC_Profile srcProfile, dstProfile; 734 if (!(srcColorSpace instanceof ICC_ColorSpace)) { 735 nonICCSrc = true; 736 srcProfile = ciespace.getProfile(); 737 } else { 738 nonICCSrc = false; 739 srcProfile = ((ICC_ColorSpace) srcColorSpace).getProfile(); 740 } 741 if (!(dstColorSpace instanceof ICC_ColorSpace)) { 742 nonICCDst = true; 743 dstProfile = ciespace.getProfile(); 744 } else { 745 nonICCDst = false; 746 dstProfile = ((ICC_ColorSpace) dstColorSpace).getProfile(); 747 } 748 749 if ((thisTransform == null) || (thisSrcProfile != srcProfile) || 750 (thisDestProfile != dstProfile) ) { 751 updateBITransform(srcProfile, dstProfile); 752 } 753 float maxNum = 65535.0f; ColorSpace cs; 756 int iccSrcNumComp; 757 if (nonICCSrc) { 758 cs = ciespace; 759 iccSrcNumComp = 3; 760 } else { 761 cs = srcColorSpace; 762 iccSrcNumComp = srcNumComp; 763 } 764 float[] srcMinVal = new float[iccSrcNumComp]; 765 float[] srcInvDiffMinMax = new float[iccSrcNumComp]; 766 for (int i = 0; i < srcNumComp; i++) { 767 srcMinVal[i] = cs.getMinValue(i); 768 srcInvDiffMinMax[i] = maxNum / (cs.getMaxValue(i) - srcMinVal[i]); 769 } 770 int iccDstNumComp; 771 if (nonICCDst) { 772 cs = ciespace; 773 &
|