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 gnu.java.awt.Buffers; 40: 41: import java.util.Arrays; 42: 43: /* FIXME: This class does not yet support data type TYPE_SHORT */ 44: 45: /** 46: * ComponentSampleModel supports a flexible organization of pixel samples in 47: * memory, permitting pixel samples to be interleaved by band, by scanline, 48: * and by pixel. 49: * 50: * A DataBuffer for this sample model has K banks of data. Pixels have N 51: * samples, so there are N bands in the DataBuffer. Each band is completely 52: * contained in one bank of data, but a bank may contain more than one band. 53: * Each pixel sample is stored in a single data element. 54: * 55: * Within a bank, each band begins at an offset stored in bandOffsets. The 56: * banks containing the band is given by bankIndices. Within the bank, there 57: * are three dimensions - band, pixel, and scanline. The dimension ordering 58: * is controlled by bandOffset, pixelStride, and scanlineStride, which means 59: * that any combination of interleavings is supported. 60: * 61: * @author Rolf W. Rasmussen (rolfwr@ii.uib.no) 62: */ 63: public class ComponentSampleModel extends SampleModel 64: { 65: /** The offsets to the first sample for each band. */ 66: protected int[] bandOffsets; 67: 68: /** The indices of the bank used to store each band in a data buffer. */ 69: protected int[] bankIndices; 70: 71: /** 72: * The number of bands in the image. 73: * @specnote This field shadows the protected numBands in SampleModel. 74: */ 75: protected int numBands; 76: 77: /** Used when creating data buffers. */ 78: protected int numBanks; 79: 80: /** 81: * The number of data elements between a sample in one row and the 82: * corresponding sample in the next row. 83: */ 84: protected int scanlineStride; 85: 86: /** 87: * The number of data elements between a sample for one pixel and the 88: * corresponding sample for the next pixel in the same row. 89: */ 90: protected int pixelStride; 91: 92: private boolean tightPixelPacking = false; 93: 94: /** 95: * Creates a new sample model that assumes that all bands are stored in a 96: * single bank of the {@link DataBuffer}. 97: * <p> 98: * Note that the <code>bandOffsets</code> array is copied to internal storage 99: * to prevent subsequent changes to the array from affecting this object. 100: * 101: * @param dataType the data type (one of {@link DataBuffer#TYPE_BYTE}, 102: * {@link DataBuffer#TYPE_USHORT}, {@link DataBuffer#TYPE_SHORT}, 103: * {@link DataBuffer#TYPE_INT}, {@link DataBuffer#TYPE_FLOAT} or 104: * {@link DataBuffer#TYPE_DOUBLE}). 105: * @param w the width in pixels. 106: * @param h the height in pixels. 107: * @param pixelStride the number of data elements in the step from a sample 108: * in one pixel to the corresponding sample in the next pixel. 109: * @param scanlineStride the number of data elements in the step from a 110: * sample in a pixel to the corresponding sample in the pixel in the next 111: * row. 112: * @param bandOffsets the offset to the first element for each band, with 113: * the size of the array defining the number of bands (<code>null</code> 114: * not permitted). 115: * 116: * @throws IllegalArgumentException if <code>dataType</code> is not one of 117: * the specified values. 118: * @throws IllegalArgumentException if <code>w</code> is less than or equal 119: * to zero. 120: * @throws IllegalArgumentException if <code>h</code> is less than or equal 121: * to zero. 122: * @throws IllegalArgumentException if <code>w * h</code> exceeds 123: * {@link Integer#MAX_VALUE}. 124: * @throws IllegalArgumentException if <code>pixelStride</code> is negative. 125: * @throws IllegalArgumentException if <code>scanlineStride</code> is less 126: * than or equal to zero. 127: * @throws IllegalArgumentException if <code>bandOffsets</code> has zero 128: * length. 129: */ 130: public ComponentSampleModel(int dataType, 131: int w, int h, 132: int pixelStride, 133: int scanlineStride, 134: int[] bandOffsets) 135: { 136: this(dataType, w, h, pixelStride, scanlineStride, 137: new int[bandOffsets.length], bandOffsets); 138: } 139: 140: /** 141: * Creates a new sample model that assumes that all bands are stored in a 142: * single bank of the {@link DataBuffer}. 143: * 144: * @param dataType the data type (one of {@link DataBuffer#TYPE_BYTE}, 145: * {@link DataBuffer#TYPE_USHORT}, {@link DataBuffer#TYPE_SHORT}, 146: * {@link DataBuffer#TYPE_INT}, {@link DataBuffer#TYPE_FLOAT} or 147: * {@link DataBuffer#TYPE_DOUBLE}). 148: * @param w the width in pixels. 149: * @param h the height in pixels. 150: * @param pixelStride the number of data elements in the step from a sample 151: * in one pixel to the corresponding sample in the next pixel. 152: * @param scanlineStride the number of data elements in the step from a 153: * sample in a pixel to the corresponding sample in the pixel in the next 154: * row. 155: * @param bankIndices the index of the bank in which each band is stored 156: * (<code>null</code> not permitted). This array is copied to internal 157: * storage so that subsequent updates to the array do not affect the sample 158: * model. 159: * @param bandOffsets the offset to the first element for each band, with 160: * the size of the array defining the number of bands (<code>null</code> 161: * not permitted). This array is copied to internal storage so that 162: * subsequent updates to the array do not affect the sample model. 163: * 164: * @throws IllegalArgumentException if <code>dataType</code> is not one of 165: * the specified values. 166: * @throws IllegalArgumentException if <code>w</code> is less than or equal 167: * to zero. 168: * @throws IllegalArgumentException if <code>h</code> is less than or equal 169: * to zero. 170: * @throws IllegalArgumentException if <code>w * h</code> exceeds 171: * {@link Integer#MAX_VALUE}. 172: * @throws IllegalArgumentException if <code>pixelStride</code> is negative. 173: * @throws IllegalArgumentException if <code>scanlineStride</code> is less 174: * than or equal to zero. 175: * @throws IllegalArgumentException if <code>bandOffsets</code> has zero 176: * length. 177: */ 178: public ComponentSampleModel(int dataType, 179: int w, int h, 180: int pixelStride, 181: int scanlineStride, 182: int[] bankIndices, 183: int[] bandOffsets) 184: { 185: super(dataType, w, h, bandOffsets.length); 186: 187: // super permits DataBuffer.TYPE_UNDEFINED but this class doesn't... 188: if (dataType == DataBuffer.TYPE_UNDEFINED) 189: throw new IllegalArgumentException("Unsupported dataType."); 190: 191: if ((pixelStride < 0) || (scanlineStride < 0) || (bandOffsets.length < 1) 192: || (bandOffsets.length != bankIndices.length)) 193: throw new IllegalArgumentException(); 194: 195: this.bandOffsets = (int[]) bandOffsets.clone(); 196: this.bankIndices = (int[]) bankIndices.clone(); 197: this.numBands = bandOffsets.length; 198: 199: this.numBanks = 0; 200: for (int b = 0; b < bankIndices.length; b++) 201: this.numBanks = Math.max(this.numBanks, bankIndices[b] + 1); 202: 203: this.scanlineStride = scanlineStride; 204: this.pixelStride = pixelStride; 205: 206: // See if we can use some speedups 207: 208: /* FIXME: May these checks should be reserved for the 209: PixelInterleavedSampleModel? */ 210: 211: if (pixelStride == numBands) 212: { 213: tightPixelPacking = true; 214: for (int b = 0; b < numBands; b++) { 215: if ((bandOffsets[b] != b) || (bankIndices[b] != 0)) 216: { 217: tightPixelPacking = false; 218: break; 219: } 220: } 221: } 222: } 223: 224: /** 225: * Creates a new sample model that is compatible with this one, but with the 226: * specified dimensions. 227: * 228: * @param w the width (must be greater than zero). 229: * @param h the height (must be greater than zero). 230: * 231: * @return A new sample model. 232: */ 233: public SampleModel createCompatibleSampleModel(int w, int h) 234: { 235: return new ComponentSampleModel(dataType, w, h, pixelStride, 236: scanlineStride, bankIndices, 237: bandOffsets); 238: } 239: 240: /** 241: * Creates a new sample model that provides access to a subset of the bands 242: * that this sample model supports. 243: * 244: * @param bands the bands (<code>null</code> not permitted). 245: * 246: * @return The new sample model. 247: */ 248: public SampleModel createSubsetSampleModel(int[] bands) 249: { 250: int numBands = bands.length; 251: 252: int[] bankIndices = new int[numBands]; 253: int[] bandOffsets = new int[numBands]; 254: for (int b = 0; b < numBands; b++) 255: { 256: bankIndices[b] = this.bankIndices[bands[b]]; 257: bandOffsets[b] = this.bandOffsets[bands[b]]; 258: } 259: 260: return new ComponentSampleModel(dataType, width, height, pixelStride, 261: scanlineStride, bankIndices, 262: bandOffsets); 263: } 264: 265: /** 266: * Creates a new data buffer that is compatible with this sample model. 267: * 268: * @return The new data buffer. 269: */ 270: public DataBuffer createDataBuffer() 271: { 272: // Maybe this value should be precalculated in the constructor? 273: int highestOffset = 0; 274: for (int b = 0; b < numBands; b++) 275: { 276: highestOffset = Math.max(highestOffset, bandOffsets[b]); 277: } 278: int size = pixelStride * (width - 1) + scanlineStride * (height - 1) 279: + highestOffset + 1; 280: 281: return Buffers.createBuffer(getDataType(), size, numBanks); 282: } 283: 284: /** 285: * Returns the offset of the sample in band 0 for the pixel at location 286: * <code>(x, y)</code>. This offset can be used to read a sample value from 287: * a {@link DataBuffer}. 288: * 289: * @param x the x-coordinate. 290: * @param y the y-coordinate. 291: * 292: * @return The offset. 293: * 294: * @see #getOffset(int, int, int) 295: */ 296: public int getOffset(int x, int y) 297: { 298: return getOffset(x, y, 0); 299: } 300: 301: /** 302: * Returns the offset of the sample in band <code>b</code> for the pixel at 303: * location <code>(x, y)</code>. This offset can be used to read a sample 304: * value from a {@link DataBuffer}. 305: * 306: * @param x the x-coordinate. 307: * @param y the y-coordinate. 308: * @param b the band index. 309: * 310: * @return The offset. 311: */ 312: public int getOffset(int x, int y, int b) 313: { 314: return bandOffsets[b] + pixelStride * x + scanlineStride * y; 315: } 316: 317: /** 318: * Returns the size in bits for each sample (one per band). For this sample 319: * model, each band has the same sample size and this is determined by the 320: * data type for the sample model. 321: * 322: * @return The sample sizes. 323: * 324: * @see SampleModel#getDataType() 325: */ 326: public final int[] getSampleSize() 327: { 328: int size = DataBuffer.getDataTypeSize(getDataType()); 329: int[] sizes = new int[numBands]; 330: 331: java.util.Arrays.fill(sizes, size); 332: return sizes; 333: } 334: 335: /** 336: * Returns the size in bits for the samples in the specified band. In this 337: * class, the sample size is the same for every band and is determined from 338: * the data type for the model. 339: * 340: * @param band the band index (ignored here). 341: * 342: * @return The sample size in bits. 343: * 344: * @see SampleModel#getDataType() 345: */ 346: public final int getSampleSize(int band) 347: { 348: return DataBuffer.getDataTypeSize(getDataType()); 349: } 350: 351: /** 352: * Returns the indices of the bank(s) in the {@link DataBuffer} used to 353: * store the samples for each band. The returned array is a copy, so that 354: * altering it will not impact the sample model. 355: * 356: * @return The bank indices. 357: */ 358: public final int[] getBankIndices() 359: { 360: return (int[]) bankIndices.clone(); 361: } 362: 363: /** 364: * Returns the offsets to the first sample in each band. The returned array 365: * is a copy, so that altering it will not impact the sample model. 366: * 367: * @return The offsets. 368: */ 369: public final int[] getBandOffsets() 370: { 371: return (int[]) bandOffsets.clone(); 372: } 373: 374: /** 375: * Returns the distance (in terms of element indices) between the sample for 376: * one pixel and the corresponding sample for the equivalent pixel in the 377: * next row. This is used in the calculation of the element offset for 378: * retrieving samples from a {@link DataBuffer}. 379: * 380: * @return The distance between pixel samples in consecutive rows. 381: */ 382: public final int getScanlineStride() 383: { 384: return scanlineStride; 385: } 386: 387: /** 388: * Returns the distance (in terms of element indices) between the sample for 389: * one pixel and the corresponding sample for the next pixel in a row. This 390: * is used in the calculation of the element offset for retrieving samples 391: * from a {@link DataBuffer}. 392: * 393: * @return The distance between pixel samples in the same row. 394: */ 395: public final int getPixelStride() 396: { 397: return pixelStride; 398: } 399: 400: /** 401: * Returns the number of data elements used to store the samples for one 402: * pixel. In this model, this is the same as the number of bands. 403: * 404: * @return The number of data elements used to store the samples for one 405: * pixel. 406: */ 407: public final int getNumDataElements() 408: { 409: return numBands; 410: } 411: 412: /** 413: * Returns the samples for the pixel at location <code>(x, y)</code> in 414: * a primitive array (the array type is determined by the data type for 415: * this model). The <code>obj</code> argument provides an option to supply 416: * an existing array to hold the result, if this is <code>null</code> a new 417: * array will be allocated. 418: * 419: * @param x the x-coordinate. 420: * @param y the y-coordinate. 421: * @param obj a primitive array that, if not <code>null</code>, will be 422: * used to store and return the sample values. 423: * @param data the data buffer (<code>null</code> not permitted). 424: * 425: * @return An array of sample values for the specified pixel. 426: */ 427: public Object getDataElements(int x, int y, Object obj, DataBuffer data) 428: { 429: int xyOffset = pixelStride * x + scanlineStride * y; 430: 431: int[] totalBandDataOffsets = new int[numBands]; 432: 433: /* Notice that band and bank offsets are different. Band offsets 434: are managed by the sample model, and bank offsets are managed 435: by the data buffer. Both must be accounted for. */ 436: 437: /* FIXME: For single pixels, it is probably easier to simple 438: call getElem instead of calculating the bank offset ourself. 439: 440: On the other hand, then we need to push the value through 441: the int type returned by the getElem method. */ 442: 443: int[] bankOffsets = data.getOffsets(); 444: 445: for (int b = 0; b < numBands; b++) 446: { 447: totalBandDataOffsets[b] = bandOffsets[b] + bankOffsets[bankIndices[b]] 448: + xyOffset; 449: } 450: 451: try 452: { 453: switch (getTransferType()) 454: { 455: case DataBuffer.TYPE_BYTE: 456: DataBufferByte inByte = (DataBufferByte) data; 457: byte[] outByte = (byte[]) obj; 458: if (outByte == null) 459: outByte = new byte[numBands]; 460: 461: for (int b = 0; b < numBands; b++) 462: { 463: int dOffset = totalBandDataOffsets[b]; 464: outByte[b] = inByte.getData(bankIndices[b])[dOffset]; 465: } 466: return outByte; 467: 468: case DataBuffer.TYPE_USHORT: 469: DataBufferUShort inUShort = (DataBufferUShort) data; 470: short[] outUShort = (short[]) obj; 471: if (outUShort == null) 472: outUShort = new short[numBands]; 473: 474: for (int b = 0; b < numBands; b++) 475: { 476: int dOffset = totalBandDataOffsets[b]; 477: outUShort[b] = inUShort.getData(bankIndices[b])[dOffset]; 478: } 479: return outUShort; 480: 481: case DataBuffer.TYPE_SHORT: 482: DataBufferShort inShort = (DataBufferShort) data; 483: short[] outShort = (short[]) obj; 484: if (outShort == null) 485: outShort = new short[numBands]; 486: 487: for (int b = 0; b < numBands; b++) 488: { 489: int dOffset = totalBandDataOffsets[b]; 490: outShort[b] = inShort.getData(bankIndices[b])[dOffset]; 491: } 492: return outShort; 493: 494: case DataBuffer.TYPE_INT: 495: DataBufferInt inInt = (DataBufferInt) data; 496: int[] outInt = (int[]) obj; 497: if (outInt == null) 498: outInt = new int[numBands]; 499: 500: for (int b = 0; b < numBands; b++) 501: { 502: int dOffset = totalBandDataOffsets[b]; 503: outInt[b] = inInt.getData(bankIndices[b])[dOffset]; 504: } 505: return outInt; 506: 507: case DataBuffer.TYPE_FLOAT: 508: DataBufferFloat inFloat = (DataBufferFloat) data; 509: float[] outFloat = (float[]) obj; 510: if (outFloat == null) 511: outFloat = new float[numBands]; 512: 513: for (int b = 0; b < numBands; b++) 514: { 515: int dOffset = totalBandDataOffsets[b]; 516: outFloat[b] = inFloat.getData(bankIndices[b])[dOffset]; 517: } 518: return outFloat; 519: 520: case DataBuffer.TYPE_DOUBLE: 521: DataBufferDouble inDouble = (DataBufferDouble) data; 522: double[] outDouble = (double[]) obj; 523: if (outDouble == null) 524: outDouble = new double[numBands]; 525: 526: for (int b = 0; b < numBands; b++) 527: { 528: int dOffset = totalBandDataOffsets[b]; 529: outDouble[b] = inDouble.getData(bankIndices[b])[dOffset]; 530: } 531: return outDouble; 532: 533: default: 534: throw new IllegalStateException("unknown transfer type " 535: + getTransferType()); 536: } 537: } 538: catch (ArrayIndexOutOfBoundsException aioobe) 539: { 540: String msg = "While reading data elements, " + 541: "x=" + x + ", y=" + y +", " + ", xyOffset=" + xyOffset + 542: ", data.getSize()=" + data.getSize() + ": " + aioobe; 543: throw new ArrayIndexOutOfBoundsException(msg); 544: } 545: } 546: 547: /** 548: * Returns the samples for the pixels in the region defined by 549: * <code>(x, y, w, h)</code> in a primitive array (the array type is 550: * determined by the data type for this model). The <code>obj</code> 551: * argument provides an option to supply an existing array to hold the 552: * result, if this is <code>null</code> a new array will be allocated. 553: * 554: * @param x the x-coordinate. 555: * @param y the y-coordinate. 556: * @param w the width. 557: * @param h the height. 558: * @param obj a primitive array that, if not <code>null</code>, will be 559: * used to store and return the sample values. 560: * @param data the data buffer (<code>null</code> not permitted). 561: * 562: * @return An array of sample values for the specified pixels. 563: * 564: * @see #setDataElements(int, int, int, int, Object, DataBuffer) 565: */ 566: public Object getDataElements(int x, int y, int w, int h, Object obj, 567: DataBuffer data) 568: { 569: if (!tightPixelPacking) 570: { 571: return super.getDataElements(x, y, w, h, obj, data); 572: } 573: 574: // using get speedup 575: 576: // We can copy whole rows 577: int rowSize = w * numBands; 578: int dataSize = rowSize * h; 579: 580: DataBuffer transferBuffer = Buffers.createBuffer(getTransferType(), obj, 581: dataSize); 582: obj = Buffers.getData(transferBuffer); 583: 584: int inOffset = pixelStride * x + scanlineStride * y + data.getOffset(); 585: // Assumes only one band is used 586: 587: /* We don't add band offsets since we assume that bands have 588: offsets 0, 1, 2, ... */ 589: 590: // See if we can copy everything in one go 591: if (scanlineStride == rowSize) 592: { 593: // Collapse scan lines: 594: rowSize *= h; 595: // We ignore scanlineStride since it won't be of any use 596: h = 1; 597: } 598: 599: int outOffset = 0; 600: Object inArray = Buffers.getData(data); 601: for (int yd = 0; yd < h; yd++) 602: { 603: System.arraycopy(inArray, inOffset, obj, outOffset, rowSize); 604: inOffset += scanlineStride; 605: outOffset += rowSize; 606: } 607: return obj; 608: } 609: 610: /** 611: * Sets the samples for the pixels in the region defined by 612: * <code>(x, y, w, h)</code> from a supplied primitive array (the array type 613: * must be consistent with the data type for this model). 614: * 615: * @param x the x-coordinate. 616: * @param y the y-coordinate. 617: * @param w the width. 618: * @param h the height. 619: * @param obj a primitive array containing the sample values. 620: * @param data the data buffer (<code>null</code> not permitted). 621: * 622: * @see #getDataElements(int, int, int, int, Object, DataBuffer) 623: */ 624: public void setDataElements(int x, int y, int w, int h, 625: Object obj, DataBuffer data) 626: { 627: if (!tightPixelPacking) 628: { 629: super.setDataElements(x, y, w, h, obj, data); 630: return; 631: } 632: 633: // using set speedup, we can copy whole rows 634: int rowSize = w * numBands; 635: int dataSize = rowSize * h; 636: 637: DataBuffer transferBuffer 638: = Buffers.createBufferFromData(getTransferType(), obj, dataSize); 639: 640: int[] bankOffsets = data.getOffsets(); 641: 642: int outOffset = pixelStride * x + scanlineStride * y + bankOffsets[0]; 643: // same assumptions as in get... 644: 645: // See if we can copy everything in one go 646: if (scanlineStride == rowSize) 647: { 648: // Collapse scan lines: 649: rowSize *= h; 650: h = 1; 651: } 652: 653: int inOffset = 0; 654: Object outArray = Buffers.getData(data); 655: for (int yd = 0; yd < h; yd++) 656: { 657: System.arraycopy(obj, inOffset, outArray, outOffset, rowSize); 658: outOffset += scanlineStride; 659: inOffset += rowSize; 660: } 661: } 662: 663: /** 664: * Returns all the samples for the pixel at location <code>(x, y)</code> 665: * stored in the specified data buffer. 666: * 667: * @param x the x-coordinate. 668: * @param y the y-coordinate. 669: * @param iArray an array that will be populated with the sample values and 670: * returned as the result. The size of this array should be equal to the 671: * number of bands in the model. If the array is <code>null</code>, a new 672: * array is created. 673: * @param data the data buffer (<code>null</code> not permitted). 674: * 675: * @return The samples for the specified pixel. 676: * 677: * @see #setPixel(int, int, int[], DataBuffer) 678: */ 679: public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) 680: { 681: int offset = pixelStride * x + scanlineStride * y; 682: if (iArray == null) 683: iArray = new int[numBands]; 684: for (int b = 0; b < numBands; b++) 685: { 686: iArray[b] = data.getElem(bankIndices[b], offset + bandOffsets[b]); 687: } 688: return iArray; 689: } 690: 691: /** 692: * Returns the samples for all the pixels in a rectangular region. 693: * 694: * @param x the x-coordinate. 695: * @param y the y-coordinate. 696: * @param w the width. 697: * @param h the height. 698: * @param iArray an array that if non-<code>null</code> will be populated 699: * with the sample values and returned as the result. 700: * @param data the data buffer (<code>null</code> not permitted). 701: * 702: * @return The samples for all the pixels in the rectangle. 703: */ 704: public int[] getPixels(int x, int y, int w, int h, int[] iArray, 705: DataBuffer data) 706: { 707: int offset = pixelStride * x + scanlineStride * y; 708: if (iArray == null) 709: iArray = new int[numBands * w * h]; 710: int outOffset = 0; 711: for (y = 0; y < h; y++) 712: { 713: int lineOffset = offset; 714: for (x = 0; x < w; x++) 715: { 716: for (int b = 0; b < numBands; b++) 717: { 718: iArray[outOffset++] 719: = data.getElem(bankIndices[b], lineOffset+bandOffsets[b]); 720: } 721: lineOffset += pixelStride; 722: } 723: offset += scanlineStride; 724: } 725: return iArray; 726: } 727: 728: /** 729: * Returns the sample for band <code>b</code> of the pixel at 730: * <code>(x, y)</code> that is stored in the specified data buffer. 731: * 732: * @param x the x-coordinate. 733: * @param y the y-coordinate. 734: * @param b the band index. 735: * @param data the data buffer (<code>null</code> not permitted). 736: * 737: * @return The sample value. 738: * 739: * @see #setSample(int, int, int, int, DataBuffer) 740: */ 741: public int getSample(int x, int y, int b, DataBuffer data) 742: { 743: return data.getElem(bankIndices[b], getOffset(x, y, b)); 744: } 745: 746: /** 747: * Sets the samples for the pixel at location <code>(x, y)</code> from the 748: * supplied primitive array (the array type must be consistent with the data 749: * type for this model). 750: * 751: * @param x the x-coordinate. 752: * @param y the y-coordinate. 753: * @param obj a primitive array containing the pixel's sample values. 754: * @param data the data buffer (<code>null</code> not permitted). 755: * 756: * @see #setDataElements(int, int, Object, DataBuffer) 757: */ 758: public void setDataElements(int x, int y, Object obj, DataBuffer data) 759: { 760: int offset = pixelStride * x + scanlineStride * y; 761: int[] totalBandDataOffsets = new int[numBands]; 762: int[] bankOffsets = data.getOffsets(); 763: for (int b = 0; b < numBands; b++) 764: totalBandDataOffsets[b] = bandOffsets[b] + bankOffsets[bankIndices[b]] 765: + offset; 766: 767: switch (getTransferType()) 768: { 769: case DataBuffer.TYPE_BYTE: 770: { 771: DataBufferByte out = (DataBufferByte) data; 772: byte[] in = (byte[]) obj; 773: 774: for (int b = 0; b < numBands; b++) 775: out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b]; 776: 777: return; 778: } 779: case DataBuffer.TYPE_USHORT: 780: { 781: DataBufferUShort out = (DataBufferUShort) data; 782: short[] in = (short[]) obj; 783: 784: for (int b = 0; b < numBands; b++) 785: out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b]; 786: 787: return; 788: } 789: case DataBuffer.TYPE_SHORT: 790: { 791: DataBufferShort out = (DataBufferShort) data; 792: short[] in = (short[]) obj; 793: 794: for (int b = 0; b < numBands; b++) 795: out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b]; 796: 797: return; 798: } 799: case DataBuffer.TYPE_INT: 800: { 801: DataBufferInt out = (DataBufferInt) data; 802: int[] in = (int[]) obj; 803: 804: for (int b = 0; b < numBands; b++) 805: out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b]; 806: 807: return; 808: } 809: case DataBuffer.TYPE_FLOAT: 810: { 811: DataBufferFloat out = (DataBufferFloat) data; 812: float[] in = (float[]) obj; 813: 814: for (int b = 0; b < numBands; b++) 815: out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b]; 816: 817: return; 818: } 819: case DataBuffer.TYPE_DOUBLE: 820: { 821: DataBufferDouble out = (DataBufferDouble) data; 822: double[] in = (double[]) obj; 823: 824: for (int b = 0; b < numBands; b++) 825: out.getData(bankIndices[b])[totalBandDataOffsets[b]] = in[b]; 826: 827: return; 828: } 829: default: 830: throw new UnsupportedOperationException("transfer type not " + 831: "implemented"); 832: } 833: } 834: 835: /** 836: * Sets the sample values for the pixel at location <code>(x, y)</code> 837: * stored in the specified data buffer. 838: * 839: * @param x the x-coordinate. 840: * @param y the y-coordinate. 841: * @param iArray the pixel sample values (<code>null</code> not permitted). 842: * @param data the data buffer (<code>null</code> not permitted). 843: * 844: * @see #getPixel(int, int, int[], DataBuffer) 845: */ 846: public void setPixel(int x, int y, int[] iArray, DataBuffer data) 847: { 848: int offset = pixelStride * x + scanlineStride * y; 849: for (int b = 0; b < numBands; b++) 850: data.setElem(bankIndices[b], offset + bandOffsets[b], iArray[b]); 851: } 852: 853: /** 854: * Sets the sample value for band <code>b</code> of the pixel at location 855: * <code>(x, y)</code> in the specified data buffer. 856: * 857: * @param x the x-coordinate. 858: * @param y the y-coordinate. 859: * @param b the band index. 860: * @param s the sample value. 861: * @param data the data buffer (<code>null</code> not permitted). 862: * 863: * @see #getSample(int, int, int, DataBuffer) 864: */ 865: public void setSample(int x, int y, int b, int s, DataBuffer data) 866: { 867: data.setElem(bankIndices[b], getOffset(x, y, b), s); 868: } 869: 870: /** 871: * Tests this sample model for equality with an arbitrary object. Returns 872: * <code>true</code> if and only if: 873: * <ul> 874: * <li><code>obj</code> is not <code>null</code>;</li> 875: * <li><code>obj</code> is an instance of <code>ComponentSampleModel</code>; 876: * </li> 877: * <li>both models have the same values for the <code>dataType</code>, 878: * <code>width</code>, <code>height</code>, <code>pixelStride</code>, 879: * <code>scanlineStride</code>, <code>bandOffsets</code> and 880: * <code>bankIndices</code> fields.</li> 881: * </ul> 882: * 883: * @param obj the object to test (<code>null</code> permitted). 884: * 885: * @return <code>true</code> if this sample model is equal to 886: * <code>obj</code>, and <code>false</code> otherwise. 887: */ 888: public boolean equals(Object obj) 889: { 890: if (obj == null) 891: return false; 892: if (! (obj instanceof ComponentSampleModel)) 893: return false; 894: ComponentSampleModel that = (ComponentSampleModel) obj; 895: if (this.dataType != that.dataType) 896: return false; 897: if (this.width != that.width) 898: return false; 899: if (this.height != that.height) 900: return false; 901: if (this.pixelStride != that.pixelStride) 902: return false; 903: if (this.scanlineStride != that.scanlineStride) 904: return false; 905: if (! Arrays.equals(this.bandOffsets, that.bandOffsets)) 906: return false; 907: if (! Arrays.equals(this.bankIndices, that.bankIndices)) 908: return false; 909: // couldn't find any difference, so... 910: return true; 911: } 912: 913: /** 914: * Returns a hash code for this sample model. 915: * 916: * @return The hash code. 917: */ 918: public int hashCode() 919: { 920: // this computation is based on the method described in Chapter 3 921: // of Joshua Bloch's Effective Java... 922: int result = 17; 923: result = 37 * result + dataType; 924: result = 37 * result + width; 925: result = 37 * result + height; 926: result = 37 * result + pixelStride; 927: result = 37 * result + scanlineStride; 928: for (int i = 0; i < bandOffsets.length; i++) 929: result = 37 * result + bandOffsets[i]; 930: for (int i = 0; i < bankIndices.length; i++) 931: result = 37 * result + bankIndices[i]; 932: return result; 933: } 934: }