< prev index next >

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

Print this page




  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.awt.image;
  27 
  28 import java.awt.color.ColorSpace;
  29 import java.awt.geom.Rectangle2D;


  30 import java.awt.Rectangle;
  31 import java.awt.geom.Point2D;
  32 import java.awt.RenderingHints;
  33 import sun.awt.image.ImagingLib;
  34 
  35 /**
  36  * This class performs a pixel-by-pixel rescaling of the data in the
  37  * source image by multiplying the sample values for each pixel by a scale
  38  * factor and then adding an offset. The scaled sample values are clipped
  39  * to the minimum/maximum representable in the destination image.
  40  * <p>
  41  * The pseudo code for the rescaling operation is as follows:
  42  * <pre>
  43  *for each pixel from Source object {
  44  *    for each band/component of the pixel {
  45  *        dstElement = (srcElement*scaleFactor) + offset
  46  *    }
  47  *}
  48  * </pre>
  49  * <p>


 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 
 198         for (int band=0; band<scale.length; band++) {
 199             float  bandScale   = scale[band];
 200             float  bandOff     = off[band];
 201             byte[] bandLutData = lutData[band];
 202             for (int i=0; i<nElems; i++) {
 203                 int val = (int)(i*bandScale + bandOff);
 204                 if ((val & 0xffffff00) != 0) {
 205                     if (val < 0) {
 206                         val = 0;
 207                     } else {
 208                         val = 255;
 209                     }
 210                 }
 211                 bandLutData[i] = (byte)val;
 212             }
 213 
 214         }











 215 
 216         return new ByteLookupTable(0, lutData);
 217     }
 218 
 219     /**
 220      * Creates a ShortLookupTable to implement the rescale.
 221      * The table may have either a SHORT or BYTE input.
 222      * @param nElems    Number of elements the table is to have.
 223      *                  This will generally be 256 for byte and
 224      *                  65536 for short.
 225      */
 226     private ShortLookupTable createShortLut(float scale[],
 227                                             float off[],
 228                                             int   nBands,
 229                                             int   nElems) {
 230 
 231         short[][]        lutData = new short[scale.length][nElems];

 232 
 233         for (int band=0; band<scale.length; band++) {
 234             float   bandScale   = scale[band];
 235             float   bandOff     = off[band];
 236             short[] bandLutData = lutData[band];
 237             for (int i=0; i<nElems; i++) {
 238                 int val = (int)(i*bandScale + bandOff);
 239                 if ((val & 0xffff0000) != 0) {
 240                     if (val < 0) {
 241                         val = 0;
 242                     } else {
 243                         val = 65535;
 244                     }
 245                 }
 246                 bandLutData[i] = (short)val;
 247             }
 248         }











 249 
 250         return new ShortLookupTable(0, lutData);
 251     }
 252 
 253 
 254     /**
 255      * Determines if the rescale can be performed as a lookup.
 256      * The dst must be a byte or short type.
 257      * The src must be less than 16 bits.
 258      * All source band sizes must be the same and all dst band sizes
 259      * must be the same.
 260      */
 261     private boolean canUseLookup(Raster src, Raster dst) {
 262 
 263         //
 264         // Check that the src datatype is either a BYTE or SHORT
 265         //
 266         int datatype = src.getDataBuffer().getDataType();
 267         if(datatype != DataBuffer.TYPE_BYTE &&
 268            datatype != DataBuffer.TYPE_USHORT) {


 283             if (bandSize != dstNbits) {
 284                 return false;
 285             }
 286         }
 287 
 288         //
 289         // Check src sample sizes. All must be the same size
 290         //
 291         SampleModel srcSM = src.getSampleModel();
 292         srcNbits = srcSM.getSampleSize(0);
 293         if (srcNbits > 16) {
 294             return false;
 295         }
 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


 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");
 344         }
 345 
 346         boolean needToConvert = false;

 347 
 348         // Include alpha
 349         if (scaleConst > numSrcColorComp && srcCM.hasAlpha()) {
 350             scaleConst = numSrcColorComp+1;
 351         }
 352 
 353         int width = src.getWidth();
 354         int height = src.getHeight();
 355 
 356         BufferedImage origDst = dst;
 357         if (dst == null) {
 358             dst = createCompatibleDestImage(src, null);
 359             dstCM = srcCM;
 360         }
 361         else {
 362             if (width != dst.getWidth()) {
 363                 throw new
 364                     IllegalArgumentException("Src width ("+width+
 365                                              ") not equal to dst width ("+
 366                                              dst.getWidth()+")");
 367             }
 368             if (height != dst.getHeight()) {
 369                 throw new
 370                     IllegalArgumentException("Src height ("+height+
 371                                              ") not equal to dst height ("+
 372                                              dst.getHeight()+")");
 373             }
 374 
 375             dstCM = dst.getColorModel();
 376             if(srcCM.getColorSpace().getType() !=
 377                dstCM.getColorSpace().getType()) {
 378                 needToConvert = true;
 379                 dst = createCompatibleDestImage(src, null);
 380             }
 381 
 382         }
 383 
 384         boolean scaleAlpha = true;
 385 
 386         //
 387         // The number of sets of scaling constants may be one,
 388         // in which case the same constants are applied to all color
 389         // (but NOT alpha) components. Otherwise, the number of sets
 390         // of scaling constants may equal the number of Source color
 391         // components, in which case NO rescaling of the alpha component
 392         // (if present) is performed.
 393         //
 394         if (numSrcColorComp == scaleConst || scaleConst == 1) {
 395             scaleAlpha = false;
 396         }
 397 
 398         //
 399         // Try to use a native BI rescale operation first
 400         //
 401         if (ImagingLib.filter(this, src, dst) == null) {






 402             //
 403             // Native BI rescale failed - convert to rasters
 404             //
 405             WritableRaster srcRaster = src.getRaster();
 406             WritableRaster dstRaster = dst.getRaster();
 407 
 408             if (!scaleAlpha) {
 409                 if (srcCM.hasAlpha()) {
 410                     // Do not rescale Alpha component
 411                     int minx = srcRaster.getMinX();
 412                     int miny = srcRaster.getMinY();
 413                     int[] bands = new int[numSrcColorComp];
 414                     for (int i=0; i < numSrcColorComp; i++) {
 415                         bands[i] = i;
 416                     }
 417                     srcRaster =
 418                         srcRaster.createWritableChild(minx, miny,
 419                                                       srcRaster.getWidth(),
 420                                                       srcRaster.getHeight(),
 421                                                       minx, miny,
 422                                                       bands);
 423                 }
 424                 if (dstCM.hasAlpha()) {
 425                     int minx = dstRaster.getMinX();
 426                     int miny = dstRaster.getMinY();
 427                     int[] bands = new int[numSrcColorComp];
 428                     for (int i=0; i < numSrcColorComp; i++) {
 429                         bands[i] = i;
 430                     }
 431                     dstRaster =
 432                         dstRaster.createWritableChild(minx, miny,
 433                                                       dstRaster.getWidth(),
 434                                                       dstRaster.getHeight(),
 435                                                       minx, miny,
 436                                                       bands);
 437                 }
 438             }
 439 
 440             //
 441             // Call the raster filter method
 442             //
 443             filterRasterImpl(srcRaster, dstRaster, scaleConst);
 444 
 445             //
 446             // here copy the unscaled src alpha to destination alpha channel
 447             //
 448             if (!scaleAlpha) {
 449                 Raster srcAlphaRaster = null;
 450                 WritableRaster dstAlphaRaster = null;
 451 
 452                 if (srcCM.hasAlpha()) {
 453                     srcAlphaRaster = src.getAlphaRaster();
 454                 }
 455                 if (dstCM.hasAlpha()) {
 456                     dstAlphaRaster = dst.getAlphaRaster();
 457                     if (srcAlphaRaster != null) {
 458                         dstAlphaRaster.setRect(srcAlphaRaster);
 459                     } else {
 460                         int alpha = 0xff << 24;
 461                         for (int cy=0; cy < dst.getHeight(); cy++) {
 462                             for (int cx=0; cx < dst.getWidth(); cx++) {
 463                                 int color = dst.getRGB(cx, cy);
 464 
 465                                 dst.setRGB(cx, cy, color | alpha);
 466                             }
 467                         }
 468                     }
 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
 517                IllegalArgumentException("Width or height of Rasters do not "+
 518                                         "match");
 519         }
 520         else if (numBands != dst.getNumBands()) {
 521             // Make sure that the number of bands are equal
 522             throw new IllegalArgumentException("Number of bands in src "
 523                             + numBands
 524                             + " does not equal number of bands in dest "
 525                             + dst.getNumBands());
 526         }
 527 
 528         // Make sure that the arrays match
 529         // Make sure that the low/high/constant arrays match
 530         if (scaleConst != 1 && scaleConst != src.getNumBands()) {
 531             throw new IllegalArgumentException("Number of scaling constants "+
 532                                                "does not equal the number of"+
 533                                                " of bands in the src raster");
 534         }
 535 
 536         //
 537         // Try for a native raster rescale first
 538         //
 539         if (ImagingLib.filter(this, src, dst) != null) {
 540             return dst;
 541         }
 542 
 543         //
 544         // Native raster rescale failed.
 545         // Try to see if a lookup operation can be used
 546         //
 547         if (canUseLookup(src, dst)) {
 548             int srcNgray = (1 << srcNbits);
 549             int dstNgray = (1 << dstNbits);
 550 


 581             //
 582             int nbits;
 583             int dstMax[] = new int[numBands];
 584             int dstMask[] = new int[numBands];
 585             SampleModel dstSM = dst.getSampleModel();
 586             for (int z=0; z<numBands; z++) {
 587                 nbits = dstSM.getSampleSize(z);
 588                 dstMax[z] = (1 << nbits) - 1;
 589                 dstMask[z] = ~(dstMax[z]);
 590             }
 591 
 592             int val;
 593             for (int y=0; y < height; y++, sY++, dY++) {
 594                 dX = dminX;
 595                 sX = sminX;
 596                 for (int x = 0; x < width; x++, sX++, dX++) {
 597                     // Get data for all bands at this x,y position
 598                     srcPix = src.getPixel(sX, sY, srcPix);
 599                     tidx = 0;
 600                     for (int z=0; z<numBands; z++, tidx += step) {




 601                         val = (int)(srcPix[z]*scaleFactors[tidx]
 602                                           + offsets[tidx]);


 603                         // Clamp
 604                         if ((val & dstMask[z]) != 0) {
 605                             if (val < 0) {
 606                                 val = 0;
 607                             } else {
 608                                 val = dstMax[z];
 609                             }
 610                         }
 611                         srcPix[z] = val;
 612 
 613                     }
 614 
 615                     // Put it back for all bands
 616                     dst.setPixel(dX, dY, srcPix);
 617                 }
 618             }
 619         }
 620         return dst;
 621     }
 622 




  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.awt.image;
  27 
  28 import java.awt.color.ColorSpace;
  29 import java.awt.geom.Rectangle2D;
  30 import java.awt.AlphaComposite;
  31 import java.awt.Graphics2D;
  32 import java.awt.Rectangle;
  33 import java.awt.geom.Point2D;
  34 import java.awt.RenderingHints;
  35 import sun.awt.image.ImagingLib;
  36 
  37 /**
  38  * This class performs a pixel-by-pixel rescaling of the data in the
  39  * source image by multiplying the sample values for each pixel by a scale
  40  * factor and then adding an offset. The scaled sample values are clipped
  41  * to the minimum/maximum representable in the destination image.
  42  * <p>
  43  * The pseudo code for the rescaling operation is as follows:
  44  * <pre>
  45  *for each pixel from Source object {
  46  *    for each band/component of the pixel {
  47  *        dstElement = (srcElement*scaleFactor) + offset
  48  *    }
  49  *}
  50  * </pre>
  51  * <p>


 178      * @return the number of scaling factors and offsets of this
 179      *         {@code RescaleOp}.
 180      */
 181     public final int getNumFactors() {
 182         return length;
 183     }
 184 
 185 
 186     /**
 187      * Creates a ByteLookupTable to implement the rescale.
 188      * The table may have either a SHORT or BYTE input.
 189      * @param nElems    Number of elements the table is to have.
 190      *                  This will generally be 256 for byte and
 191      *                  65536 for short.
 192      */
 193     private ByteLookupTable createByteLut(float scale[],
 194                                           float off[],
 195                                           int   nBands,
 196                                           int   nElems) {
 197 
 198         byte[][]        lutData = new byte[nBands][nElems];
 199         int band;
 200 
 201         for (band=0; band<scale.length; band++) {
 202             float  bandScale   = scale[band];
 203             float  bandOff     = off[band];
 204             byte[] bandLutData = lutData[band];
 205             for (int i=0; i<nElems; i++) {
 206                 int val = (int)(i*bandScale + bandOff);
 207                 if ((val & 0xffffff00) != 0) {
 208                     if (val < 0) {
 209                         val = 0;
 210                     } else {
 211                         val = 255;
 212                     }
 213                 }
 214                 bandLutData[i] = (byte)val;
 215             }
 216 
 217         }
 218         int maxToCopy = (nBands == 4 && scale.length == 4) ? 4 : 3;
 219         while (band < lutData.length && band < maxToCopy) {
 220            System.arraycopy(lutData[band-1], 0, lutData[band], 0, nElems);
 221            band++;
 222         }
 223         if (nBands == 4 && band < nBands) {
 224            byte[] bandLutData = lutData[band];
 225            for (int i=0; i<nElems; i++) {
 226               bandLutData[i] = (byte)i;
 227            }
 228         }
 229 
 230         return new ByteLookupTable(0, lutData);
 231     }
 232 
 233     /**
 234      * Creates a ShortLookupTable to implement the rescale.
 235      * The table may have either a SHORT or BYTE input.
 236      * @param nElems    Number of elements the table is to have.
 237      *                  This will generally be 256 for byte and
 238      *                  65536 for short.
 239      */
 240     private ShortLookupTable createShortLut(float scale[],
 241                                             float off[],
 242                                             int   nBands,
 243                                             int   nElems) {
 244 
 245         short[][]        lutData = new short[nBands][nElems];
 246         int band = 0;
 247 
 248         for (band=0; band<scale.length; band++) {
 249             float   bandScale   = scale[band];
 250             float   bandOff     = off[band];
 251             short[] bandLutData = lutData[band];
 252             for (int i=0; i<nElems; i++) {
 253                 int val = (int)(i*bandScale + bandOff);
 254                 if ((val & 0xffff0000) != 0) {
 255                     if (val < 0) {
 256                         val = 0;
 257                     } else {
 258                         val = 65535;
 259                     }
 260                 }
 261                 bandLutData[i] = (short)val;
 262             }
 263         }
 264         int maxToCopy = (nBands == 4 && scale.length == 4) ? 4 : 3;
 265         while (band < lutData.length && band < maxToCopy) {
 266            System.arraycopy(lutData[band-1], 0, lutData[band], 0, nElems);
 267            band++;
 268         }
 269         if (nBands == 4 && band < nBands) {
 270            short[] bandLutData = lutData[band];
 271            for (int i=0; i<nElems; i++) {
 272               bandLutData[i] = (short)i;
 273            }
 274         }
 275 
 276         return new ShortLookupTable(0, lutData);
 277     }
 278 
 279 
 280     /**
 281      * Determines if the rescale can be performed as a lookup.
 282      * The dst must be a byte or short type.
 283      * The src must be less than 16 bits.
 284      * All source band sizes must be the same and all dst band sizes
 285      * must be the same.
 286      */
 287     private boolean canUseLookup(Raster src, Raster dst) {
 288 
 289         //
 290         // Check that the src datatype is either a BYTE or SHORT
 291         //
 292         int datatype = src.getDataBuffer().getDataType();
 293         if(datatype != DataBuffer.TYPE_BYTE &&
 294            datatype != DataBuffer.TYPE_USHORT) {


 309             if (bandSize != dstNbits) {
 310                 return false;
 311             }
 312         }
 313 
 314         //
 315         // Check src sample sizes. All must be the same size
 316         //
 317         SampleModel srcSM = src.getSampleModel();
 318         srcNbits = srcSM.getSampleSize(0);
 319         if (srcNbits > 16) {
 320             return false;
 321         }
 322         for (int i=1; i<src.getNumBands(); i++) {
 323             int bandSize = srcSM.getSampleSize(i);
 324             if (bandSize != srcNbits) {
 325                 return false;
 326             }
 327         }
 328 
 329       if (dstSM instanceof ComponentSampleModel) {
 330            ComponentSampleModel dsm = (ComponentSampleModel)dstSM;
 331            if (dsm.getPixelStride() != dst.getNumBands()) {
 332                return false;
 333            }
 334         }
 335         if (srcSM instanceof ComponentSampleModel) {
 336            ComponentSampleModel csm = (ComponentSampleModel)srcSM;
 337            if (csm.getPixelStride() != src.getNumBands()) {
 338                return false;
 339            }
 340         }
 341 
 342         return true;
 343     }
 344 
 345     /**
 346      * Rescales the source BufferedImage.
 347      * If the color model in the source image is not the same as that
 348      * in the destination image, the pixels will be converted
 349      * in the destination.  If the destination image is null,
 350      * a BufferedImage will be created with the source ColorModel.
 351      * An IllegalArgumentException may be thrown if the number of
 352      * scaling factors/offsets in this object does not meet the
 353      * restrictions stated in the class comments above, or if the
 354      * source image has an IndexColorModel.
 355      * @param src the {@code BufferedImage} to be filtered
 356      * @param dst the destination for the filtering operation
 357      *            or {@code null}
 358      * @return the filtered {@code BufferedImage}.
 359      * @throws IllegalArgumentException if the {@code ColorModel}
 360      *         of {@code src} is an {@code IndexColorModel},
 361      *         or if the number of scaling factors and offsets in this


 366         ColorModel srcCM = src.getColorModel();
 367         ColorModel dstCM;
 368         int numSrcColorComp = srcCM.getNumColorComponents();
 369         int scaleConst = length;
 370 
 371         if (srcCM instanceof IndexColorModel) {
 372             throw new
 373                 IllegalArgumentException("Rescaling cannot be "+
 374                                          "performed on an indexed image");
 375         }
 376         if (scaleConst != 1 && scaleConst != numSrcColorComp &&
 377             scaleConst != srcCM.getNumComponents())
 378         {
 379             throw new IllegalArgumentException("Number of scaling constants "+
 380                                                "does not equal the number of"+
 381                                                " of color or color/alpha "+
 382                                                " components");
 383         }
 384 
 385         boolean needToConvert = false;
 386         boolean needToDraw = false;
 387 
 388         // Include alpha
 389         if (scaleConst > numSrcColorComp && srcCM.hasAlpha()) {
 390             scaleConst = numSrcColorComp+1;
 391         }
 392 
 393         int width = src.getWidth();
 394         int height = src.getHeight();
 395 
 396         BufferedImage origDst = dst;
 397         if (dst == null) {
 398             dst = createCompatibleDestImage(src, null);
 399             dstCM = srcCM;
 400         }
 401         else {
 402             if (width != dst.getWidth()) {
 403                 throw new
 404                     IllegalArgumentException("Src width ("+width+
 405                                              ") not equal to dst width ("+
 406                                              dst.getWidth()+")");
 407             }
 408             if (height != dst.getHeight()) {
 409                 throw new
 410                     IllegalArgumentException("Src height ("+height+
 411                                              ") not equal to dst height ("+
 412                                              dst.getHeight()+")");
 413             }
 414 
 415             dstCM = dst.getColorModel();
 416             if(srcCM.getColorSpace().getType() !=
 417                  dstCM.getColorSpace().getType()) {
 418                 needToConvert = true;
 419                 dst = createCompatibleDestImage(src, null);
 420             }
 421 
 422         }
 423 














 424         //
 425         // Try to use a native BI rescale operation first
 426         //
 427         if (ImagingLib.filter(this, src, dst) == null) {
 428             if (src.getRaster().getNumBands() !=
 429                 dst.getRaster().getNumBands()) {
 430                 needToDraw = true;
 431                 dst = createCompatibleDestImage(src, null);
 432             }
 433 
 434             //
 435             // Native BI rescale failed - convert to rasters
 436             //
 437             WritableRaster srcRaster = src.getRaster();
 438             WritableRaster dstRaster = dst.getRaster();
 439 
































 440             //
 441             // Call the raster filter method
 442             //
 443             filterRasterImpl(srcRaster, dstRaster, scaleConst, false);










 444         }









 445 
 446         if (needToDraw) {
 447              Graphics2D g = origDst.createGraphics();
 448              g.setComposite(AlphaComposite.Src);
 449              g.drawImage(dst, 0, 0, width, height, null);
 450              g.dispose();
 451         }


 452         if (needToConvert) {
 453             // ColorModels are not the same
 454             ColorConvertOp ccop = new ColorConvertOp(hints);
 455             dst = ccop.filter(dst, origDst);
 456         }
 457         return dst;
 458     }
 459 
 460     /**
 461      * Rescales the pixel data in the source Raster.
 462      * If the destination Raster is null, a new Raster will be created.
 463      * The source and destination must have the same number of bands.
 464      * Otherwise, an IllegalArgumentException is thrown.
 465      * Note that the number of scaling factors/offsets in this object must
 466      * meet the restrictions stated in the class comments above.
 467      * Otherwise, an IllegalArgumentException is thrown.
 468      * @param src the {@code Raster} to be filtered
 469      * @param dst the destination for the filtering operation
 470      *            or {@code null}
 471      * @return the filtered {@code WritableRaster}.
 472      * @throws IllegalArgumentException if {@code src} and
 473      *         {@code dst} do not have the same number of bands,
 474      *         or if the number of scaling factors and offsets in this
 475      *         {@code RescaleOp} do not meet the requirements
 476      *         stated in the class comments.
 477      */
 478     public final WritableRaster filter (Raster src, WritableRaster dst)  {
 479         return filterRasterImpl(src, dst, length, true);
 480     }
 481 
 482     private WritableRaster filterRasterImpl(Raster src, WritableRaster dst,
 483                                             int scaleConst, boolean sCheck) {
 484         int numBands = src.getNumBands();
 485         int width  = src.getWidth();
 486         int height = src.getHeight();
 487         int[] srcPix = null;
 488         int step = 0;
 489         int tidx = 0;
 490 
 491         // Create a new destination Raster, if needed
 492         if (dst == null) {
 493             dst = createCompatibleDestRaster(src);
 494         }
 495         else if (height != dst.getHeight() || width != dst.getWidth()) {
 496             throw new
 497                IllegalArgumentException("Width or height of Rasters do not "+
 498                                         "match");
 499         }
 500         else if (numBands != dst.getNumBands()) {
 501             // Make sure that the number of bands are equal
 502             throw new IllegalArgumentException("Number of bands in src "
 503                             + numBands
 504                             + " does not equal number of bands in dest "
 505                             + dst.getNumBands());
 506         }
 507 
 508         // Make sure that the arrays match
 509         // Make sure that the low/high/constant arrays match
 510         if (sCheck && scaleConst != 1 && scaleConst != src.getNumBands()) {
 511             throw new IllegalArgumentException("Number of scaling constants "+
 512                                                "does not equal the number of"+
 513                                                " of bands in the src raster");
 514         }
 515 
 516         //
 517         // Try for a native raster rescale first
 518         //
 519         if (ImagingLib.filter(this, src, dst) != null) {
 520             return dst;
 521         }
 522 
 523         //
 524         // Native raster rescale failed.
 525         // Try to see if a lookup operation can be used
 526         //
 527         if (canUseLookup(src, dst)) {
 528             int srcNgray = (1 << srcNbits);
 529             int dstNgray = (1 << dstNbits);
 530 


 561             //
 562             int nbits;
 563             int dstMax[] = new int[numBands];
 564             int dstMask[] = new int[numBands];
 565             SampleModel dstSM = dst.getSampleModel();
 566             for (int z=0; z<numBands; z++) {
 567                 nbits = dstSM.getSampleSize(z);
 568                 dstMax[z] = (1 << nbits) - 1;
 569                 dstMask[z] = ~(dstMax[z]);
 570             }
 571 
 572             int val;
 573             for (int y=0; y < height; y++, sY++, dY++) {
 574                 dX = dminX;
 575                 sX = sminX;
 576                 for (int x = 0; x < width; x++, sX++, dX++) {
 577                     // Get data for all bands at this x,y position
 578                     srcPix = src.getPixel(sX, sY, srcPix);
 579                     tidx = 0;
 580                     for (int z=0; z<numBands; z++, tidx += step) {
 581                         if ((scaleConst == 1 || scaleConst == 3) &&
 582                             (z == 3) && (numBands == 4)) {
 583                            val = srcPix[z];
 584                         } else {
 585                             val = (int)(srcPix[z]*scaleFactors[tidx]
 586                                               + offsets[tidx]);
 587 
 588                         }
 589                         // Clamp
 590                         if ((val & dstMask[z]) != 0) {
 591                             if (val < 0) {
 592                                 val = 0;
 593                             } else {
 594                                 val = dstMax[z];
 595                             }
 596                         }
 597                         srcPix[z] = val;
 598 
 599                     }
 600 
 601                     // Put it back for all bands
 602                     dst.setPixel(dX, dY, srcPix);
 603                 }
 604             }
 605         }
 606         return dst;
 607     }
 608 


< prev index next >