Frames | No Frames |
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: }