1 /*
   2  * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  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 /* ****************************************************************
  27  ******************************************************************
  28  ******************************************************************
  29  *** COPYRIGHT (c) Eastman Kodak Company, 1997
  30  *** As  an unpublished  work pursuant to Title 17 of the United
  31  *** States Code.  All rights reserved.
  32  ******************************************************************
  33  ******************************************************************
  34  ******************************************************************/
  35 
  36 package java.awt.image;
  37 
  38 /**
  39  *  This class represents image data which is stored in a band interleaved
  40  *  fashion and for
  41  *  which each sample of a pixel occupies one data element of the DataBuffer.
  42  *  It subclasses ComponentSampleModel but provides a more efficient
  43  *  implementation for accessing band interleaved image data than is provided
  44  *  by ComponentSampleModel.  This class should typically be used when working
  45  *  with images which store sample data for each band in a different bank of the
  46  *  DataBuffer. Accessor methods are provided so that image data can be
  47  *  manipulated directly. Pixel stride is the number of
  48  *  data array elements between two samples for the same band on the same
  49  *  scanline. The pixel stride for a BandedSampleModel is one.
  50  *  Scanline stride is the number of data array elements between
  51  *  a given sample and the corresponding sample in the same column of the next
  52  *  scanline.  Band offsets denote the number
  53  *  of data array elements from the first data array element of the bank
  54  *  of the DataBuffer holding each band to the first sample of the band.
  55  *  The bands are numbered from 0 to N-1.
  56  *  Bank indices denote the correspondence between a bank of the data buffer
  57  *  and a band of image data.  This class supports
  58  *  {@link DataBuffer#TYPE_BYTE TYPE_BYTE},
  59  *  {@link DataBuffer#TYPE_USHORT TYPE_USHORT},
  60  *  {@link DataBuffer#TYPE_SHORT TYPE_SHORT},
  61  *  {@link DataBuffer#TYPE_INT TYPE_INT},
  62  *  {@link DataBuffer#TYPE_FLOAT TYPE_FLOAT}, and
  63  *  {@link DataBuffer#TYPE_DOUBLE TYPE_DOUBLE} datatypes
  64  */
  65 
  66 
  67 public final class BandedSampleModel extends ComponentSampleModel
  68 {
  69 
  70     /**
  71      * Constructs a BandedSampleModel with the specified parameters.
  72      * The pixel stride will be one data element.  The scanline stride
  73      * will be the same as the width.  Each band will be stored in
  74      * a separate bank and all band offsets will be zero.
  75      * @param dataType  The data type for storing samples.
  76      * @param w         The width (in pixels) of the region of
  77      *                  image data described.
  78      * @param h         The height (in pixels) of the region of image
  79      *                  data described.
  80      * @param numBands  The number of bands for the image data.
  81      * @throws IllegalArgumentException if {@code dataType} is not
  82      *         one of the supported data types
  83      */
  84     public BandedSampleModel(int dataType, int w, int h, int numBands) {
  85         super(dataType, w, h, 1, w,
  86               BandedSampleModel.createIndicesArray(numBands),
  87               BandedSampleModel.createOffsetArray(numBands));
  88     }
  89 
  90     /**
  91      * Constructs a BandedSampleModel with the specified parameters.
  92      * The number of bands will be inferred from the lengths of the
  93      * bandOffsets bankIndices arrays, which must be equal.  The pixel
  94      * stride will be one data element.
  95      * @param dataType  The data type for storing samples.
  96      * @param w         The width (in pixels) of the region of
  97      *                  image data described.
  98      * @param h         The height (in pixels) of the region of
  99      *                  image data described.
 100      * @param scanlineStride The line stride of the of the image data.
 101      * @param bankIndices The bank index for each band.
 102      * @param bandOffsets The band offset for each band.
 103      * @throws IllegalArgumentException if {@code dataType} is not
 104      *         one of the supported data types
 105      */
 106     public BandedSampleModel(int dataType,
 107                              int w, int h,
 108                              int scanlineStride,
 109                              int bankIndices[],
 110                              int bandOffsets[]) {
 111 
 112         super(dataType, w, h, 1,scanlineStride, bankIndices, bandOffsets);
 113     }
 114 
 115     /**
 116      * Creates a new BandedSampleModel with the specified
 117      * width and height.  The new BandedSampleModel will have the same
 118      * number of bands, storage data type, and bank indices
 119      * as this BandedSampleModel.  The band offsets will be compressed
 120      * such that the offset between bands will be w*pixelStride and
 121      * the minimum of all of the band offsets is zero.
 122      * @param w the width of the resulting {@code BandedSampleModel}
 123      * @param h the height of the resulting {@code BandedSampleModel}
 124      * @return a new {@code BandedSampleModel} with the specified
 125      *         width and height.
 126      * @throws IllegalArgumentException if {@code w} or
 127      *         {@code h} equals either
 128      *         {@code Integer.MAX_VALUE} or
 129      *         {@code Integer.MIN_VALUE}
 130      * @throws IllegalArgumentException if {@code dataType} is not
 131      *         one of the supported data types
 132      */
 133     public SampleModel createCompatibleSampleModel(int w, int h) {
 134         int[] bandOffs;
 135 
 136         if (numBanks == 1) {
 137             bandOffs = orderBands(bandOffsets, w*h);
 138         }
 139         else {
 140             bandOffs = new int[bandOffsets.length];
 141         }
 142 
 143         SampleModel sampleModel =
 144             new BandedSampleModel(dataType, w, h, w, bankIndices, bandOffs);
 145         return sampleModel;
 146     }
 147 
 148     /**
 149      * Creates a new BandedSampleModel with a subset of the bands of this
 150      * BandedSampleModel.  The new BandedSampleModel can be
 151      * used with any DataBuffer that the existing BandedSampleModel
 152      * can be used with.  The new BandedSampleModel/DataBuffer
 153      * combination will represent an image with a subset of the bands
 154      * of the original BandedSampleModel/DataBuffer combination.
 155      * @throws RasterFormatException if the number of bands is greater than
 156      *                               the number of banks in this sample model.
 157      * @throws IllegalArgumentException if {@code dataType} is not
 158      *         one of the supported data types
 159      */
 160     public SampleModel createSubsetSampleModel(int bands[]) {
 161         if (bands.length > bankIndices.length)
 162             throw new RasterFormatException("There are only " +
 163                                             bankIndices.length +
 164                                             " bands");
 165         int newBankIndices[] = new int[bands.length];
 166         int newBandOffsets[] = new int[bands.length];
 167 
 168         for (int i=0; i<bands.length; i++) {
 169             newBankIndices[i] = bankIndices[bands[i]];
 170             newBandOffsets[i] = bandOffsets[bands[i]];
 171         }
 172 
 173         return new BandedSampleModel(this.dataType, width, height,
 174                                      this.scanlineStride,
 175                                      newBankIndices, newBandOffsets);
 176     }
 177 
 178     /**
 179      * Creates a DataBuffer that corresponds to this BandedSampleModel,
 180      * The DataBuffer's data type, number of banks, and size
 181      * will be consistent with this BandedSampleModel.
 182      * @throws IllegalArgumentException if {@code dataType} is not
 183      *         one of the supported types.
 184      */
 185     public DataBuffer createDataBuffer() {
 186         DataBuffer dataBuffer = null;
 187 
 188         int size = scanlineStride * height;
 189         switch (dataType) {
 190         case DataBuffer.TYPE_BYTE:
 191             dataBuffer = new DataBufferByte(size, numBanks);
 192             break;
 193         case DataBuffer.TYPE_USHORT:
 194             dataBuffer = new DataBufferUShort(size, numBanks);
 195             break;
 196         case DataBuffer.TYPE_SHORT:
 197             dataBuffer = new DataBufferShort(size, numBanks);
 198             break;
 199         case DataBuffer.TYPE_INT:
 200             dataBuffer = new DataBufferInt(size, numBanks);
 201             break;
 202         case DataBuffer.TYPE_FLOAT:
 203             dataBuffer = new DataBufferFloat(size, numBanks);
 204             break;
 205         case DataBuffer.TYPE_DOUBLE:
 206             dataBuffer = new DataBufferDouble(size, numBanks);
 207             break;
 208         default:
 209             throw new IllegalArgumentException("dataType is not one " +
 210                 "of the supported types.");
 211         }
 212 
 213         return dataBuffer;
 214     }
 215 
 216 
 217     /**
 218      * Returns data for a single pixel in a primitive array of type
 219      * TransferType.  For a BandedSampleModel, this will be the same
 220      * as the data type, and samples will be returned one per array
 221      * element.  Generally, obj
 222      * should be passed in as null, so that the Object will be created
 223      * automatically and will be of the right primitive data type.
 224      * <p>
 225      * The following code illustrates transferring data for one pixel from
 226      * DataBuffer {@code db1}, whose storage layout is described by
 227      * BandedSampleModel {@code bsm1}, to DataBuffer {@code db2},
 228      * whose storage layout is described by
 229      * BandedSampleModel {@code bsm2}.
 230      * The transfer will generally be more efficient than using
 231      * getPixel/setPixel.
 232      * <pre>
 233      *       BandedSampleModel bsm1, bsm2;
 234      *       DataBufferInt db1, db2;
 235      *       bsm2.setDataElements(x, y, bsm1.getDataElements(x, y, null, db1),
 236      *                            db2);
 237      * </pre>
 238      * Using getDataElements/setDataElements to transfer between two
 239      * DataBuffer/SampleModel pairs is legitimate if the SampleModels have
 240      * the same number of bands, corresponding bands have the same number of
 241      * bits per sample, and the TransferTypes are the same.
 242      * <p>
 243      * If obj is non-null, it should be a primitive array of type TransferType.
 244      * Otherwise, a ClassCastException is thrown.  An
 245      * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
 246      * not in bounds, or if obj is non-null and is not large enough to hold
 247      * the pixel data.
 248      * @param x         The X coordinate of the pixel location
 249      * @param y         The Y coordinate of the pixel location
 250      * @param obj       If non-null, a primitive array in which to return
 251      *                  the pixel data.
 252      * @param data      The DataBuffer containing the image data.
 253      * @return the data for the specified pixel.
 254      * @see #setDataElements(int, int, Object, DataBuffer)
 255      */
 256     public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
 257         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
 258             throw new ArrayIndexOutOfBoundsException
 259                 ("Coordinate out of bounds!");
 260         }
 261         int type = getTransferType();
 262         int numDataElems = getNumDataElements();
 263         int pixelOffset = y*scanlineStride + x;
 264 
 265         switch(type) {
 266 
 267         case DataBuffer.TYPE_BYTE:
 268 
 269             byte[] bdata;
 270 
 271             if (obj == null) {
 272                 bdata = new byte[numDataElems];
 273             } else {
 274                 bdata = (byte[])obj;
 275             }
 276 
 277             for (int i=0; i<numDataElems; i++) {
 278                 bdata[i] = (byte)data.getElem(bankIndices[i],
 279                                               pixelOffset + bandOffsets[i]);
 280             }
 281 
 282             obj = (Object)bdata;
 283             break;
 284 
 285         case DataBuffer.TYPE_USHORT:
 286         case DataBuffer.TYPE_SHORT:
 287 
 288             short[] sdata;
 289 
 290             if (obj == null) {
 291                 sdata = new short[numDataElems];
 292             } else {
 293                 sdata = (short[])obj;
 294             }
 295 
 296             for (int i=0; i<numDataElems; i++) {
 297                 sdata[i] = (short)data.getElem(bankIndices[i],
 298                                                pixelOffset + bandOffsets[i]);
 299             }
 300 
 301             obj = (Object)sdata;
 302             break;
 303 
 304         case DataBuffer.TYPE_INT:
 305 
 306             int[] idata;
 307 
 308             if (obj == null) {
 309                 idata = new int[numDataElems];
 310             } else {
 311                 idata = (int[])obj;
 312             }
 313 
 314             for (int i=0; i<numDataElems; i++) {
 315                 idata[i] = data.getElem(bankIndices[i],
 316                                         pixelOffset + bandOffsets[i]);
 317             }
 318 
 319             obj = (Object)idata;
 320             break;
 321 
 322         case DataBuffer.TYPE_FLOAT:
 323 
 324             float[] fdata;
 325 
 326             if (obj == null) {
 327                 fdata = new float[numDataElems];
 328             } else {
 329                 fdata = (float[])obj;
 330             }
 331 
 332             for (int i=0; i<numDataElems; i++) {
 333                 fdata[i] = data.getElemFloat(bankIndices[i],
 334                                              pixelOffset + bandOffsets[i]);
 335             }
 336 
 337             obj = (Object)fdata;
 338             break;
 339 
 340         case DataBuffer.TYPE_DOUBLE:
 341 
 342             double[] ddata;
 343 
 344             if (obj == null) {
 345                 ddata = new double[numDataElems];
 346             } else {
 347                 ddata = (double[])obj;
 348             }
 349 
 350             for (int i=0; i<numDataElems; i++) {
 351                 ddata[i] = data.getElemDouble(bankIndices[i],
 352                                               pixelOffset + bandOffsets[i]);
 353             }
 354 
 355             obj = (Object)ddata;
 356             break;
 357         }
 358 
 359         return obj;
 360     }
 361 
 362     /**
 363      * Returns all samples for the specified pixel in an int array.
 364      * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
 365      * not in bounds.
 366      * @param x         The X coordinate of the pixel location
 367      * @param y         The Y coordinate of the pixel location
 368      * @param iArray    If non-null, returns the samples in this array
 369      * @param data      The DataBuffer containing the image data
 370      * @return the samples for the specified pixel.
 371      * @see #setPixel(int, int, int[], DataBuffer)
 372      */
 373     public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
 374         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
 375             throw new ArrayIndexOutOfBoundsException
 376                 ("Coordinate out of bounds!");
 377         }
 378 
 379         int[] pixels;
 380 
 381         if (iArray != null) {
 382            pixels = iArray;
 383         } else {
 384            pixels = new int [numBands];
 385         }
 386 
 387         int pixelOffset = y*scanlineStride + x;
 388         for (int i=0; i<numBands; i++) {
 389             pixels[i] = data.getElem(bankIndices[i],
 390                                      pixelOffset + bandOffsets[i]);
 391         }
 392         return pixels;
 393     }
 394 
 395     /**
 396      * Returns all samples for the specified rectangle of pixels in
 397      * an int array, one sample per data array element.
 398      * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
 399      * not in bounds.
 400      * @param x         The X coordinate of the upper left pixel location
 401      * @param y         The Y coordinate of the upper left pixel location
 402      * @param w         The width of the pixel rectangle
 403      * @param h         The height of the pixel rectangle
 404      * @param iArray    If non-null, returns the samples in this array
 405      * @param data      The DataBuffer containing the image data
 406      * @return the samples for the pixels within the specified region.
 407      * @see #setPixels(int, int, int, int, int[], DataBuffer)
 408      */
 409     public int[] getPixels(int x, int y, int w, int h,
 410                            int iArray[], DataBuffer data) {
 411         int x1 = x + w;
 412         int y1 = y + h;
 413 
 414         if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
 415             y < 0 || y >= height || h > height || y1 < 0 || y1 >  height)
 416         {
 417             throw new ArrayIndexOutOfBoundsException
 418                 ("Coordinate out of bounds!");
 419         }
 420         int[] pixels;
 421 
 422         if (iArray != null) {
 423            pixels = iArray;
 424         } else {
 425            pixels = new int[w*h*numBands];
 426         }
 427 
 428         for (int k = 0; k < numBands; k++) {
 429             int lineOffset = y*scanlineStride + x + bandOffsets[k];
 430             int srcOffset = k;
 431             int bank = bankIndices[k];
 432 
 433             for (int i = 0; i < h; i++) {
 434                 int pixelOffset = lineOffset;
 435                 for (int j = 0; j < w; j++) {
 436                     pixels[srcOffset] = data.getElem(bank, pixelOffset++);
 437                     srcOffset += numBands;
 438                 }
 439                 lineOffset += scanlineStride;
 440             }
 441         }
 442         return pixels;
 443     }
 444 
 445     /**
 446      * Returns as int the sample in a specified band for the pixel
 447      * located at (x,y).
 448      * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
 449      * not in bounds.
 450      * @param x         The X coordinate of the pixel location
 451      * @param y         The Y coordinate of the pixel location
 452      * @param b         The band to return
 453      * @param data      The DataBuffer containing the image data
 454      * @return the sample in the specified band for the specified pixel.
 455      * @see #setSample(int, int, int, int, DataBuffer)
 456      */
 457     public int getSample(int x, int y, int b, DataBuffer data) {
 458         // Bounds check for 'b' will be performed automatically
 459         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
 460             throw new ArrayIndexOutOfBoundsException
 461                 ("Coordinate out of bounds!");
 462         }
 463         int sample =
 464             data.getElem(bankIndices[b],
 465                          y*scanlineStride + x + bandOffsets[b]);
 466         return sample;
 467     }
 468 
 469     /**
 470      * Returns the sample in a specified band
 471      * for the pixel located at (x,y) as a float.
 472      * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
 473      * not in bounds.
 474      * @param x         The X coordinate of the pixel location
 475      * @param y         The Y coordinate of the pixel location
 476      * @param b         The band to return
 477      * @param data      The DataBuffer containing the image data
 478      * @return a float value that represents the sample in the specified
 479      * band for the specified pixel.
 480      */
 481     public float getSampleFloat(int x, int y, int b, DataBuffer data) {
 482         // Bounds check for 'b' will be performed automatically
 483         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
 484             throw new ArrayIndexOutOfBoundsException
 485                 ("Coordinate out of bounds!");
 486         }
 487 
 488         float sample = data.getElemFloat(bankIndices[b],
 489                                     y*scanlineStride + x + bandOffsets[b]);
 490         return sample;
 491     }
 492 
 493     /**
 494      * Returns the sample in a specified band
 495      * for a pixel located at (x,y) as a double.
 496      * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
 497      * not in bounds.
 498      * @param x         The X coordinate of the pixel location
 499      * @param y         The Y coordinate of the pixel location
 500      * @param b         The band to return
 501      * @param data      The DataBuffer containing the image data
 502      * @return a double value that represents the sample in the specified
 503      * band for the specified pixel.
 504      */
 505     public double getSampleDouble(int x, int y, int b, DataBuffer data) {
 506         // Bounds check for 'b' will be performed automatically
 507         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
 508             throw new ArrayIndexOutOfBoundsException
 509                 ("Coordinate out of bounds!");
 510         }
 511 
 512         double sample = data.getElemDouble(bankIndices[b],
 513                                        y*scanlineStride + x + bandOffsets[b]);
 514         return sample;
 515     }
 516 
 517     /**
 518      * Returns the samples in a specified band for the specified rectangle
 519      * of pixels in an int array, one sample per data array element.
 520      * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
 521      * not in bounds.
 522      * @param x         The X coordinate of the upper left pixel location
 523      * @param y         The Y coordinate of the upper left pixel location
 524      * @param w         The width of the pixel rectangle
 525      * @param h         The height of the pixel rectangle
 526      * @param b         The band to return
 527      * @param iArray    If non-null, returns the samples in this array
 528      * @param data      The DataBuffer containing the image data
 529      * @return the samples in the specified band for the pixels within
 530      * the specified region.
 531      * @see #setSamples(int, int, int, int, int, int[], DataBuffer)
 532      */
 533     public int[] getSamples(int x, int y, int w, int h, int b,
 534                             int iArray[], DataBuffer data) {
 535         // Bounds check for 'b' will be performed automatically
 536         if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
 537             throw new ArrayIndexOutOfBoundsException
 538                 ("Coordinate out of bounds!");
 539         }
 540         int samples[];
 541         if (iArray != null) {
 542            samples = iArray;
 543         } else {
 544            samples = new int [w*h];
 545         }
 546 
 547         int lineOffset = y*scanlineStride + x + bandOffsets[b];
 548         int srcOffset = 0;
 549         int bank = bankIndices[b];
 550 
 551         for (int i = 0; i < h; i++) {
 552            int sampleOffset = lineOffset;
 553            for (int j = 0; j < w; j++) {
 554                samples[srcOffset++] = data.getElem(bank, sampleOffset++);
 555            }
 556            lineOffset += scanlineStride;
 557         }
 558         return samples;
 559     }
 560 
 561     /**
 562      * Sets the data for a single pixel in the specified DataBuffer from a
 563      * primitive array of type TransferType.  For a BandedSampleModel,
 564      * this will be the same as the data type, and samples are transferred
 565      * one per array element.
 566      * <p>
 567      * The following code illustrates transferring data for one pixel from
 568      * DataBuffer {@code db1}, whose storage layout is described by
 569      * BandedSampleModel {@code bsm1}, to DataBuffer {@code db2},
 570      * whose storage layout is described by
 571      * BandedSampleModel {@code bsm2}.
 572      * The transfer will generally be more efficient than using
 573      * getPixel/setPixel.
 574      * <pre>
 575      *       BandedSampleModel bsm1, bsm2;
 576      *       DataBufferInt db1, db2;
 577      *       bsm2.setDataElements(x, y, bsm1.getDataElements(x, y, null, db1),
 578      *                            db2);
 579      * </pre>
 580      * Using getDataElements/setDataElements to transfer between two
 581      * DataBuffer/SampleModel pairs is legitimate if the SampleModels have
 582      * the same number of bands, corresponding bands have the same number of
 583      * bits per sample, and the TransferTypes are the same.
 584      * <p>
 585      * obj must be a primitive array of type TransferType.  Otherwise,
 586      * a ClassCastException is thrown.  An
 587      * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
 588      * not in bounds, or if obj is not large enough to hold the pixel data.
 589      * @param x         The X coordinate of the pixel location
 590      * @param y         The Y coordinate of the pixel location
 591      * @param obj       If non-null, returns the primitive array in this
 592      *                  object
 593      * @param data      The DataBuffer containing the image data
 594      * @see #getDataElements(int, int, Object, DataBuffer)
 595      */
 596     public void setDataElements(int x, int y, Object obj, DataBuffer data) {
 597         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
 598             throw new ArrayIndexOutOfBoundsException
 599                 ("Coordinate out of bounds!");
 600         }
 601         int type = getTransferType();
 602         int numDataElems = getNumDataElements();
 603         int pixelOffset = y*scanlineStride + x;
 604 
 605         switch(type) {
 606 
 607         case DataBuffer.TYPE_BYTE:
 608 
 609             byte[] barray = (byte[])obj;
 610 
 611             for (int i=0; i<numDataElems; i++) {
 612                 data.setElem(bankIndices[i], pixelOffset + bandOffsets[i],
 613                              barray[i] & 0xff);
 614             }
 615             break;
 616 
 617         case DataBuffer.TYPE_USHORT:
 618         case DataBuffer.TYPE_SHORT:
 619 
 620             short[] sarray = (short[])obj;
 621 
 622             for (int i=0; i<numDataElems; i++) {
 623                 data.setElem(bankIndices[i], pixelOffset + bandOffsets[i],
 624                              sarray[i] & 0xffff);
 625             }
 626             break;
 627 
 628         case DataBuffer.TYPE_INT:
 629 
 630             int[] iarray = (int[])obj;
 631 
 632             for (int i=0; i<numDataElems; i++) {
 633                 data.setElem(bankIndices[i], pixelOffset + bandOffsets[i],
 634                              iarray[i]);
 635             }
 636             break;
 637 
 638         case DataBuffer.TYPE_FLOAT:
 639 
 640             float[] farray = (float[])obj;
 641 
 642             for (int i=0; i<numDataElems; i++) {
 643                 data.setElemFloat(bankIndices[i], pixelOffset + bandOffsets[i],
 644                                   farray[i]);
 645             }
 646             break;
 647 
 648         case DataBuffer.TYPE_DOUBLE:
 649 
 650             double[] darray = (double[])obj;
 651 
 652             for (int i=0; i<numDataElems; i++) {
 653                 data.setElemDouble(bankIndices[i], pixelOffset + bandOffsets[i],
 654                                    darray[i]);
 655             }
 656             break;
 657 
 658         }
 659     }
 660 
 661     /**
 662      * Sets a pixel in the DataBuffer using an int array of samples for input.
 663      * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
 664      * not in bounds.
 665      * @param x         The X coordinate of the pixel location
 666      * @param y         The Y coordinate of the pixel location
 667      * @param iArray    The input samples in an int array
 668      * @param data      The DataBuffer containing the image data
 669      * @see #getPixel(int, int, int[], DataBuffer)
 670      */
 671     public void setPixel(int x, int y, int iArray[], DataBuffer data) {
 672         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
 673             throw new ArrayIndexOutOfBoundsException
 674                 ("Coordinate out of bounds!");
 675         }
 676        int pixelOffset = y*scanlineStride + x;
 677        for (int i=0; i<numBands; i++) {
 678            data.setElem(bankIndices[i], pixelOffset + bandOffsets[i],
 679                         iArray[i]);
 680        }
 681     }
 682 
 683     /**
 684      * Sets all samples for a rectangle of pixels from an int array containing
 685      * one sample per array element.
 686      * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
 687      * not in bounds.
 688      * @param x         The X coordinate of the upper left pixel location
 689      * @param y         The Y coordinate of the upper left pixel location
 690      * @param w         The width of the pixel rectangle
 691      * @param h         The height of the pixel rectangle
 692      * @param iArray    The input samples in an int array
 693      * @param data      The DataBuffer containing the image data
 694      * @see #getPixels(int, int, int, int, int[], DataBuffer)
 695      */
 696     public void setPixels(int x, int y, int w, int h,
 697                           int iArray[], DataBuffer data) {
 698         int x1 = x + w;
 699         int y1 = y + h;
 700 
 701         if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
 702             y < 0 || y >= height || h > height || y1 < 0 || y1 >  height)
 703         {
 704             throw new ArrayIndexOutOfBoundsException
 705                 ("Coordinate out of bounds!");
 706         }
 707 
 708         for (int k = 0; k < numBands; k++) {
 709             int lineOffset = y*scanlineStride + x + bandOffsets[k];
 710             int srcOffset = k;
 711             int bank = bankIndices[k];
 712 
 713             for (int i = 0; i < h; i++) {
 714                 int pixelOffset = lineOffset;
 715                 for (int j = 0; j < w; j++) {
 716                     data.setElem(bank, pixelOffset++, iArray[srcOffset]);
 717                     srcOffset += numBands;
 718                 }
 719                 lineOffset += scanlineStride;
 720            }
 721         }
 722     }
 723 
 724     /**
 725      * Sets a sample in the specified band for the pixel located at (x,y)
 726      * in the DataBuffer using an int for input.
 727      * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
 728      * not in bounds.
 729      * @param x         The X coordinate of the pixel location
 730      * @param y         The Y coordinate of the pixel location
 731      * @param b         The band to set
 732      * @param s         The input sample as an int
 733      * @param data      The DataBuffer containing the image data
 734      * @see #getSample(int, int, int, DataBuffer)
 735      */
 736     public void setSample(int x, int y, int b, int s,
 737                           DataBuffer data) {
 738         // Bounds check for 'b' will be performed automatically
 739         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
 740             throw new ArrayIndexOutOfBoundsException
 741                 ("Coordinate out of bounds!");
 742         }
 743         data.setElem(bankIndices[b],
 744                      y*scanlineStride + x + bandOffsets[b], s);
 745     }
 746 
 747     /**
 748      * Sets a sample in the specified band for the pixel located at (x,y)
 749      * in the DataBuffer using a float for input.
 750      * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
 751      * not in bounds.
 752      * @param x         The X coordinate of the pixel location
 753      * @param y         The Y coordinate of the pixel location
 754      * @param b         The band to set
 755      * @param s         The input sample as a float
 756      * @param data      The DataBuffer containing the image data
 757      * @see #getSample(int, int, int, DataBuffer)
 758      */
 759     public void setSample(int x, int y, int b,
 760                           float s ,
 761                           DataBuffer data) {
 762         // Bounds check for 'b' will be performed automatically
 763         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
 764             throw new ArrayIndexOutOfBoundsException
 765                 ("Coordinate out of bounds!");
 766         }
 767         data.setElemFloat(bankIndices[b],
 768                           y*scanlineStride + x + bandOffsets[b], s);
 769     }
 770 
 771     /**
 772      * Sets a sample in the specified band for the pixel located at (x,y)
 773      * in the DataBuffer using a double for input.
 774      * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
 775      * not in bounds.
 776      * @param x         The X coordinate of the pixel location
 777      * @param y         The Y coordinate of the pixel location
 778      * @param b         The band to set
 779      * @param s         The input sample as a double
 780      * @param data      The DataBuffer containing the image data
 781      * @see #getSample(int, int, int, DataBuffer)
 782      */
 783     public void setSample(int x, int y, int b,
 784                           double s,
 785                           DataBuffer data) {
 786         // Bounds check for 'b' will be performed automatically
 787         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
 788             throw new ArrayIndexOutOfBoundsException
 789                 ("Coordinate out of bounds!");
 790         }
 791         data.setElemDouble(bankIndices[b],
 792                           y*scanlineStride + x + bandOffsets[b], s);
 793     }
 794 
 795     /**
 796      * Sets the samples in the specified band for the specified rectangle
 797      * of pixels from an int array containing one sample per data array element.
 798      * ArrayIndexOutOfBoundsException may be thrown if the coordinates are
 799      * not in bounds.
 800      * @param x         The X coordinate of the upper left pixel location
 801      * @param y         The Y coordinate of the upper left pixel location
 802      * @param w         The width of the pixel rectangle
 803      * @param h         The height of the pixel rectangle
 804      * @param b         The band to set
 805      * @param iArray    The input sample array
 806      * @param data      The DataBuffer containing the image data
 807      * @see #getSamples(int, int, int, int, int, int[], DataBuffer)
 808      */
 809     public void setSamples(int x, int y, int w, int h, int b,
 810                            int iArray[], DataBuffer data) {
 811         // Bounds check for 'b' will be performed automatically
 812         if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
 813             throw new ArrayIndexOutOfBoundsException
 814                 ("Coordinate out of bounds!");
 815         }
 816         int lineOffset = y*scanlineStride + x + bandOffsets[b];
 817         int srcOffset = 0;
 818         int bank = bankIndices[b];
 819 
 820         for (int i = 0; i < h; i++) {
 821            int sampleOffset = lineOffset;
 822            for (int j = 0; j < w; j++) {
 823               data.setElem(bank, sampleOffset++, iArray[srcOffset++]);
 824            }
 825            lineOffset += scanlineStride;
 826         }
 827     }
 828 
 829     private static int[] createOffsetArray(int numBands) {
 830         int[] bandOffsets = new int[numBands];
 831         for (int i=0; i < numBands; i++) {
 832             bandOffsets[i] = 0;
 833         }
 834         return bandOffsets;
 835     }
 836 
 837     private static int[] createIndicesArray(int numBands) {
 838         int[] bankIndices = new int[numBands];
 839         for (int i=0; i < numBands; i++) {
 840             bankIndices[i] = i;
 841         }
 842         return bankIndices;
 843     }
 844 
 845     // Differentiate hash code from other ComponentSampleModel subclasses
 846     public int hashCode() {
 847         return super.hashCode() ^ 0x2;
 848     }
 849 }