1 /*
   2  * Copyright (c) 1997, 2014, 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 import java.util.Arrays;
  39 
  40 /**
  41  *  This class represents image data which is stored such that each sample
  42  *  of a pixel occupies one data element of the DataBuffer.  It stores the
  43  *  N samples which make up a pixel in N separate data array elements.
  44  *  Different bands may be in different banks of the DataBuffer.
  45  *  Accessor methods are provided so that image data can be manipulated
  46  *  directly. This class can support different kinds of interleaving, e.g.
  47  *  band interleaving, scanline interleaving, and pixel interleaving.
  48  *  Pixel stride is the number of data array elements between two samples
  49  *  for the same band on the same scanline. Scanline stride is the number
  50  *  of data array elements between a given sample and the corresponding sample
  51  *  in the same column of the next scanline.  Band offsets denote the number
  52  *  of data array elements from the first data array element of the bank
  53  *  of the DataBuffer holding each band to the first sample of the band.
  54  *  The bands are numbered from 0 to N-1.  This class can represent image
  55  *  data for which each sample is an unsigned integral number which can be
  56  *  stored in 8, 16, or 32 bits (using <code>DataBuffer.TYPE_BYTE</code>,
  57  *  <code>DataBuffer.TYPE_USHORT</code>, or <code>DataBuffer.TYPE_INT</code>,
  58  *  respectively), data for which each sample is a signed integral number
  59  *  which can be stored in 16 bits (using <code>DataBuffer.TYPE_SHORT</code>),
  60  *  or data for which each sample is a signed float or double quantity
  61  *  (using <code>DataBuffer.TYPE_FLOAT</code> or
  62  *  <code>DataBuffer.TYPE_DOUBLE</code>, respectively).
  63  *  All samples of a given ComponentSampleModel
  64  *  are stored with the same precision.  All strides and offsets must be
  65  *  non-negative.  This class supports
  66  *  {@link DataBuffer#TYPE_BYTE TYPE_BYTE},
  67  *  {@link DataBuffer#TYPE_USHORT TYPE_USHORT},
  68  *  {@link DataBuffer#TYPE_SHORT TYPE_SHORT},
  69  *  {@link DataBuffer#TYPE_INT TYPE_INT},
  70  *  {@link DataBuffer#TYPE_FLOAT TYPE_FLOAT},
  71  *  {@link DataBuffer#TYPE_DOUBLE TYPE_DOUBLE},
  72  *  @see java.awt.image.PixelInterleavedSampleModel
  73  *  @see java.awt.image.BandedSampleModel
  74  */
  75 
  76 public class ComponentSampleModel extends SampleModel
  77 {
  78     /** Offsets for all bands in data array elements. */
  79     protected int bandOffsets[];
  80 
  81     /** Index for each bank storing a band of image data. */
  82     protected int[] bankIndices;
  83 
  84     /**
  85      * The number of bands in this
  86      * <code>ComponentSampleModel</code>.
  87      */
  88     protected int numBands = 1;
  89 
  90     /**
  91      * The number of banks in this
  92      * <code>ComponentSampleModel</code>.
  93      */
  94     protected int numBanks = 1;
  95 
  96     /**
  97      *  Line stride (in data array elements) of the region of image
  98      *  data described by this ComponentSampleModel.
  99      */
 100     protected int scanlineStride;
 101 
 102     /** Pixel stride (in data array elements) of the region of image
 103      *  data described by this ComponentSampleModel.
 104      */
 105     protected int pixelStride;
 106 
 107     static private native void initIDs();
 108     static {
 109         ColorModel.loadLibraries();
 110         initIDs();
 111     }
 112 
 113     /**
 114      * Constructs a ComponentSampleModel with the specified parameters.
 115      * The number of bands will be given by the length of the bandOffsets array.
 116      * All bands will be stored in the first bank of the DataBuffer.
 117      * @param dataType  the data type for storing samples
 118      * @param w         the width (in pixels) of the region of
 119      *     image data described
 120      * @param h         the height (in pixels) of the region of
 121      *     image data described
 122      * @param pixelStride the pixel stride of the region of image
 123      *     data described
 124      * @param scanlineStride the line stride of the region of image
 125      *     data described
 126      * @param bandOffsets the offsets of all bands
 127      * @throws IllegalArgumentException if <code>w</code> or
 128      *         <code>h</code> is not greater than 0
 129      * @throws IllegalArgumentException if <code>pixelStride</code>
 130      *         is less than 0
 131      * @throws IllegalArgumentException if <code>scanlineStride</code>
 132      *         is less than 0
 133      * @throws IllegalArgumentException if <code>numBands</code>
 134      *         is less than 1
 135      * @throws IllegalArgumentException if the product of <code>w</code>
 136      *         and <code>h</code> is greater than
 137      *         <code>Integer.MAX_VALUE</code>
 138      * @throws IllegalArgumentException if <code>dataType</code> is not
 139      *         one of the supported data types
 140      */
 141     public ComponentSampleModel(int dataType,
 142                                 int w, int h,
 143                                 int pixelStride,
 144                                 int scanlineStride,
 145                                 int bandOffsets[]) {
 146         super(dataType, w, h, bandOffsets.length);
 147         this.dataType = dataType;
 148         this.pixelStride = pixelStride;
 149         this.scanlineStride  = scanlineStride;
 150         this.bandOffsets = bandOffsets.clone();
 151         numBands = this.bandOffsets.length;
 152         if (pixelStride < 0) {
 153             throw new IllegalArgumentException("Pixel stride must be >= 0");
 154         }
 155         // TODO - bug 4296691 - remove this check
 156         if (scanlineStride < 0) {
 157             throw new IllegalArgumentException("Scanline stride must be >= 0");
 158         }
 159         if (numBands < 1) {
 160             throw new IllegalArgumentException("Must have at least one band.");
 161         }
 162         if ((dataType < DataBuffer.TYPE_BYTE) ||
 163             (dataType > DataBuffer.TYPE_DOUBLE)) {
 164             throw new IllegalArgumentException("Unsupported dataType.");
 165         }
 166         bankIndices = new int[numBands];
 167         for (int i=0; i<numBands; i++) {
 168             bankIndices[i] = 0;
 169         }
 170         verify();
 171     }
 172 
 173 
 174     /**
 175      * Constructs a ComponentSampleModel with the specified parameters.
 176      * The number of bands will be given by the length of the bandOffsets array.
 177      * Different bands may be stored in different banks of the DataBuffer.
 178      *
 179      * @param dataType  the data type for storing samples
 180      * @param w         the width (in pixels) of the region of
 181      *     image data described
 182      * @param h         the height (in pixels) of the region of
 183      *     image data described
 184      * @param pixelStride the pixel stride of the region of image
 185      *     data described
 186      * @param scanlineStride The line stride of the region of image
 187      *     data described
 188      * @param bankIndices the bank indices of all bands
 189      * @param bandOffsets the band offsets of all bands
 190      * @throws IllegalArgumentException if <code>w</code> or
 191      *         <code>h</code> is not greater than 0
 192      * @throws IllegalArgumentException if <code>pixelStride</code>
 193      *         is less than 0
 194      * @throws IllegalArgumentException if <code>scanlineStride</code>
 195      *         is less than 0
 196      * @throws IllegalArgumentException if the length of
 197      *         <code>bankIndices</code> does not equal the length of
 198      *         <code>bankOffsets</code>
 199      * @throws IllegalArgumentException if any of the bank indices
 200      *         of <code>bandIndices</code> is less than 0
 201      * @throws IllegalArgumentException if <code>dataType</code> is not
 202      *         one of the supported data types
 203      */
 204     public ComponentSampleModel(int dataType,
 205                                 int w, int h,
 206                                 int pixelStride,
 207                                 int scanlineStride,
 208                                 int bankIndices[],
 209                                 int bandOffsets[]) {
 210         super(dataType, w, h, bandOffsets.length);
 211         this.dataType = dataType;
 212         this.pixelStride = pixelStride;
 213         this.scanlineStride  = scanlineStride;
 214         this.bandOffsets = bandOffsets.clone();
 215         this.bankIndices = bankIndices.clone();
 216         if (pixelStride < 0) {
 217             throw new IllegalArgumentException("Pixel stride must be >= 0");
 218         }
 219         // TODO - bug 4296691 - remove this check
 220         if (scanlineStride < 0) {
 221             throw new IllegalArgumentException("Scanline stride must be >= 0");
 222         }
 223         if ((dataType < DataBuffer.TYPE_BYTE) ||
 224             (dataType > DataBuffer.TYPE_DOUBLE)) {
 225             throw new IllegalArgumentException("Unsupported dataType.");
 226         }
 227         int maxBank = this.bankIndices[0];
 228         if (maxBank < 0) {
 229             throw new IllegalArgumentException("Index of bank 0 is less than "+
 230                                                "0 ("+maxBank+")");
 231         }
 232         for (int i=1; i < this.bankIndices.length; i++) {
 233             if (this.bankIndices[i] > maxBank) {
 234                 maxBank = this.bankIndices[i];
 235             }
 236             else if (this.bankIndices[i] < 0) {
 237                 throw new IllegalArgumentException("Index of bank "+i+
 238                                                    " is less than 0 ("+
 239                                                    maxBank+")");
 240             }
 241         }
 242         numBanks         = maxBank+1;
 243         numBands         = this.bandOffsets.length;
 244         if (this.bandOffsets.length != this.bankIndices.length) {
 245             throw new IllegalArgumentException("Length of bandOffsets must "+
 246                                                "equal length of bankIndices.");
 247         }
 248         verify();
 249     }
 250 
 251     private void verify() {
 252         int requiredSize = getBufferSize();
 253     }
 254 
 255     /**
 256      * Returns the size of the data buffer (in data elements) needed
 257      * for a data buffer that matches this ComponentSampleModel.
 258      */
 259      private int getBufferSize() {
 260          int maxBandOff=bandOffsets[0];
 261          for (int i=1; i<bandOffsets.length; i++) {
 262              maxBandOff = Math.max(maxBandOff,bandOffsets[i]);
 263          }
 264 
 265          if (maxBandOff < 0 || maxBandOff > (Integer.MAX_VALUE - 1)) {
 266              throw new IllegalArgumentException("Invalid band offset");
 267          }
 268 
 269          if (pixelStride < 0 || pixelStride > (Integer.MAX_VALUE / width)) {
 270              throw new IllegalArgumentException("Invalid pixel stride");
 271          }
 272 
 273          if (scanlineStride < 0 || scanlineStride > (Integer.MAX_VALUE / height)) {
 274              throw new IllegalArgumentException("Invalid scanline stride");
 275          }
 276 
 277          int size = maxBandOff + 1;
 278 
 279          int val = pixelStride * (width - 1);
 280 
 281          if (val > (Integer.MAX_VALUE - size)) {
 282              throw new IllegalArgumentException("Invalid pixel stride");
 283          }
 284 
 285          size += val;
 286 
 287          val = scanlineStride * (height - 1);
 288 
 289          if (val > (Integer.MAX_VALUE - size)) {
 290              throw new IllegalArgumentException("Invalid scan stride");
 291          }
 292 
 293          size += val;
 294 
 295          return size;
 296      }
 297 
 298      /**
 299       * Preserves band ordering with new step factor...
 300       */
 301     int []orderBands(int orig[], int step) {
 302         int map[] = new int[orig.length];
 303         int ret[] = new int[orig.length];
 304 
 305         for (int i=0; i<map.length; i++) map[i] = i;
 306 
 307         for (int i = 0; i < ret.length; i++) {
 308             int index = i;
 309             for (int j = i+1; j < ret.length; j++) {
 310                 if (orig[map[index]] > orig[map[j]]) {
 311                     index = j;
 312                 }
 313             }
 314             ret[map[index]] = i*step;
 315             map[index]  = map[i];
 316         }
 317         return ret;
 318     }
 319 
 320     /**
 321      * Creates a new <code>ComponentSampleModel</code> with the specified
 322      * width and height.  The new <code>SampleModel</code> will have the same
 323      * number of bands, storage data type, interleaving scheme, and
 324      * pixel stride as this <code>SampleModel</code>.
 325      * @param w the width of the resulting <code>SampleModel</code>
 326      * @param h the height of the resulting <code>SampleModel</code>
 327      * @return a new <code>ComponentSampleModel</code> with the specified size
 328      * @throws IllegalArgumentException if <code>w</code> or
 329      *         <code>h</code> is not greater than 0
 330      */
 331     public SampleModel createCompatibleSampleModel(int w, int h) {
 332         SampleModel ret=null;
 333         long size;
 334         int minBandOff=bandOffsets[0];
 335         int maxBandOff=bandOffsets[0];
 336         for (int i=1; i<bandOffsets.length; i++) {
 337             minBandOff = Math.min(minBandOff,bandOffsets[i]);
 338             maxBandOff = Math.max(maxBandOff,bandOffsets[i]);
 339         }
 340         maxBandOff -= minBandOff;
 341 
 342         int bands   = bandOffsets.length;
 343         int bandOff[];
 344         int pStride = Math.abs(pixelStride);
 345         int lStride = Math.abs(scanlineStride);
 346         int bStride = Math.abs(maxBandOff);
 347 
 348         if (pStride > lStride) {
 349             if (pStride > bStride) {
 350                 if (lStride > bStride) { // pix > line > band
 351                     bandOff = new int[bandOffsets.length];
 352                     for (int i=0; i<bands; i++)
 353                         bandOff[i] = bandOffsets[i]-minBandOff;
 354                     lStride = bStride+1;
 355                     pStride = lStride*h;
 356                 } else { // pix > band > line
 357                     bandOff = orderBands(bandOffsets,lStride*h);
 358                     pStride = bands*lStride*h;
 359                 }
 360             } else { // band > pix > line
 361                 pStride = lStride*h;
 362                 bandOff = orderBands(bandOffsets,pStride*w);
 363             }
 364         } else {
 365             if (pStride > bStride) { // line > pix > band
 366                 bandOff = new int[bandOffsets.length];
 367                 for (int i=0; i<bands; i++)
 368                     bandOff[i] = bandOffsets[i]-minBandOff;
 369                 pStride = bStride+1;
 370                 lStride = pStride*w;
 371             } else {
 372                 if (lStride > bStride) { // line > band > pix
 373                     bandOff = orderBands(bandOffsets,pStride*w);
 374                     lStride = bands*pStride*w;
 375                 } else { // band > line > pix
 376                     lStride = pStride*w;
 377                     bandOff = orderBands(bandOffsets,lStride*h);
 378                 }
 379             }
 380         }
 381 
 382         // make sure we make room for negative offsets...
 383         int base = 0;
 384         if (scanlineStride < 0) {
 385             base += lStride*h;
 386             lStride *= -1;
 387         }
 388         if (pixelStride    < 0) {
 389             base += pStride*w;
 390             pStride *= -1;
 391         }
 392 
 393         for (int i=0; i<bands; i++)
 394             bandOff[i] += base;
 395         return new ComponentSampleModel(dataType, w, h, pStride,
 396                                         lStride, bankIndices, bandOff);
 397     }
 398 
 399     /**
 400      * Creates a new ComponentSampleModel with a subset of the bands
 401      * of this ComponentSampleModel.  The new ComponentSampleModel can be
 402      * used with any DataBuffer that the existing ComponentSampleModel
 403      * can be used with.  The new ComponentSampleModel/DataBuffer
 404      * combination will represent an image with a subset of the bands
 405      * of the original ComponentSampleModel/DataBuffer combination.
 406      * @param bands a subset of bands from this
 407      *              <code>ComponentSampleModel</code>
 408      * @return a <code>ComponentSampleModel</code> created with a subset
 409      *          of bands from this <code>ComponentSampleModel</code>.
 410      */
 411     public SampleModel createSubsetSampleModel(int bands[]) {
 412        if (bands.length > bankIndices.length)
 413             throw new RasterFormatException("There are only " +
 414                                             bankIndices.length +
 415                                             " bands");
 416         int newBankIndices[] = new int[bands.length];
 417         int newBandOffsets[] = new int[bands.length];
 418 
 419         for (int i=0; i<bands.length; i++) {
 420             newBankIndices[i] = bankIndices[bands[i]];
 421             newBandOffsets[i] = bandOffsets[bands[i]];
 422         }
 423 
 424         return new ComponentSampleModel(this.dataType, width, height,
 425                                         this.pixelStride,
 426                                         this.scanlineStride,
 427                                         newBankIndices, newBandOffsets);
 428     }
 429 
 430     /**
 431      * Creates a <code>DataBuffer</code> that corresponds to this
 432      * <code>ComponentSampleModel</code>.
 433      * The <code>DataBuffer</code> object's data type, number of banks,
 434      * and size are be consistent with this <code>ComponentSampleModel</code>.
 435      * @return a <code>DataBuffer</code> whose data type, number of banks
 436      *         and size are consistent with this
 437      *         <code>ComponentSampleModel</code>.
 438      */
 439     public DataBuffer createDataBuffer() {
 440         DataBuffer dataBuffer = null;
 441 
 442         int size = getBufferSize();
 443         switch (dataType) {
 444         case DataBuffer.TYPE_BYTE:
 445             dataBuffer = new DataBufferByte(size, numBanks);
 446             break;
 447         case DataBuffer.TYPE_USHORT:
 448             dataBuffer = new DataBufferUShort(size, numBanks);
 449             break;
 450         case DataBuffer.TYPE_SHORT:
 451             dataBuffer = new DataBufferShort(size, numBanks);
 452             break;
 453         case DataBuffer.TYPE_INT:
 454             dataBuffer = new DataBufferInt(size, numBanks);
 455             break;
 456         case DataBuffer.TYPE_FLOAT:
 457             dataBuffer = new DataBufferFloat(size, numBanks);
 458             break;
 459         case DataBuffer.TYPE_DOUBLE:
 460             dataBuffer = new DataBufferDouble(size, numBanks);
 461             break;
 462         }
 463 
 464         return dataBuffer;
 465     }
 466 
 467 
 468     /** Gets the offset for the first band of pixel (x,y).
 469      *  A sample of the first band can be retrieved from a
 470      * <code>DataBuffer</code>
 471      *  <code>data</code> with a <code>ComponentSampleModel</code>
 472      * <code>csm</code> as
 473      * <pre>
 474      *        data.getElem(csm.getOffset(x, y));
 475      * </pre>
 476      * @param x the X location of the pixel
 477      * @param y the Y location of the pixel
 478      * @return the offset for the first band of the specified pixel.
 479      */
 480     public int getOffset(int x, int y) {
 481         int offset = y*scanlineStride + x*pixelStride + bandOffsets[0];
 482         return offset;
 483     }
 484 
 485     /** Gets the offset for band b of pixel (x,y).
 486      *  A sample of band <code>b</code> can be retrieved from a
 487      *  <code>DataBuffer</code> <code>data</code>
 488      *  with a <code>ComponentSampleModel</code> <code>csm</code> as
 489      * <pre>
 490      *       data.getElem(csm.getOffset(x, y, b));
 491      * </pre>
 492      * @param x the X location of the specified pixel
 493      * @param y the Y location of the specified pixel
 494      * @param b the specified band
 495      * @return the offset for the specified band of the specified pixel.
 496      */
 497     public int getOffset(int x, int y, int b) {
 498         int offset = y*scanlineStride + x*pixelStride + bandOffsets[b];
 499         return offset;
 500     }
 501 
 502     /** Returns the number of bits per sample for all bands.
 503      *  @return an array containing the number of bits per sample
 504      *          for all bands, where each element in the array
 505      *          represents a band.
 506      */
 507     public final int[] getSampleSize() {
 508         int sampleSize[] = new int [numBands];
 509         int sizeInBits = getSampleSize(0);
 510 
 511         for (int i=0; i<numBands; i++)
 512             sampleSize[i] = sizeInBits;
 513 
 514         return sampleSize;
 515     }
 516 
 517     /** Returns the number of bits per sample for the specified band.
 518      *  @param band the specified band
 519      *  @return the number of bits per sample for the specified band.
 520      */
 521     public final int getSampleSize(int band) {
 522         return DataBuffer.getDataTypeSize(dataType);
 523     }
 524 
 525     /** Returns the bank indices for all bands.
 526      *  @return the bank indices for all bands.
 527      */
 528     public final int [] getBankIndices() {
 529         return bankIndices.clone();
 530     }
 531 
 532     /** Returns the band offset for all bands.
 533      *  @return the band offsets for all bands.
 534      */
 535     public final int [] getBandOffsets() {
 536         return bandOffsets.clone();
 537     }
 538 
 539     /** Returns the scanline stride of this ComponentSampleModel.
 540      *  @return the scanline stride of this <code>ComponentSampleModel</code>.
 541      */
 542     public final int getScanlineStride() {
 543         return scanlineStride;
 544     }
 545 
 546     /** Returns the pixel stride of this ComponentSampleModel.
 547      *  @return the pixel stride of this <code>ComponentSampleModel</code>.
 548      */
 549     public final int getPixelStride() {
 550         return pixelStride;
 551     }
 552 
 553     /**
 554      * Returns the number of data elements needed to transfer a pixel
 555      * with the
 556      * {@link #getDataElements(int, int, Object, DataBuffer) } and
 557      * {@link #setDataElements(int, int, Object, DataBuffer) }
 558      * methods.
 559      * For a <code>ComponentSampleModel</code>, this is identical to the
 560      * number of bands.
 561      * @return the number of data elements needed to transfer a pixel with
 562      *         the <code>getDataElements</code> and
 563      *         <code>setDataElements</code> methods.
 564      * @see java.awt.image.SampleModel#getNumDataElements
 565      * @see #getNumBands
 566      */
 567     public final int getNumDataElements() {
 568         return getNumBands();
 569     }
 570 
 571     /**
 572      * Returns data for a single pixel in a primitive array of type
 573      * <code>TransferType</code>.  For a <code>ComponentSampleModel</code>,
 574      * this is the same as the data type, and samples are returned
 575      * one per array element.  Generally, <code>obj</code> should
 576      * be passed in as <code>null</code>, so that the <code>Object</code>
 577      * is created automatically and is the right primitive data type.
 578      * <p>
 579      * The following code illustrates transferring data for one pixel from
 580      * <code>DataBuffer</code> <code>db1</code>, whose storage layout is
 581      * described by <code>ComponentSampleModel</code> <code>csm1</code>,
 582      * to <code>DataBuffer</code> <code>db2</code>, whose storage layout
 583      * is described by <code>ComponentSampleModel</code> <code>csm2</code>.
 584      * The transfer is usually more efficient than using
 585      * <code>getPixel</code> and <code>setPixel</code>.
 586      * <pre>
 587      *       ComponentSampleModel csm1, csm2;
 588      *       DataBufferInt db1, db2;
 589      *       csm2.setDataElements(x, y,
 590      *                            csm1.getDataElements(x, y, null, db1), db2);
 591      * </pre>
 592      *
 593      * Using <code>getDataElements</code> and <code>setDataElements</code>
 594      * to transfer between two <code>DataBuffer/SampleModel</code>
 595      * pairs is legitimate if the <code>SampleModel</code> objects have
 596      * the same number of bands, corresponding bands have the same number of
 597      * bits per sample, and the <code>TransferType</code>s are the same.
 598      * <p>
 599      * If <code>obj</code> is not <code>null</code>, it should be a
 600      * primitive array of type <code>TransferType</code>.
 601      * Otherwise, a <code>ClassCastException</code> is thrown.  An
 602      * <code>ArrayIndexOutOfBoundsException</code> might be thrown if the
 603      * coordinates are not in bounds, or if <code>obj</code> is not
 604      * <code>null</code> and is not large enough to hold
 605      * the pixel data.
 606      *
 607      * @param x         the X coordinate of the pixel location
 608      * @param y         the Y coordinate of the pixel location
 609      * @param obj       if non-<code>null</code>, a primitive array
 610      *                  in which to return the pixel data
 611      * @param data      the <code>DataBuffer</code> containing the image data
 612      * @return the data of the specified pixel
 613      * @see #setDataElements(int, int, Object, DataBuffer)
 614      *
 615      * @throws NullPointerException if data is null.
 616      * @throws ArrayIndexOutOfBoundsException if the coordinates are
 617      * not in bounds, or if obj is too small to hold the output.
 618      */
 619     public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
 620         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
 621             throw new ArrayIndexOutOfBoundsException
 622                 ("Coordinate out of bounds!");
 623         }
 624 
 625         int type = getTransferType();
 626         int numDataElems = getNumDataElements();
 627         int pixelOffset = y*scanlineStride + x*pixelStride;
 628 
 629         switch(type) {
 630 
 631         case DataBuffer.TYPE_BYTE:
 632 
 633             byte[] bdata;
 634 
 635             if (obj == null)
 636                 bdata = new byte[numDataElems];
 637             else
 638                 bdata = (byte[])obj;
 639 
 640             for (int i=0; i<numDataElems; i++) {
 641                 bdata[i] = (byte)data.getElem(bankIndices[i],
 642                                               pixelOffset + bandOffsets[i]);
 643             }
 644 
 645             obj = (Object)bdata;
 646             break;
 647 
 648         case DataBuffer.TYPE_USHORT:
 649         case DataBuffer.TYPE_SHORT:
 650 
 651             short[] sdata;
 652 
 653             if (obj == null)
 654                 sdata = new short[numDataElems];
 655             else
 656                 sdata = (short[])obj;
 657 
 658             for (int i=0; i<numDataElems; i++) {
 659                 sdata[i] = (short)data.getElem(bankIndices[i],
 660                                                pixelOffset + bandOffsets[i]);
 661             }
 662 
 663             obj = (Object)sdata;
 664             break;
 665 
 666         case DataBuffer.TYPE_INT:
 667 
 668             int[] idata;
 669 
 670             if (obj == null)
 671                 idata = new int[numDataElems];
 672             else
 673                 idata = (int[])obj;
 674 
 675             for (int i=0; i<numDataElems; i++) {
 676                 idata[i] = data.getElem(bankIndices[i],
 677                                         pixelOffset + bandOffsets[i]);
 678             }
 679 
 680             obj = (Object)idata;
 681             break;
 682 
 683         case DataBuffer.TYPE_FLOAT:
 684 
 685             float[] fdata;
 686 
 687             if (obj == null)
 688                 fdata = new float[numDataElems];
 689             else
 690                 fdata = (float[])obj;
 691 
 692             for (int i=0; i<numDataElems; i++) {
 693                 fdata[i] = data.getElemFloat(bankIndices[i],
 694                                              pixelOffset + bandOffsets[i]);
 695             }
 696 
 697             obj = (Object)fdata;
 698             break;
 699 
 700         case DataBuffer.TYPE_DOUBLE:
 701 
 702             double[] ddata;
 703 
 704             if (obj == null)
 705                 ddata = new double[numDataElems];
 706             else
 707                 ddata = (double[])obj;
 708 
 709             for (int i=0; i<numDataElems; i++) {
 710                 ddata[i] = data.getElemDouble(bankIndices[i],
 711                                               pixelOffset + bandOffsets[i]);
 712             }
 713 
 714             obj = (Object)ddata;
 715             break;
 716         }
 717 
 718         return obj;
 719     }
 720 
 721     /**
 722      * Returns all samples for the specified pixel in an int array,
 723      * one sample per array element.
 724      * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if
 725      * the coordinates are not in bounds.
 726      * @param x         the X coordinate of the pixel location
 727      * @param y         the Y coordinate of the pixel location
 728      * @param iArray    If non-null, returns the samples in this array
 729      * @param data      The DataBuffer containing the image data
 730      * @return the samples of the specified pixel.
 731      * @see #setPixel(int, int, int[], DataBuffer)
 732      *
 733      * @throws NullPointerException if data is null.
 734      * @throws ArrayIndexOutOfBoundsException if the coordinates are
 735      * not in bounds, or if iArray is too small to hold the output.
 736      */
 737     public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
 738         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
 739             throw new ArrayIndexOutOfBoundsException
 740                 ("Coordinate out of bounds!");
 741         }
 742         int pixels[];
 743         if (iArray != null) {
 744            pixels = iArray;
 745         } else {
 746            pixels = new int [numBands];
 747         }
 748         int pixelOffset = y*scanlineStride + x*pixelStride;
 749         for (int i=0; i<numBands; i++) {
 750             pixels[i] = data.getElem(bankIndices[i],
 751                                      pixelOffset + bandOffsets[i]);
 752         }
 753         return pixels;
 754     }
 755 
 756     /**
 757      * Returns all samples for the specified rectangle of pixels in
 758      * an int array, one sample per array element.
 759      * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if
 760      * the coordinates are not in bounds.
 761      * @param x         The X coordinate of the upper left pixel location
 762      * @param y         The Y coordinate of the upper left pixel location
 763      * @param w         The width of the pixel rectangle
 764      * @param h         The height of the pixel rectangle
 765      * @param iArray    If non-null, returns the samples in this array
 766      * @param data      The DataBuffer containing the image data
 767      * @return the samples of the pixels within the specified region.
 768      * @see #setPixels(int, int, int, int, int[], DataBuffer)
 769      */
 770     public int[] getPixels(int x, int y, int w, int h,
 771                            int iArray[], DataBuffer data) {
 772         int x1 = x + w;
 773         int y1 = y + h;
 774 
 775         if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
 776             y < 0 || y >= height || y > height || y1 < 0 || y1 >  height)
 777         {
 778             throw new ArrayIndexOutOfBoundsException
 779                 ("Coordinate out of bounds!");
 780         }
 781         int pixels[];
 782         if (iArray != null) {
 783            pixels = iArray;
 784         } else {
 785            pixels = new int [w*h*numBands];
 786         }
 787         int lineOffset = y*scanlineStride + x*pixelStride;
 788         int srcOffset = 0;
 789 
 790         for (int i = 0; i < h; i++) {
 791            int pixelOffset = lineOffset;
 792            for (int j = 0; j < w; j++) {
 793               for (int k=0; k < numBands; k++) {
 794                  pixels[srcOffset++] =
 795                     data.getElem(bankIndices[k], pixelOffset + bandOffsets[k]);
 796               }
 797               pixelOffset += pixelStride;
 798            }
 799            lineOffset += scanlineStride;
 800         }
 801         return pixels;
 802     }
 803 
 804     /**
 805      * Returns as int the sample in a specified band for the pixel
 806      * located at (x,y).
 807      * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if
 808      * the coordinates are not in bounds.
 809      * @param x         the X coordinate of the pixel location
 810      * @param y         the Y coordinate of the pixel location
 811      * @param b         the band to return
 812      * @param data      the <code>DataBuffer</code> containing the image data
 813      * @return the sample in a specified band for the specified pixel
 814      * @see #setSample(int, int, int, int, DataBuffer)
 815      */
 816     public int getSample(int x, int y, int b, DataBuffer data) {
 817         // Bounds check for 'b' will be performed automatically
 818         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
 819             throw new ArrayIndexOutOfBoundsException
 820                 ("Coordinate out of bounds!");
 821         }
 822         int sample = data.getElem(bankIndices[b],
 823                                   y*scanlineStride + x*pixelStride +
 824                                   bandOffsets[b]);
 825         return sample;
 826     }
 827 
 828     /**
 829      * Returns the sample in a specified band
 830      * for the pixel located at (x,y) as a float.
 831      * An <code>ArrayIndexOutOfBoundsException</code> might be
 832      * thrown if the coordinates are not in bounds.
 833      * @param x         The X coordinate of the pixel location
 834      * @param y         The Y coordinate of the pixel location
 835      * @param b         The band to return
 836      * @param data      The DataBuffer containing the image data
 837      * @return a float value representing the sample in the specified
 838      * band for the specified pixel.
 839      */
 840     public float getSampleFloat(int x, int y, int b, DataBuffer data) {
 841         // Bounds check for 'b' will be performed automatically
 842         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
 843             throw new ArrayIndexOutOfBoundsException
 844                 ("Coordinate out of bounds!");
 845         }
 846 
 847         float sample = data.getElemFloat(bankIndices[b],
 848                                          y*scanlineStride + x*pixelStride +
 849                                          bandOffsets[b]);
 850         return sample;
 851     }
 852 
 853     /**
 854      * Returns the sample in a specified band
 855      * for a pixel located at (x,y) as a double.
 856      * An <code>ArrayIndexOutOfBoundsException</code> might be
 857      * thrown if the coordinates are not in bounds.
 858      * @param x         The X coordinate of the pixel location
 859      * @param y         The Y coordinate of the pixel location
 860      * @param b         The band to return
 861      * @param data      The DataBuffer containing the image data
 862      * @return a double value representing the sample in the specified
 863      * band for the specified pixel.
 864      */
 865     public double getSampleDouble(int x, int y, int b, DataBuffer data) {
 866         // Bounds check for 'b' will be performed automatically
 867         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
 868             throw new ArrayIndexOutOfBoundsException
 869                 ("Coordinate out of bounds!");
 870         }
 871 
 872         double sample = data.getElemDouble(bankIndices[b],
 873                                            y*scanlineStride + x*pixelStride +
 874                                            bandOffsets[b]);
 875         return sample;
 876     }
 877 
 878     /**
 879      * Returns the samples in a specified band for the specified rectangle
 880      * of pixels in an int array, one sample per data array element.
 881      * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if
 882      * the coordinates are not in bounds.
 883      * @param x         The X coordinate of the upper left pixel location
 884      * @param y         The Y coordinate of the upper left pixel location
 885      * @param w         the width of the pixel rectangle
 886      * @param h         the height of the pixel rectangle
 887      * @param b         the band to return
 888      * @param iArray    if non-<code>null</code>, returns the samples
 889      *                  in this array
 890      * @param data      the <code>DataBuffer</code> containing the image data
 891      * @return the samples in the specified band of the specified pixel
 892      * @see #setSamples(int, int, int, int, int, int[], DataBuffer)
 893      */
 894     public int[] getSamples(int x, int y, int w, int h, int b,
 895                             int iArray[], DataBuffer data) {
 896         // Bounds check for 'b' will be performed automatically
 897         if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
 898             throw new ArrayIndexOutOfBoundsException
 899                 ("Coordinate out of bounds!");
 900         }
 901         int samples[];
 902         if (iArray != null) {
 903            samples = iArray;
 904         } else {
 905            samples = new int [w*h];
 906         }
 907         int lineOffset = y*scanlineStride + x*pixelStride +  bandOffsets[b];
 908         int srcOffset = 0;
 909 
 910         for (int i = 0; i < h; i++) {
 911            int sampleOffset = lineOffset;
 912            for (int j = 0; j < w; j++) {
 913               samples[srcOffset++] = data.getElem(bankIndices[b],
 914                                                   sampleOffset);
 915               sampleOffset += pixelStride;
 916            }
 917            lineOffset += scanlineStride;
 918         }
 919         return samples;
 920     }
 921 
 922     /**
 923      * Sets the data for a single pixel in the specified
 924      * <code>DataBuffer</code> from a primitive array of type
 925      * <code>TransferType</code>.  For a <code>ComponentSampleModel</code>,
 926      * this is the same as the data type, and samples are transferred
 927      * one per array element.
 928      * <p>
 929      * The following code illustrates transferring data for one pixel from
 930      * <code>DataBuffer</code> <code>db1</code>, whose storage layout is
 931      * described by <code>ComponentSampleModel</code> <code>csm1</code>,
 932      * to <code>DataBuffer</code> <code>db2</code>, whose storage layout
 933      * is described by <code>ComponentSampleModel</code> <code>csm2</code>.
 934      * The transfer is usually more efficient than using
 935      * <code>getPixel</code> and <code>setPixel</code>.
 936      * <pre>
 937      *       ComponentSampleModel csm1, csm2;
 938      *       DataBufferInt db1, db2;
 939      *       csm2.setDataElements(x, y, csm1.getDataElements(x, y, null, db1),
 940      *                            db2);
 941      * </pre>
 942      * Using <code>getDataElements</code> and <code>setDataElements</code>
 943      * to transfer between two <code>DataBuffer/SampleModel</code> pairs
 944      * is legitimate if the <code>SampleModel</code> objects have
 945      * the same number of bands, corresponding bands have the same number of
 946      * bits per sample, and the <code>TransferType</code>s are the same.
 947      * <p>
 948      * A <code>ClassCastException</code> is thrown if <code>obj</code> is not
 949      * a primitive array of type <code>TransferType</code>.
 950      * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if
 951      * the coordinates are not in bounds, or if <code>obj</code> is not large
 952      * enough to hold the pixel data.
 953      * @param x         the X coordinate of the pixel location
 954      * @param y         the Y coordinate of the pixel location
 955      * @param obj       a primitive array containing pixel data
 956      * @param data      the DataBuffer containing the image data
 957      * @see #getDataElements(int, int, Object, DataBuffer)
 958      */
 959     public void setDataElements(int x, int y, Object obj, DataBuffer data) {
 960         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
 961             throw new ArrayIndexOutOfBoundsException
 962                 ("Coordinate out of bounds!");
 963         }
 964 
 965         int type = getTransferType();
 966         int numDataElems = getNumDataElements();
 967         int pixelOffset = y*scanlineStride + x*pixelStride;
 968 
 969         switch(type) {
 970 
 971         case DataBuffer.TYPE_BYTE:
 972 
 973             byte[] barray = (byte[])obj;
 974 
 975             for (int i=0; i<numDataElems; i++) {
 976                 data.setElem(bankIndices[i], pixelOffset + bandOffsets[i],
 977                            ((int)barray[i])&0xff);
 978             }
 979             break;
 980 
 981         case DataBuffer.TYPE_USHORT:
 982         case DataBuffer.TYPE_SHORT:
 983 
 984             short[] sarray = (short[])obj;
 985 
 986             for (int i=0; i<numDataElems; i++) {
 987                 data.setElem(bankIndices[i], pixelOffset + bandOffsets[i],
 988                            ((int)sarray[i])&0xffff);
 989             }
 990             break;
 991 
 992         case DataBuffer.TYPE_INT:
 993 
 994             int[] iarray = (int[])obj;
 995 
 996             for (int i=0; i<numDataElems; i++) {
 997                 data.setElem(bankIndices[i],
 998                              pixelOffset + bandOffsets[i], iarray[i]);
 999             }
1000             break;
1001 
1002         case DataBuffer.TYPE_FLOAT:
1003 
1004             float[] farray = (float[])obj;
1005 
1006             for (int i=0; i<numDataElems; i++) {
1007                 data.setElemFloat(bankIndices[i],
1008                              pixelOffset + bandOffsets[i], farray[i]);
1009             }
1010             break;
1011 
1012         case DataBuffer.TYPE_DOUBLE:
1013 
1014             double[] darray = (double[])obj;
1015 
1016             for (int i=0; i<numDataElems; i++) {
1017                 data.setElemDouble(bankIndices[i],
1018                              pixelOffset + bandOffsets[i], darray[i]);
1019             }
1020             break;
1021 
1022         }
1023     }
1024 
1025     /**
1026      * Sets a pixel in the <code>DataBuffer</code> using an int array of
1027      * samples for input.  An <code>ArrayIndexOutOfBoundsException</code>
1028      * might be thrown if the coordinates are
1029      * not in bounds.
1030      * @param x         The X coordinate of the pixel location
1031      * @param y         The Y coordinate of the pixel location
1032      * @param iArray    The input samples in an int array
1033      * @param data      The DataBuffer containing the image data
1034      * @see #getPixel(int, int, int[], DataBuffer)
1035      */
1036     public void setPixel(int x, int y, int iArray[], DataBuffer data) {
1037         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
1038             throw new ArrayIndexOutOfBoundsException
1039                 ("Coordinate out of bounds!");
1040         }
1041        int pixelOffset = y*scanlineStride + x*pixelStride;
1042        for (int i=0; i<numBands; i++) {
1043            data.setElem(bankIndices[i],
1044                         pixelOffset + bandOffsets[i],iArray[i]);
1045        }
1046     }
1047 
1048     /**
1049      * Sets all samples for a rectangle of pixels from an int array containing
1050      * one sample per array element.
1051      * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if the
1052      * coordinates are not in bounds.
1053      * @param x         The X coordinate of the upper left pixel location
1054      * @param y         The Y coordinate of the upper left pixel location
1055      * @param w         The width of the pixel rectangle
1056      * @param h         The height of the pixel rectangle
1057      * @param iArray    The input samples in an int array
1058      * @param data      The DataBuffer containing the image data
1059      * @see #getPixels(int, int, int, int, int[], DataBuffer)
1060      */
1061     public void setPixels(int x, int y, int w, int h,
1062                           int iArray[], DataBuffer data) {
1063         int x1 = x + w;
1064         int y1 = y + h;
1065 
1066         if (x < 0 || x >= width || w > width || x1 < 0 || x1 > width ||
1067             y < 0 || y >= height || h > height || y1 < 0 || y1 >  height)
1068         {
1069             throw new ArrayIndexOutOfBoundsException
1070                 ("Coordinate out of bounds!");
1071         }
1072 
1073         int lineOffset = y*scanlineStride + x*pixelStride;
1074         int srcOffset = 0;
1075 
1076         for (int i = 0; i < h; i++) {
1077            int pixelOffset = lineOffset;
1078            for (int j = 0; j < w; j++) {
1079               for (int k=0; k < numBands; k++) {
1080                  data.setElem(bankIndices[k], pixelOffset + bandOffsets[k],
1081                               iArray[srcOffset++]);
1082               }
1083               pixelOffset += pixelStride;
1084            }
1085            lineOffset += scanlineStride;
1086         }
1087     }
1088 
1089     /**
1090      * Sets a sample in the specified band for the pixel located at (x,y)
1091      * in the <code>DataBuffer</code> using an int for input.
1092      * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if the
1093      * coordinates are not in bounds.
1094      * @param x         The X coordinate of the pixel location
1095      * @param y         The Y coordinate of the pixel location
1096      * @param b         the band to set
1097      * @param s         the input sample as an int
1098      * @param data      the DataBuffer containing the image data
1099      * @see #getSample(int, int, int, DataBuffer)
1100      */
1101     public void setSample(int x, int y, int b, int s,
1102                           DataBuffer data) {
1103         // Bounds check for 'b' will be performed automatically
1104         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
1105             throw new ArrayIndexOutOfBoundsException
1106                 ("Coordinate out of bounds!");
1107         }
1108         data.setElem(bankIndices[b],
1109                      y*scanlineStride + x*pixelStride + bandOffsets[b], s);
1110     }
1111 
1112     /**
1113      * Sets a sample in the specified band for the pixel located at (x,y)
1114      * in the <code>DataBuffer</code> using a float for input.
1115      * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if
1116      * the coordinates are not in bounds.
1117      * @param x         The X coordinate of the pixel location
1118      * @param y         The Y coordinate of the pixel location
1119      * @param b         The band to set
1120      * @param s         The input sample as a float
1121      * @param data      The DataBuffer containing the image data
1122      * @see #getSample(int, int, int, DataBuffer)
1123      */
1124     public void setSample(int x, int y, int b,
1125                           float s ,
1126                           DataBuffer data) {
1127         // Bounds check for 'b' will be performed automatically
1128         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
1129             throw new ArrayIndexOutOfBoundsException
1130                 ("Coordinate out of bounds!");
1131         }
1132         data.setElemFloat(bankIndices[b],
1133                           y*scanlineStride + x*pixelStride + bandOffsets[b],
1134                           s);
1135     }
1136 
1137     /**
1138      * Sets a sample in the specified band for the pixel located at (x,y)
1139      * in the <code>DataBuffer</code> using a double for input.
1140      * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if
1141      * the coordinates are not in bounds.
1142      * @param x         The X coordinate of the pixel location
1143      * @param y         The Y coordinate of the pixel location
1144      * @param b         The band to set
1145      * @param s         The input sample as a double
1146      * @param data      The DataBuffer containing the image data
1147      * @see #getSample(int, int, int, DataBuffer)
1148      */
1149     public void setSample(int x, int y, int b,
1150                           double s,
1151                           DataBuffer data) {
1152         // Bounds check for 'b' will be performed automatically
1153         if ((x < 0) || (y < 0) || (x >= width) || (y >= height)) {
1154             throw new ArrayIndexOutOfBoundsException
1155                 ("Coordinate out of bounds!");
1156         }
1157         data.setElemDouble(bankIndices[b],
1158                           y*scanlineStride + x*pixelStride + bandOffsets[b],
1159                           s);
1160     }
1161 
1162     /**
1163      * Sets the samples in the specified band for the specified rectangle
1164      * of pixels from an int array containing one sample per data array element.
1165      * An <code>ArrayIndexOutOfBoundsException</code> might be thrown if the
1166      * coordinates are not in bounds.
1167      * @param x         The X coordinate of the upper left pixel location
1168      * @param y         The Y coordinate of the upper left pixel location
1169      * @param w         The width of the pixel rectangle
1170      * @param h         The height of the pixel rectangle
1171      * @param b         The band to set
1172      * @param iArray    The input samples in an int array
1173      * @param data      The DataBuffer containing the image data
1174      * @see #getSamples(int, int, int, int, int, int[], DataBuffer)
1175      */
1176     public void setSamples(int x, int y, int w, int h, int b,
1177                            int iArray[], DataBuffer data) {
1178         // Bounds check for 'b' will be performed automatically
1179         if ((x < 0) || (y < 0) || (x + w > width) || (y + h > height)) {
1180             throw new ArrayIndexOutOfBoundsException
1181                 ("Coordinate out of bounds!");
1182         }
1183         int lineOffset = y*scanlineStride + x*pixelStride + bandOffsets[b];
1184         int srcOffset = 0;
1185 
1186         for (int i = 0; i < h; i++) {
1187            int sampleOffset = lineOffset;
1188            for (int j = 0; j < w; j++) {
1189               data.setElem(bankIndices[b], sampleOffset, iArray[srcOffset++]);
1190               sampleOffset += pixelStride;
1191            }
1192            lineOffset += scanlineStride;
1193         }
1194     }
1195 
1196     public boolean equals(Object o) {
1197         if ((o == null) || !(o instanceof ComponentSampleModel)) {
1198             return false;
1199         }
1200 
1201         ComponentSampleModel that = (ComponentSampleModel)o;
1202         return this.width == that.width &&
1203             this.height == that.height &&
1204             this.numBands == that.numBands &&
1205             this.dataType == that.dataType &&
1206             Arrays.equals(this.bandOffsets, that.bandOffsets) &&
1207             Arrays.equals(this.bankIndices, that.bankIndices) &&
1208             this.numBands == that.numBands &&
1209             this.numBanks == that.numBanks &&
1210             this.scanlineStride == that.scanlineStride &&
1211             this.pixelStride == that.pixelStride;
1212     }
1213 
1214     // If we implement equals() we must also implement hashCode
1215     public int hashCode() {
1216         int hash = 0;
1217         hash = width;
1218         hash <<= 8;
1219         hash ^= height;
1220         hash <<= 8;
1221         hash ^= numBands;
1222         hash <<= 8;
1223         hash ^= dataType;
1224         hash <<= 8;
1225         for (int i = 0; i < bandOffsets.length; i++) {
1226             hash ^= bandOffsets[i];
1227             hash <<= 8;
1228         }
1229         for (int i = 0; i < bankIndices.length; i++) {
1230             hash ^= bankIndices[i];
1231             hash <<= 8;
1232         }
1233         hash ^= numBands;
1234         hash <<= 8;
1235         hash ^= numBanks;
1236         hash <<= 8;
1237         hash ^= scanlineStride;
1238         hash <<= 8;
1239         hash ^= pixelStride;
1240         return hash;
1241     }
1242 }