< prev index next >

src/java.desktop/share/classes/java/awt/image/ColorConvertOp.java

Print this page




  75     ICC_Profile      thisSrcProfile, thisDestProfile;
  76     RenderingHints   hints;
  77     boolean          gotProfiles;
  78     float[]          srcMinVals, srcMaxVals, dstMinVals, dstMaxVals;
  79 
  80     /* the class initializer */
  81     static {
  82         if (ProfileDeferralMgr.deferring) {
  83             ProfileDeferralMgr.activateProfiles();
  84         }
  85     }
  86 
  87     /**
  88      * Constructs a new ColorConvertOp which will convert
  89      * from a source color space to a destination color space.
  90      * The RenderingHints argument may be null.
  91      * This Op can be used only with BufferedImages, and will convert
  92      * directly from the ColorSpace of the source image to that of the
  93      * destination.  The destination argument of the filter method
  94      * cannot be specified as null.
  95      * @param hints the <code>RenderingHints</code> object used to control
  96      *        the color conversion, or <code>null</code>
  97      */
  98     public ColorConvertOp (RenderingHints hints)
  99     {
 100         profileList = new ICC_Profile [0];    /* 0 length list */
 101         this.hints  = hints;
 102     }
 103 
 104     /**
 105      * Constructs a new ColorConvertOp from a ColorSpace object.
 106      * The RenderingHints argument may be null.  This
 107      * Op can be used only with BufferedImages, and is primarily useful
 108      * when the {@link #filter(BufferedImage, BufferedImage) filter}
 109      * method is invoked with a destination argument of null.
 110      * In that case, the ColorSpace defines the destination color space
 111      * for the destination created by the filter method.  Otherwise, the
 112      * ColorSpace defines an intermediate space to which the source is
 113      * converted before being converted to the destination space.
 114      * @param cspace defines the destination <code>ColorSpace</code> or an
 115      *        intermediate <code>ColorSpace</code>
 116      * @param hints the <code>RenderingHints</code> object used to control
 117      *        the color conversion, or <code>null</code>
 118      * @throws NullPointerException if cspace is null
 119      */
 120     public ColorConvertOp (ColorSpace cspace, RenderingHints hints)
 121     {
 122         if (cspace == null) {
 123             throw new NullPointerException("ColorSpace cannot be null");
 124         }
 125         if (cspace instanceof ICC_ColorSpace) {
 126             profileList = new ICC_Profile [1];    /* 1 profile in the list */
 127 
 128             profileList [0] = ((ICC_ColorSpace) cspace).getProfile();
 129         }
 130         else {
 131             CSList = new ColorSpace[1]; /* non-ICC case: 1 ColorSpace in list */
 132             CSList[0] = cspace;
 133         }
 134         this.hints  = hints;
 135     }
 136 
 137 
 138     /**
 139      * Constructs a new ColorConvertOp from two ColorSpace objects.
 140      * The RenderingHints argument may be null.
 141      * This Op is primarily useful for calling the filter method on
 142      * Rasters, in which case the two ColorSpaces define the operation
 143      * to be performed on the Rasters.  In that case, the number of bands
 144      * in the source Raster must match the number of components in
 145      * srcCspace, and the number of bands in the destination Raster
 146      * must match the number of components in dstCspace.  For BufferedImages,
 147      * the two ColorSpaces define intermediate spaces through which the
 148      * source is converted before being converted to the destination space.
 149      * @param srcCspace the source <code>ColorSpace</code>
 150      * @param dstCspace the destination <code>ColorSpace</code>
 151      * @param hints the <code>RenderingHints</code> object used to control
 152      *        the color conversion, or <code>null</code>
 153      * @throws NullPointerException if either srcCspace or dstCspace is null
 154      */
 155     public ColorConvertOp(ColorSpace srcCspace, ColorSpace dstCspace,
 156                            RenderingHints hints)
 157     {
 158         if ((srcCspace == null) || (dstCspace == null)) {
 159             throw new NullPointerException("ColorSpaces cannot be null");
 160         }
 161         if ((srcCspace instanceof ICC_ColorSpace) &&
 162             (dstCspace instanceof ICC_ColorSpace)) {
 163             profileList = new ICC_Profile [2];    /* 2 profiles in the list */
 164 
 165             profileList [0] = ((ICC_ColorSpace) srcCspace).getProfile();
 166             profileList [1] = ((ICC_ColorSpace) dstCspace).getProfile();
 167 
 168             getMinMaxValsFromColorSpaces(srcCspace, dstCspace);
 169         } else {
 170             /* non-ICC case: 2 ColorSpaces in list */
 171             CSList = new ColorSpace[2];
 172             CSList[0] = srcCspace;


 179      /**
 180      * Constructs a new ColorConvertOp from an array of ICC_Profiles.
 181      * The RenderingHints argument may be null.
 182      * The sequence of profiles may include profiles that represent color
 183      * spaces, profiles that represent effects, etc.  If the whole sequence
 184      * does not represent a well-defined color conversion, an exception is
 185      * thrown.
 186      * <p>For BufferedImages, if the ColorSpace
 187      * of the source BufferedImage does not match the requirements of the
 188      * first profile in the array,
 189      * the first conversion is to an appropriate ColorSpace.
 190      * If the requirements of the last profile in the array are not met
 191      * by the ColorSpace of the destination BufferedImage,
 192      * the last conversion is to the destination's ColorSpace.
 193      * <p>For Rasters, the number of bands in the source Raster must match
 194      * the requirements of the first profile in the array, and the
 195      * number of bands in the destination Raster must match the requirements
 196      * of the last profile in the array.  The array must have at least two
 197      * elements or calling the filter method for Rasters will throw an
 198      * IllegalArgumentException.
 199      * @param profiles the array of <code>ICC_Profile</code> objects
 200      * @param hints the <code>RenderingHints</code> object used to control
 201      *        the color conversion, or <code>null</code>
 202      * @exception IllegalArgumentException when the profile sequence does not
 203      *             specify a well-defined color conversion
 204      * @exception NullPointerException if profiles is null
 205      */
 206     public ColorConvertOp (ICC_Profile[] profiles, RenderingHints hints)
 207     {
 208         if (profiles == null) {
 209             throw new NullPointerException("Profiles cannot be null");
 210         }
 211         gotProfiles = true;
 212         profileList = new ICC_Profile[profiles.length];
 213         for (int i1 = 0; i1 < profiles.length; i1++) {
 214             profileList[i1] = profiles[i1];
 215         }
 216         this.hints  = hints;
 217     }
 218 
 219 
 220     /**
 221      * Returns the array of ICC_Profiles used to construct this ColorConvertOp.
 222      * Returns null if the ColorConvertOp was not constructed from such an
 223      * array.
 224      * @return the array of <code>ICC_Profile</code> objects of this
 225      *         <code>ColorConvertOp</code>, or <code>null</code> if this
 226      *         <code>ColorConvertOp</code> was not constructed with an
 227      *         array of <code>ICC_Profile</code> objects.
 228      */
 229     public final ICC_Profile[] getICC_Profiles() {
 230         if (gotProfiles) {
 231             ICC_Profile[] profiles = new ICC_Profile[profileList.length];
 232             for (int i1 = 0; i1 < profileList.length; i1++) {
 233                 profiles[i1] = profileList[i1];
 234             }
 235             return profiles;
 236         }
 237         return null;
 238     }
 239 
 240     /**
 241      * ColorConverts the source BufferedImage.
 242      * If the destination image is null,
 243      * a BufferedImage will be created with an appropriate ColorModel.
 244      * @param src the source <code>BufferedImage</code> to be converted
 245      * @param dest the destination <code>BufferedImage</code>,
 246      *        or <code>null</code>
 247      * @return <code>dest</code> color converted from <code>src</code>
 248      *         or a new, converted <code>BufferedImage</code>
 249      *         if <code>dest</code> is <code>null</code>
 250      * @exception IllegalArgumentException if dest is null and this op was
 251      *             constructed using the constructor which takes only a
 252      *             RenderingHints argument, since the operation is ill defined.
 253      */
 254     public final BufferedImage filter(BufferedImage src, BufferedImage dest) {
 255         ColorSpace srcColorSpace, destColorSpace;
 256         BufferedImage savdest = null;
 257 
 258         if (src.getColorModel() instanceof IndexColorModel) {
 259             IndexColorModel icm = (IndexColorModel) src.getColorModel();
 260             src = icm.convertToIntDiscrete(src.getRaster(), true);
 261         }
 262         srcColorSpace = src.getColorModel().getColorSpace();
 263         if (dest != null) {
 264             if (dest.getColorModel() instanceof IndexColorModel) {
 265                 savdest = dest;
 266                 dest = null;
 267                 destColorSpace = null;
 268             } else {
 269                 destColorSpace = dest.getColorModel().getColorSpace();


 438             /* "middle" profiles use simulation transform */
 439             whichTrans = ColorTransform.Simulation;
 440         }
 441 
 442         /* make the net transform */
 443         thisTransform = mdl.createTransform(theTransforms);
 444 
 445         /* update corresponding source and dest profiles */
 446         thisSrcProfile = srcProfile;
 447         thisDestProfile = destProfile;
 448     }
 449 
 450     /**
 451      * ColorConverts the image data in the source Raster.
 452      * If the destination Raster is null, a new Raster will be created.
 453      * The number of bands in the source and destination Rasters must
 454      * meet the requirements explained above.  The constructor used to
 455      * create this ColorConvertOp must have provided enough information
 456      * to define both source and destination color spaces.  See above.
 457      * Otherwise, an exception is thrown.
 458      * @param src the source <code>Raster</code> to be converted
 459      * @param dest the destination <code>WritableRaster</code>,
 460      *        or <code>null</code>
 461      * @return <code>dest</code> color converted from <code>src</code>
 462      *         or a new, converted <code>WritableRaster</code>
 463      *         if <code>dest</code> is <code>null</code>
 464      * @exception IllegalArgumentException if the number of source or
 465      *             destination bands is incorrect, the source or destination
 466      *             color spaces are undefined, or this op was constructed
 467      *             with one of the constructors that applies only to
 468      *             operations on BufferedImages.
 469      */
 470     public final WritableRaster filter (Raster src, WritableRaster dest)  {
 471 
 472         if (CSList != null) {
 473             /* non-ICC case */
 474             return nonICCRasterFilter(src, dest);
 475         }
 476         int nProfiles = profileList.length;
 477         if (nProfiles < 2) {
 478             throw new IllegalArgumentException(
 479                 "Source or Destination ColorSpace is undefined");
 480         }
 481         if (src.getNumBands() != profileList[0].getNumComponents()) {
 482             throw new IllegalArgumentException(
 483                 "Numbers of source Raster bands and source color space " +


 562                 getMinMaxValsFromProfiles(profileList[0],
 563                                           profileList[nProfiles-1]);
 564             }
 565             /* color convert the raster */
 566             thisRasterTransform.colorConvert(src, dest,
 567                                              srcMinVals, srcMaxVals,
 568                                              dstMinVals, dstMaxVals);
 569         } else {
 570             /* color convert the raster */
 571             thisRasterTransform.colorConvert(src, dest);
 572         }
 573 
 574 
 575         return dest;
 576     }
 577 
 578     /**
 579      * Returns the bounding box of the destination, given this source.
 580      * Note that this will be the same as the bounding box of the
 581      * source.
 582      * @param src the source <code>BufferedImage</code>
 583      * @return a <code>Rectangle2D</code> that is the bounding box
 584      *         of the destination, given the specified <code>src</code>
 585      */
 586     public final Rectangle2D getBounds2D (BufferedImage src) {
 587         return getBounds2D(src.getRaster());
 588     }
 589 
 590     /**
 591      * Returns the bounding box of the destination, given this source.
 592      * Note that this will be the same as the bounding box of the
 593      * source.
 594      * @param src the source <code>Raster</code>
 595      * @return a <code>Rectangle2D</code> that is the bounding box
 596      *         of the destination, given the specified <code>src</code>
 597      */
 598     public final Rectangle2D getBounds2D (Raster src) {
 599         /*        return new Rectangle (src.getXOffset(),
 600                               src.getYOffset(),
 601                               src.getWidth(), src.getHeight()); */
 602         return src.getBounds();
 603     }
 604 
 605     /**
 606      * Creates a zeroed destination image with the correct size and number of
 607      * bands, given this source.
 608      * @param src       Source image for the filter operation.
 609      * @param destCM    ColorModel of the destination.  If null, an
 610      *                  appropriate ColorModel will be used.
 611      * @return a <code>BufferedImage</code> with the correct size and
 612      * number of bands from the specified <code>src</code>.
 613      * @throws IllegalArgumentException if <code>destCM</code> is
 614      *         <code>null</code> and this <code>ColorConvertOp</code> was
 615      *         created without any <code>ICC_Profile</code> or
 616      *         <code>ColorSpace</code> defined for the destination
 617      */
 618     public BufferedImage createCompatibleDestImage (BufferedImage src,
 619                                                     ColorModel destCM) {
 620         ColorSpace cs = null;;
 621         if (destCM == null) {
 622             if (CSList == null) {
 623                 /* ICC case */
 624                 int nProfiles = profileList.length;
 625                 if (nProfiles == 0) {
 626                     throw new IllegalArgumentException(
 627                         "Destination ColorSpace is undefined");
 628                 }
 629                 ICC_Profile destProfile = profileList[nProfiles - 1];
 630                 cs = new ICC_ColorSpace(destProfile);
 631             } else {
 632                 /* non-ICC case */
 633                 int nSpaces = CSList.length;
 634                 cs = CSList[nSpaces - 1];
 635             }
 636         }


 652             for (int i = 0; i < nbands; i++) {
 653                 nbits[i] = 8;
 654             }
 655             destCM = new ComponentColorModel(destCS, nbits, hasAlpha,
 656                                              srcCM.isAlphaPremultiplied(),
 657                                              srcCM.getTransparency(),
 658                                              DataBuffer.TYPE_BYTE);
 659         }
 660         int w = src.getWidth();
 661         int h = src.getHeight();
 662         image = new BufferedImage(destCM,
 663                                   destCM.createCompatibleWritableRaster(w, h),
 664                                   destCM.isAlphaPremultiplied(), null);
 665         return image;
 666     }
 667 
 668 
 669     /**
 670      * Creates a zeroed destination Raster with the correct size and number of
 671      * bands, given this source.
 672      * @param src the specified <code>Raster</code>
 673      * @return a <code>WritableRaster</code> with the correct size and number
 674      *         of bands from the specified <code>src</code>
 675      * @throws IllegalArgumentException if this <code>ColorConvertOp</code>
 676      *         was created without sufficient information to define the
 677      *         <code>dst</code> and <code>src</code> color spaces
 678      */
 679     public WritableRaster createCompatibleDestRaster (Raster src) {
 680         int ncomponents;
 681 
 682         if (CSList != null) {
 683             /* non-ICC case */
 684             if (CSList.length != 2) {
 685                 throw new IllegalArgumentException(
 686                     "Destination ColorSpace is undefined");
 687             }
 688             ncomponents = CSList[1].getNumComponents();
 689         } else {
 690             /* ICC case */
 691             int nProfiles = profileList.length;
 692             if (nProfiles < 2) {
 693                 throw new IllegalArgumentException(
 694                     "Destination ColorSpace is undefined");
 695             }
 696             ncomponents = profileList[nProfiles-1].getNumComponents();
 697         }
 698 
 699         WritableRaster dest =
 700             Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
 701                                   src.getWidth(),
 702                                   src.getHeight(),
 703                                   ncomponents,
 704                                   new Point(src.getMinX(), src.getMinY()));
 705         return dest;
 706     }
 707 
 708     /**
 709      * Returns the location of the destination point given a
 710      * point in the source.  If <code>dstPt</code> is non-null,
 711      * it will be used to hold the return value.  Note that
 712      * for this class, the destination point will be the same
 713      * as the source point.
 714      * @param srcPt the specified source <code>Point2D</code>
 715      * @param dstPt the destination <code>Point2D</code>
 716      * @return <code>dstPt</code> after setting its location to be
 717      *         the same as <code>srcPt</code>
 718      */
 719     public final Point2D getPoint2D (Point2D srcPt, Point2D dstPt) {
 720         if (dstPt == null) {
 721             dstPt = new Point2D.Float();
 722         }
 723         dstPt.setLocation(srcPt.getX(), srcPt.getY());
 724 
 725         return dstPt;
 726     }
 727 
 728 
 729     /**
 730      * Returns the RenderingIntent from the specified ICC Profile.
 731      */
 732     private int getRenderingIntent (ICC_Profile profile) {
 733         byte[] header = profile.getData(ICC_Profile.icSigHead);
 734         int index = ICC_Profile.icHdrRenderingIntent;
 735 
 736         /* According to ICC spec, only the least-significant 16 bits shall be
 737          * used to encode the rendering intent. The most significant 16 bits
 738          * shall be set to zero. Thus, we are ignoring two most significant
 739          * bytes here.
 740          *
 741          *  See http://www.color.org/ICC1v42_2006-05.pdf, section 7.2.15.
 742          */
 743         return ((header[index+2] & 0xff) <<  8) |
 744                 (header[index+3] & 0xff);
 745     }
 746 
 747     /**
 748      * Returns the rendering hints used by this op.
 749      * @return the <code>RenderingHints</code> object of this
 750      *         <code>ColorConvertOp</code>
 751      */
 752     public final RenderingHints getRenderingHints() {
 753         return hints;
 754     }
 755 
 756     private final BufferedImage nonICCBIFilter(BufferedImage src,
 757                                                ColorSpace srcColorSpace,
 758                                                BufferedImage dst,
 759                                                ColorSpace dstColorSpace) {
 760 
 761         int w = src.getWidth();
 762         int h = src.getHeight();
 763         ICC_ColorSpace ciespace =
 764             (ICC_ColorSpace) ColorSpace.getInstance(ColorSpace.CS_CIEXYZ);
 765         if (dst == null) {
 766             dst = createCompatibleDestImage(src, null);
 767             dstColorSpace = dst.getColorModel().getColorSpace();
 768         } else {
 769             if ((h != dst.getHeight()) || (w != dst.getWidth())) {
 770                 throw new IllegalArgumentException(




  75     ICC_Profile      thisSrcProfile, thisDestProfile;
  76     RenderingHints   hints;
  77     boolean          gotProfiles;
  78     float[]          srcMinVals, srcMaxVals, dstMinVals, dstMaxVals;
  79 
  80     /* the class initializer */
  81     static {
  82         if (ProfileDeferralMgr.deferring) {
  83             ProfileDeferralMgr.activateProfiles();
  84         }
  85     }
  86 
  87     /**
  88      * Constructs a new ColorConvertOp which will convert
  89      * from a source color space to a destination color space.
  90      * The RenderingHints argument may be null.
  91      * This Op can be used only with BufferedImages, and will convert
  92      * directly from the ColorSpace of the source image to that of the
  93      * destination.  The destination argument of the filter method
  94      * cannot be specified as null.
  95      * @param hints the {@code RenderingHints} object used to control
  96      *        the color conversion, or {@code null}
  97      */
  98     public ColorConvertOp (RenderingHints hints)
  99     {
 100         profileList = new ICC_Profile [0];    /* 0 length list */
 101         this.hints  = hints;
 102     }
 103 
 104     /**
 105      * Constructs a new ColorConvertOp from a ColorSpace object.
 106      * The RenderingHints argument may be null.  This
 107      * Op can be used only with BufferedImages, and is primarily useful
 108      * when the {@link #filter(BufferedImage, BufferedImage) filter}
 109      * method is invoked with a destination argument of null.
 110      * In that case, the ColorSpace defines the destination color space
 111      * for the destination created by the filter method.  Otherwise, the
 112      * ColorSpace defines an intermediate space to which the source is
 113      * converted before being converted to the destination space.
 114      * @param cspace defines the destination {@code ColorSpace} or an
 115      *        intermediate {@code ColorSpace}
 116      * @param hints the {@code RenderingHints} object used to control
 117      *        the color conversion, or {@code null}
 118      * @throws NullPointerException if cspace is null
 119      */
 120     public ColorConvertOp (ColorSpace cspace, RenderingHints hints)
 121     {
 122         if (cspace == null) {
 123             throw new NullPointerException("ColorSpace cannot be null");
 124         }
 125         if (cspace instanceof ICC_ColorSpace) {
 126             profileList = new ICC_Profile [1];    /* 1 profile in the list */
 127 
 128             profileList [0] = ((ICC_ColorSpace) cspace).getProfile();
 129         }
 130         else {
 131             CSList = new ColorSpace[1]; /* non-ICC case: 1 ColorSpace in list */
 132             CSList[0] = cspace;
 133         }
 134         this.hints  = hints;
 135     }
 136 
 137 
 138     /**
 139      * Constructs a new ColorConvertOp from two ColorSpace objects.
 140      * The RenderingHints argument may be null.
 141      * This Op is primarily useful for calling the filter method on
 142      * Rasters, in which case the two ColorSpaces define the operation
 143      * to be performed on the Rasters.  In that case, the number of bands
 144      * in the source Raster must match the number of components in
 145      * srcCspace, and the number of bands in the destination Raster
 146      * must match the number of components in dstCspace.  For BufferedImages,
 147      * the two ColorSpaces define intermediate spaces through which the
 148      * source is converted before being converted to the destination space.
 149      * @param srcCspace the source {@code ColorSpace}
 150      * @param dstCspace the destination {@code ColorSpace}
 151      * @param hints the {@code RenderingHints} object used to control
 152      *        the color conversion, or {@code null}
 153      * @throws NullPointerException if either srcCspace or dstCspace is null
 154      */
 155     public ColorConvertOp(ColorSpace srcCspace, ColorSpace dstCspace,
 156                            RenderingHints hints)
 157     {
 158         if ((srcCspace == null) || (dstCspace == null)) {
 159             throw new NullPointerException("ColorSpaces cannot be null");
 160         }
 161         if ((srcCspace instanceof ICC_ColorSpace) &&
 162             (dstCspace instanceof ICC_ColorSpace)) {
 163             profileList = new ICC_Profile [2];    /* 2 profiles in the list */
 164 
 165             profileList [0] = ((ICC_ColorSpace) srcCspace).getProfile();
 166             profileList [1] = ((ICC_ColorSpace) dstCspace).getProfile();
 167 
 168             getMinMaxValsFromColorSpaces(srcCspace, dstCspace);
 169         } else {
 170             /* non-ICC case: 2 ColorSpaces in list */
 171             CSList = new ColorSpace[2];
 172             CSList[0] = srcCspace;


 179      /**
 180      * Constructs a new ColorConvertOp from an array of ICC_Profiles.
 181      * The RenderingHints argument may be null.
 182      * The sequence of profiles may include profiles that represent color
 183      * spaces, profiles that represent effects, etc.  If the whole sequence
 184      * does not represent a well-defined color conversion, an exception is
 185      * thrown.
 186      * <p>For BufferedImages, if the ColorSpace
 187      * of the source BufferedImage does not match the requirements of the
 188      * first profile in the array,
 189      * the first conversion is to an appropriate ColorSpace.
 190      * If the requirements of the last profile in the array are not met
 191      * by the ColorSpace of the destination BufferedImage,
 192      * the last conversion is to the destination's ColorSpace.
 193      * <p>For Rasters, the number of bands in the source Raster must match
 194      * the requirements of the first profile in the array, and the
 195      * number of bands in the destination Raster must match the requirements
 196      * of the last profile in the array.  The array must have at least two
 197      * elements or calling the filter method for Rasters will throw an
 198      * IllegalArgumentException.
 199      * @param profiles the array of {@code ICC_Profile} objects
 200      * @param hints the {@code RenderingHints} object used to control
 201      *        the color conversion, or {@code null}
 202      * @exception IllegalArgumentException when the profile sequence does not
 203      *             specify a well-defined color conversion
 204      * @exception NullPointerException if profiles is null
 205      */
 206     public ColorConvertOp (ICC_Profile[] profiles, RenderingHints hints)
 207     {
 208         if (profiles == null) {
 209             throw new NullPointerException("Profiles cannot be null");
 210         }
 211         gotProfiles = true;
 212         profileList = new ICC_Profile[profiles.length];
 213         for (int i1 = 0; i1 < profiles.length; i1++) {
 214             profileList[i1] = profiles[i1];
 215         }
 216         this.hints  = hints;
 217     }
 218 
 219 
 220     /**
 221      * Returns the array of ICC_Profiles used to construct this ColorConvertOp.
 222      * Returns null if the ColorConvertOp was not constructed from such an
 223      * array.
 224      * @return the array of {@code ICC_Profile} objects of this
 225      *         {@code ColorConvertOp}, or {@code null} if this
 226      *         {@code ColorConvertOp} was not constructed with an
 227      *         array of {@code ICC_Profile} objects.
 228      */
 229     public final ICC_Profile[] getICC_Profiles() {
 230         if (gotProfiles) {
 231             ICC_Profile[] profiles = new ICC_Profile[profileList.length];
 232             for (int i1 = 0; i1 < profileList.length; i1++) {
 233                 profiles[i1] = profileList[i1];
 234             }
 235             return profiles;
 236         }
 237         return null;
 238     }
 239 
 240     /**
 241      * ColorConverts the source BufferedImage.
 242      * If the destination image is null,
 243      * a BufferedImage will be created with an appropriate ColorModel.
 244      * @param src the source {@code BufferedImage} to be converted
 245      * @param dest the destination {@code BufferedImage},
 246      *        or {@code null}
 247      * @return {@code dest} color converted from {@code src}
 248      *         or a new, converted {@code BufferedImage}
 249      *         if {@code dest} is {@code null}
 250      * @exception IllegalArgumentException if dest is null and this op was
 251      *             constructed using the constructor which takes only a
 252      *             RenderingHints argument, since the operation is ill defined.
 253      */
 254     public final BufferedImage filter(BufferedImage src, BufferedImage dest) {
 255         ColorSpace srcColorSpace, destColorSpace;
 256         BufferedImage savdest = null;
 257 
 258         if (src.getColorModel() instanceof IndexColorModel) {
 259             IndexColorModel icm = (IndexColorModel) src.getColorModel();
 260             src = icm.convertToIntDiscrete(src.getRaster(), true);
 261         }
 262         srcColorSpace = src.getColorModel().getColorSpace();
 263         if (dest != null) {
 264             if (dest.getColorModel() instanceof IndexColorModel) {
 265                 savdest = dest;
 266                 dest = null;
 267                 destColorSpace = null;
 268             } else {
 269                 destColorSpace = dest.getColorModel().getColorSpace();


 438             /* "middle" profiles use simulation transform */
 439             whichTrans = ColorTransform.Simulation;
 440         }
 441 
 442         /* make the net transform */
 443         thisTransform = mdl.createTransform(theTransforms);
 444 
 445         /* update corresponding source and dest profiles */
 446         thisSrcProfile = srcProfile;
 447         thisDestProfile = destProfile;
 448     }
 449 
 450     /**
 451      * ColorConverts the image data in the source Raster.
 452      * If the destination Raster is null, a new Raster will be created.
 453      * The number of bands in the source and destination Rasters must
 454      * meet the requirements explained above.  The constructor used to
 455      * create this ColorConvertOp must have provided enough information
 456      * to define both source and destination color spaces.  See above.
 457      * Otherwise, an exception is thrown.
 458      * @param src the source {@code Raster} to be converted
 459      * @param dest the destination {@code WritableRaster},
 460      *        or {@code null}
 461      * @return {@code dest} color converted from {@code src}
 462      *         or a new, converted {@code WritableRaster}
 463      *         if {@code dest} is {@code null}
 464      * @exception IllegalArgumentException if the number of source or
 465      *             destination bands is incorrect, the source or destination
 466      *             color spaces are undefined, or this op was constructed
 467      *             with one of the constructors that applies only to
 468      *             operations on BufferedImages.
 469      */
 470     public final WritableRaster filter (Raster src, WritableRaster dest)  {
 471 
 472         if (CSList != null) {
 473             /* non-ICC case */
 474             return nonICCRasterFilter(src, dest);
 475         }
 476         int nProfiles = profileList.length;
 477         if (nProfiles < 2) {
 478             throw new IllegalArgumentException(
 479                 "Source or Destination ColorSpace is undefined");
 480         }
 481         if (src.getNumBands() != profileList[0].getNumComponents()) {
 482             throw new IllegalArgumentException(
 483                 "Numbers of source Raster bands and source color space " +


 562                 getMinMaxValsFromProfiles(profileList[0],
 563                                           profileList[nProfiles-1]);
 564             }
 565             /* color convert the raster */
 566             thisRasterTransform.colorConvert(src, dest,
 567                                              srcMinVals, srcMaxVals,
 568                                              dstMinVals, dstMaxVals);
 569         } else {
 570             /* color convert the raster */
 571             thisRasterTransform.colorConvert(src, dest);
 572         }
 573 
 574 
 575         return dest;
 576     }
 577 
 578     /**
 579      * Returns the bounding box of the destination, given this source.
 580      * Note that this will be the same as the bounding box of the
 581      * source.
 582      * @param src the source {@code BufferedImage}
 583      * @return a {@code Rectangle2D} that is the bounding box
 584      *         of the destination, given the specified {@code src}
 585      */
 586     public final Rectangle2D getBounds2D (BufferedImage src) {
 587         return getBounds2D(src.getRaster());
 588     }
 589 
 590     /**
 591      * Returns the bounding box of the destination, given this source.
 592      * Note that this will be the same as the bounding box of the
 593      * source.
 594      * @param src the source {@code Raster}
 595      * @return a {@code Rectangle2D} that is the bounding box
 596      *         of the destination, given the specified {@code src}
 597      */
 598     public final Rectangle2D getBounds2D (Raster src) {
 599         /*        return new Rectangle (src.getXOffset(),
 600                               src.getYOffset(),
 601                               src.getWidth(), src.getHeight()); */
 602         return src.getBounds();
 603     }
 604 
 605     /**
 606      * Creates a zeroed destination image with the correct size and number of
 607      * bands, given this source.
 608      * @param src       Source image for the filter operation.
 609      * @param destCM    ColorModel of the destination.  If null, an
 610      *                  appropriate ColorModel will be used.
 611      * @return a {@code BufferedImage} with the correct size and
 612      * number of bands from the specified {@code src}.
 613      * @throws IllegalArgumentException if {@code destCM} is
 614      *         {@code null} and this {@code ColorConvertOp} was
 615      *         created without any {@code ICC_Profile} or
 616      *         {@code ColorSpace} defined for the destination
 617      */
 618     public BufferedImage createCompatibleDestImage (BufferedImage src,
 619                                                     ColorModel destCM) {
 620         ColorSpace cs = null;;
 621         if (destCM == null) {
 622             if (CSList == null) {
 623                 /* ICC case */
 624                 int nProfiles = profileList.length;
 625                 if (nProfiles == 0) {
 626                     throw new IllegalArgumentException(
 627                         "Destination ColorSpace is undefined");
 628                 }
 629                 ICC_Profile destProfile = profileList[nProfiles - 1];
 630                 cs = new ICC_ColorSpace(destProfile);
 631             } else {
 632                 /* non-ICC case */
 633                 int nSpaces = CSList.length;
 634                 cs = CSList[nSpaces - 1];
 635             }
 636         }


 652             for (int i = 0; i < nbands; i++) {
 653                 nbits[i] = 8;
 654             }
 655             destCM = new ComponentColorModel(destCS, nbits, hasAlpha,
 656                                              srcCM.isAlphaPremultiplied(),
 657                                              srcCM.getTransparency(),
 658                                              DataBuffer.TYPE_BYTE);
 659         }
 660         int w = src.getWidth();
 661         int h = src.getHeight();
 662         image = new BufferedImage(destCM,
 663                                   destCM.createCompatibleWritableRaster(w, h),
 664                                   destCM.isAlphaPremultiplied(), null);
 665         return image;
 666     }
 667 
 668 
 669     /**
 670      * Creates a zeroed destination Raster with the correct size and number of
 671      * bands, given this source.
 672      * @param src the specified {@code Raster}
 673      * @return a {@code WritableRaster} with the correct size and number
 674      *         of bands from the specified {@code src}
 675      * @throws IllegalArgumentException if this {@code ColorConvertOp}
 676      *         was created without sufficient information to define the
 677      *         {@code dst} and {@code src} color spaces
 678      */
 679     public WritableRaster createCompatibleDestRaster (Raster src) {
 680         int ncomponents;
 681 
 682         if (CSList != null) {
 683             /* non-ICC case */
 684             if (CSList.length != 2) {
 685                 throw new IllegalArgumentException(
 686                     "Destination ColorSpace is undefined");
 687             }
 688             ncomponents = CSList[1].getNumComponents();
 689         } else {
 690             /* ICC case */
 691             int nProfiles = profileList.length;
 692             if (nProfiles < 2) {
 693                 throw new IllegalArgumentException(
 694                     "Destination ColorSpace is undefined");
 695             }
 696             ncomponents = profileList[nProfiles-1].getNumComponents();
 697         }
 698 
 699         WritableRaster dest =
 700             Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
 701                                   src.getWidth(),
 702                                   src.getHeight(),
 703                                   ncomponents,
 704                                   new Point(src.getMinX(), src.getMinY()));
 705         return dest;
 706     }
 707 
 708     /**
 709      * Returns the location of the destination point given a
 710      * point in the source.  If {@code dstPt} is non-null,
 711      * it will be used to hold the return value.  Note that
 712      * for this class, the destination point will be the same
 713      * as the source point.
 714      * @param srcPt the specified source {@code Point2D}
 715      * @param dstPt the destination {@code Point2D}
 716      * @return {@code dstPt} after setting its location to be
 717      *         the same as {@code srcPt}
 718      */
 719     public final Point2D getPoint2D (Point2D srcPt, Point2D dstPt) {
 720         if (dstPt == null) {
 721             dstPt = new Point2D.Float();
 722         }
 723         dstPt.setLocation(srcPt.getX(), srcPt.getY());
 724 
 725         return dstPt;
 726     }
 727 
 728 
 729     /**
 730      * Returns the RenderingIntent from the specified ICC Profile.
 731      */
 732     private int getRenderingIntent (ICC_Profile profile) {
 733         byte[] header = profile.getData(ICC_Profile.icSigHead);
 734         int index = ICC_Profile.icHdrRenderingIntent;
 735 
 736         /* According to ICC spec, only the least-significant 16 bits shall be
 737          * used to encode the rendering intent. The most significant 16 bits
 738          * shall be set to zero. Thus, we are ignoring two most significant
 739          * bytes here.
 740          *
 741          *  See http://www.color.org/ICC1v42_2006-05.pdf, section 7.2.15.
 742          */
 743         return ((header[index+2] & 0xff) <<  8) |
 744                 (header[index+3] & 0xff);
 745     }
 746 
 747     /**
 748      * Returns the rendering hints used by this op.
 749      * @return the {@code RenderingHints} object of this
 750      *         {@code ColorConvertOp}
 751      */
 752     public final RenderingHints getRenderingHints() {
 753         return hints;
 754     }
 755 
 756     private final BufferedImage nonICCBIFilter(BufferedImage src,
 757                                                ColorSpace srcColorSpace,
 758                                                BufferedImage dst,
 759                                                ColorSpace dstColorSpace) {
 760 
 761         int w = src.getWidth();
 762         int h = src.getHeight();
 763         ICC_ColorSpace ciespace =
 764             (ICC_ColorSpace) ColorSpace.getInstance(ColorSpace.CS_CIEXYZ);
 765         if (dst == null) {
 766             dst = createCompatibleDestImage(src, null);
 767             dstColorSpace = dst.getColorModel().getColorSpace();
 768         } else {
 769             if ((h != dst.getHeight()) || (w != dst.getWidth())) {
 770                 throw new IllegalArgumentException(


< prev index next >