Source for java.awt.image.ComponentSampleModel

   1: /* Copyright (C) 2000, 2002, 2006,  Free Software Foundation
   2: 
   3: This file is part of GNU Classpath.
   4: 
   5: GNU Classpath is free software; you can redistribute it and/or modify
   6: it under the terms of the GNU General Public License as published by
   7: the Free Software Foundation; either version 2, or (at your option)
   8: any later version.
   9: 
  10: GNU Classpath is distributed in the hope that it will be useful, but
  11: WITHOUT ANY WARRANTY; without even the implied warranty of
  12: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13: General Public License for more details.
  14: 
  15: You should have received a copy of the GNU General Public License
  16: along with GNU Classpath; see the file COPYING.  If not, write to the
  17: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  18: 02110-1301 USA.
  19: 
  20: Linking this library statically or dynamically with other modules is
  21: making a combined work based on this library.  Thus, the terms and
  22: conditions of the GNU General Public License cover the whole
  23: combination.
  24: 
  25: As a special exception, the copyright holders of this library give you
  26: permission to link this library with independent modules to produce an
  27: executable, regardless of the license terms of these independent
  28: modules, and to copy and distribute the resulting executable under
  29: terms of your choice, provided that you also meet, for each linked
  30: independent module, the terms and conditions of the license of that
  31: module.  An independent module is a module which is not derived from
  32: or based on this library.  If you modify this library, you may extend
  33: this exception to your version of the library, but you are not
  34: obligated to do so.  If you do not wish to do so, delete this
  35: exception statement from your version. */
  36: 
  37: package java.awt.image;
  38: 
  39: import java.util.Arrays;
  40: 
  41: /**
  42:  * ComponentSampleModel supports a flexible organization of pixel samples in
  43:  * memory, permitting pixel samples to be interleaved by band, by scanline,
  44:  * and by pixel.
  45:  *
  46:  * A DataBuffer for this sample model has K banks of data.  Pixels have N
  47:  * samples, so there are N bands in the DataBuffer.  Each band is completely
  48:  * contained in one bank of data, but a bank may contain more than one band.
  49:  * Each pixel sample is stored in a single data element.
  50:  *
  51:  * Within a bank, each band begins at an offset stored in bandOffsets.  The
  52:  * banks containing the band is given by bankIndices.  Within the bank, there
  53:  * are three dimensions - band, pixel, and scanline.  The dimension ordering
  54:  * is controlled by bandOffset, pixelStride, and scanlineStride, which means
  55:  * that any combination of interleavings is supported.
  56:  *
  57:  * @author Rolf W. Rasmussen (rolfwr@ii.uib.no)
  58:  */
  59: public class ComponentSampleModel extends SampleModel
  60: {
  61:   /** The offsets to the first sample for each band. */
  62:   protected int[] bandOffsets;
  63:   
  64:   /** The indices of the bank used to store each band in a data buffer. */
  65:   protected int[] bankIndices;
  66:   
  67:   /** 
  68:    * The number of bands in the image.
  69:    * @specnote This field shadows the protected numBands in SampleModel.
  70:    */
  71:   protected int numBands;
  72:   
  73:   /** Used when creating data buffers. */
  74:   protected int numBanks;
  75: 
  76:   /** 
  77:    * The number of data elements between a sample in one row and the 
  78:    * corresponding sample in the next row.
  79:    */
  80:   protected int scanlineStride;
  81:   
  82:   /**
  83:    * The number of data elements between a sample for one pixel and the 
  84:    * corresponding sample for the next pixel in the same row.
  85:    */
  86:   protected int pixelStride;
  87: 
  88:   /**
  89:    * Creates a new sample model that assumes that all bands are stored in a 
  90:    * single bank of the {@link DataBuffer}.
  91:    * <p>
  92:    * Note that the <code>bandOffsets</code> array is copied to internal storage
  93:    * to prevent subsequent changes to the array from affecting this object.
  94:    * 
  95:    * @param dataType  the data type (one of {@link DataBuffer#TYPE_BYTE},
  96:    *   {@link DataBuffer#TYPE_USHORT}, {@link DataBuffer#TYPE_SHORT},
  97:    *   {@link DataBuffer#TYPE_INT}, {@link DataBuffer#TYPE_FLOAT} or 
  98:    *   {@link DataBuffer#TYPE_DOUBLE}).
  99:    * @param w  the width in pixels.
 100:    * @param h  the height in pixels.
 101:    * @param pixelStride  the number of data elements in the step from a sample
 102:    *   in one pixel to the corresponding sample in the next pixel.
 103:    * @param scanlineStride  the number of data elements in the step from a 
 104:    *   sample in a pixel to the corresponding sample in the pixel in the next
 105:    *   row.
 106:    * @param bandOffsets  the offset to the first element for each band, with 
 107:    *   the size of the array defining the number of bands (<code>null</code>
 108:    *   not permitted).
 109:    *   
 110:    * @throws IllegalArgumentException if <code>dataType</code> is not one of
 111:    *   the specified values.
 112:    * @throws IllegalArgumentException if <code>w</code> is less than or equal
 113:    *   to zero.
 114:    * @throws IllegalArgumentException if <code>h</code> is less than or equal 
 115:    *   to zero.
 116:    * @throws IllegalArgumentException if <code>w * h</code> exceeds
 117:    *   {@link Integer#MAX_VALUE}.
 118:    * @throws IllegalArgumentException if <code>pixelStride</code> is negative.
 119:    * @throws IllegalArgumentException if <code>scanlineStride</code> is less 
 120:    *   than or equal to zero.
 121:    * @throws IllegalArgumentException if <code>bandOffsets</code> has zero 
 122:    *   length.
 123:    */
 124:   public ComponentSampleModel(int dataType,
 125:                               int w, int h,
 126:                               int pixelStride,
 127:                               int scanlineStride,
 128:                               int[] bandOffsets)
 129:   {
 130:     this(dataType, w, h, pixelStride, scanlineStride,
 131:          new int[bandOffsets.length], bandOffsets);
 132:   }
 133:     
 134:   /**
 135:    * Creates a new sample model that assumes that all bands are stored in a 
 136:    * single bank of the {@link DataBuffer}.
 137:    * 
 138:    * @param dataType  the data type (one of {@link DataBuffer#TYPE_BYTE},
 139:    *   {@link DataBuffer#TYPE_USHORT}, {@link DataBuffer#TYPE_SHORT},
 140:    *   {@link DataBuffer#TYPE_INT}, {@link DataBuffer#TYPE_FLOAT} or 
 141:    *   {@link DataBuffer#TYPE_DOUBLE}).
 142:    * @param w  the width in pixels.
 143:    * @param h  the height in pixels.
 144:    * @param pixelStride  the number of data elements in the step from a sample
 145:    *   in one pixel to the corresponding sample in the next pixel.
 146:    * @param scanlineStride  the number of data elements in the step from a 
 147:    *   sample in a pixel to the corresponding sample in the pixel in the next
 148:    *   row.
 149:    * @param bankIndices  the index of the bank in which each band is stored 
 150:    *   (<code>null</code> not permitted).  This array is copied to internal
 151:    *   storage so that subsequent updates to the array do not affect the sample 
 152:    *   model.
 153:    * @param bandOffsets  the offset to the first element for each band, with 
 154:    *   the size of the array defining the number of bands (<code>null</code>
 155:    *   not permitted).  This array is copied to internal storage so that 
 156:    *   subsequent updates to the array do not affect the sample model.
 157:    *   
 158:    * @throws IllegalArgumentException if <code>dataType</code> is not one of
 159:    *   the specified values.
 160:    * @throws IllegalArgumentException if <code>w</code> is less than or equal
 161:    *   to zero.
 162:    * @throws IllegalArgumentException if <code>h</code> is less than or equal 
 163:    *   to zero.
 164:    * @throws IllegalArgumentException if <code>w * h</code> exceeds
 165:    *   {@link Integer#MAX_VALUE}.
 166:    * @throws IllegalArgumentException if <code>pixelStride</code> is negative.
 167:    * @throws IllegalArgumentException if <code>scanlineStride</code> is less 
 168:    *   than or equal to zero.
 169:    * @throws IllegalArgumentException if <code>bandOffsets</code> has zero 
 170:    *   length.
 171:    */
 172:   public ComponentSampleModel(int dataType,
 173:                               int w, int h,
 174:                               int pixelStride,
 175:                               int scanlineStride,
 176:                               int[] bankIndices,
 177:                               int[] bandOffsets)
 178:   {
 179:     super(dataType, w, h, bandOffsets.length);
 180:     
 181:     // super permits DataBuffer.TYPE_UNDEFINED but this class doesn't...
 182:     if (dataType == DataBuffer.TYPE_UNDEFINED)
 183:       throw new IllegalArgumentException("Unsupported dataType.");
 184:     
 185:     if ((pixelStride < 0) || (scanlineStride < 0) || (bandOffsets.length < 1) 
 186:         || (bandOffsets.length != bankIndices.length))
 187:       throw new IllegalArgumentException();
 188:     
 189:     this.bandOffsets = (int[]) bandOffsets.clone();
 190:     this.bankIndices = (int[]) bankIndices.clone();
 191:     this.numBands = bandOffsets.length;
 192: 
 193:     this.numBanks = 0;
 194:     for (int b = 0; b < bankIndices.length; b++)
 195:       this.numBanks = Math.max(this.numBanks, bankIndices[b] + 1);
 196: 
 197:     this.scanlineStride = scanlineStride;
 198:     this.pixelStride = pixelStride;
 199: 
 200:   }             
 201: 
 202:   /**
 203:    * Creates a new sample model that is compatible with this one, but with the
 204:    * specified dimensions.
 205:    * 
 206:    * @param w  the width (must be greater than zero).
 207:    * @param h  the height (must be greater than zero).
 208:    * 
 209:    * @return A new sample model.
 210:    */
 211:   public SampleModel createCompatibleSampleModel(int w, int h)
 212:   {
 213:     return new ComponentSampleModel(dataType, w, h, pixelStride,
 214:                                     scanlineStride, bankIndices,
 215:                                     bandOffsets);
 216:   }
 217: 
 218:   /**
 219:    * Creates a new sample model that provides access to a subset of the bands
 220:    * that this sample model supports.
 221:    * 
 222:    * @param bands  the bands (<code>null</code> not permitted).
 223:    * 
 224:    * @return The new sample model.
 225:    */
 226:   public SampleModel createSubsetSampleModel(int[] bands)
 227:   {
 228:     int numBands = bands.length;
 229:     
 230:     int[] bankIndices = new int[numBands];
 231:     int[] bandOffsets = new int[numBands];
 232:     for (int b = 0; b < numBands; b++)
 233:       {
 234:         bankIndices[b] = this.bankIndices[bands[b]];
 235:         bandOffsets[b] = this.bandOffsets[bands[b]];
 236:       }
 237: 
 238:     return new ComponentSampleModel(dataType, width, height, pixelStride,
 239:                                     scanlineStride, bankIndices,
 240:                                     bandOffsets);
 241:   }
 242: 
 243:   /**
 244:    * Creates a new data buffer that is compatible with this sample model.
 245:    * 
 246:    * @return The new data buffer.
 247:    */
 248:   public DataBuffer createDataBuffer()
 249:   {
 250:     // Maybe this value should be precalculated in the constructor?
 251:     int highestOffset = 0;
 252:     for (int b = 0; b < numBands; b++)
 253:       highestOffset = Math.max(highestOffset, bandOffsets[b]);    
 254:     int size = pixelStride * (width - 1) + scanlineStride * (height - 1) 
 255:         + highestOffset + 1;
 256: 
 257:     DataBuffer buffer = null;
 258:     switch (getTransferType())
 259:       {
 260:       case DataBuffer.TYPE_BYTE:
 261:         buffer = new DataBufferByte(size, numBanks);
 262:         break;
 263:       case DataBuffer.TYPE_SHORT:
 264:         buffer = new DataBufferShort(size, numBanks);
 265:         break;
 266:       case DataBuffer.TYPE_USHORT:
 267:         buffer = new DataBufferUShort(size, numBanks);
 268:         break;
 269:       case DataBuffer.TYPE_INT:
 270:         buffer = new DataBufferInt(size, numBanks);
 271:         break;
 272:       case DataBuffer.TYPE_FLOAT:
 273:         buffer = new DataBufferFloat(size, numBanks);
 274:         break;
 275:       case DataBuffer.TYPE_DOUBLE:
 276:         buffer = new DataBufferDouble(size, numBanks);
 277:         break;
 278:       }
 279:     return buffer;
 280:   }
 281: 
 282:   /**
 283:    * Returns the offset of the sample in band 0 for the pixel at location
 284:    * <code>(x, y)</code>.  This offset can be used to read a sample value from
 285:    * a {@link DataBuffer}.
 286:    * 
 287:    * @param x  the x-coordinate.
 288:    * @param y  the y-coordinate.
 289:    * 
 290:    * @return The offset.
 291:    * 
 292:    * @see #getOffset(int, int, int)
 293:    */
 294:   public int getOffset(int x, int y)
 295:   {
 296:     return getOffset(x, y, 0);
 297:   }
 298: 
 299:   /**
 300:    * Returns the offset of the sample in band <code>b</code> for the pixel at
 301:    * location <code>(x, y)</code>.  This offset can be used to read a sample
 302:    * value from a {@link DataBuffer}.
 303:    * 
 304:    * @param x  the x-coordinate.
 305:    * @param y  the y-coordinate.
 306:    * @param b  the band index.
 307:    * 
 308:    * @return The offset.
 309:    */
 310:   public int getOffset(int x, int y, int b)
 311:   {
 312:     return bandOffsets[b] + pixelStride * x + scanlineStride * y;
 313:   }
 314: 
 315:   /**
 316:    * Returns the size in bits for each sample (one per band).  For this sample
 317:    * model, each band has the same sample size and this is determined by the
 318:    * data type for the sample model.
 319:    * 
 320:    * @return The sample sizes.
 321:    * 
 322:    * @see SampleModel#getDataType()
 323:    */
 324:   public final int[] getSampleSize()
 325:   {
 326:     int size = DataBuffer.getDataTypeSize(getDataType());
 327:     int[] sizes = new int[numBands];
 328: 
 329:     java.util.Arrays.fill(sizes, size);
 330:     return sizes;
 331:   }
 332: 
 333:   /**
 334:    * Returns the size in bits for the samples in the specified band.  In this
 335:    * class, the sample size is the same for every band and is determined from 
 336:    * the data type for the model.
 337:    * 
 338:    * @param band  the band index (ignored here).
 339:    * 
 340:    * @return The sample size in bits.
 341:    * 
 342:    * @see SampleModel#getDataType()
 343:    */
 344:   public final int getSampleSize(int band)
 345:   {
 346:     return DataBuffer.getDataTypeSize(getDataType());
 347:   }
 348: 
 349:   /**
 350:    * Returns the indices of the bank(s) in the {@link DataBuffer} used to 
 351:    * store the samples for each band.  The returned array is a copy, so that
 352:    * altering it will not impact the sample model.
 353:    * 
 354:    * @return The bank indices.
 355:    */
 356:   public final int[] getBankIndices()
 357:   {
 358:     return (int[]) bankIndices.clone();
 359:   }
 360: 
 361:   /**
 362:    * Returns the offsets to the first sample in each band.  The returned array
 363:    * is a copy, so that altering it will not impact the sample model.
 364:    * 
 365:    * @return The offsets.
 366:    */
 367:   public final int[] getBandOffsets()
 368:   {
 369:     return (int[]) bandOffsets.clone();
 370:   }
 371: 
 372:   /**
 373:    * Returns the distance (in terms of element indices) between the sample for
 374:    * one pixel and the corresponding sample for the equivalent pixel in the 
 375:    * next row.  This is used in the calculation of the element offset for
 376:    * retrieving samples from a {@link DataBuffer}.
 377:    * 
 378:    * @return The distance between pixel samples in consecutive rows.
 379:    */
 380:   public final int getScanlineStride()
 381:   {
 382:     return scanlineStride;
 383:   }
 384: 
 385:   /**
 386:    * Returns the distance (in terms of element indices) between the sample for 
 387:    * one pixel and the corresponding sample for the next pixel in a row.  This 
 388:    * is used in the calculation of the element offset for retrieving samples 
 389:    * from a {@link DataBuffer}.
 390:    * 
 391:    * @return The distance between pixel samples in the same row.
 392:    */
 393:   public final int getPixelStride()
 394:   {
 395:     return pixelStride;
 396:   }
 397: 
 398:   /**
 399:    * Returns the number of data elements used to store the samples for one 
 400:    * pixel.  In this model, this is the same as the number of bands.
 401:    * 
 402:    * @return The number of data elements used to store the samples for one 
 403:    *   pixel.
 404:    */
 405:   public final int getNumDataElements()
 406:   {
 407:     return numBands;
 408:   }
 409: 
 410:   /**
 411:    * Returns the samples for the pixel at location <code>(x, y)</code> in
 412:    * a primitive array (the array type is determined by the data type for 
 413:    * this model).  The <code>obj</code> argument provides an option to supply
 414:    * an existing array to hold the result, if this is <code>null</code> a new
 415:    * array will be allocated.
 416:    * 
 417:    * @param x  the x-coordinate.
 418:    * @param y  the y-coordinate.
 419:    * @param obj  a primitive array that, if not <code>null</code>, will be 
 420:    *   used to store and return the sample values.
 421:    * @param data  the data buffer (<code>null</code> not permitted).
 422:    * 
 423:    * @return An array of sample values for the specified pixel.
 424:    */
 425:   public Object getDataElements(int x, int y, Object obj, DataBuffer data)
 426:   {
 427:     int type = getTransferType();
 428:     int numDataEls = getNumDataElements();
 429:     int offset = y * scanlineStride + x * pixelStride;
 430:     switch (type)
 431:       {
 432:       case DataBuffer.TYPE_BYTE:
 433:         byte[] bData;
 434:         if (obj == null)
 435:           bData = new byte[numDataEls];
 436:         else
 437:           bData = (byte[]) obj;
 438:         for (int i = 0; i < numDataEls; i++)
 439:           {
 440:             bData[i] = (byte) data.getElem(bankIndices[i],
 441:                                            offset + bandOffsets[i]);
 442:           }
 443:         obj = bData;
 444:         break;
 445:       case DataBuffer.TYPE_SHORT:
 446:       case DataBuffer.TYPE_USHORT:
 447:         short[] sData;
 448:         if (obj == null)
 449:           sData = new short[numDataEls];
 450:         else
 451:           sData = (short[]) obj;
 452:         for (int i = 0; i < numDataEls; i++)
 453:           {
 454:             sData[i] = (short) data.getElem(bankIndices[i],
 455:                                             offset + bandOffsets[i]);
 456:           }
 457:         obj = sData;
 458:         break;
 459:       case DataBuffer.TYPE_INT:
 460:         int[] iData;
 461:         if (obj == null)
 462:           iData = new int[numDataEls];
 463:         else
 464:           iData = (int[]) obj;
 465:         for (int i = 0; i < numDataEls; i++)
 466:           {
 467:             iData[i] = data.getElem(bankIndices[i], offset + bandOffsets[i]);
 468:           }
 469:         obj = iData;
 470:         break;
 471:       case DataBuffer.TYPE_FLOAT:
 472:         float[] fData;
 473:         if (obj == null)
 474:           fData = new float[numDataEls];
 475:         else
 476:           fData = (float[]) obj;
 477:         for (int i = 0; i < numDataEls; i++)
 478:           {
 479:             fData[i] = data.getElemFloat(bankIndices[i],
 480:                                          offset + bandOffsets[i]);
 481:           }
 482:         obj = fData;
 483:         break;
 484:       case DataBuffer.TYPE_DOUBLE:
 485:         double[] dData;
 486:         if (obj == null)
 487:           dData = new double[numDataEls];
 488:         else
 489:           dData = (double[]) obj;
 490:         for (int i = 0; i < numDataEls; i++)
 491:           {
 492:             dData[i] = data.getElemDouble(bankIndices[i],
 493:                                           offset + bandOffsets[i]);
 494:           }
 495:         obj = dData;
 496:         break;
 497:       }
 498:     return obj;
 499:   }
 500: 
 501: 
 502:   /**
 503:    * Returns all the samples for the pixel at location <code>(x, y)</code>
 504:    * stored in the specified data buffer.
 505:    * 
 506:    * @param x  the x-coordinate.
 507:    * @param y  the y-coordinate.
 508:    * @param iArray  an array that will be populated with the sample values and
 509:    *   returned as the result.  The size of this array should be equal to the 
 510:    *   number of bands in the model.  If the array is <code>null</code>, a new
 511:    *   array is created.
 512:    * @param data  the data buffer (<code>null</code> not permitted).
 513:    * 
 514:    * @return The samples for the specified pixel.
 515:    * 
 516:    * @see #setPixel(int, int, int[], DataBuffer)
 517:    */
 518:   public int[] getPixel(int x, int y, int[] iArray, DataBuffer data)
 519:   {
 520:     if (x < 0 || x >= width || y < 0 || y >= height)
 521:       throw new ArrayIndexOutOfBoundsException("Pixel (" + x + ", " + y 
 522:                                                + ") is out of bounds.");
 523:     int offset = pixelStride * x + scanlineStride * y;
 524:     if (iArray == null)
 525:       iArray = new int[numBands];
 526:     for (int b = 0; b < numBands; b++)
 527:       {
 528:         iArray[b] = data.getElem(bankIndices[b], offset + bandOffsets[b]);
 529:       }
 530:     return iArray;
 531:   }
 532: 
 533:   /**
 534:    * Returns the samples for all the pixels in a rectangular region.
 535:    * 
 536:    * @param x  the x-coordinate.
 537:    * @param y  the y-coordinate.
 538:    * @param w  the width.
 539:    * @param h  the height.
 540:    * @param iArray  an array that if non-<code>null</code> will be populated 
 541:    *   with the sample values and returned as the result.
 542:    * @param data  the data buffer (<code>null</code> not permitted).
 543:    * 
 544:    * @return The samples for all the pixels in the rectangle.
 545:    */
 546:   public int[] getPixels(int x, int y, int w, int h, int[] iArray,
 547:                          DataBuffer data)
 548:   {
 549:     int offset = pixelStride * x + scanlineStride * y;
 550:     if (iArray == null) 
 551:       iArray = new int[numBands * w * h];
 552:     int outOffset = 0;
 553:     for (y = 0; y < h; y++)
 554:       {
 555:         int lineOffset = offset;
 556:         for (x = 0; x < w; x++)
 557:           {
 558:             for (int b = 0; b < numBands; b++)
 559:               {
 560:                 iArray[outOffset++] 
 561:                     = data.getElem(bankIndices[b], lineOffset+bandOffsets[b]);
 562:               }
 563:             lineOffset += pixelStride;
 564:           }
 565:         offset += scanlineStride;
 566:       }
 567:     return iArray;
 568:   }
 569:  
 570:   /**
 571:    * Returns the sample for band <code>b</code> of the pixel at 
 572:    * <code>(x, y)</code> that is stored in the specified data buffer.
 573:    * 
 574:    * @param x  the x-coordinate.
 575:    * @param y  the y-coordinate.
 576:    * @param b  the band index.
 577:    * @param data  the data buffer (<code>null</code> not permitted).
 578:    * 
 579:    * @return The sample value.
 580:    * 
 581:    * @throws ArrayIndexOutOfBoundsException if <code>(x, y)</code> is outside 
 582:    *     the bounds <code>[0, 0, width, height]</code>.
 583:    *     
 584:    * @see #setSample(int, int, int, int, DataBuffer)
 585:    */
 586:   public int getSample(int x, int y, int b, DataBuffer data)
 587:   {
 588:     if (x < 0 || x >= width || y < 0 || y >= height)
 589:       throw new ArrayIndexOutOfBoundsException("Sample (" + x + ", " + y 
 590:                                                + ") is out of bounds.");
 591:     return data.getElem(bankIndices[b], getOffset(x, y, b));
 592:   }
 593: 
 594:   /**
 595:    * Sets the samples for the pixel at location <code>(x, y)</code> from the 
 596:    * supplied primitive array (the array type must be consistent with the data 
 597:    * type for this model).
 598:    * 
 599:    * @param x  the x-coordinate.
 600:    * @param y  the y-coordinate.
 601:    * @param obj  a primitive array containing the pixel's sample values.
 602:    * @param data  the data buffer (<code>null</code> not permitted).
 603:    * 
 604:    * @see #setDataElements(int, int, Object, DataBuffer)
 605:    */
 606:   public void setDataElements(int x, int y, Object obj, DataBuffer data)
 607:   {
 608:     int type = getTransferType();
 609:     int numDataEls = getNumDataElements();
 610:     int offset = y * scanlineStride + x * pixelStride;
 611:     switch (type)
 612:       {
 613:       case DataBuffer.TYPE_BYTE:
 614:         byte[] bData = (byte[]) obj;
 615:         for (int i = 0; i < numDataEls; i++)
 616:           {
 617:             data.setElem(bankIndices[i], offset + bandOffsets[i],
 618:                          ((int) bData[i]) & 0xFF);
 619:           }
 620:         break;
 621:       case DataBuffer.TYPE_SHORT:
 622:       case DataBuffer.TYPE_USHORT:
 623:         short[] sData = (short[]) obj;
 624:         for (int i = 0; i < numDataEls; i++)
 625:           {
 626:             data.setElem(bankIndices[i], offset + bandOffsets[i],
 627:                          ((int) sData[i]) & 0xFFFF);
 628:           }
 629:         break;
 630:       case DataBuffer.TYPE_INT:
 631:         int[] iData = (int[]) obj;
 632:         for (int i = 0; i < numDataEls; i++)
 633:           {
 634:             data.setElem(bankIndices[i], offset + bandOffsets[i], iData[i]);
 635:           }
 636:         break;
 637:       case DataBuffer.TYPE_FLOAT:
 638:         float[] fData = (float[]) obj;
 639:         for (int i = 0; i < numDataEls; i++)
 640:           {
 641:             data.setElemFloat(bankIndices[i], offset + bandOffsets[i],
 642:                               fData[i]);
 643:           }
 644:         break;
 645:       case DataBuffer.TYPE_DOUBLE:
 646:         double[] dData = (double[]) obj;
 647:         for (int i = 0; i < numDataEls; i++)
 648:           {
 649:             data.setElemDouble(bankIndices[i], offset + bandOffsets[i],
 650:                                dData[i]);
 651:           }
 652:         break;
 653:       }
 654:   }
 655:   
 656:   /**
 657:    * Sets the sample values for the pixel at location <code>(x, y)</code>
 658:    * stored in the specified data buffer.
 659:    * 
 660:    * @param x  the x-coordinate.
 661:    * @param y  the y-coordinate.
 662:    * @param iArray  the pixel sample values (<code>null</code> not permitted).
 663:    * @param data  the data buffer (<code>null</code> not permitted).
 664:    * 
 665:    * @see #getPixel(int, int, int[], DataBuffer)
 666:    */
 667:   public void setPixel(int x, int y, int[] iArray, DataBuffer data)
 668:   {
 669:     int offset = pixelStride * x + scanlineStride * y;
 670:     for (int b = 0; b < numBands; b++)
 671:       data.setElem(bankIndices[b], offset + bandOffsets[b], iArray[b]);
 672:   }
 673:     
 674:   /**
 675:    * Sets the sample value for band <code>b</code> of the pixel at location
 676:    * <code>(x, y)</code> in the specified data buffer.
 677:    * 
 678:    * @param x  the x-coordinate.
 679:    * @param y  the y-coordinate.
 680:    * @param b  the band index.
 681:    * @param s  the sample value.
 682:    * @param data  the data buffer (<code>null</code> not permitted).
 683:    * 
 684:    * @see #getSample(int, int, int, DataBuffer)
 685:    */
 686:   public void setSample(int x, int y, int b, int s, DataBuffer data)
 687:   {
 688:     data.setElem(bankIndices[b], getOffset(x, y, b), s);
 689:   }
 690:   
 691:   /**
 692:    * Tests this sample model for equality with an arbitrary object.  Returns
 693:    * <code>true</code> if and only if:
 694:    * <ul>
 695:    * <li><code>obj</code> is not <code>null</code>;</li>
 696:    * <li><code>obj</code> is an instance of <code>ComponentSampleModel</code>;
 697:    *   </li>
 698:    * <li>both models have the same values for the <code>dataType</code>,
 699:    *   <code>width</code>, <code>height</code>, <code>pixelStride</code>,
 700:    *   <code>scanlineStride</code>, <code>bandOffsets</code> and
 701:    *   <code>bankIndices</code> fields.</li>
 702:    * </ul>
 703:    * 
 704:    * @param obj  the object to test (<code>null</code> permitted).
 705:    * 
 706:    * @return <code>true</code> if this sample model is equal to 
 707:    *   <code>obj</code>, and <code>false</code> otherwise.
 708:    */
 709:   public boolean equals(Object obj)
 710:   {
 711:     if (obj == null)
 712:       return false;
 713:     if (! (obj instanceof ComponentSampleModel))
 714:       return false;
 715:     ComponentSampleModel that = (ComponentSampleModel) obj;
 716:     if (this.dataType != that.dataType)
 717:       return false;
 718:     if (this.width != that.width)
 719:       return false;
 720:     if (this.height != that.height)
 721:       return false;
 722:     if (this.pixelStride != that.pixelStride)
 723:       return false;
 724:     if (this.scanlineStride != that.scanlineStride)
 725:       return false;
 726:     if (! Arrays.equals(this.bandOffsets, that.bandOffsets))
 727:       return false;
 728:     if (! Arrays.equals(this.bankIndices, that.bankIndices))
 729:       return false;
 730:     // couldn't find any difference, so...
 731:     return true;
 732:   }
 733:   
 734:   /**
 735:    * Returns a hash code for this sample model.
 736:    * 
 737:    * @return The hash code.
 738:    */
 739:   public int hashCode()
 740:   {
 741:     // this computation is based on the method described in Chapter 3
 742:     // of Joshua Bloch's Effective Java...
 743:     int result = 17;
 744:     result = 37 * result + dataType;
 745:     result = 37 * result + width;
 746:     result = 37 * result + height;
 747:     result = 37 * result + pixelStride;
 748:     result = 37 * result + scanlineStride;
 749:     for (int i = 0; i < bandOffsets.length; i++)
 750:       result = 37 * result + bandOffsets[i];
 751:     for (int i = 0; i < bankIndices.length; i++)
 752:       result = 37 * result + bankIndices[i];
 753:     return result;
 754:   }
 755: }