< prev index next >

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

Print this page




  80  * @see java.awt.RenderingHints#KEY_COLOR_RENDERING
  81  * @see java.awt.RenderingHints#KEY_DITHERING
  82  */
  83 public class RescaleOp implements BufferedImageOp, RasterOp {
  84     float[] scaleFactors;
  85     float[] offsets;
  86     int length = 0;
  87     RenderingHints hints;
  88 
  89     private int srcNbits;
  90     private int dstNbits;
  91 
  92 
  93     /**
  94      * Constructs a new RescaleOp with the desired scale factors
  95      * and offsets.  The length of the scaleFactor and offset arrays
  96      * must meet the restrictions stated in the class comments above.
  97      * The RenderingHints argument may be null.
  98      * @param scaleFactors the specified scale factors
  99      * @param offsets the specified offsets
 100      * @param hints the specified <code>RenderingHints</code>, or
 101      *        <code>null</code>
 102      */
 103     public RescaleOp (float[] scaleFactors, float[] offsets,
 104                       RenderingHints hints) {
 105         length = scaleFactors.length;
 106         if (length > offsets.length) length = offsets.length;
 107 
 108         this.scaleFactors = new float[length];
 109         this.offsets      = new float[length];
 110         for (int i=0; i < length; i++) {
 111             this.scaleFactors[i] = scaleFactors[i];
 112             this.offsets[i]      = offsets[i];
 113         }
 114         this.hints = hints;
 115     }
 116 
 117     /**
 118      * Constructs a new RescaleOp with the desired scale factor
 119      * and offset.  The scaleFactor and offset will be applied to
 120      * all bands in a source Raster and to all color (but not alpha)
 121      * components in a BufferedImage.
 122      * The RenderingHints argument may be null.
 123      * @param scaleFactor the specified scale factor
 124      * @param offset the specified offset
 125      * @param hints the specified <code>RenderingHints</code>, or
 126      *        <code>null</code>
 127      */
 128     public RescaleOp (float scaleFactor, float offset, RenderingHints hints) {
 129         length = 1;
 130         this.scaleFactors = new float[1];
 131         this.offsets      = new float[1];
 132         this.scaleFactors[0] = scaleFactor;
 133         this.offsets[0]       = offset;
 134         this.hints = hints;
 135     }
 136 
 137     /**
 138      * Returns the scale factors in the given array. The array is also
 139      * returned for convenience.  If scaleFactors is null, a new array
 140      * will be allocated.
 141      * @param scaleFactors the array to contain the scale factors of
 142      *        this <code>RescaleOp</code>
 143      * @return the scale factors of this <code>RescaleOp</code>.
 144      */
 145     public final float[] getScaleFactors (float scaleFactors[]) {
 146         if (scaleFactors == null) {
 147             return this.scaleFactors.clone();
 148         }
 149         System.arraycopy (this.scaleFactors, 0, scaleFactors, 0,
 150                           Math.min(this.scaleFactors.length,
 151                                    scaleFactors.length));
 152         return scaleFactors;
 153     }
 154 
 155     /**
 156      * Returns the offsets in the given array. The array is also returned
 157      * for convenience.  If offsets is null, a new array
 158      * will be allocated.
 159      * @param offsets the array to contain the offsets of
 160      *        this <code>RescaleOp</code>
 161      * @return the offsets of this <code>RescaleOp</code>.
 162      */
 163     public final float[] getOffsets(float offsets[]) {
 164         if (offsets == null) {
 165             return this.offsets.clone();
 166         }
 167 
 168         System.arraycopy (this.offsets, 0, offsets, 0,
 169                           Math.min(this.offsets.length, offsets.length));
 170         return offsets;
 171     }
 172 
 173     /**
 174      * Returns the number of scaling factors and offsets used in this
 175      * RescaleOp.
 176      * @return the number of scaling factors and offsets of this
 177      *         <code>RescaleOp</code>.
 178      */
 179     public final int getNumFactors() {
 180         return length;
 181     }
 182 
 183 
 184     /**
 185      * Creates a ByteLookupTable to implement the rescale.
 186      * The table may have either a SHORT or BYTE input.
 187      * @param nElems    Number of elements the table is to have.
 188      *                  This will generally be 256 for byte and
 189      *                  65536 for short.
 190      */
 191     private ByteLookupTable createByteLut(float scale[],
 192                                           float off[],
 193                                           int   nBands,
 194                                           int   nElems) {
 195 
 196         byte[][]        lutData = new byte[scale.length][nElems];
 197 


 296         for (int i=1; i<src.getNumBands(); i++) {
 297             int bandSize = srcSM.getSampleSize(i);
 298             if (bandSize != srcNbits) {
 299                 return false;
 300             }
 301         }
 302 
 303         return true;
 304     }
 305 
 306     /**
 307      * Rescales the source BufferedImage.
 308      * If the color model in the source image is not the same as that
 309      * in the destination image, the pixels will be converted
 310      * in the destination.  If the destination image is null,
 311      * a BufferedImage will be created with the source ColorModel.
 312      * An IllegalArgumentException may be thrown if the number of
 313      * scaling factors/offsets in this object does not meet the
 314      * restrictions stated in the class comments above, or if the
 315      * source image has an IndexColorModel.
 316      * @param src the <code>BufferedImage</code> to be filtered
 317      * @param dst the destination for the filtering operation
 318      *            or <code>null</code>
 319      * @return the filtered <code>BufferedImage</code>.
 320      * @throws IllegalArgumentException if the <code>ColorModel</code>
 321      *         of <code>src</code> is an <code>IndexColorModel</code>,
 322      *         or if the number of scaling factors and offsets in this
 323      *         <code>RescaleOp</code> do not meet the requirements
 324      *         stated in the class comments.
 325      */
 326     public final BufferedImage filter (BufferedImage src, BufferedImage dst) {
 327         ColorModel srcCM = src.getColorModel();
 328         ColorModel dstCM;
 329         int numSrcColorComp = srcCM.getNumColorComponents();
 330         int scaleConst = length;
 331 
 332         if (srcCM instanceof IndexColorModel) {
 333             throw new
 334                 IllegalArgumentException("Rescaling cannot be "+
 335                                          "performed on an indexed image");
 336         }
 337         if (scaleConst != 1 && scaleConst != numSrcColorComp &&
 338             scaleConst != srcCM.getNumComponents())
 339         {
 340             throw new IllegalArgumentException("Number of scaling constants "+
 341                                                "does not equal the number of"+
 342                                                " of color or color/alpha "+
 343                                                " components");


 469                 }
 470             }
 471         }
 472 
 473         if (needToConvert) {
 474             // ColorModels are not the same
 475             ColorConvertOp ccop = new ColorConvertOp(hints);
 476             dst = ccop.filter(dst, origDst);
 477         }
 478         return dst;
 479     }
 480 
 481     /**
 482      * Rescales the pixel data in the source Raster.
 483      * If the destination Raster is null, a new Raster will be created.
 484      * The source and destination must have the same number of bands.
 485      * Otherwise, an IllegalArgumentException is thrown.
 486      * Note that the number of scaling factors/offsets in this object must
 487      * meet the restrictions stated in the class comments above.
 488      * Otherwise, an IllegalArgumentException is thrown.
 489      * @param src the <code>Raster</code> to be filtered
 490      * @param dst the destination for the filtering operation
 491      *            or <code>null</code>
 492      * @return the filtered <code>WritableRaster</code>.
 493      * @throws IllegalArgumentException if <code>src</code> and
 494      *         <code>dst</code> do not have the same number of bands,
 495      *         or if the number of scaling factors and offsets in this
 496      *         <code>RescaleOp</code> do not meet the requirements
 497      *         stated in the class comments.
 498      */
 499     public final WritableRaster filter (Raster src, WritableRaster dst)  {
 500         return filterRasterImpl(src, dst, length);
 501     }
 502 
 503     private WritableRaster filterRasterImpl(Raster src, WritableRaster dst, int scaleConst) {
 504         int numBands = src.getNumBands();
 505         int width  = src.getWidth();
 506         int height = src.getHeight();
 507         int[] srcPix = null;
 508         int step = 0;
 509         int tidx = 0;
 510 
 511         // Create a new destination Raster, if needed
 512         if (dst == null) {
 513             dst = createCompatibleDestRaster(src);
 514         }
 515         else if (height != dst.getHeight() || width != dst.getWidth()) {
 516             throw new


 616                     dst.setPixel(dX, dY, srcPix);
 617                 }
 618             }
 619         }
 620         return dst;
 621     }
 622 
 623     /**
 624      * Returns the bounding box of the rescaled destination image.  Since
 625      * this is not a geometric operation, the bounding box does not
 626      * change.
 627      */
 628     public final Rectangle2D getBounds2D (BufferedImage src) {
 629          return getBounds2D(src.getRaster());
 630     }
 631 
 632     /**
 633      * Returns the bounding box of the rescaled destination Raster.  Since
 634      * this is not a geometric operation, the bounding box does not
 635      * change.
 636      * @param src the rescaled destination <code>Raster</code>
 637      * @return the bounds of the specified <code>Raster</code>.
 638      */
 639     public final Rectangle2D getBounds2D (Raster src) {
 640         return src.getBounds();
 641     }
 642 
 643     /**
 644      * Creates a zeroed destination image with the correct size and number of
 645      * bands.
 646      * @param src       Source image for the filter operation.
 647      * @param destCM    ColorModel of the destination.  If null, the
 648      *                  ColorModel of the source will be used.
 649      * @return the zeroed-destination image.
 650      */
 651     public BufferedImage createCompatibleDestImage (BufferedImage src,
 652                                                     ColorModel destCM) {
 653         BufferedImage image;
 654         if (destCM == null) {
 655             ColorModel cm = src.getColorModel();
 656             image = new BufferedImage(cm,
 657                                       src.getRaster().createCompatibleWritableRaster(),
 658                                       cm.isAlphaPremultiplied(),
 659                                       null);
 660         }
 661         else {
 662             int w = src.getWidth();
 663             int h = src.getHeight();
 664             image = new BufferedImage (destCM,
 665                                    destCM.createCompatibleWritableRaster(w, h),
 666                                    destCM.isAlphaPremultiplied(), null);
 667         }
 668 
 669         return image;
 670     }
 671 
 672     /**
 673      * Creates a zeroed-destination <code>Raster</code> with the correct
 674      * size and number of bands, given this source.
 675      * @param src       the source <code>Raster</code>
 676      * @return the zeroed-destination <code>Raster</code>.
 677      */
 678     public WritableRaster createCompatibleDestRaster (Raster src) {
 679         return src.createCompatibleWritableRaster(src.getWidth(), src.getHeight());
 680     }
 681 
 682     /**
 683      * Returns the location of the destination point given a
 684      * point in the source.  If dstPt is non-null, it will
 685      * be used to hold the return value.  Since this is not a geometric
 686      * operation, the srcPt will equal the dstPt.
 687      * @param srcPt a point in the source image
 688      * @param dstPt the destination point or <code>null</code>
 689      * @return the location of the destination point.
 690      */
 691     public final Point2D getPoint2D (Point2D srcPt, Point2D dstPt) {
 692         if (dstPt == null) {
 693             dstPt = new Point2D.Float();
 694         }
 695         dstPt.setLocation(srcPt.getX(), srcPt.getY());
 696         return dstPt;
 697     }
 698 
 699     /**
 700      * Returns the rendering hints for this op.
 701      * @return the rendering hints of this <code>RescaleOp</code>.
 702      */
 703     public final RenderingHints getRenderingHints() {
 704         return hints;
 705     }
 706 }


  80  * @see java.awt.RenderingHints#KEY_COLOR_RENDERING
  81  * @see java.awt.RenderingHints#KEY_DITHERING
  82  */
  83 public class RescaleOp implements BufferedImageOp, RasterOp {
  84     float[] scaleFactors;
  85     float[] offsets;
  86     int length = 0;
  87     RenderingHints hints;
  88 
  89     private int srcNbits;
  90     private int dstNbits;
  91 
  92 
  93     /**
  94      * Constructs a new RescaleOp with the desired scale factors
  95      * and offsets.  The length of the scaleFactor and offset arrays
  96      * must meet the restrictions stated in the class comments above.
  97      * The RenderingHints argument may be null.
  98      * @param scaleFactors the specified scale factors
  99      * @param offsets the specified offsets
 100      * @param hints the specified {@code RenderingHints}, or
 101      *        {@code null}
 102      */
 103     public RescaleOp (float[] scaleFactors, float[] offsets,
 104                       RenderingHints hints) {
 105         length = scaleFactors.length;
 106         if (length > offsets.length) length = offsets.length;
 107 
 108         this.scaleFactors = new float[length];
 109         this.offsets      = new float[length];
 110         for (int i=0; i < length; i++) {
 111             this.scaleFactors[i] = scaleFactors[i];
 112             this.offsets[i]      = offsets[i];
 113         }
 114         this.hints = hints;
 115     }
 116 
 117     /**
 118      * Constructs a new RescaleOp with the desired scale factor
 119      * and offset.  The scaleFactor and offset will be applied to
 120      * all bands in a source Raster and to all color (but not alpha)
 121      * components in a BufferedImage.
 122      * The RenderingHints argument may be null.
 123      * @param scaleFactor the specified scale factor
 124      * @param offset the specified offset
 125      * @param hints the specified {@code RenderingHints}, or
 126      *        {@code null}
 127      */
 128     public RescaleOp (float scaleFactor, float offset, RenderingHints hints) {
 129         length = 1;
 130         this.scaleFactors = new float[1];
 131         this.offsets      = new float[1];
 132         this.scaleFactors[0] = scaleFactor;
 133         this.offsets[0]       = offset;
 134         this.hints = hints;
 135     }
 136 
 137     /**
 138      * Returns the scale factors in the given array. The array is also
 139      * returned for convenience.  If scaleFactors is null, a new array
 140      * will be allocated.
 141      * @param scaleFactors the array to contain the scale factors of
 142      *        this {@code RescaleOp}
 143      * @return the scale factors of this {@code RescaleOp}.
 144      */
 145     public final float[] getScaleFactors (float scaleFactors[]) {
 146         if (scaleFactors == null) {
 147             return this.scaleFactors.clone();
 148         }
 149         System.arraycopy (this.scaleFactors, 0, scaleFactors, 0,
 150                           Math.min(this.scaleFactors.length,
 151                                    scaleFactors.length));
 152         return scaleFactors;
 153     }
 154 
 155     /**
 156      * Returns the offsets in the given array. The array is also returned
 157      * for convenience.  If offsets is null, a new array
 158      * will be allocated.
 159      * @param offsets the array to contain the offsets of
 160      *        this {@code RescaleOp}
 161      * @return the offsets of this {@code RescaleOp}.
 162      */
 163     public final float[] getOffsets(float offsets[]) {
 164         if (offsets == null) {
 165             return this.offsets.clone();
 166         }
 167 
 168         System.arraycopy (this.offsets, 0, offsets, 0,
 169                           Math.min(this.offsets.length, offsets.length));
 170         return offsets;
 171     }
 172 
 173     /**
 174      * Returns the number of scaling factors and offsets used in this
 175      * RescaleOp.
 176      * @return the number of scaling factors and offsets of this
 177      *         {@code RescaleOp}.
 178      */
 179     public final int getNumFactors() {
 180         return length;
 181     }
 182 
 183 
 184     /**
 185      * Creates a ByteLookupTable to implement the rescale.
 186      * The table may have either a SHORT or BYTE input.
 187      * @param nElems    Number of elements the table is to have.
 188      *                  This will generally be 256 for byte and
 189      *                  65536 for short.
 190      */
 191     private ByteLookupTable createByteLut(float scale[],
 192                                           float off[],
 193                                           int   nBands,
 194                                           int   nElems) {
 195 
 196         byte[][]        lutData = new byte[scale.length][nElems];
 197 


 296         for (int i=1; i<src.getNumBands(); i++) {
 297             int bandSize = srcSM.getSampleSize(i);
 298             if (bandSize != srcNbits) {
 299                 return false;
 300             }
 301         }
 302 
 303         return true;
 304     }
 305 
 306     /**
 307      * Rescales the source BufferedImage.
 308      * If the color model in the source image is not the same as that
 309      * in the destination image, the pixels will be converted
 310      * in the destination.  If the destination image is null,
 311      * a BufferedImage will be created with the source ColorModel.
 312      * An IllegalArgumentException may be thrown if the number of
 313      * scaling factors/offsets in this object does not meet the
 314      * restrictions stated in the class comments above, or if the
 315      * source image has an IndexColorModel.
 316      * @param src the {@code BufferedImage} to be filtered
 317      * @param dst the destination for the filtering operation
 318      *            or {@code null}
 319      * @return the filtered {@code BufferedImage}.
 320      * @throws IllegalArgumentException if the {@code ColorModel}
 321      *         of {@code src} is an {@code IndexColorModel},
 322      *         or if the number of scaling factors and offsets in this
 323      *         {@code RescaleOp} do not meet the requirements
 324      *         stated in the class comments.
 325      */
 326     public final BufferedImage filter (BufferedImage src, BufferedImage dst) {
 327         ColorModel srcCM = src.getColorModel();
 328         ColorModel dstCM;
 329         int numSrcColorComp = srcCM.getNumColorComponents();
 330         int scaleConst = length;
 331 
 332         if (srcCM instanceof IndexColorModel) {
 333             throw new
 334                 IllegalArgumentException("Rescaling cannot be "+
 335                                          "performed on an indexed image");
 336         }
 337         if (scaleConst != 1 && scaleConst != numSrcColorComp &&
 338             scaleConst != srcCM.getNumComponents())
 339         {
 340             throw new IllegalArgumentException("Number of scaling constants "+
 341                                                "does not equal the number of"+
 342                                                " of color or color/alpha "+
 343                                                " components");


 469                 }
 470             }
 471         }
 472 
 473         if (needToConvert) {
 474             // ColorModels are not the same
 475             ColorConvertOp ccop = new ColorConvertOp(hints);
 476             dst = ccop.filter(dst, origDst);
 477         }
 478         return dst;
 479     }
 480 
 481     /**
 482      * Rescales the pixel data in the source Raster.
 483      * If the destination Raster is null, a new Raster will be created.
 484      * The source and destination must have the same number of bands.
 485      * Otherwise, an IllegalArgumentException is thrown.
 486      * Note that the number of scaling factors/offsets in this object must
 487      * meet the restrictions stated in the class comments above.
 488      * Otherwise, an IllegalArgumentException is thrown.
 489      * @param src the {@code Raster} to be filtered
 490      * @param dst the destination for the filtering operation
 491      *            or {@code null}
 492      * @return the filtered {@code WritableRaster}.
 493      * @throws IllegalArgumentException if {@code src} and
 494      *         {@code dst} do not have the same number of bands,
 495      *         or if the number of scaling factors and offsets in this
 496      *         {@code RescaleOp} do not meet the requirements
 497      *         stated in the class comments.
 498      */
 499     public final WritableRaster filter (Raster src, WritableRaster dst)  {
 500         return filterRasterImpl(src, dst, length);
 501     }
 502 
 503     private WritableRaster filterRasterImpl(Raster src, WritableRaster dst, int scaleConst) {
 504         int numBands = src.getNumBands();
 505         int width  = src.getWidth();
 506         int height = src.getHeight();
 507         int[] srcPix = null;
 508         int step = 0;
 509         int tidx = 0;
 510 
 511         // Create a new destination Raster, if needed
 512         if (dst == null) {
 513             dst = createCompatibleDestRaster(src);
 514         }
 515         else if (height != dst.getHeight() || width != dst.getWidth()) {
 516             throw new


 616                     dst.setPixel(dX, dY, srcPix);
 617                 }
 618             }
 619         }
 620         return dst;
 621     }
 622 
 623     /**
 624      * Returns the bounding box of the rescaled destination image.  Since
 625      * this is not a geometric operation, the bounding box does not
 626      * change.
 627      */
 628     public final Rectangle2D getBounds2D (BufferedImage src) {
 629          return getBounds2D(src.getRaster());
 630     }
 631 
 632     /**
 633      * Returns the bounding box of the rescaled destination Raster.  Since
 634      * this is not a geometric operation, the bounding box does not
 635      * change.
 636      * @param src the rescaled destination {@code Raster}
 637      * @return the bounds of the specified {@code Raster}.
 638      */
 639     public final Rectangle2D getBounds2D (Raster src) {
 640         return src.getBounds();
 641     }
 642 
 643     /**
 644      * Creates a zeroed destination image with the correct size and number of
 645      * bands.
 646      * @param src       Source image for the filter operation.
 647      * @param destCM    ColorModel of the destination.  If null, the
 648      *                  ColorModel of the source will be used.
 649      * @return the zeroed-destination image.
 650      */
 651     public BufferedImage createCompatibleDestImage (BufferedImage src,
 652                                                     ColorModel destCM) {
 653         BufferedImage image;
 654         if (destCM == null) {
 655             ColorModel cm = src.getColorModel();
 656             image = new BufferedImage(cm,
 657                                       src.getRaster().createCompatibleWritableRaster(),
 658                                       cm.isAlphaPremultiplied(),
 659                                       null);
 660         }
 661         else {
 662             int w = src.getWidth();
 663             int h = src.getHeight();
 664             image = new BufferedImage (destCM,
 665                                    destCM.createCompatibleWritableRaster(w, h),
 666                                    destCM.isAlphaPremultiplied(), null);
 667         }
 668 
 669         return image;
 670     }
 671 
 672     /**
 673      * Creates a zeroed-destination {@code Raster} with the correct
 674      * size and number of bands, given this source.
 675      * @param src       the source {@code Raster}
 676      * @return the zeroed-destination {@code Raster}.
 677      */
 678     public WritableRaster createCompatibleDestRaster (Raster src) {
 679         return src.createCompatibleWritableRaster(src.getWidth(), src.getHeight());
 680     }
 681 
 682     /**
 683      * Returns the location of the destination point given a
 684      * point in the source.  If dstPt is non-null, it will
 685      * be used to hold the return value.  Since this is not a geometric
 686      * operation, the srcPt will equal the dstPt.
 687      * @param srcPt a point in the source image
 688      * @param dstPt the destination point or {@code null}
 689      * @return the location of the destination point.
 690      */
 691     public final Point2D getPoint2D (Point2D srcPt, Point2D dstPt) {
 692         if (dstPt == null) {
 693             dstPt = new Point2D.Float();
 694         }
 695         dstPt.setLocation(srcPt.getX(), srcPt.getY());
 696         return dstPt;
 697     }
 698 
 699     /**
 700      * Returns the rendering hints for this op.
 701      * @return the rendering hints of this {@code RescaleOp}.
 702      */
 703     public final RenderingHints getRenderingHints() {
 704         return hints;
 705     }
 706 }
< prev index next >