001/* Copyright (C) 2000, 2002, 2006, Free Software Foundation 002 003This file is part of GNU Classpath. 004 005GNU Classpath is free software; you can redistribute it and/or modify 006it under the terms of the GNU General Public License as published by 007the Free Software Foundation; either version 2, or (at your option) 008any later version. 009 010GNU Classpath is distributed in the hope that it will be useful, but 011WITHOUT ANY WARRANTY; without even the implied warranty of 012MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 013General Public License for more details. 014 015You should have received a copy of the GNU General Public License 016along with GNU Classpath; see the file COPYING. If not, write to the 017Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 01802110-1301 USA. 019 020Linking this library statically or dynamically with other modules is 021making a combined work based on this library. Thus, the terms and 022conditions of the GNU General Public License cover the whole 023combination. 024 025As a special exception, the copyright holders of this library give you 026permission to link this library with independent modules to produce an 027executable, regardless of the license terms of these independent 028modules, and to copy and distribute the resulting executable under 029terms of your choice, provided that you also meet, for each linked 030independent module, the terms and conditions of the license of that 031module. An independent module is a module which is not derived from 032or based on this library. If you modify this library, you may extend 033this exception to your version of the library, but you are not 034obligated to do so. If you do not wish to do so, delete this 035exception statement from your version. */ 036 037package java.awt.image; 038 039import java.util.Arrays; 040 041/** 042 * ComponentSampleModel supports a flexible organization of pixel samples in 043 * memory, permitting pixel samples to be interleaved by band, by scanline, 044 * and by pixel. 045 * 046 * A DataBuffer for this sample model has K banks of data. Pixels have N 047 * samples, so there are N bands in the DataBuffer. Each band is completely 048 * contained in one bank of data, but a bank may contain more than one band. 049 * Each pixel sample is stored in a single data element. 050 * 051 * Within a bank, each band begins at an offset stored in bandOffsets. The 052 * banks containing the band is given by bankIndices. Within the bank, there 053 * are three dimensions - band, pixel, and scanline. The dimension ordering 054 * is controlled by bandOffset, pixelStride, and scanlineStride, which means 055 * that any combination of interleavings is supported. 056 * 057 * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) 058 */ 059public class ComponentSampleModel extends SampleModel 060{ 061 /** The offsets to the first sample for each band. */ 062 protected int[] bandOffsets; 063 064 /** The indices of the bank used to store each band in a data buffer. */ 065 protected int[] bankIndices; 066 067 /** 068 * The number of bands in the image. 069 * @specnote This field shadows the protected numBands in SampleModel. 070 */ 071 protected int numBands; 072 073 /** Used when creating data buffers. */ 074 protected int numBanks; 075 076 /** 077 * The number of data elements between a sample in one row and the 078 * corresponding sample in the next row. 079 */ 080 protected int scanlineStride; 081 082 /** 083 * The number of data elements between a sample for one pixel and the 084 * corresponding sample for the next pixel in the same row. 085 */ 086 protected int pixelStride; 087 088 /** 089 * Creates a new sample model that assumes that all bands are stored in a 090 * single bank of the {@link DataBuffer}. 091 * <p> 092 * Note that the <code>bandOffsets</code> array is copied to internal storage 093 * to prevent subsequent changes to the array from affecting this object. 094 * 095 * @param dataType the data type (one of {@link DataBuffer#TYPE_BYTE}, 096 * {@link DataBuffer#TYPE_USHORT}, {@link DataBuffer#TYPE_SHORT}, 097 * {@link DataBuffer#TYPE_INT}, {@link DataBuffer#TYPE_FLOAT} or 098 * {@link DataBuffer#TYPE_DOUBLE}). 099 * @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}